/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef __avmplus_VectorClass_impl__
#define __avmplus_VectorClass_impl__

namespace avmplus
{
    // ----------------------------

    Atom TypedVectorClassBase::call(int argc, Atom* argv)
    {
        Toplevel* toplevel = this->toplevel();
        AvmCore* core = toplevel->core();
        
        if (argc != 1)
            toplevel->throwArgumentError(kCoerceArgumentCountError, core->toErrorString(argc));

        Traits* itraits = ivtable()->traits;
        if (AvmCore::istype(argv[1], itraits))
            return argv[1];

        if (!AvmCore::isObject(argv[1]))
            toplevel->throwTypeError(kCheckTypeFailedError, core->atomToErrorString(argv[1]), core->toErrorString(itraits));

        ScriptObject* so_args = AvmCore::atomToScriptObject(argv[1]);
        uint32_t len = so_args->getLengthProperty();
        return createAndInitVectorFromObject(so_args, len);
    }

    void TypedVectorClassBase::_forEach(Atom thisAtom, ScriptObject* callback, Atom thisObject)
    {
        return ArrayClass::generic_forEach(toplevel(), thisAtom, callback, thisObject);
    }
    
    bool TypedVectorClassBase::_every(Atom thisAtom, ScriptObject* callback, Atom thisObject)
    {
        return ArrayClass::generic_every(toplevel(), thisAtom, callback, thisObject);
    }
    
    bool TypedVectorClassBase::_some(Atom thisAtom, ScriptObject* callback, Atom thisObject)
    {
        return ArrayClass::generic_some(toplevel(), thisAtom, callback, thisObject);
    }
    
    Atom TypedVectorClassBase::_sort(Atom thisAtom, ArrayObject* args)
    {
        return ArrayClass::generic_sort(toplevel(), thisAtom, args);
    }

    // ----------------------------

    template<class OBJ>
    TypedVectorClass<OBJ>::TypedVectorClass(VTable* vtable)
        : TypedVectorClassBase(vtable)
    {
        setPrototypePtr(toplevel()->objectClass->construct());
    }

    template<class OBJ>
    OBJ* TypedVectorClass<OBJ>::newVector(uint32_t length, bool fixed)
    {
        OBJ* v = (OBJ*)OBJ::create(gc(), ivtable(), prototypePtr());
        v->m_vecClass = this;
        if (length > 0)
            v->set_length(length);
        v->m_fixed = fixed;
        return v;
    }

    template<class OBJ>
    Atom TypedVectorClass<OBJ>::createAndInitVectorFromObject(ScriptObject* so_args, uint32_t len)
    {
        OBJ* v = newVector();
        v->_spliceHelper_so(0, len, 0, so_args, 0);
        return v->atom();
    }

    template<class OBJ>
    Atom TypedVectorClass<OBJ>::constructImpl(int argc, Atom* argv)
    {
        uint32_t len = 0;
        bool fixed = false;
        if (argc > 0)
        {
            len = AvmCore::toUInt32(argv[1]);
            if (argc > 1)
            {
                fixed = AvmCore::boolean(argv[2]) != 0;
                if (argc > 2)
                {
                    vtable->init->argcError(argc);
                }
            }
        }
        OBJ* v = newVector(len, fixed);
        return v->atom();
    }

    // ----------------------------

    VectorBaseObject::VectorBaseObject(VTable* ivtable, ScriptObject* delegate)
        : ScriptObject(ivtable, delegate)
        , m_vecClass(NULL)
        , m_fixed(false)
    {
    }

    VectorBaseObject* VectorBaseObject::_newVector()
    {
        AvmAssert(m_vecClass != NULL);
        Atom args[1] = { nullObjectAtom };
        return (VectorBaseObject*)AvmCore::atomToScriptObject(m_vecClass->construct(0, args));
    }

    void FASTCALL VectorBaseObject::throwFixedError() const
    {
        toplevel()->throwRangeError(kVectorFixedError);
    }

    Atom VectorBaseObject::_mapImpl(ScriptObject* callback, Atom thisObject, VectorBaseObject* r, uint32_t len)
    {
        AvmCore* core = this->core();
        if (callback)
        {
            ScriptObject* d = this;
            for (uint32_t i = 0; i < len; i++)
            {
                // If thisObject is null, the call function will substitute the global object
                // args are modified in place by callee
                Atom args[4] = {
                    thisObject,
                    d->getUintProperty(i), // element
                    core->uintToAtom(i), // index
                    this->atom()
                };
                Atom result = callback->call(3, args);
                r->setUintProperty(i, result);
            }
        }
        return r->atom();
    }

