#include #include #include "scriptdictionary.h" #include "../scriptarray/scriptarray.h" BEGIN_AS_NAMESPACE using namespace std; //------------------------------------------------------------------------ // Object types are cached as user data to avoid costly runtime lookups // We just define a number here that we assume nobody else is using for // object type user data. The add-ons have reserved the numbers 1000 // through 1999 for this purpose, so we should be fine. const asPWORD DICTIONARY_CACHE = 1003; // This cache holds the object type of the dictionary type and array type // so it isn't necessary to look this up each time the dictionary or array // is created. struct SDictionaryCache { asITypeInfo *dictType; asITypeInfo *arrayType; asITypeInfo *keyType; // This is called from RegisterScriptDictionary static void Setup(asIScriptEngine *engine) { SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); if( cache == 0 ) { cache = new SDictionaryCache; engine->SetUserData(cache, DICTIONARY_CACHE); engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); cache->dictType = engine->GetTypeInfoByName("dictionary"); cache->arrayType = engine->GetTypeInfoByDecl("array"); cache->keyType = engine->GetTypeInfoByDecl("string"); } } // This is called from the engine when shutting down static void Cleanup(asIScriptEngine *engine) { SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); if( cache ) delete cache; } }; //-------------------------------------------------------------------------- // CScriptDictionary implementation CScriptDictionary *CScriptDictionary::Create(asIScriptEngine *engine) { // Use the custom memory routine from AngelScript to allow application to better control how much memory is used CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); new(obj) CScriptDictionary(engine); return obj; } CScriptDictionary *CScriptDictionary::Create(asBYTE *buffer) { // Use the custom memory routine from AngelScript to allow application to better control how much memory is used CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); new(obj) CScriptDictionary(buffer); return obj; } CScriptDictionary::CScriptDictionary(asIScriptEngine *engine) { Init(engine); } void CScriptDictionary::Init(asIScriptEngine *e) { // We start with one reference refCount = 1; gcFlag = false; // Keep a reference to the engine for as long as we live // We don't increment the reference counter, because the // engine will hold a pointer to the object in the GC. engine = e; // The dictionary object type is cached to avoid dynamically parsing it each time SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); // Notify the garbage collector of this object engine->NotifyGarbageCollectorOfNewObject(this, cache->dictType); } CScriptDictionary::CScriptDictionary(asBYTE *buffer) { // This constructor will always be called from a script // so we can get the engine from the active context asIScriptContext *ctx = asGetActiveContext(); Init(ctx->GetEngine()); // Determine if the dictionary key type is registered as reference type or value type SDictionaryCache& cache = *reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); bool keyAsRef = cache.keyType->GetFlags() & asOBJ_REF ? true : false; // Initialize the dictionary from the buffer asUINT length = *(asUINT*)buffer; buffer += 4; while( length-- ) { // Align the buffer pointer on a 4 byte boundary in // case previous value was smaller than 4 bytes if( asPWORD(buffer) & 0x3 ) buffer += 4 - (asPWORD(buffer) & 0x3); // Get the name value pair from the buffer and insert it in the dictionary dictKey_t name; if (keyAsRef) { name = **(dictKey_t**)buffer; buffer += sizeof(dictKey_t*); } else { name = *(dictKey_t*)buffer; buffer += sizeof(dictKey_t); } // Get the type id of the value int typeId = *(int*)buffer; buffer += sizeof(int); // Depending on the type id, the value will inline in the buffer or a pointer void *ref = (void*)buffer; if( typeId >= asTYPEID_INT8 && typeId <= asTYPEID_DOUBLE ) { // Convert primitive values to either int64 or double, so we can use the overloaded Set methods asINT64 i64; double d; switch( typeId ) { case asTYPEID_INT8: i64 = *(char*) ref; break; case asTYPEID_INT16: i64 = *(short*) ref; break; case asTYPEID_INT32: i64 = *(int*) ref; break; case asTYPEID_INT64: i64 = *(asINT64*) ref; break; case asTYPEID_UINT8: i64 = *(unsigned char*) ref; break; case asTYPEID_UINT16: i64 = *(unsigned short*)ref; break; case asTYPEID_UINT32: i64 = *(unsigned int*) ref; break; case asTYPEID_UINT64: i64 = *(asINT64*) ref; break; case asTYPEID_FLOAT: d = *(float*) ref; break; case asTYPEID_DOUBLE: d = *(double*) ref; break; } if( typeId >= asTYPEID_FLOAT ) Set(name, d); else Set(name, i64); } else { if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) && (engine->GetTypeInfoById(typeId)->GetFlags() & asOBJ_REF) ) { // Dereference the pointer to get the reference to the actual object ref = *(void**)ref; } Set(name, ref, typeId); } // Advance the buffer pointer with the size of the value if( typeId & asTYPEID_MASK_OBJECT ) { asITypeInfo *ti = engine->GetTypeInfoById(typeId); if( ti->GetFlags() & asOBJ_VALUE ) buffer += ti->GetSize(); else buffer += sizeof(void*); } else if( typeId == 0 ) { // null pointer buffer += sizeof(void*); } else { buffer += engine->GetSizeOfPrimitiveType(typeId); } } } CScriptDictionary::~CScriptDictionary() { // Delete all keys and values DeleteAll(); } void CScriptDictionary::AddRef() const { // We need to clear the GC flag gcFlag = false; asAtomicInc(refCount); } void CScriptDictionary::Release() const { // We need to clear the GC flag gcFlag = false; if( asAtomicDec(refCount) == 0 ) { this->~CScriptDictionary(); asFreeMem(const_cast(this)); } } int CScriptDictionary::GetRefCount() { return refCount; } void CScriptDictionary::SetGCFlag() { gcFlag = true; } bool CScriptDictionary::GetGCFlag() { return gcFlag; } void CScriptDictionary::EnumReferences(asIScriptEngine *inEngine) { // TODO: If garbage collection can be done from a separate thread, then this method must be // protected so that it doesn't get lost during the iteration if the dictionary is modified // Call the gc enum callback for each of the objects dictMap_t::iterator it; for( it = dict.begin(); it != dict.end(); it++ ) { if (it->second.m_typeId & asTYPEID_MASK_OBJECT) { asITypeInfo *subType = engine->GetTypeInfoById(it->second.m_typeId); if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) { // For value types we need to forward the enum callback // to the object so it can decide what to do engine->ForwardGCEnumReferences(it->second.m_valueObj, subType); } else { // For others, simply notify the GC about the reference inEngine->GCEnumCallback(it->second.m_valueObj); } } } } void CScriptDictionary::ReleaseAllReferences(asIScriptEngine * /*engine*/) { // We're being told to release all references in // order to break circular references for dead objects DeleteAll(); } CScriptDictionary &CScriptDictionary::operator =(const CScriptDictionary &other) { // Clear everything we had before DeleteAll(); // Do a shallow copy of the dictionary dictMap_t::const_iterator it; for( it = other.dict.begin(); it != other.dict.end(); it++ ) { if( it->second.m_typeId & asTYPEID_OBJHANDLE ) Set(it->first, (void*)&it->second.m_valueObj, it->second.m_typeId); else if( it->second.m_typeId & asTYPEID_MASK_OBJECT ) Set(it->first, (void*)it->second.m_valueObj, it->second.m_typeId); else Set(it->first, (void*)&it->second.m_valueInt, it->second.m_typeId); } return *this; } CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) { // Return the existing value if it exists, else insert an empty value return &dict[key]; } const CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) const { // Return the existing value if it exists dictMap_t::const_iterator it; it = dict.find(key); if( it != dict.end() ) return &it->second; // Else raise an exception asIScriptContext *ctx = asGetActiveContext(); if( ctx ) ctx->SetException("Invalid access to non-existing value"); return 0; } void CScriptDictionary::Set(const dictKey_t &key, void *value, int typeId) { dictMap_t::iterator it; it = dict.find(key); if( it == dict.end() ) it = dict.insert(dictMap_t::value_type(key, CScriptDictValue())).first; it->second.Set(engine, value, typeId); } // This overloaded method is implemented so that all integer and // unsigned integers types will be stored in the dictionary as int64 // through implicit conversions. This simplifies the management of the // numeric types when the script retrieves the stored value using a // different type. void CScriptDictionary::Set(const dictKey_t &key, const asINT64 &value) { Set(key, const_cast(&value), asTYPEID_INT64); } // This overloaded method is implemented so that all floating point types // will be stored in the dictionary as double through implicit conversions. // This simplifies the management of the numeric types when the script // retrieves the stored value using a different type. void CScriptDictionary::Set(const dictKey_t &key, const double &value) { Set(key, const_cast(&value), asTYPEID_DOUBLE); } // Returns true if the value was successfully retrieved bool CScriptDictionary::Get(const dictKey_t &key, void *value, int typeId) const { dictMap_t::const_iterator it; it = dict.find(key); if( it != dict.end() ) return it->second.Get(engine, value, typeId); // AngelScript has already initialized the value with a default value, // so we don't have to do anything if we don't find the element, or if // the element is incompatible with the requested type. return false; } // Returns the type id of the stored value int CScriptDictionary::GetTypeId(const dictKey_t &key) const { dictMap_t::const_iterator it; it = dict.find(key); if( it != dict.end() ) return it->second.m_typeId; return -1; } bool CScriptDictionary::Get(const dictKey_t &key, asINT64 &value) const { return Get(key, &value, asTYPEID_INT64); } bool CScriptDictionary::Get(const dictKey_t &key, double &value) const { return Get(key, &value, asTYPEID_DOUBLE); } bool CScriptDictionary::Exists(const dictKey_t &key) const { dictMap_t::const_iterator it; it = dict.find(key); if( it != dict.end() ) return true; return false; } bool CScriptDictionary::IsEmpty() const { if( dict.size() == 0 ) return true; return false; } asUINT CScriptDictionary::GetSize() const { return asUINT(dict.size()); } bool CScriptDictionary::Delete(const dictKey_t &key) { dictMap_t::iterator it; it = dict.find(key); if( it != dict.end() ) { it->second.FreeValue(engine); dict.erase(it); return true; } return false; } void CScriptDictionary::DeleteAll() { dictMap_t::iterator it; for( it = dict.begin(); it != dict.end(); it++ ) it->second.FreeValue(engine); dict.clear(); } CScriptArray* CScriptDictionary::GetKeys() const { // Retrieve the object type for the array from the cache SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); asITypeInfo *ti = cache->arrayType; // Create the array object CScriptArray *array = CScriptArray::Create(ti, asUINT(dict.size())); long current = -1; dictMap_t::const_iterator it; for( it = dict.begin(); it != dict.end(); it++ ) { current++; *(dictKey_t*)array->At(current) = it->first; } return array; } //-------------------------------------------------------------------------- // Generic wrappers void ScriptDictionaryFactory_Generic(asIScriptGeneric *gen) { *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(gen->GetEngine()); } void ScriptDictionaryListFactory_Generic(asIScriptGeneric *gen) { asBYTE *buffer = (asBYTE*)gen->GetArgAddress(0); *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(buffer); } void ScriptDictionaryAddRef_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dict->AddRef(); } void ScriptDictionaryRelease_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dict->Release(); } void ScriptDictionaryAssign_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); CScriptDictionary *other = *(CScriptDictionary**)gen->GetAddressOfArg(0); *dict = *other; *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = dict; } void ScriptDictionarySet_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); void *ref = *(void**)gen->GetAddressOfArg(1); int typeId = gen->GetArgTypeId(1); dict->Set(*key, ref, typeId); } void ScriptDictionarySetInt_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); void *ref = *(void**)gen->GetAddressOfArg(1); dict->Set(*key, *(asINT64*)ref); } void ScriptDictionarySetFlt_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); void *ref = *(void**)gen->GetAddressOfArg(1); dict->Set(*key, *(double*)ref); } void ScriptDictionaryGet_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); void *ref = *(void**)gen->GetAddressOfArg(1); int typeId = gen->GetArgTypeId(1); *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, ref, typeId); } void ScriptDictionaryGetInt_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); void *ref = *(void**)gen->GetAddressOfArg(1); *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(asINT64*)ref); } void ScriptDictionaryGetFlt_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); void *ref = *(void**)gen->GetAddressOfArg(1); *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(double*)ref); } void ScriptDictionaryExists_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); bool ret = dict->Exists(*key); *(bool*)gen->GetAddressOfReturnLocation() = ret; } void ScriptDictionaryIsEmpty_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); bool ret = dict->IsEmpty(); *(bool*)gen->GetAddressOfReturnLocation() = ret; } void ScriptDictionaryGetSize_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); asUINT ret = dict->GetSize(); *(asUINT*)gen->GetAddressOfReturnLocation() = ret; } void ScriptDictionaryDelete_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); *(bool*)gen->GetAddressOfReturnLocation() = dict->Delete(*key); } void ScriptDictionaryDeleteAll_Generic(asIScriptGeneric *gen) { CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); dict->DeleteAll(); } static void ScriptDictionaryGetRefCount_Generic(asIScriptGeneric *gen) { CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); } static void ScriptDictionarySetGCFlag_Generic(asIScriptGeneric *gen) { CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); self->SetGCFlag(); } static void ScriptDictionaryGetGCFlag_Generic(asIScriptGeneric *gen) { CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); *(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag(); } static void ScriptDictionaryEnumReferences_Generic(asIScriptGeneric *gen) { CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); self->EnumReferences(engine); } static void ScriptDictionaryReleaseAllReferences_Generic(asIScriptGeneric *gen) { CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); self->ReleaseAllReferences(engine); } static void CScriptDictionaryGetKeys_Generic(asIScriptGeneric *gen) { CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); *(CScriptArray**)gen->GetAddressOfReturnLocation() = self->GetKeys(); } static void CScriptDictionary_opIndex_Generic(asIScriptGeneric *gen) { CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); } static void CScriptDictionary_opIndex_const_Generic(asIScriptGeneric *gen) { const CScriptDictionary *self = (const CScriptDictionary*)gen->GetObject(); dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); *(const CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); } //------------------------------------------------------------------------- // CScriptDictValue CScriptDictValue::CScriptDictValue() { m_valueObj = 0; m_typeId = 0; } CScriptDictValue::CScriptDictValue(asIScriptEngine *engine, void *value, int typeId) { m_valueObj = 0; m_typeId = 0; Set(engine, value, typeId); } CScriptDictValue::~CScriptDictValue() { if (m_valueObj && m_typeId) { asIScriptContext *ctx = asGetActiveContext(); if (ctx) FreeValue(ctx->GetEngine()); else { // Must not hold an object when destroyed, as then the object will never be freed assert((m_typeId & asTYPEID_MASK_OBJECT) == 0); } } } void CScriptDictValue::FreeValue(asIScriptEngine *engine) { // If it is a handle or a ref counted object, call release if( m_typeId & asTYPEID_MASK_OBJECT ) { // Let the engine release the object engine->ReleaseScriptObject(m_valueObj, engine->GetTypeInfoById(m_typeId)); m_valueObj = 0; m_typeId = 0; } // For primitives, there's nothing to do } void CScriptDictValue::EnumReferences(asIScriptEngine *inEngine) { // If we're holding a reference, we'll notify the garbage collector of it if (m_valueObj) inEngine->GCEnumCallback(m_valueObj); // The object type itself is also garbage collected if (m_typeId) inEngine->GCEnumCallback(inEngine->GetTypeInfoById(m_typeId)); } void CScriptDictValue::Set(asIScriptEngine *engine, void *value, int typeId) { FreeValue(engine); m_typeId = typeId; if( typeId & asTYPEID_OBJHANDLE ) { // We're receiving a reference to the handle, so we need to dereference it m_valueObj = *(void**)value; engine->AddRefScriptObject(m_valueObj, engine->GetTypeInfoById(typeId)); } else if( typeId & asTYPEID_MASK_OBJECT ) { // Create a copy of the object m_valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId)); if( m_valueObj == 0 ) { asIScriptContext *ctx = asGetActiveContext(); if( ctx ) ctx->SetException("Cannot create copy of object"); } } else { // Copy the primitive value // We receive a pointer to the value. int size = engine->GetSizeOfPrimitiveType(typeId); memcpy(&m_valueInt, value, size); } } void CScriptDictValue::Set(asIScriptEngine *engine, CScriptDictValue &value) { if( value.m_typeId & asTYPEID_OBJHANDLE ) Set(engine, (void*)&value.m_valueObj, value.m_typeId); else if( value.m_typeId & asTYPEID_MASK_OBJECT ) Set(engine, (void*)value.m_valueObj, value.m_typeId); else Set(engine, (void*)&value.m_valueInt, value.m_typeId); } // This overloaded method is implemented so that all integer and // unsigned integers types will be stored in the dictionary as int64 // through implicit conversions. This simplifies the management of the // numeric types when the script retrieves the stored value using a // different type. void CScriptDictValue::Set(asIScriptEngine *engine, const asINT64 &value) { Set(engine, const_cast(&value), asTYPEID_INT64); } // This overloaded method is implemented so that all floating point types // will be stored in the dictionary as double through implicit conversions. // This simplifies the management of the numeric types when the script // retrieves the stored value using a different type. void CScriptDictValue::Set(asIScriptEngine *engine, const double &value) { Set(engine, const_cast(&value), asTYPEID_DOUBLE); } bool CScriptDictValue::Get(asIScriptEngine *engine, void *value, int typeId) const { // Return the value if( typeId & asTYPEID_OBJHANDLE ) { // A handle can be retrieved if the stored type is a handle of same or compatible type // or if the stored type is an object that implements the interface that the handle refer to. if( (m_typeId & asTYPEID_MASK_OBJECT) ) { // Don't allow the get if the stored handle is to a const, but the desired handle is not if( (m_typeId & asTYPEID_HANDLETOCONST) && !(typeId & asTYPEID_HANDLETOCONST) ) return false; // RefCastObject will increment the refcount if successful engine->RefCastObject(m_valueObj, engine->GetTypeInfoById(m_typeId), engine->GetTypeInfoById(typeId), reinterpret_cast(value)); return true; } } else if( typeId & asTYPEID_MASK_OBJECT ) { // Verify that the copy can be made bool isCompatible = false; // Allow a handle to be value assigned if the wanted type is not a handle if( (m_typeId & ~(asTYPEID_OBJHANDLE | asTYPEID_HANDLETOCONST) ) == typeId && m_valueObj != 0 ) isCompatible = true; // Copy the object into the given reference if( isCompatible ) { engine->AssignScriptObject(value, m_valueObj, engine->GetTypeInfoById(typeId)); return true; } } else { if( m_typeId == typeId ) { int size = engine->GetSizeOfPrimitiveType(typeId); memcpy(value, &m_valueInt, size); return true; } // We know all numbers are stored as either int64 or double, since we register overloaded functions for those // Only bool and enums needs to be treated separately if( typeId == asTYPEID_DOUBLE ) { if( m_typeId == asTYPEID_INT64 ) *(double*)value = double(m_valueInt); else if (m_typeId == asTYPEID_BOOL) { // Use memcpy instead of type cast to make sure the code is endianess agnostic char localValue; memcpy(&localValue, &m_valueInt, sizeof(char)); *(double*)value = localValue ? 1.0 : 0.0; } else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) { // Use memcpy instead of type cast to make sure the code is endianess agnostic int localValue; memcpy(&localValue, &m_valueInt, sizeof(int)); *(double*)value = double(localValue); // enums are 32bit } else { // The stored type is an object // TODO: Check if the object has a conversion operator to a primitive value *(double*)value = 0; return false; } return true; } else if( typeId == asTYPEID_INT64 ) { if( m_typeId == asTYPEID_DOUBLE ) *(asINT64*)value = asINT64(m_valueFlt); else if (m_typeId == asTYPEID_BOOL) { // Use memcpy instead of type cast to make sure the code is endianess agnostic char localValue; memcpy(&localValue, &m_valueInt, sizeof(char)); *(asINT64*)value = localValue ? 1 : 0; } else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) { // Use memcpy instead of type cast to make sure the code is endianess agnostic int localValue; memcpy(&localValue, &m_valueInt, sizeof(int)); *(asINT64*)value = localValue; // enums are 32bit } else { // The stored type is an object // TODO: Check if the object has a conversion operator to a primitive value *(asINT64*)value = 0; return false; } return true; } else if( typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0 ) { // The desired type is an enum. These are always 32bit integers if( m_typeId == asTYPEID_DOUBLE ) *(int*)value = int(m_valueFlt); else if( m_typeId == asTYPEID_INT64 ) *(int*)value = int(m_valueInt); else if (m_typeId == asTYPEID_BOOL) { // Use memcpy instead of type cast to make sure the code is endianess agnostic char localValue; memcpy(&localValue, &m_valueInt, sizeof(char)); *(int*)value = localValue ? 1 : 0; } else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) { // Use memcpy instead of type cast to make sure the code is endianess agnostic int localValue; memcpy(&localValue, &m_valueInt, sizeof(int)); *(int*)value = localValue; // enums are 32bit } else { // The stored type is an object // TODO: Check if the object has a conversion operator to a primitive value *(int*)value = 0; return false; } return true; } else if( typeId == asTYPEID_BOOL ) { if (m_typeId & asTYPEID_OBJHANDLE) { // TODO: Check if the object has a conversion operator to a primitive value *(bool*)value = m_valueObj ? true : false; } else if( m_typeId & asTYPEID_MASK_OBJECT ) { // TODO: Check if the object has a conversion operator to a primitive value *(bool*)value = true; } else { // Compare only the bytes that were actually set asQWORD zero = 0; int size = engine->GetSizeOfPrimitiveType(m_typeId); *(bool*)value = memcmp(&m_valueInt, &zero, size) == 0 ? false : true; } return true; } } // It was not possible to retrieve the value using the desired typeId return false; } const void * CScriptDictValue::GetAddressOfValue() const { if( (m_typeId & asTYPEID_MASK_OBJECT) && !(m_typeId & asTYPEID_OBJHANDLE) ) { // Return the address to the object directly return m_valueObj; } // Return the address of the primitive or the pointer to the object return reinterpret_cast(&m_valueObj); } bool CScriptDictValue::Get(asIScriptEngine *engine, asINT64 &value) const { return Get(engine, &value, asTYPEID_INT64); } bool CScriptDictValue::Get(asIScriptEngine *engine, double &value) const { return Get(engine, &value, asTYPEID_DOUBLE); } int CScriptDictValue::GetTypeId() const { return m_typeId; } static void CScriptDictValue_Construct(void *mem) { new(mem) CScriptDictValue(); } static void CScriptDictValue_Destruct(CScriptDictValue *obj) { asIScriptContext *ctx = asGetActiveContext(); if( ctx ) { asIScriptEngine *engine = ctx->GetEngine(); obj->FreeValue(engine); } obj->~CScriptDictValue(); } static CScriptDictValue &CScriptDictValue_opAssign(void *ref, int typeId, CScriptDictValue *obj) { asIScriptContext *ctx = asGetActiveContext(); if( ctx ) { asIScriptEngine *engine = ctx->GetEngine(); obj->Set(engine, ref, typeId); } return *obj; } static CScriptDictValue &CScriptDictValue_opAssign(const CScriptDictValue &other, CScriptDictValue *obj) { asIScriptContext *ctx = asGetActiveContext(); if( ctx ) { asIScriptEngine *engine = ctx->GetEngine(); obj->Set(engine, const_cast(other)); } return *obj; } static CScriptDictValue &CScriptDictValue_opAssign(double val, CScriptDictValue *obj) { return CScriptDictValue_opAssign(&val, asTYPEID_DOUBLE, obj); } static CScriptDictValue &CScriptDictValue_opAssign(asINT64 val, CScriptDictValue *obj) { return CScriptDictValue_opAssign(&val, asTYPEID_INT64, obj); } static void CScriptDictValue_opCast(void *ref, int typeId, CScriptDictValue *obj) { asIScriptContext *ctx = asGetActiveContext(); if( ctx ) { asIScriptEngine *engine = ctx->GetEngine(); obj->Get(engine, ref, typeId); } } static asINT64 CScriptDictValue_opConvInt(CScriptDictValue *obj) { asINT64 value; CScriptDictValue_opCast(&value, asTYPEID_INT64, obj); return value; } static double CScriptDictValue_opConvDouble(CScriptDictValue *obj) { double value; CScriptDictValue_opCast(&value, asTYPEID_DOUBLE, obj); return value; } //------------------------------------------------------------------- // generic wrapper for CScriptDictValue static void CScriptDictValue_opConvDouble_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); double value; self->Get(gen->GetEngine(), value); *(double*)gen->GetAddressOfReturnLocation() = value; } static void CScriptDictValue_opConvInt_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); asINT64 value; self->Get(gen->GetEngine(), value); *(asINT64*)gen->GetAddressOfReturnLocation() = value; } static void CScriptDictValue_opCast_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); self->Get(gen->GetEngine(), gen->GetArgAddress(0), gen->GetArgTypeId(0)); } static void CScriptDictValue_opAssign_int64_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign((asINT64)gen->GetArgQWord(0), self); } static void CScriptDictValue_opAssign_double_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgDouble(0), self); } static void CScriptDictValue_opAssign_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgAddress(0), gen->GetArgTypeId(0), self); } static void CScriptDictValue_opCopyAssign_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(*reinterpret_cast(gen->GetArgAddress(0)), self); } static void CScriptDictValue_Construct_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); CScriptDictValue_Construct(self); } static void CScriptDictValue_Destruct_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); CScriptDictValue_Destruct(self); } static void CScriptDictValue_EnumReferences_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); self->EnumReferences(gen->GetEngine()); } static void CScriptDictValue_FreeValue_Generic(asIScriptGeneric *gen) { CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); self->FreeValue(gen->GetEngine()); } //-------------------------------------------------------------------------- // Register the type void RegisterScriptDictionary(asIScriptEngine *engine) { if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) RegisterScriptDictionary_Generic(engine); else RegisterScriptDictionary_Native(engine); } void RegisterScriptDictionary_Native(asIScriptEngine *engine) { int r; // The array type must be available assert( engine->GetTypeInfoByDecl("array") ); #if AS_CAN_USE_CPP11 // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); #else r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); #endif r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictValue, EnumReferences), asCALL_THISCALL); assert(r >= 0); r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictValue, FreeValue), asCALL_THISCALL); assert(r >= 0); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert(r >= 0); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTIONPR(CScriptDictValue_opAssign, (double, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTIONPR(CScriptDictValue_opAssign, (asINT64, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTIONPR(CScriptDictValue_opConvInt, (CScriptDictValue*), asINT64), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTIONPR(CScriptDictValue_opConvDouble, (CScriptDictValue*), double), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); // Use the generic interface to construct the object since we need the engine pointer, we could also have retrieved the engine pointer from the active context r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asMETHODPR(CScriptDictionary, operator=, (const CScriptDictionary &), CScriptDictionary&), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,void*,int),void), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const double&),void), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &), CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &) const, const CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); // Register GC behaviours r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 ); #if AS_USE_STLNAMES == 1 // Same as isEmpty r = engine->RegisterObjectMethod("dictionary", "bool empty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); // Same as getSize r = engine->RegisterObjectMethod("dictionary", "uint size() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); // Same as delete r = engine->RegisterObjectMethod("dictionary", "void erase(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); // Same as deleteAll r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); #endif // Cache some things the dictionary will need at runtime SDictionaryCache::Setup(engine); } void RegisterScriptDictionary_Generic(asIScriptEngine *engine) { int r; // Register the cleanup callback for the object type cache engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); #if AS_CAN_USE_CPP11 // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); #else r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); #endif r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_FreeValue_Generic), asCALL_GENERIC); assert(r >= 0); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTION(CScriptDictValue_opAssign_double_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTION(CScriptDictValue_opAssign_int64_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTION(CScriptDictValue_opConvInt_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTION(CScriptDictValue_opConvDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asFUNCTION(ScriptDictionaryAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asFUNCTION(ScriptDictionaryIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asFUNCTION(ScriptDictionaryGetSize_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asFUNCTION(CScriptDictionary_opIndex_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asFUNCTION(CScriptDictionary_opIndex_const_Generic), asCALL_GENERIC); assert( r >= 0 ); // Register GC behaviours r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); // Cache some things the dictionary will need at runtime SDictionaryCache::Setup(engine); } //------------------------------------------------------------------ // Iterator implementation CScriptDictionary::CIterator CScriptDictionary::begin() const { return CIterator(*this, dict.begin()); } CScriptDictionary::CIterator CScriptDictionary::end() const { return CIterator(*this, dict.end()); } CScriptDictionary::CIterator CScriptDictionary::find(const dictKey_t &key) const { return CIterator(*this, dict.find(key)); } CScriptDictionary::CIterator::CIterator( const CScriptDictionary &dict, dictMap_t::const_iterator it) : m_it(it), m_dict(dict) {} void CScriptDictionary::CIterator::operator++() { ++m_it; } void CScriptDictionary::CIterator::operator++(int) { ++m_it; // Normally the post increment would return a copy of the object with the original state, // but it is rarely used so we skip this extra copy to avoid unnecessary overhead } CScriptDictionary::CIterator &CScriptDictionary::CIterator::operator*() { return *this; } bool CScriptDictionary::CIterator::operator==(const CIterator &other) const { return m_it == other.m_it; } bool CScriptDictionary::CIterator::operator!=(const CIterator &other) const { return m_it != other.m_it; } const dictKey_t &CScriptDictionary::CIterator::GetKey() const { return m_it->first; } int CScriptDictionary::CIterator::GetTypeId() const { return m_it->second.m_typeId; } bool CScriptDictionary::CIterator::GetValue(asINT64 &value) const { return m_it->second.Get(m_dict.engine, &value, asTYPEID_INT64); } bool CScriptDictionary::CIterator::GetValue(double &value) const { return m_it->second.Get(m_dict.engine, &value, asTYPEID_DOUBLE); } bool CScriptDictionary::CIterator::GetValue(void *value, int typeId) const { return m_it->second.Get(m_dict.engine, value, typeId); } const void *CScriptDictionary::CIterator::GetAddressOfValue() const { return m_it->second.GetAddressOfValue(); } END_AS_NAMESPACE