1 #include <assert.h>
2 #include <string.h>
3 #include "scriptdictionary.h"
4 #include "scriptarray.h"
5 
6 BEGIN_AS_NAMESPACE
7 
8 using namespace std;
9 
10 //------------------------------------------------------------------------
11 // Object types are cached as user data to avoid costly runtime lookups
12 
13 // We just define a number here that we assume nobody else is using for
14 // object type user data. The add-ons have reserved the numbers 1000
15 // through 1999 for this purpose, so we should be fine.
16 const asPWORD DICTIONARY_CACHE = 1003;
17 
18 // This cache holds the object type of the dictionary type and array type
19 // so it isn't necessary to look this up each time the dictionary or array
20 // is created.
21 struct SDictionaryCache
22 {
23 	asITypeInfo *dictType;
24 	asITypeInfo *arrayType;
25 
26 	// This is called from RegisterScriptDictionary
SetupSDictionaryCache27 	static void Setup(asIScriptEngine *engine)
28 	{
29 		SDictionaryCache *cache = reinterpret_cast<SDictionaryCache*>(engine->GetUserData(DICTIONARY_CACHE));
30 		if( cache == 0 )
31 		{
32 			cache = new SDictionaryCache;
33 			engine->SetUserData(cache, DICTIONARY_CACHE);
34 			engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE);
35 
36 			cache->dictType = engine->GetTypeInfoByName("dictionary");
37 			cache->arrayType = engine->GetTypeInfoByDecl("array<string>");
38 		}
39 	}
40 
41 	// This is called from the engine when shutting down
CleanupSDictionaryCache42 	static void Cleanup(asIScriptEngine *engine)
43 	{
44 		SDictionaryCache *cache = reinterpret_cast<SDictionaryCache*>(engine->GetUserData(DICTIONARY_CACHE));
45 		if( cache )
46 			delete cache;
47 	}
48 };
49 
50 //--------------------------------------------------------------------------
51 // CScriptDictionary implementation
52 
Create(asIScriptEngine * engine)53 CScriptDictionary *CScriptDictionary::Create(asIScriptEngine *engine)
54 {
55 	// Use the custom memory routine from AngelScript to allow application to better control how much memory is used
56 	CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary));
57 	new(obj) CScriptDictionary(engine);
58 	return obj;
59 }
60 
Create(asBYTE * buffer)61 CScriptDictionary *CScriptDictionary::Create(asBYTE *buffer)
62 {
63 	// Use the custom memory routine from AngelScript to allow application to better control how much memory is used
64 	CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary));
65 	new(obj) CScriptDictionary(buffer);
66 	return obj;
67 }
68 
CScriptDictionary(asIScriptEngine * engine)69 CScriptDictionary::CScriptDictionary(asIScriptEngine *engine)
70 {
71 	Init(engine);
72 }
73 
Init(asIScriptEngine * e)74 void CScriptDictionary::Init(asIScriptEngine *e)
75 {
76 	// We start with one reference
77 	refCount = 1;
78 	gcFlag = false;
79 
80 	// Keep a reference to the engine for as long as we live
81 	// We don't increment the reference counter, because the
82 	// engine will hold a pointer to the object in the GC.
83 	engine = e;
84 
85 	// The dictionary object type is cached to avoid dynamically parsing it each time
86 	SDictionaryCache *cache = reinterpret_cast<SDictionaryCache*>(engine->GetUserData(DICTIONARY_CACHE));
87 
88 	// Notify the garbage collector of this object
89 	engine->NotifyGarbageCollectorOfNewObject(this, cache->dictType);
90 }
91 
CScriptDictionary(asBYTE * buffer)92 CScriptDictionary::CScriptDictionary(asBYTE *buffer)
93 {
94 	// This constructor will always be called from a script
95 	// so we can get the engine from the active context
96 	asIScriptContext *ctx = asGetActiveContext();
97 	Init(ctx->GetEngine());
98 
99 	// Initialize the dictionary from the buffer
100 	asUINT length = *(asUINT*)buffer;
101 	buffer += 4;
102 
103 	while( length-- )
104 	{
105 		// Align the buffer pointer on a 4 byte boundary in
106 		// case previous value was smaller than 4 bytes
107 		if( asPWORD(buffer) & 0x3 )
108 			buffer += 4 - (asPWORD(buffer) & 0x3);
109 
110 		// Get the name value pair from the buffer and insert it in the dictionary
111 		dictKey_t name = *(dictKey_t*)buffer;
112 		buffer += sizeof(dictKey_t);
113 
114 		// Get the type id of the value
115 		int typeId = *(int*)buffer;
116 		buffer += sizeof(int);
117 
118 		// Depending on the type id, the value will inline in the buffer or a pointer
119 		void *ref = (void*)buffer;
120 
121 		if( typeId >= asTYPEID_INT8 && typeId <= asTYPEID_DOUBLE )
122 		{
123 			// Convert primitive values to either int64 or double, so we can use the overloaded Set methods
124 			asINT64 i64;
125 			double d;
126 			switch( typeId )
127 			{
128 			case asTYPEID_INT8:   i64 = *(char*)          ref; break;
129 			case asTYPEID_INT16:  i64 = *(short*)         ref; break;
130 			case asTYPEID_INT32:  i64 = *(int*)           ref; break;
131 			case asTYPEID_INT64:  i64 = *(asINT64*)       ref; break;
132 			case asTYPEID_UINT8:  i64 = *(unsigned char*) ref; break;
133 			case asTYPEID_UINT16: i64 = *(unsigned short*)ref; break;
134 			case asTYPEID_UINT32: i64 = *(unsigned int*)  ref; break;
135 			case asTYPEID_UINT64: i64 = *(asINT64*)       ref; break;
136 			case asTYPEID_FLOAT:  d   = *(float*)         ref; break;
137 			case asTYPEID_DOUBLE: d   = *(double*)        ref; break;
138 			}
139 
140 			if( typeId >= asTYPEID_FLOAT )
141 				Set(name, d);
142 			else
143 				Set(name, i64);
144 		}
145 		else
146 		{
147 			if( (typeId & asTYPEID_MASK_OBJECT) &&
148 				!(typeId & asTYPEID_OBJHANDLE) &&
149 				(engine->GetTypeInfoById(typeId)->GetFlags() & asOBJ_REF) )
150 			{
151 				// Dereference the pointer to get the reference to the actual object
152 				ref = *(void**)ref;
153 			}
154 
155 			Set(name, ref, typeId);
156 		}
157 
158 		// Advance the buffer pointer with the size of the value
159 		if( typeId & asTYPEID_MASK_OBJECT )
160 		{
161 			asITypeInfo *ti = engine->GetTypeInfoById(typeId);
162 			if( ti->GetFlags() & asOBJ_VALUE )
163 				buffer += ti->GetSize();
164 			else
165 				buffer += sizeof(void*);
166 		}
167 		else if( typeId == 0 )
168 		{
169 			// null pointer
170 			buffer += sizeof(void*);
171 		}
172 		else
173 		{
174 			buffer += engine->GetSizeOfPrimitiveType(typeId);
175 		}
176 	}
177 }
178 
~CScriptDictionary()179 CScriptDictionary::~CScriptDictionary()
180 {
181 	// Delete all keys and values
182 	DeleteAll();
183 }
184 
AddRef() const185 void CScriptDictionary::AddRef() const
186 {
187 	// We need to clear the GC flag
188 	gcFlag = false;
189 	refCount.fetch_add(1);
190 }
191 
Release() const192 void CScriptDictionary::Release() const
193 {
194 	// We need to clear the GC flag
195 	gcFlag = false;
196 	if( refCount.fetch_sub(1) == 1 )
197 	{
198 		this->~CScriptDictionary();
199 		asFreeMem(const_cast<CScriptDictionary*>(this));
200 	}
201 }
202 
GetRefCount()203 int CScriptDictionary::GetRefCount()
204 {
205 	return refCount;
206 }
207 
SetGCFlag()208 void CScriptDictionary::SetGCFlag()
209 {
210 	gcFlag = true;
211 }
212 
GetGCFlag()213 bool CScriptDictionary::GetGCFlag()
214 {
215 	return gcFlag;
216 }
217 
EnumReferences(asIScriptEngine * inEngine)218 void CScriptDictionary::EnumReferences(asIScriptEngine *inEngine)
219 {
220 	// TODO: If garbage collection can be done from a separate thread, then this method must be
221 	//       protected so that it doesn't get lost during the iteration if the dictionary is modified
222 
223 	// Call the gc enum callback for each of the objects
224 	dictMap_t::iterator it;
225 	for( it = dict.begin(); it != dict.end(); it++ )
226 	{
227 		if( it->second.m_typeId & asTYPEID_MASK_OBJECT )
228 			inEngine->GCEnumCallback(it->second.m_valueObj);
229 	}
230 }
231 
ReleaseAllReferences(asIScriptEngine *)232 void CScriptDictionary::ReleaseAllReferences(asIScriptEngine * /*engine*/)
233 {
234 	// We're being told to release all references in
235 	// order to break circular references for dead objects
236 	DeleteAll();
237 }
238 
operator =(const CScriptDictionary & other)239 CScriptDictionary &CScriptDictionary::operator =(const CScriptDictionary &other)
240 {
241 	// Clear everything we had before
242 	DeleteAll();
243 
244 	// Do a shallow copy of the dictionary
245 	dictMap_t::const_iterator it;
246 	for( it = other.dict.begin(); it != other.dict.end(); it++ )
247 	{
248 		if( it->second.m_typeId & asTYPEID_OBJHANDLE )
249 			Set(it->first, (void*)&it->second.m_valueObj, it->second.m_typeId);
250 		else if( it->second.m_typeId & asTYPEID_MASK_OBJECT )
251 			Set(it->first, (void*)it->second.m_valueObj, it->second.m_typeId);
252 		else
253 			Set(it->first, (void*)&it->second.m_valueInt, it->second.m_typeId);
254 	}
255 
256 	return *this;
257 }
258 
operator [](const dictKey_t & key)259 CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key)
260 {
261 	// Return the existing value if it exists, else insert an empty value
262 	return &dict[key];
263 }
264 
operator [](const dictKey_t & key) const265 const CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) const
266 {
267 	// Return the existing value if it exists
268 	dictMap_t::const_iterator it;
269 	it = dict.find(key);
270 	if( it != dict.end() )
271 		return &it->second;
272 
273 	// Else raise an exception
274 	asIScriptContext *ctx = asGetActiveContext();
275 	if( ctx )
276 		ctx->SetException("Invalid access to non-existing value");
277 
278 	return 0;
279 }
280 
Set(const dictKey_t & key,void * value,int typeId)281 void CScriptDictionary::Set(const dictKey_t &key, void *value, int typeId)
282 {
283 	dictMap_t::iterator it;
284 	it = dict.find(key);
285 	if( it == dict.end() )
286 		it = dict.insert(dictMap_t::value_type(key, CScriptDictValue())).first;
287 
288 	it->second.Set(engine, value, typeId);
289 }
290 
291 // This overloaded method is implemented so that all integer and
292 // unsigned integers types will be stored in the dictionary as int64
293 // through implicit conversions. This simplifies the management of the
294 // numeric types when the script retrieves the stored value using a
295 // different type.
Set(const dictKey_t & key,const asINT64 & value)296 void CScriptDictionary::Set(const dictKey_t &key, const asINT64 &value)
297 {
298 	Set(key, const_cast<asINT64*>(&value), asTYPEID_INT64);
299 }
300 
301 // This overloaded method is implemented so that all floating point types
302 // will be stored in the dictionary as double through implicit conversions.
303 // This simplifies the management of the numeric types when the script
304 // retrieves the stored value using a different type.
Set(const dictKey_t & key,const double & value)305 void CScriptDictionary::Set(const dictKey_t &key, const double &value)
306 {
307 	Set(key, const_cast<double*>(&value), asTYPEID_DOUBLE);
308 }
309 
310 // Returns true if the value was successfully retrieved
Get(const dictKey_t & key,void * value,int typeId) const311 bool CScriptDictionary::Get(const dictKey_t &key, void *value, int typeId) const
312 {
313 	dictMap_t::const_iterator it;
314 	it = dict.find(key);
315 	if( it != dict.end() )
316 		return it->second.Get(engine, value, typeId);
317 
318 	// AngelScript has already initialized the value with a default value,
319 	// so we don't have to do anything if we don't find the element, or if
320 	// the element is incompatible with the requested type.
321 
322 	return false;
323 }
324 
325 // Returns the type id of the stored value
GetTypeId(const dictKey_t & key) const326 int CScriptDictionary::GetTypeId(const dictKey_t &key) const
327 {
328 	dictMap_t::const_iterator it;
329 	it = dict.find(key);
330 	if( it != dict.end() )
331 		return it->second.m_typeId;
332 
333 	return -1;
334 }
335 
Get(const dictKey_t & key,asINT64 & value) const336 bool CScriptDictionary::Get(const dictKey_t &key, asINT64 &value) const
337 {
338 	return Get(key, &value, asTYPEID_INT64);
339 }
340 
Get(const dictKey_t & key,double & value) const341 bool CScriptDictionary::Get(const dictKey_t &key, double &value) const
342 {
343 	return Get(key, &value, asTYPEID_DOUBLE);
344 }
345 
Exists(const dictKey_t & key) const346 bool CScriptDictionary::Exists(const dictKey_t &key) const
347 {
348 	dictMap_t::const_iterator it;
349 	it = dict.find(key);
350 	if( it != dict.end() )
351 		return true;
352 
353 	return false;
354 }
355 
IsEmpty() const356 bool CScriptDictionary::IsEmpty() const
357 {
358 	if( dict.size() == 0 )
359 		return true;
360 
361 	return false;
362 }
363 
GetSize() const364 asUINT CScriptDictionary::GetSize() const
365 {
366 	return asUINT(dict.size());
367 }
368 
Delete(const dictKey_t & key)369 bool CScriptDictionary::Delete(const dictKey_t &key)
370 {
371 	dictMap_t::iterator it;
372 	it = dict.find(key);
373 	if( it != dict.end() )
374 	{
375 		it->second.FreeValue(engine);
376 		dict.erase(it);
377 		return true;
378 	}
379 
380 	return false;
381 }
382 
DeleteAll()383 void CScriptDictionary::DeleteAll()
384 {
385 	dictMap_t::iterator it;
386 	for( it = dict.begin(); it != dict.end(); it++ )
387 		it->second.FreeValue(engine);
388 
389 	dict.clear();
390 }
391 
GetKeys() const392 CScriptArray* CScriptDictionary::GetKeys() const
393 {
394 	// Retrieve the object type for the array<string> from the cache
395 	SDictionaryCache *cache = reinterpret_cast<SDictionaryCache*>(engine->GetUserData(DICTIONARY_CACHE));
396 	asITypeInfo *ti = cache->arrayType;
397 
398 	// Create the array object
399 	CScriptArray *array = CScriptArray::Create(ti, asUINT(dict.size()));
400 	long current = -1;
401 	dictMap_t::const_iterator it;
402 	for( it = dict.begin(); it != dict.end(); it++ )
403 	{
404 		current++;
405 		*(dictKey_t*)array->At(static_cast<asUINT> (current)) = it->first;
406 	}
407 
408 	return array;
409 }
410 
411 //--------------------------------------------------------------------------
412 // Generic wrappers
413 
ScriptDictionaryFactory_Generic(asIScriptGeneric * gen)414 void ScriptDictionaryFactory_Generic(asIScriptGeneric *gen)
415 {
416 	*(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(gen->GetEngine());
417 }
418 
ScriptDictionaryListFactory_Generic(asIScriptGeneric * gen)419 void ScriptDictionaryListFactory_Generic(asIScriptGeneric *gen)
420 {
421 	asBYTE *buffer = (asBYTE*)gen->GetArgAddress(0);
422 	*(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(buffer);
423 }
424 
ScriptDictionaryAddRef_Generic(asIScriptGeneric * gen)425 void ScriptDictionaryAddRef_Generic(asIScriptGeneric *gen)
426 {
427 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
428 	dict->AddRef();
429 }
430 
ScriptDictionaryRelease_Generic(asIScriptGeneric * gen)431 void ScriptDictionaryRelease_Generic(asIScriptGeneric *gen)
432 {
433 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
434 	dict->Release();
435 }
436 
ScriptDictionaryAssign_Generic(asIScriptGeneric * gen)437 void ScriptDictionaryAssign_Generic(asIScriptGeneric *gen)
438 {
439 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
440 	CScriptDictionary *other = *(CScriptDictionary**)gen->GetAddressOfArg(0);
441 	*dict = *other;
442 	*(CScriptDictionary**)gen->GetAddressOfReturnLocation() = dict;
443 }
444 
ScriptDictionarySet_Generic(asIScriptGeneric * gen)445 void ScriptDictionarySet_Generic(asIScriptGeneric *gen)
446 {
447 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
448 	dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0);
449 	void *ref = *(void**)gen->GetAddressOfArg(1);
450 	int typeId = gen->GetArgTypeId(1);
451 	dict->Set(*key, ref, typeId);
452 }
453 
ScriptDictionarySetInt_Generic(asIScriptGeneric * gen)454 void ScriptDictionarySetInt_Generic(asIScriptGeneric *gen)
455 {
456 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
457 	dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0);
458 	void *ref = *(void**)gen->GetAddressOfArg(1);
459 	dict->Set(*key, *(asINT64*)ref);
460 }
461 
ScriptDictionarySetFlt_Generic(asIScriptGeneric * gen)462 void ScriptDictionarySetFlt_Generic(asIScriptGeneric *gen)
463 {
464 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
465 	dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0);
466 	void *ref = *(void**)gen->GetAddressOfArg(1);
467 	dict->Set(*key, *(double*)ref);
468 }
469 
ScriptDictionaryGet_Generic(asIScriptGeneric * gen)470 void ScriptDictionaryGet_Generic(asIScriptGeneric *gen)
471 {
472 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
473 	dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0);
474 	void *ref = *(void**)gen->GetAddressOfArg(1);
475 	int typeId = gen->GetArgTypeId(1);
476 	*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, ref, typeId);
477 }
478 
ScriptDictionaryGetInt_Generic(asIScriptGeneric * gen)479 void ScriptDictionaryGetInt_Generic(asIScriptGeneric *gen)
480 {
481 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
482 	dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0);
483 	void *ref = *(void**)gen->GetAddressOfArg(1);
484 	*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(asINT64*)ref);
485 }
486 
ScriptDictionaryGetFlt_Generic(asIScriptGeneric * gen)487 void ScriptDictionaryGetFlt_Generic(asIScriptGeneric *gen)
488 {
489 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
490 	dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0);
491 	void *ref = *(void**)gen->GetAddressOfArg(1);
492 	*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(double*)ref);
493 }
494 
ScriptDictionaryExists_Generic(asIScriptGeneric * gen)495 void ScriptDictionaryExists_Generic(asIScriptGeneric *gen)
496 {
497 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
498 	dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0);
499 	bool ret = dict->Exists(*key);
500 	*(bool*)gen->GetAddressOfReturnLocation() = ret;
501 }
502 
ScriptDictionaryIsEmpty_Generic(asIScriptGeneric * gen)503 void ScriptDictionaryIsEmpty_Generic(asIScriptGeneric *gen)
504 {
505 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
506 	bool ret = dict->IsEmpty();
507 	*(bool*)gen->GetAddressOfReturnLocation() = ret;
508 }
509 
ScriptDictionaryGetSize_Generic(asIScriptGeneric * gen)510 void ScriptDictionaryGetSize_Generic(asIScriptGeneric *gen)
511 {
512 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
513 	asUINT ret = dict->GetSize();
514 	*(asUINT*)gen->GetAddressOfReturnLocation() = ret;
515 }
516 
ScriptDictionaryDelete_Generic(asIScriptGeneric * gen)517 void ScriptDictionaryDelete_Generic(asIScriptGeneric *gen)
518 {
519 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
520 	dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0);
521 	*(bool*)gen->GetAddressOfReturnLocation() = dict->Delete(*key);
522 }
523 
ScriptDictionaryDeleteAll_Generic(asIScriptGeneric * gen)524 void ScriptDictionaryDeleteAll_Generic(asIScriptGeneric *gen)
525 {
526 	CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
527 	dict->DeleteAll();
528 }
529 
ScriptDictionaryGetRefCount_Generic(asIScriptGeneric * gen)530 static void ScriptDictionaryGetRefCount_Generic(asIScriptGeneric *gen)
531 {
532 	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
533 	*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
534 }
535 
ScriptDictionarySetGCFlag_Generic(asIScriptGeneric * gen)536 static void ScriptDictionarySetGCFlag_Generic(asIScriptGeneric *gen)
537 {
538 	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
539 	self->SetGCFlag();
540 }
541 
ScriptDictionaryGetGCFlag_Generic(asIScriptGeneric * gen)542 static void ScriptDictionaryGetGCFlag_Generic(asIScriptGeneric *gen)
543 {
544 	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
545 	*(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag();
546 }
547 
ScriptDictionaryEnumReferences_Generic(asIScriptGeneric * gen)548 static void ScriptDictionaryEnumReferences_Generic(asIScriptGeneric *gen)
549 {
550 	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
551 	asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
552 	self->EnumReferences(engine);
553 }
554 
ScriptDictionaryReleaseAllReferences_Generic(asIScriptGeneric * gen)555 static void ScriptDictionaryReleaseAllReferences_Generic(asIScriptGeneric *gen)
556 {
557 	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
558 	asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
559 	self->ReleaseAllReferences(engine);
560 }
561 
CScriptDictionaryGetKeys_Generic(asIScriptGeneric * gen)562 static void CScriptDictionaryGetKeys_Generic(asIScriptGeneric *gen)
563 {
564 	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
565 	*(CScriptArray**)gen->GetAddressOfReturnLocation() = self->GetKeys();
566 }
567 
CScriptDictionary_opIndex_Generic(asIScriptGeneric * gen)568 static void CScriptDictionary_opIndex_Generic(asIScriptGeneric *gen)
569 {
570 	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
571 	dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0);
572 	*(CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key);
573 }
574 
CScriptDictionary_opIndex_const_Generic(asIScriptGeneric * gen)575 static void CScriptDictionary_opIndex_const_Generic(asIScriptGeneric *gen)
576 {
577 	const CScriptDictionary *self = (const CScriptDictionary*)gen->GetObject();
578 	dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0);
579 	*(const CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key);
580 }
581 
582 
583 //-------------------------------------------------------------------------
584 // CScriptDictValue
585 
CScriptDictValue()586 CScriptDictValue::CScriptDictValue()
587 {
588 	m_valueObj = 0;
589 	m_typeId   = 0;
590 }
591 
CScriptDictValue(asIScriptEngine * engine,void * value,int typeId)592 CScriptDictValue::CScriptDictValue(asIScriptEngine *engine, void *value, int typeId)
593 {
594 	m_valueObj = 0;
595 	m_typeId   = 0;
596 	Set(engine, value, typeId);
597 }
598 
~CScriptDictValue()599 CScriptDictValue::~CScriptDictValue()
600 {
601 	// Must not hold an object when destroyed, as then the object will never be freed
602 	assert( (m_typeId & asTYPEID_MASK_OBJECT) == 0 );
603 }
604 
FreeValue(asIScriptEngine * engine)605 void CScriptDictValue::FreeValue(asIScriptEngine *engine)
606 {
607 	// If it is a handle or a ref counted object, call release
608 	if( m_typeId & asTYPEID_MASK_OBJECT )
609 	{
610 		// Let the engine release the object
611 		engine->ReleaseScriptObject(m_valueObj, engine->GetTypeInfoById(m_typeId));
612 		m_valueObj = 0;
613 		m_typeId = 0;
614 	}
615 
616 	// For primitives, there's nothing to do
617 }
618 
Set(asIScriptEngine * engine,void * value,int typeId)619 void CScriptDictValue::Set(asIScriptEngine *engine, void *value, int typeId)
620 {
621 	FreeValue(engine);
622 
623 	m_typeId = typeId;
624 	if( typeId & asTYPEID_OBJHANDLE )
625 	{
626 		// We're receiving a reference to the handle, so we need to dereference it
627 		m_valueObj = *(void**)value;
628 		engine->AddRefScriptObject(m_valueObj, engine->GetTypeInfoById(typeId));
629 	}
630 	else if( typeId & asTYPEID_MASK_OBJECT )
631 	{
632 		// Create a copy of the object
633 		m_valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId));
634 	}
635 	else
636 	{
637 		// Copy the primitive value
638 		// We receive a pointer to the value.
639 		int size = engine->GetSizeOfPrimitiveType(typeId);
640 		memcpy(&m_valueInt, value, size);
641 	}
642 }
643 
Set(asIScriptEngine * engine,CScriptDictValue & value)644 void CScriptDictValue::Set(asIScriptEngine *engine, CScriptDictValue &value)
645 {
646 	if( value.m_typeId & asTYPEID_OBJHANDLE )
647 		Set(engine, (void*)&value.m_valueObj, value.m_typeId);
648 	else if( value.m_typeId & asTYPEID_MASK_OBJECT )
649 		Set(engine, (void*)value.m_valueObj, value.m_typeId);
650 	else
651 		Set(engine, (void*)&value.m_valueInt, value.m_typeId);
652 }
653 
654 // This overloaded method is implemented so that all integer and
655 // unsigned integers types will be stored in the dictionary as int64
656 // through implicit conversions. This simplifies the management of the
657 // numeric types when the script retrieves the stored value using a
658 // different type.
Set(asIScriptEngine * engine,const asINT64 & value)659 void CScriptDictValue::Set(asIScriptEngine *engine, const asINT64 &value)
660 {
661 	Set(engine, const_cast<asINT64*>(&value), asTYPEID_INT64);
662 }
663 
664 // This overloaded method is implemented so that all floating point types
665 // will be stored in the dictionary as double through implicit conversions.
666 // This simplifies the management of the numeric types when the script
667 // retrieves the stored value using a different type.
Set(asIScriptEngine * engine,const double & value)668 void CScriptDictValue::Set(asIScriptEngine *engine, const double &value)
669 {
670 	Set(engine, const_cast<double*>(&value), asTYPEID_DOUBLE);
671 }
672 
Get(asIScriptEngine * engine,void * value,int typeId) const673 bool CScriptDictValue::Get(asIScriptEngine *engine, void *value, int typeId) const
674 {
675 	// Return the value
676 	if( typeId & asTYPEID_OBJHANDLE )
677 	{
678 		// A handle can be retrieved if the stored type is a handle of same or compatible type
679 		// or if the stored type is an object that implements the interface that the handle refer to.
680 		if( (m_typeId & asTYPEID_MASK_OBJECT) )
681 		{
682 			// Don't allow the get if the stored handle is to a const, but the desired handle is not
683 			if( (m_typeId & asTYPEID_HANDLETOCONST) && !(typeId & asTYPEID_HANDLETOCONST) )
684 				return false;
685 
686 			// RefCastObject will increment the refcount if successful
687 			engine->RefCastObject(m_valueObj, engine->GetTypeInfoById(m_typeId), engine->GetTypeInfoById(typeId), reinterpret_cast<void**>(value));
688 
689 			return true;
690 		}
691 	}
692 	else if( typeId & asTYPEID_MASK_OBJECT )
693 	{
694 		// Verify that the copy can be made
695 		bool isCompatible = false;
696 
697 		// Allow a handle to be value assigned if the wanted type is not a handle
698 		if( (m_typeId & ~asTYPEID_OBJHANDLE) == typeId && m_valueObj != 0 )
699 			isCompatible = true;
700 
701 		// Copy the object into the given reference
702 		if( isCompatible )
703 		{
704 			engine->AssignScriptObject(value, m_valueObj, engine->GetTypeInfoById(typeId));
705 
706 			return true;
707 		}
708 	}
709 	else
710 	{
711 		if( m_typeId == typeId )
712 		{
713 			int size = engine->GetSizeOfPrimitiveType(typeId);
714 			memcpy(value, &m_valueInt, size);
715 			return true;
716 		}
717 
718 		// We know all numbers are stored as either int64 or double, since we register overloaded functions for those
719 		// Only bool and enums needs to be treated separately
720 		if( typeId == asTYPEID_DOUBLE )
721 		{
722 			if( m_typeId == asTYPEID_INT64 )
723 				*(double*)value = double(m_valueInt);
724 			else if (m_typeId == asTYPEID_BOOL)
725 			{
726 				// Use memcpy instead of type cast to make sure the code is endianess agnostic
727 				char localValue;
728 				memcpy(&localValue, &m_valueInt, sizeof(char));
729 				*(double*)value = localValue ? 1.0 : 0.0;
730 			}
731 			else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0)
732 			{
733 				// Use memcpy instead of type cast to make sure the code is endianess agnostic
734 				int localValue;
735 				memcpy(&localValue, &m_valueInt, sizeof(int));
736 				*(double*)value = double(localValue); // enums are 32bit
737 			}
738 			else
739 			{
740 				// The stored type is an object
741 				// TODO: Check if the object has a conversion operator to a primitive value
742 				*(double*)value = 0;
743 			}
744 			return true;
745 		}
746 		else if( typeId == asTYPEID_INT64 )
747 		{
748 			if( m_typeId == asTYPEID_DOUBLE )
749 				*(asINT64*)value = asINT64(m_valueFlt);
750 			else if (m_typeId == asTYPEID_BOOL)
751 			{
752 				// Use memcpy instead of type cast to make sure the code is endianess agnostic
753 				char localValue;
754 				memcpy(&localValue, &m_valueInt, sizeof(char));
755 				*(asINT64*)value = localValue ? 1 : 0;
756 			}
757 			else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0)
758 			{
759 				// Use memcpy instead of type cast to make sure the code is endianess agnostic
760 				int localValue;
761 				memcpy(&localValue, &m_valueInt, sizeof(int));
762 				*(asINT64*)value = localValue; // enums are 32bit
763 			}
764 			else
765 			{
766 				// The stored type is an object
767 				// TODO: Check if the object has a conversion operator to a primitive value
768 				*(asINT64*)value = 0;
769 			}
770 			return true;
771 		}
772 		else if( typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0 )
773 		{
774 			// The desired type is an enum. These are always 32bit integers
775 			if( m_typeId == asTYPEID_DOUBLE )
776 				*(int*)value = int(m_valueFlt);
777 			else if( m_typeId == asTYPEID_INT64 )
778 				*(int*)value = int(m_valueInt);
779 			else if (m_typeId == asTYPEID_BOOL)
780 			{
781 				// Use memcpy instead of type cast to make sure the code is endianess agnostic
782 				char localValue;
783 				memcpy(&localValue, &m_valueInt, sizeof(char));
784 				*(int*)value = localValue ? 1 : 0;
785 			}
786 			else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0)
787 			{
788 				// Use memcpy instead of type cast to make sure the code is endianess agnostic
789 				int localValue;
790 				memcpy(&localValue, &m_valueInt, sizeof(int));
791 				*(int*)value = localValue; // enums are 32bit
792 			}
793 			else
794 			{
795 				// The stored type is an object
796 				// TODO: Check if the object has a conversion operator to a primitive value
797 				*(int*)value = 0;
798 			}
799 		}
800 		else if( typeId == asTYPEID_BOOL )
801 		{
802 			if (m_typeId & asTYPEID_OBJHANDLE)
803 			{
804 				// TODO: Check if the object has a conversion operator to a primitive value
805 				*(bool*)value = m_valueObj ? true : false;
806 			}
807 			else if( m_typeId & asTYPEID_MASK_OBJECT )
808 			{
809 				// TODO: Check if the object has a conversion operator to a primitive value
810 				*(bool*)value = true;
811 			}
812 			else
813 			{
814 				// Compare only the bytes that were actually set
815 				asQWORD zero = 0;
816 				int size = engine->GetSizeOfPrimitiveType(m_typeId);
817 				*(bool*)value = memcmp(&m_valueInt, &zero, size) == 0 ? false : true;
818 			}
819 		}
820 	}
821 
822 	// It was not possible to retrieve the value using the desired typeId
823 	return false;
824 }
825 
GetAddressOfValue() const826 const void * CScriptDictValue::GetAddressOfValue() const
827 {
828 	if( (m_typeId & asTYPEID_MASK_OBJECT) && !(m_typeId & asTYPEID_OBJHANDLE) )
829 	{
830 		// Return the address to the object directly
831 		return m_valueObj;
832 	}
833 
834 	// Return the address of the primitive or the pointer to the object
835 	return reinterpret_cast<const void*>(&m_valueObj);
836 }
837 
Get(asIScriptEngine * engine,asINT64 & value) const838 bool CScriptDictValue::Get(asIScriptEngine *engine, asINT64 &value) const
839 {
840 	return Get(engine, &value, asTYPEID_INT64);
841 }
842 
Get(asIScriptEngine * engine,double & value) const843 bool CScriptDictValue::Get(asIScriptEngine *engine, double &value) const
844 {
845 	return Get(engine, &value, asTYPEID_DOUBLE);
846 }
847 
GetTypeId() const848 int CScriptDictValue::GetTypeId() const
849 {
850 	return m_typeId;
851 }
852 
CScriptDictValue_Construct(void * mem)853 static void CScriptDictValue_Construct(void *mem)
854 {
855 	new(mem) CScriptDictValue();
856 }
857 
CScriptDictValue_Destruct(CScriptDictValue * obj)858 static void CScriptDictValue_Destruct(CScriptDictValue *obj)
859 {
860 	asIScriptContext *ctx = asGetActiveContext();
861 	if( ctx )
862 	{
863 		asIScriptEngine *engine = ctx->GetEngine();
864 		obj->FreeValue(engine);
865 	}
866 	obj->~CScriptDictValue();
867 }
868 
CScriptDictValue_opAssign(void * ref,int typeId,CScriptDictValue * obj)869 static CScriptDictValue &CScriptDictValue_opAssign(void *ref, int typeId, CScriptDictValue *obj)
870 {
871 	asIScriptContext *ctx = asGetActiveContext();
872 	if( ctx )
873 	{
874 		asIScriptEngine *engine = ctx->GetEngine();
875 		obj->Set(engine, ref, typeId);
876 	}
877 	return *obj;
878 }
879 
CScriptDictValue_opAssign(const CScriptDictValue & other,CScriptDictValue * obj)880 static CScriptDictValue &CScriptDictValue_opAssign(const CScriptDictValue &other, CScriptDictValue *obj)
881 {
882 	asIScriptContext *ctx = asGetActiveContext();
883 	if( ctx )
884 	{
885 		asIScriptEngine *engine = ctx->GetEngine();
886 		obj->Set(engine, const_cast<CScriptDictValue&>(other));
887 	}
888 
889 	return *obj;
890 }
891 
CScriptDictValue_opAssign(double val,CScriptDictValue * obj)892 static CScriptDictValue &CScriptDictValue_opAssign(double val, CScriptDictValue *obj)
893 {
894 	return CScriptDictValue_opAssign(&val, asTYPEID_DOUBLE, obj);
895 }
896 
CScriptDictValue_opAssign(asINT64 val,CScriptDictValue * obj)897 static CScriptDictValue &CScriptDictValue_opAssign(asINT64 val, CScriptDictValue *obj)
898 {
899 	return CScriptDictValue_opAssign(&val, asTYPEID_INT64, obj);
900 }
901 
CScriptDictValue_opCast(void * ref,int typeId,CScriptDictValue * obj)902 static void CScriptDictValue_opCast(void *ref, int typeId, CScriptDictValue *obj)
903 {
904 	asIScriptContext *ctx = asGetActiveContext();
905 	if( ctx )
906 	{
907 		asIScriptEngine *engine = ctx->GetEngine();
908 		obj->Get(engine, ref, typeId);
909 	}
910 }
911 
CScriptDictValue_opConvInt(CScriptDictValue * obj)912 static asINT64 CScriptDictValue_opConvInt(CScriptDictValue *obj)
913 {
914 	asINT64 value;
915 	CScriptDictValue_opCast(&value, asTYPEID_INT64, obj);
916 	return value;
917 }
918 
CScriptDictValue_opConvDouble(CScriptDictValue * obj)919 static double CScriptDictValue_opConvDouble(CScriptDictValue *obj)
920 {
921 	double value;
922 	CScriptDictValue_opCast(&value, asTYPEID_DOUBLE, obj);
923 	return value;
924 }
925 
926 //-------------------------------------------------------------------
927 // generic wrapper for CScriptDictValue
928 
CScriptDictValue_opConvDouble_Generic(asIScriptGeneric * gen)929 static void CScriptDictValue_opConvDouble_Generic(asIScriptGeneric *gen)
930 {
931 	CScriptDictValue *self = (CScriptDictValue*)gen->GetObject();
932 	double value;
933 	self->Get(gen->GetEngine(), value);
934 	*(double*)gen->GetAddressOfReturnLocation() = value;
935 }
936 
CScriptDictValue_opConvInt_Generic(asIScriptGeneric * gen)937 static void CScriptDictValue_opConvInt_Generic(asIScriptGeneric *gen)
938 {
939 	CScriptDictValue *self = (CScriptDictValue*)gen->GetObject();
940 	asINT64 value;
941 	self->Get(gen->GetEngine(), value);
942 	*(asINT64*)gen->GetAddressOfReturnLocation() = value;
943 }
944 
CScriptDictValue_opCast_Generic(asIScriptGeneric * gen)945 static void CScriptDictValue_opCast_Generic(asIScriptGeneric *gen)
946 {
947 	CScriptDictValue *self = (CScriptDictValue*)gen->GetObject();
948 	self->Get(gen->GetEngine(), gen->GetArgAddress(0), gen->GetArgTypeId(0));
949 }
950 
CScriptDictValue_opAssign_int64_Generic(asIScriptGeneric * gen)951 static void CScriptDictValue_opAssign_int64_Generic(asIScriptGeneric *gen)
952 {
953 	CScriptDictValue *self = (CScriptDictValue*)gen->GetObject();
954 	*(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign((asINT64)gen->GetArgQWord(0), self);
955 }
956 
CScriptDictValue_opAssign_double_Generic(asIScriptGeneric * gen)957 static void CScriptDictValue_opAssign_double_Generic(asIScriptGeneric *gen)
958 {
959 	CScriptDictValue *self = (CScriptDictValue*)gen->GetObject();
960 	*(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgDouble(0), self);
961 }
962 
CScriptDictValue_opAssign_Generic(asIScriptGeneric * gen)963 static void CScriptDictValue_opAssign_Generic(asIScriptGeneric *gen)
964 {
965 	CScriptDictValue *self = (CScriptDictValue*)gen->GetObject();
966 	*(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgAddress(0), gen->GetArgTypeId(0), self);
967 }
968 
CScriptDictValue_opCopyAssign_Generic(asIScriptGeneric * gen)969 static void CScriptDictValue_opCopyAssign_Generic(asIScriptGeneric *gen)
970 {
971 	CScriptDictValue *self = (CScriptDictValue*)gen->GetObject();
972 	*(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(*reinterpret_cast<CScriptDictValue*>(gen->GetArgAddress(0)), self);
973 }
974 
CScriptDictValue_Construct_Generic(asIScriptGeneric * gen)975 static void CScriptDictValue_Construct_Generic(asIScriptGeneric *gen)
976 {
977 	CScriptDictValue *self = (CScriptDictValue*)gen->GetObject();
978 	CScriptDictValue_Construct(self);
979 }
980 
CScriptDictValue_Destruct_Generic(asIScriptGeneric * gen)981 static void CScriptDictValue_Destruct_Generic(asIScriptGeneric *gen)
982 {
983 	CScriptDictValue *self = (CScriptDictValue*)gen->GetObject();
984 	CScriptDictValue_Destruct(self);
985 }
986 
987 //--------------------------------------------------------------------------
988 // Register the type
989 
RegisterScriptDictionary(asIScriptEngine * engine)990 void RegisterScriptDictionary(asIScriptEngine *engine)
991 {
992 	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
993 		RegisterScriptDictionary_Generic(engine);
994 	else
995 		RegisterScriptDictionary_Native(engine);
996 }
997 
RegisterScriptDictionary_Native(asIScriptEngine * engine)998 void RegisterScriptDictionary_Native(asIScriptEngine *engine)
999 {
1000 	int r;
1001 
1002 	// The array<string> type must be available
1003 	assert( engine->GetTypeInfoByDecl("array<string>") );
1004 
1005 #if AS_CAN_USE_CPP11
1006 	// With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class
1007 	r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asGetTypeTraits<CScriptDictValue>()); assert( r >= 0 );
1008 #else
1009 	r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_APP_CLASS_CD); assert( r >= 0 );
1010 #endif
1011 	r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1012 	r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1013 	r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1014 	r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1015 	r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1016 	r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTIONPR(CScriptDictValue_opAssign, (double, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1017 	r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTIONPR(CScriptDictValue_opAssign, (asINT64, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1018 	r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1019 	r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1020 	r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTIONPR(CScriptDictValue_opConvInt, (CScriptDictValue*), asINT64), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1021 	r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTIONPR(CScriptDictValue_opConvDouble, (CScriptDictValue*), double), asCALL_CDECL_OBJLAST); assert( r >= 0 );
1022 
1023 	r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
1024 	// 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
1025 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r >= 0 );
1026 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 );
1027 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 );
1028 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 );
1029 
1030 	r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asMETHODPR(CScriptDictionary, operator=, (const CScriptDictionary &), CScriptDictionary&), asCALL_THISCALL); assert( r >= 0 );
1031 
1032 	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 );
1033 	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 );
1034 
1035 	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 );
1036 	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 );
1037 
1038 	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 );
1039 	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 );
1040 
1041 	r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 );
1042 	r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 );
1043 	r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 );
1044 	r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 );
1045 	r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
1046 
1047 	r = engine->RegisterObjectMethod("dictionary", "array<string> @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), asCALL_THISCALL); assert( r >= 0 );
1048 
1049 	r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &), CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 );
1050 	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 );
1051 
1052 	// Register GC behaviours
1053 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 );
1054 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 );
1055 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 );
1056 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 );
1057 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 );
1058 
1059 #if AS_USE_STLNAMES == 1
1060 	// Same as isEmpty
1061 	r = engine->RegisterObjectMethod("dictionary", "bool empty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 );
1062 	// Same as getSize
1063 	r = engine->RegisterObjectMethod("dictionary", "uint size() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 );
1064 	// Same as delete
1065 	r = engine->RegisterObjectMethod("dictionary", "void erase(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 );
1066 	// Same as deleteAll
1067 	r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
1068 #endif
1069 
1070 	// Cache some things the dictionary will need at runtime
1071 	SDictionaryCache::Setup(engine);
1072 }
1073 
RegisterScriptDictionary_Generic(asIScriptEngine * engine)1074 void RegisterScriptDictionary_Generic(asIScriptEngine *engine)
1075 {
1076 	int r;
1077 
1078 	// Register the cleanup callback for the object type cache
1079 	engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE);
1080 
1081 #if AS_CAN_USE_CPP11
1082 	// With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class
1083 	r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asGetTypeTraits<CScriptDictValue>()); assert( r >= 0 );
1084 #else
1085 	r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_APP_CLASS_CD); assert( r >= 0 );
1086 #endif
1087 	r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct_Generic), asCALL_GENERIC); assert( r >= 0 );
1088 	r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 );
1089 	r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 );
1090 	r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 );
1091 	r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 );
1092 	r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTION(CScriptDictValue_opAssign_double_Generic), asCALL_GENERIC); assert( r >= 0 );
1093 	r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTION(CScriptDictValue_opAssign_int64_Generic), asCALL_GENERIC); assert( r >= 0 );
1094 	r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 );
1095 	r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 );
1096 	r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTION(CScriptDictValue_opConvInt_Generic), asCALL_GENERIC); assert( r >= 0 );
1097 	r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTION(CScriptDictValue_opConvDouble_Generic), asCALL_GENERIC); assert( r >= 0 );
1098 
1099 	r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
1100 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 );
1101 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 );
1102 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 );
1103 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 );
1104 
1105 	r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asFUNCTION(ScriptDictionaryAssign_Generic), asCALL_GENERIC); assert( r >= 0 );
1106 
1107 	r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 );
1108 	r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 );
1109 
1110 	r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 );
1111 	r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 );
1112 
1113 	r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
1114 	r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
1115 
1116 	r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 );
1117 	r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asFUNCTION(ScriptDictionaryIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 );
1118 	r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asFUNCTION(ScriptDictionaryGetSize_Generic), asCALL_GENERIC); assert( r >= 0 );
1119 	r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 );
1120 	r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 );
1121 
1122 	r = engine->RegisterObjectMethod("dictionary", "array<string> @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 );
1123 
1124 	r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asFUNCTION(CScriptDictionary_opIndex_Generic), asCALL_GENERIC); assert( r >= 0 );
1125 	r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asFUNCTION(CScriptDictionary_opIndex_const_Generic), asCALL_GENERIC); assert( r >= 0 );
1126 
1127 	// Register GC behaviours
1128 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 );
1129 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
1130 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
1131 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
1132 	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
1133 
1134 	// Cache some things the dictionary will need at runtime
1135 	SDictionaryCache::Setup(engine);
1136 }
1137 
1138 //------------------------------------------------------------------
1139 // Iterator implementation
1140 
begin() const1141 CScriptDictionary::CIterator CScriptDictionary::begin() const
1142 {
1143 	return CIterator(*this, dict.begin());
1144 }
1145 
end() const1146 CScriptDictionary::CIterator CScriptDictionary::end() const
1147 {
1148 	return CIterator(*this, dict.end());
1149 }
1150 
find(const dictKey_t & key) const1151 CScriptDictionary::CIterator CScriptDictionary::find(const dictKey_t &key) const
1152 {
1153 	return CIterator(*this, dict.find(key));
1154 }
1155 
CIterator(const CScriptDictionary & dict,dictMap_t::const_iterator it)1156 CScriptDictionary::CIterator::CIterator(
1157 		const CScriptDictionary &dict,
1158 		dictMap_t::const_iterator it)
1159 	: m_it(it), m_dict(dict)
1160 {}
1161 
operator ++()1162 void CScriptDictionary::CIterator::operator++()
1163 {
1164 	++m_it;
1165 }
1166 
operator ++(int)1167 void CScriptDictionary::CIterator::operator++(int)
1168 {
1169 	++m_it;
1170 
1171 	// Normally the post increment would return a copy of the object with the original state,
1172 	// but it is rarely used so we skip this extra copy to avoid unnecessary overhead
1173 }
1174 
operator *()1175 CScriptDictionary::CIterator &CScriptDictionary::CIterator::operator*()
1176 {
1177 	return *this;
1178 }
1179 
operator ==(const CIterator & other) const1180 bool CScriptDictionary::CIterator::operator==(const CIterator &other) const
1181 {
1182 	return m_it == other.m_it;
1183 }
1184 
operator !=(const CIterator & other) const1185 bool CScriptDictionary::CIterator::operator!=(const CIterator &other) const
1186 {
1187 	return m_it != other.m_it;
1188 }
1189 
GetKey() const1190 const dictKey_t &CScriptDictionary::CIterator::GetKey() const
1191 {
1192 	return m_it->first;
1193 }
1194 
GetTypeId() const1195 int CScriptDictionary::CIterator::GetTypeId() const
1196 {
1197 	return m_it->second.m_typeId;
1198 }
1199 
GetValue(asINT64 & value) const1200 bool CScriptDictionary::CIterator::GetValue(asINT64 &value) const
1201 {
1202 	return m_it->second.Get(m_dict.engine, &value, asTYPEID_INT64);
1203 }
1204 
GetValue(double & value) const1205 bool CScriptDictionary::CIterator::GetValue(double &value) const
1206 {
1207 	return m_it->second.Get(m_dict.engine, &value, asTYPEID_DOUBLE);
1208 }
1209 
GetValue(void * value,int typeId) const1210 bool CScriptDictionary::CIterator::GetValue(void *value, int typeId) const
1211 {
1212 	return m_it->second.Get(m_dict.engine, value, typeId);
1213 }
1214 
GetAddressOfValue() const1215 const void *CScriptDictionary::CIterator::GetAddressOfValue() const
1216 {
1217 	return m_it->second.GetAddressOfValue();
1218 }
1219 
1220 END_AS_NAMESPACE
1221 
1222 
1223