    Atom VectorBaseObject::_filterImpl(ScriptObject* callback, Atom thisObject, VectorBaseObject* r, uint32_t len)
    {
        AvmCore* core = this->core();
        if (callback)
        {
            ScriptObject* d = this;
            for (uint32_t i = 0, k = 0; i < len; i++)
            {
                // If thisObject is null, the call function will substitute the global object
                // args are modified in place by callee
                Atom element = d->getUintProperty(i);
                Atom args[4] = {
                    thisObject,
                    element,
                    core->uintToAtom(i), // index
                    this->atom()
                };
                Atom result = callback->call(3, args);
                if (result == trueAtom)
                    r->setUintProperty(k++, element);
            }
        }
        return r->atom();
    }

    // ----------------------------

    template<class TLIST>
    TypedVectorObject<TLIST>::TypedVectorObject(VTable* ivtable, ScriptObject* delegate)
        : VectorBaseObject(ivtable, delegate)
#ifdef DEBUGGER
        , m_created(false)
        , m_flushBeforeConstructionComplete(false)
#endif
        , m_list(ivtable->gc(), 0)
    {
#ifdef DEBUGGER
        m_created = true;
        if (m_flushBeforeConstructionComplete) {
            registerDependentObjects(getSampler());
            getSampler()->recordObjectReallocation(this);
        }
#endif
    }

    template<class TLIST>
    bool TypedVectorObject<TLIST>::hasAtomProperty(Atom name) const
    {
        uint32_t index;
        VectorIndexStatus status = getVectorIndex(name, index);
        if (status == kValidNumber)
        {
            return index < m_list.length();
        }
        else if (status == kInvalidNumber)
        {
            if (core()->currentBugCompatibility()->bugzilla456852b)
                return false;
            else if (!isNegativeVectorIndexAtom(name))
                // Prior to SWF11, isNumber was incorrectly set false for negative numbers,
                // so we fall through and allow searching the prototype chain for these.
                // See getAtomProperty() below.
                return false;
        }

        // status == kNotNumber, or index is negative and compatibility is earlier than SWF11.
        return ScriptObject::hasAtomProperty(name);
    }
        
    template<class TLIST>
    void TypedVectorObject<TLIST>::setAtomProperty(Atom name, Atom value)
    {
        uint32_t index;
        VectorIndexStatus status = getVectorIndex(name, index);
        if (status == kValidNumber)
        {
            setUintProperty(index, value);
        }
        else if (status == kInvalidNumber && core()->currentBugCompatibility()->bugzilla456852b)
        {
            throwRangeError_a(name);
        }
        else
        {
            toplevel()->throwReferenceError(kWriteSealedError, core()->string(name), traits());
        }
    }
        
    template<class TLIST>
    Atom TypedVectorObject<TLIST>::getAtomProperty(Atom name) const
    {
        uint32_t index;
        VectorIndexStatus status = getVectorIndex(name, index);
        if (status == kValidNumber)
        {
            return getUintProperty(index);
        }
        else if (status == kInvalidNumber)
        {
            if (core()->currentBugCompatibility()->bugzilla456852b)
            {
                throwRangeError_a(name);
                return undefinedAtom; // not reached
            }
            else if (!isNegativeVectorIndexAtom(name))
            {
                // Prior to SWF11, isNumber was incorrectly set false for negative numbers.
                toplevel()->throwReferenceError(kReadSealedError, core()->string(name), traits());
                return undefinedAtom; // not reached
            }
        }

        // status == kNotNumber, or index is negative and compatibility is earlier than SWF11.
        // Check the prototype chain - that will throw if there is no match.
        return getAtomPropertyFromProtoChain(name, getDelegate(), traits());
    }

    template<class TLIST>
    /*virtual*/ uint32_t TypedVectorObject<TLIST>::getLength() const
    {
        return get_length();
    }

    template<class TLIST>
    /*virtual*/ void TypedVectorObject<TLIST>::setLength(uint32_t length)
    {
        set_length(length);
    }
	
#ifdef VMCFG_VECTOR_SMASH_PROTECTION
    template<class TLIST>
    /*virtual*/ void TypedVectorObject<TLIST>::setLengthUnchecked(uint32_t length)
    {
        m_list.set_length_unchecked(length);
    }
#endif

