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