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