PageRenderTime 204ms CodeModel.GetById 157ms app.highlight 42ms RepoModel.GetById 2ms app.codeStats 0ms

/xbmc/visualizations/Vortex/angelscript/add_on/scriptdictionary/scriptdictionary.cpp

http://github.com/xbmc/xbmc
C++ | 467 lines | 342 code | 75 blank | 50 comment | 39 complexity | 55e318b3c708a72c2655688f9e4308ce MD5 | raw file
  1#include <assert.h>
  2#include <string.h>
  3#include "scriptdictionary.h"
  4
  5BEGIN_AS_NAMESPACE
  6
  7using namespace std;
  8
  9//--------------------------------------------------------------------------
 10// CScriptDictionary implementation
 11
 12CScriptDictionary::CScriptDictionary(asIScriptEngine *engine)
 13{
 14    // We start with one reference
 15    refCount = 1;
 16
 17    // Keep a reference to the engine for as long as we live
 18	// We don't increment the reference counter, because the 
 19	// engine will hold a pointer to the object. 
 20    this->engine = engine;
 21
 22	// Notify the garbage collector of this object
 23	// TODO: The type id should be cached
 24	engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeIdByDecl("dictionary"));
 25}
 26
 27CScriptDictionary::~CScriptDictionary()
 28{
 29    // Delete all keys and values
 30    DeleteAll();
 31}
 32
 33void CScriptDictionary::AddRef()
 34{
 35	// We need to clear the GC flag
 36	refCount = (refCount & 0x7FFFFFFF) + 1;
 37}
 38
 39void CScriptDictionary::Release()
 40{
 41	// We need to clear the GC flag
 42	refCount = (refCount & 0x7FFFFFFF) - 1;
 43	if( refCount == 0 )
 44        delete this;
 45}
 46
 47int CScriptDictionary::GetRefCount()
 48{
 49	return refCount & 0x7FFFFFFF;
 50}
 51
 52void CScriptDictionary::SetGCFlag()
 53{
 54	refCount |= 0x80000000;
 55}
 56
 57bool CScriptDictionary::GetGCFlag()
 58{
 59	return (refCount & 0x80000000) ? true : false;
 60}
 61
 62void CScriptDictionary::EnumReferences(asIScriptEngine *engine)
 63{
 64	// Call the gc enum callback for each of the objects
 65    map<string, valueStruct>::iterator it;
 66    for( it = dict.begin(); it != dict.end(); it++ )
 67    {
 68		if( it->second.typeId & asTYPEID_MASK_OBJECT )
 69			engine->GCEnumCallback(it->second.valueObj);
 70    }
 71}
 72
 73void CScriptDictionary::ReleaseAllReferences(asIScriptEngine * /*engine*/)
 74{
 75	// We're being told to release all references in 
 76	// order to break circular references for dead objects
 77	DeleteAll();
 78}
 79
 80CScriptDictionary &CScriptDictionary::operator =(const CScriptDictionary & /*other*/)
 81{
 82    // Do nothing
 83	// TODO: Should do a shallow copy of the dictionary
 84
 85    return *this;
 86}
 87
 88void CScriptDictionary::Set(const string &key, void *value, int typeId)
 89{
 90	valueStruct valStruct = {{0},0};
 91	valStruct.typeId = typeId;
 92	if( typeId & asTYPEID_OBJHANDLE )
 93	{
 94		// We're receiving a reference to the handle, so we need to dereference it
 95		valStruct.valueObj = *(void**)value;
 96		engine->AddRefScriptObject(valStruct.valueObj, typeId);
 97	}
 98	else if( typeId & asTYPEID_MASK_OBJECT )
 99	{
100		// Create a copy of the object
101		valStruct.valueObj = engine->CreateScriptObjectCopy(value, typeId);
102	}
103	else
104	{
105		// Copy the primitive value
106		// We receive a pointer to the value.
107		int size = engine->GetSizeOfPrimitiveType(typeId);
108		memcpy(&valStruct.valueInt, value, size);
109	}
110
111    map<string, valueStruct>::iterator it;
112    it = dict.find(key);
113    if( it != dict.end() )
114    {
115        FreeValue(it->second);
116
117        // Insert the new value
118        it->second = valStruct;
119    }
120    else
121    {
122        dict.insert(map<string, valueStruct>::value_type(key, valStruct));
123    }
124}
125
126// This overloaded method is implemented so that all integer and
127// unsigned integers types will be stored in the dictionary as int64
128// through implicit conversions. This simplifies the management of the
129// numeric types when the script retrieves the stored value using a 
130// different type.
131void CScriptDictionary::Set(const string &key, asINT64 &value)
132{
133	Set(key, &value, asTYPEID_INT64);
134}
135
136// This overloaded method is implemented so that all floating point types 
137// will be stored in the dictionary as double through implicit conversions. 
138// This simplifies the management of the numeric types when the script 
139// retrieves the stored value using a different type.
140void CScriptDictionary::Set(const string &key, double &value)
141{
142	Set(key, &value, asTYPEID_DOUBLE);
143}
144
145// Returns true if the value was successfully retrieved
146bool CScriptDictionary::Get(const string &key, void *value, int typeId) const
147{
148    map<string, valueStruct>::const_iterator it;
149    it = dict.find(key);
150    if( it != dict.end() )
151    {
152        // Return the value
153		if( typeId & asTYPEID_OBJHANDLE )
154		{
155			// A handle can be retrieved if the stored type is a handle of same or compatible type
156			// or if the stored type is an object that implements the interface that the handle refer to.
157			if( (it->second.typeId & asTYPEID_MASK_OBJECT) && 
158				engine->IsHandleCompatibleWithObject(it->second.valueObj, it->second.typeId, typeId) )
159			{
160				engine->AddRefScriptObject(it->second.valueObj, it->second.typeId);
161				*(void**)value = it->second.valueObj;
162
163				return true;
164			}
165		}
166		else if( typeId & asTYPEID_MASK_OBJECT )
167		{
168			// Verify that the copy can be made
169			bool isCompatible = false;
170			if( it->second.typeId == typeId )
171				isCompatible = true;
172
173			// Copy the object into the given reference
174			if( isCompatible )
175			{
176				engine->CopyScriptObject(value, it->second.valueObj, typeId);
177
178				return true;
179			}
180		}
181		else
182		{
183			if( it->second.typeId == typeId )
184			{
185				int size = engine->GetSizeOfPrimitiveType(typeId);
186				memcpy(value, &it->second.valueInt, size);
187				return true;
188			}
189
190			// We know all numbers are stored as either int64 or double, since we register overloaded functions for those
191			if( it->second.typeId == asTYPEID_INT64 && typeId == asTYPEID_DOUBLE )
192			{
193				*(double*)value = double(it->second.valueInt);
194				return true;
195			}
196			else if( it->second.typeId == asTYPEID_DOUBLE && typeId == asTYPEID_INT64 )
197			{
198				*(asINT64*)value = asINT64(it->second.valueFlt);
199				return true;
200			}
201		}
202    }
203
204    // AngelScript has already initialized the value with a default value,
205    // so we don't have to do anything if we don't find the element, or if 
206	// the element is incompatible with the requested type.
207
208	return false;
209}
210
211bool CScriptDictionary::Get(const string &key, asINT64 &value) const
212{
213	return Get(key, &value, asTYPEID_INT64);
214}
215
216bool CScriptDictionary::Get(const string &key, double &value) const
217{
218	return Get(key, &value, asTYPEID_DOUBLE);
219}
220
221bool CScriptDictionary::Exists(const string &key) const
222{
223    map<string, valueStruct>::const_iterator it;
224    it = dict.find(key);
225    if( it != dict.end() )
226    {
227        return true;
228    }
229
230    return false;
231}
232
233void CScriptDictionary::Delete(const string &key)
234{
235    map<string, valueStruct>::iterator it;
236    it = dict.find(key);
237    if( it != dict.end() )
238    {
239        FreeValue(it->second);
240
241        dict.erase(it);
242    }
243}
244
245void CScriptDictionary::DeleteAll()
246{
247    map<string, valueStruct>::iterator it;
248    for( it = dict.begin(); it != dict.end(); it++ )
249    {
250        FreeValue(it->second);
251    }
252
253    dict.clear();
254}
255
256void CScriptDictionary::FreeValue(valueStruct &value)
257{
258    // If it is a handle or a ref counted object, call release
259	if( value.typeId & asTYPEID_MASK_OBJECT )
260	{
261		// Let the engine release the object
262		engine->ReleaseScriptObject(value.valueObj, value.typeId);
263		value.valueObj = 0;
264		value.typeId = 0;
265	}
266
267    // For primitives, there's nothing to do
268}
269
270//--------------------------------------------------------------------------
271// Generic wrappers
272
273void ScriptDictionaryFactory_Generic(asIScriptGeneric *gen)
274{
275    *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = new CScriptDictionary(gen->GetEngine());
276}
277
278void ScriptDictionaryAddRef_Generic(asIScriptGeneric *gen)
279{
280    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
281    dict->AddRef();
282}
283
284void ScriptDictionaryRelease_Generic(asIScriptGeneric *gen)
285{
286    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
287    dict->Release();
288}
289
290void ScriptDictionarySet_Generic(asIScriptGeneric *gen)
291{
292    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
293    string *key = *(string**)gen->GetAddressOfArg(0);
294    void *ref = *(void**)gen->GetAddressOfArg(1);
295    int typeId = gen->GetArgTypeId(1);
296    dict->Set(*key, ref, typeId);
297}
298
299void ScriptDictionarySetInt_Generic(asIScriptGeneric *gen)
300{
301    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
302    string *key = *(string**)gen->GetAddressOfArg(0);
303    void *ref = *(void**)gen->GetAddressOfArg(1);
304    dict->Set(*key, *(asINT64*)ref);
305}
306
307void ScriptDictionarySetFlt_Generic(asIScriptGeneric *gen)
308{
309    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
310    string *key = *(string**)gen->GetAddressOfArg(0);
311    void *ref = *(void**)gen->GetAddressOfArg(1);
312    dict->Set(*key, *(double*)ref);
313}
314
315void ScriptDictionaryGet_Generic(asIScriptGeneric *gen)
316{
317    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
318    string *key = *(string**)gen->GetAddressOfArg(0);
319    void *ref = *(void**)gen->GetAddressOfArg(1);
320    int typeId = gen->GetArgTypeId(1);
321    *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, ref, typeId);
322}
323
324void ScriptDictionaryGetInt_Generic(asIScriptGeneric *gen)
325{
326    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
327    string *key = *(string**)gen->GetAddressOfArg(0);
328    void *ref = *(void**)gen->GetAddressOfArg(1);
329    *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(asINT64*)ref);
330}
331
332void ScriptDictionaryGetFlt_Generic(asIScriptGeneric *gen)
333{
334    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
335    string *key = *(string**)gen->GetAddressOfArg(0);
336    void *ref = *(void**)gen->GetAddressOfArg(1);
337    *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(double*)ref);
338}
339
340void ScriptDictionaryExists_Generic(asIScriptGeneric *gen)
341{
342    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
343    string *key = *(string**)gen->GetAddressOfArg(0);
344    bool ret = dict->Exists(*key);
345    *(bool*)gen->GetAddressOfReturnLocation() = ret;
346}
347
348void ScriptDictionaryDelete_Generic(asIScriptGeneric *gen)
349{
350    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
351    string *key = *(string**)gen->GetAddressOfArg(0);
352    dict->Delete(*key);
353}
354
355void ScriptDictionaryDeleteAll_Generic(asIScriptGeneric *gen)
356{
357    CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
358    dict->DeleteAll();
359}
360
361static void ScriptDictionaryGetRefCount_Generic(asIScriptGeneric *gen)
362{
363	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
364	*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
365}
366
367static void ScriptDictionarySetGCFlag_Generic(asIScriptGeneric *gen)
368{
369	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
370	self->SetGCFlag();
371}
372
373static void ScriptDictionaryGetGCFlag_Generic(asIScriptGeneric *gen)
374{
375	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
376	*(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag();
377}
378
379static void ScriptDictionaryEnumReferences_Generic(asIScriptGeneric *gen)
380{
381	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
382	asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
383	self->EnumReferences(engine);
384}
385
386static void ScriptDictionaryReleaseAllReferences_Generic(asIScriptGeneric *gen)
387{
388	CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
389	asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
390	self->ReleaseAllReferences(engine);
391}
392
393//--------------------------------------------------------------------------
394// Register the type
395
396void RegisterScriptDictionary(asIScriptEngine *engine)
397{
398	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
399		RegisterScriptDictionary_Generic(engine);
400	else
401		RegisterScriptDictionary_Native(engine);
402}
403
404void RegisterScriptDictionary_Native(asIScriptEngine *engine)
405{
406	int r;
407
408    r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
409	// 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
410    r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 );
411    r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 );
412    r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 );
413
414    r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, ?&in)", asMETHODPR(CScriptDictionary,Set,(const string&,void*,int),void), asCALL_THISCALL); assert( r >= 0 );
415    r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const string&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 );
416
417    r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, int64&in)", asMETHODPR(CScriptDictionary,Set,(const string&,asINT64&),void), asCALL_THISCALL); assert( r >= 0 );
418    r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const string&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 );
419
420    r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, double&in)", asMETHODPR(CScriptDictionary,Set,(const string&,double&),void), asCALL_THISCALL); assert( r >= 0 );
421    r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const string&,double&) const,bool), asCALL_THISCALL); assert( r >= 0 );
422    
423	r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 );
424    r = engine->RegisterObjectMethod("dictionary", "void delete(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 );
425    r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
426
427	// Register GC behaviours
428	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 );
429	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 );
430	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 );
431	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 );
432	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 );
433}
434
435void RegisterScriptDictionary_Generic(asIScriptEngine *engine)
436{
437    int r;
438
439    r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
440    r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 );
441    r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 );
442    r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 );
443
444    r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 );
445    r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 );
446    
447    r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 );
448    r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 );
449
450    r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
451    r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
452
453	r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 );
454    r = engine->RegisterObjectMethod("dictionary", "void delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 );
455    r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 );
456
457	// Register GC behaviours
458	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 );
459	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
460	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
461	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
462	r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
463}
464
465END_AS_NAMESPACE
466
467