    template<class TLIST>
    void TypedVectorObject<TLIST>::set_length(uint32_t newLength)
    {
        checkFixed();
        // this is what the old code did, so we'll do it too: set the capacity explicitly if we grow
        if (newLength > m_list.capacity())
        {
            m_list.set_capacity(newLength);
        }
        m_list.set_length(newLength);
    }
        
    template<class TLIST>
    Atom TypedVectorObject<TLIST>::nextName(int index)
    {
        AvmAssert(index > 0);
        if (uint32_t(index) <= m_list.length())
        {
            return core()->intToAtom(index-1);
        }
        else
        {
            return nullStringAtom;
        }
    }
        
    template<class TLIST>
    Atom TypedVectorObject<TLIST>::nextValue(int index)
    {
        AvmAssert(index > 0);
        if (uint32_t(index) <= m_list.length())
        {
            return getUintProperty(index-1);
        }
        else
        {
            return undefinedAtom;
        }
    }
        
    template<class TLIST>
    int TypedVectorObject<TLIST>::nextNameIndex(int index)
    {
        if (uint32_t(index) < m_list.length())
        {
            return index + 1;
        }
        else
        {
            return 0;
        }
    }
        
    template<class TLIST>
    Atom TypedVectorObject<TLIST>::_map(ScriptObject* callback, Atom thisObject)
    {
        TypedVectorObject<TLIST>* r = (TypedVectorObject<TLIST>*)_newVector();
        uint32_t const len = m_list.length();
        r->set_length(len);
        return _mapImpl(callback, thisObject, r, len);
    }

    template<class TLIST>
    Atom TypedVectorObject<TLIST>::_filter(ScriptObject* callback, Atom thisObject)
    {
        TypedVectorObject<TLIST>* r = (TypedVectorObject<TLIST>*)_newVector();
        uint32_t const len = m_list.length();
        return _filterImpl(callback, thisObject, r, len);
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_spliceHelper_so(uint32_t insertPoint, uint32_t insertCount, uint32_t deleteCount, ScriptObject* so_args, uint32_t offset)
    {
        AvmAssert(!AvmCore::istype(so_args->atom(), vtable->traits));

        // NB: so_args could be any kind of object, but in practice,
        // it's almost always an ArrayObject; it might be profitable
        // to sniff for that case and optimize appropriately.

        // passing NULL for args inserts the proper space, but leaves the inserted entries empty
        m_list.splice(insertPoint, insertCount, deleteCount, NULL);
        for (uint32_t i = 0; i < insertCount; i++)
        {
            typename TLIST::OPAQUE_TYPE value;
            atomToValue(so_args->getUintProperty(i+offset), value);
            m_list.set(insertPoint+i, (typename TLIST::TYPE)value);
        }
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_spliceHelper(uint32_t insertPoint, uint32_t insertCount, uint32_t deleteCount, Atom args, uint32_t offset)
    {
        if (AvmCore::istype(args, vtable->traits))
        {
            TypedVectorObject<TLIST>* vec_args = (TypedVectorObject<TLIST>*)AvmCore::atomToScriptObject(args);
            m_list.splice(insertPoint, insertCount, deleteCount, vec_args->m_list, offset);
        }
        else if (AvmCore::isObject(args))
        {
            ScriptObject* so_args = AvmCore::atomToScriptObject(args);
            _spliceHelper_so(insertPoint, insertCount, deleteCount, so_args, offset);
        }
        else
        {
            AvmAssert(insertCount == 0);
            m_list.splice(insertPoint, 0, deleteCount, NULL);
        }
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_splice(uint32_t insertPoint, uint32_t insertCount, uint32_t deleteCount, const Atom* argv)
    {
        // passing NULL for args inserts the proper space, but leaves the inserted entries empty
        m_list.splice(insertPoint, insertCount, deleteCount, NULL);
        for (uint32_t i = 0; i < insertCount; i++)
        {
            typename TLIST::OPAQUE_TYPE value;
            atomToValue(argv[i], value);
            m_list.set(insertPoint+i, (typename TLIST::TYPE)value);
        }
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::AS3_insertAt(int32_t index, typename TLIST::TYPE element)
    {
        // Throw exception for fixed Vector.  Note that splice() fails to do so, contrary to documentation.
        // This is a bug, which we choose not to propagate here.  Fixing splice() will require versioning.
        checkFixed();
        // Convert index argument to unsigned index into the underlying list.  Negative values count
        // backwards from last element. Resulting list index is clamped to interval (0, length), so it
        // can never be out-of-bounds.
        uint32_t insertPoint;
        if (index < 0)
        {
            uint32_t length = m_list.length();
            if (int32_t(length) + index < 0)
			{
                insertPoint = 0;
			}
            else
			{
                insertPoint = length + index;
			}
        }
        else
        {
            insertPoint = uint32_t(index);
        }
        // TLIST::insert() will further clamp index to length.
        m_list.insert(insertPoint, element);
    }
	
	// Template specialization.
    template<>
    void TypedVectorObject<AtomList>::AS3_insertAt(int32_t index, Atom element)
    {
		// Vector$Object is used for Vector.<T> for any reference type T,
		// i.e., a subclass of Object, not just Object itself.  We must perform
		// an explicit coercion/typecheck here to enforce the expected element type.
		// The coercion notionally takes place at the call site, so do it first.
        AvmAssert(m_vecClass != NULL);
        Atom value = avmplus::coerce(toplevel(), element, m_vecClass->getTypeTraits());

        // Throw exception for fixed Vector.  Note that splice() fails to do so, contrary to documentation.
        // This is a bug, which we choose not to propagate here.  Fixing splice() will require versioning.
        checkFixed();
        // Convert index argument to unsigned index into the underlying list.  Negative values count
        // backwards from last element. Resulting list index is clamped to interval (0, length), so it
        // can never be out-of-bounds.
        uint32_t insertPoint;
        if (index < 0)
        {
            uint32_t length = m_list.length();
            if (int32_t(length) + index < 0)
			{
                insertPoint = 0;
			}
            else
			{
                insertPoint = length + index;
			}
        }
        else
        {
            insertPoint = uint32_t(index);
        }
        // TLIST::insert() will further clamp index to length.
        m_list.insert(insertPoint, value);
    }
	
    template<class TLIST>
    typename TLIST::TYPE TypedVectorObject<TLIST>::AS3_removeAt(int32_t index)
    {
        // Throw exception for fixed Vector.  Note that splice() fails to do so, contrary to documentation.
        // This is a bug, which we choose not to propagate here.  Fixing splice() will require versioning.
        checkFixed();
        // Convert index argument to unsigned index into the underlying list.  Negative values count
        // backwards from last element. Resulting list index must point to valid element, otherwise out-of-bounds.
        uint32_t removePoint;
        uint32_t length = m_list.length();
        if (index < 0)
        {
            if (int32_t(length) + index < 0)
            {
                removePoint = 0;
            }
            else
			{
                removePoint = length + index;
			}
        }
        else
        {
            removePoint = uint32_t(index);
        }
        // Curiously, vec.splice(n, 1) for empty vector v does not throw, instead returning an empty vector,
        // but vec.removeAt(n) is defined to be equal to vec.splice(n, 1)[0], so we will throw in this case
        // as well.  The diagnostic message, however, will reflect the actual index, however, rather than 0.
        if (removePoint >= length)
        {
            throwRangeError_u(removePoint);
        }
        return m_list.removeAt(removePoint);
    }

    template<class TLIST>
    uint32_t TypedVectorObject<TLIST>::AS3_push(Atom* argv, int argc)
    {
        checkFixed();
        _splice(m_list.length(), argc, 0, argv);
        return m_list.length();
    }

    template<class TLIST>
    typename TLIST::TYPE TypedVectorObject<TLIST>::AS3_pop()
    {
        checkFixed();
        return m_list.isEmpty() ?
                (typename TLIST::TYPE)TypedVectorConstants<typename TLIST::OPAQUE_TYPE>::undefinedValue() :
                m_list.removeLast();
    }

#ifdef VMCFG_FLOAT
    template<class TLIST>
    void TypedVectorObject<TLIST>::AS3_pop(typename TLIST::TYPE* retval)
    {
        checkFixed();
        *retval = m_list.isEmpty() ?
        (typename TLIST::TYPE)TypedVectorConstants<typename TLIST::OPAQUE_TYPE>::undefinedValue() :
        m_list.removeLast();
    }
#endif
    
    template<class TLIST>
    typename TLIST::TYPE TypedVectorObject<TLIST>::AS3_shift()
    {
        checkFixed();
        return m_list.isEmpty() ?
                (typename TLIST::TYPE)TypedVectorConstants<typename TLIST::OPAQUE_TYPE>::undefinedValue() :
                m_list.removeFirst();
    }

#ifdef VMCFG_FLOAT
    template<class TLIST>
    void TypedVectorObject<TLIST>::AS3_shift(typename TLIST::TYPE* retval)
    {
        checkFixed();
        *retval = m_list.isEmpty() ?
        (typename TLIST::TYPE)TypedVectorConstants<typename TLIST::OPAQUE_TYPE>::undefinedValue() :
        m_list.removeFirst();
    }
#endif
    
    template<class TLIST>
    uint32_t TypedVectorObject<TLIST>::AS3_unshift(Atom* argv, int argc)
    {
        checkFixed();
        _splice(0, argc, 0, argv);
        return m_list.length();
    }

    template<class TLIST>
    REALLY_INLINE typename TLIST::TYPE TypedVectorObject<TLIST>::_getNativeIntProperty(int32_t index_i) const
    {
        AvmAssertMsg(!IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _getNativeIntProperty helper used for Vector.<float4>");
        uint32_t const index = checkReadIndex_i(index_i);
        return m_list.get(index);
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_setNativeIntProperty(int32_t index_i, typename TLIST::TYPE value)
    {
        AvmAssertMsg(!IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _setNativeIntProperty helper used for Vector.<float4>");
        uint32_t const index = checkWriteIndex_i(index_i);
       	m_list.set(index, value);
    }

#ifdef VMCFG_AOT
    template<class TLIST>
    NO_INLINE void TypedVectorObject<TLIST>::_setNativeIntPropertySlow(int32_t index_i, typename TLIST::TYPE value)
    {
        uint32_t const length = m_list.length();
        AvmAssert(uint32_t(index_i) >= length);
        uint32_t const limit = length + 1 - uint32_t(m_fixed);
        if (uint32_t(index_i) >= limit)
            throwRangeError_i(index_i);
        AvmAssertMsg(!IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _setNativeIntProperty helper used for Vector.<float4>");
		m_list.set((uint32_t)index_i, value);
    }
#endif

    template<class TLIST>
    typename TLIST::TYPE TypedVectorObject<TLIST>::_getNativeUintProperty(uint32_t index) const
    {
        AvmAssertMsg(!IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _getNativeUIntProperty helper used for Vector.<float4>");
        checkReadIndex_u(index);
        return m_list.get(index);
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_setNativeUintProperty(uint32_t index, typename TLIST::TYPE value)
    {
        AvmAssertMsg(!IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _setNativeUIntProperty helper used for Vector.<float4>");
        checkWriteIndex_u(index);
        m_list.set(index, value);
    }

    template<class TLIST>
    typename TLIST::TYPE TypedVectorObject<TLIST>::_getNativeDoubleProperty(double index_d) const
    {
        AvmAssertMsg(!IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _getNativeDoubleProperty helper used for Vector.<float4>");
        uint32_t const index = checkReadIndex_d(index_d);
        return m_list.get(index);
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_setNativeDoubleProperty(double index_d, typename TLIST::TYPE value)
    {
        AvmAssertMsg(!IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _setNativeDoubleProperty helper used for Vector.<float4>");
        uint32_t const index = checkWriteIndex_d(index_d);
        m_list.set(index, value);
    }

#ifdef VMCFG_FLOAT
    template<class TLIST>
    void TypedVectorObject<TLIST>::_getFloat4IntProperty(typename TLIST::TYPE* result, int32_t index_i) const
    {
        AvmAssertMsg(IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _getNativeIntProperty helper used for Vector.<*>");
        uint32_t const index = checkReadIndex_i(index_i);
        if(result) 
            *result = m_list.get(index);
        return;
    }
    
    template<class TLIST>
    void TypedVectorObject<TLIST>::_setFloat4IntProperty(int32_t index_i, const typename TLIST::TYPE& value)
    {
        AvmAssertMsg(IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _setNativeIntProperty helper used for Vector.<*>");
        uint32_t const index = checkWriteIndex_i(index_i);
        m_list.set(index, value);
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_getFloat4UintProperty(typename TLIST::TYPE* result, uint32_t index) const
    {
        AvmAssertMsg(IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _getNativeUIntProperty helper used for Vector.<*>");
        checkReadIndex_u(index);
        if(result) 
            *result = m_list.get(index);
        return;
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_setFloat4UintProperty(uint32_t index, const typename TLIST::TYPE& value)
    {
        AvmAssertMsg(IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _setNativeUIntProperty helper used for Vector.<*>");
        checkWriteIndex_u(index);
        m_list.set(index, value);
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_getFloat4DoubleProperty(typename TLIST::TYPE* result, double index_d) const
    {
        AvmAssertMsg(IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _getNativeDoubleProperty helper used for Vector.<*>");
        uint32_t const index = checkReadIndex_d(index_d);
        if(result) 
            *result = m_list.get(index);
        return;
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_setFloat4DoubleProperty(double index_d, const typename TLIST::TYPE& value)
    {
        AvmAssertMsg(IS_FLOAT4_TYPE(typename TLIST::TYPE), "wrong _setNativeDoubleProperty helper used for Vector.<*>");
        uint32_t const index = checkWriteIndex_d(index_d);
        m_list.set(index, value); // needed to compile for most types; hopefully the useless call will be optimized-away.
    }
#endif

    template<class TLIST>
    bool TypedVectorObject<TLIST>::_hasUintProperty(uint32_t index) const
    {
        return (index < m_list.length());
    }

    template<class TLIST>
    Atom TypedVectorObject<TLIST>::_getUintProperty(uint32_t index) const
    {
        checkReadIndex_u(index);
        return valueToAtom((typename TLIST::OPAQUE_TYPE)m_list.get(index));
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_setUintProperty(uint32_t index, Atom value)
    {
        typename TLIST::OPAQUE_TYPE tmp;
        atomToValue(value, tmp);
        checkWriteIndex_u(index);
        m_list.set(index, (typename TLIST::TYPE)tmp);
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_setKnownUintProperty(uint32_t index, Atom value)
    {
        typename TLIST::OPAQUE_TYPE tmp;
        atomToValueKnown(value, tmp);
        checkWriteIndex_u(index);
        m_list.set(index, (typename TLIST::TYPE)tmp);
    }
    
    template<class TLIST>
    Atom TypedVectorObject<TLIST>::_getIntProperty(int32_t index_i) const
    {
        uint32_t const index = checkReadIndex_i(index_i);
        return valueToAtom((typename TLIST::OPAQUE_TYPE)m_list.get(index));
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_setIntProperty(int32_t index_i, Atom value)
    {
        typename TLIST::OPAQUE_TYPE tmp;
        atomToValue(value, tmp);
        uint32_t index = checkWriteIndex_i(index_i);
        m_list.set(index, (typename TLIST::TYPE)tmp);
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_setKnownIntProperty(int32_t index_i, Atom value)
    {
        typename TLIST::OPAQUE_TYPE tmp;
        atomToValueKnown(value, tmp);
        uint32_t index = checkWriteIndex_i(index_i);
        m_list.set(index, (typename TLIST::TYPE)tmp);
    }
    
    template<class TLIST>
    Atom TypedVectorObject<TLIST>::_getDoubleProperty(double index_d) const
    {
        uint32_t const index = checkReadIndex_d(index_d);
        return valueToAtom((typename TLIST::OPAQUE_TYPE)m_list.get(index));
    }

    template<class TLIST>
    void TypedVectorObject<TLIST>::_setDoubleProperty(double index_d, Atom value)
    {
        typename TLIST::OPAQUE_TYPE tmp;
        atomToValue(value, tmp);
        uint32_t index = checkWriteIndex_d(index_d);
        m_list.set(index, (typename TLIST::TYPE)tmp);
    }
    
    template<class TLIST>
    void TypedVectorObject<TLIST>::_setKnownDoubleProperty(double index_d, Atom value)
    {
        typename TLIST::OPAQUE_TYPE tmp;
        atomToValueKnown(value, tmp);
        uint32_t index = checkWriteIndex_d(index_d);
        m_list.set(index, (typename TLIST::TYPE)tmp);
    }
    
    template<class TLIST>
    void FASTCALL TypedVectorObject<TLIST>::throwRangeError_u(uint32_t index) const
    {
        toplevel()->throwRangeError(kOutOfRangeError, core()->uintToString(index), core()->uintToString(m_list.length()));
    }

    template<class TLIST>
    void FASTCALL TypedVectorObject<TLIST>::throwRangeError_i(int32_t index) const
    {
        toplevel()->throwRangeError(kOutOfRangeError, core()->intToString(index), core()->uintToString(m_list.length()));
    }

    template<class TLIST>
    void FASTCALL TypedVectorObject<TLIST>::throwRangeError_a(Atom index) const
    {
        toplevel()->throwRangeError(kOutOfRangeError, core()->string(index), core()->uintToString(m_list.length()));
    }

    // ----------------------------
}

#endif /* __avmplus_VectorClass_impl__ */
