Addons.cpp 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Addons.h"
  24. #include <cstring>
  25. #include <new>
  26. #include <stdio.h>
  27. // Adapted from Angelscript's scriptarray & scriptstdstring add-ons, but with garbage collection disabled
  28. namespace Urho3D
  29. {
  30. using namespace std;
  31. /// %Script array buffer.
  32. struct SArrayBuffer
  33. {
  34. asDWORD maxElements;
  35. asDWORD numElements;
  36. asBYTE data[1];
  37. };
  38. /// %Script array cache.
  39. struct SArrayCache
  40. {
  41. asIScriptFunction *cmpFunc;
  42. asIScriptFunction *eqFunc;
  43. int cmpFuncReturnCode; // To allow better error message in case of multiple matches
  44. int eqFuncReturnCode;
  45. };
  46. // We just define a number here that we assume nobody else is using for
  47. // object type user data. The add-ons have reserved the numbers 1000
  48. // through 1999 for this purpose, so we should be fine.
  49. const asPWORD ARRAY_CACHE = 1000;
  50. static void CleanupObjectTypeArrayCache(asIObjectType *type)
  51. {
  52. SArrayCache *cache = reinterpret_cast<SArrayCache*>(type->GetUserData(ARRAY_CACHE));
  53. if( cache )
  54. delete cache;
  55. }
  56. static CScriptArray* ScriptArrayFactory2(asIObjectType *ot, asUINT length)
  57. {
  58. CScriptArray *a = new CScriptArray(length, ot);
  59. // It's possible the constructor raised a script exception, in which case we
  60. // need to free the memory and return null instead, else we get a memory leak.
  61. asIScriptContext *ctx = asGetActiveContext();
  62. if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION )
  63. {
  64. a->Release();
  65. return 0;
  66. }
  67. return a;
  68. }
  69. static CScriptArray* ScriptArrayListFactory(asIObjectType *ot, void *initList)
  70. {
  71. CScriptArray *a = new CScriptArray(ot, initList);
  72. // It's possible the constructor raised a script exception, in which case we
  73. // need to free the memory and return null instead, else we get a memory leak.
  74. asIScriptContext *ctx = asGetActiveContext();
  75. if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION )
  76. {
  77. a->Release();
  78. return 0;
  79. }
  80. return a;
  81. }
  82. static CScriptArray* ScriptArrayFactoryDefVal(asIObjectType *ot, asUINT length, void *defVal)
  83. {
  84. CScriptArray *a = new CScriptArray(length, defVal, ot);
  85. // It's possible the constructor raised a script exception, in which case we
  86. // need to free the memory and return null instead, else we get a memory leak.
  87. asIScriptContext *ctx = asGetActiveContext();
  88. if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION )
  89. {
  90. a->Release();
  91. return 0;
  92. }
  93. return a;
  94. }
  95. static CScriptArray* ScriptArrayFactory(asIObjectType *ot)
  96. {
  97. return ScriptArrayFactory2(ot, 0);
  98. }
  99. // This optional callback is called when the template type is first used by the compiler.
  100. // It allows the application to validate if the template can be instanciated for the requested
  101. // subtype at compile time, instead of at runtime. The output argument dontGarbageCollect
  102. // allow the callback to tell the engine if the template instance type shouldn't be garbage collected,
  103. // i.e. no asOBJ_GC flag.
  104. static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageCollect)
  105. {
  106. // Urho3D: nothing is garbage collected
  107. dontGarbageCollect = true;
  108. // Make sure the subtype can be instanciated with a default factory/constructor,
  109. // otherwise we won't be able to instanciate the elements.
  110. int typeId = ot->GetSubTypeId();
  111. if( typeId == asTYPEID_VOID )
  112. return false;
  113. if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) )
  114. {
  115. asIObjectType *subtype = ot->GetEngine()->GetObjectTypeById(typeId);
  116. asDWORD flags = subtype->GetFlags();
  117. if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) )
  118. {
  119. // Verify that there is a default constructor
  120. bool found = false;
  121. for( asUINT n = 0; n < subtype->GetBehaviourCount(); n++ )
  122. {
  123. asEBehaviours beh;
  124. asIScriptFunction *func = subtype->GetBehaviourByIndex(n, &beh);
  125. if( beh != asBEHAVE_CONSTRUCT ) continue;
  126. if( func->GetParamCount() == 0 )
  127. {
  128. // Found the default constructor
  129. found = true;
  130. break;
  131. }
  132. }
  133. if( !found )
  134. {
  135. // There is no default constructor
  136. return false;
  137. }
  138. }
  139. else if( (flags & asOBJ_REF) )
  140. {
  141. bool found = false;
  142. // If value assignment for ref type has been disabled then the array
  143. // can be created if the type has a default factory function
  144. if( !ot->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) )
  145. {
  146. // Verify that there is a default factory
  147. for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ )
  148. {
  149. asIScriptFunction *func = subtype->GetFactoryByIndex(n);
  150. if( func->GetParamCount() == 0 )
  151. {
  152. // Found the default factory
  153. found = true;
  154. break;
  155. }
  156. }
  157. }
  158. if( !found )
  159. {
  160. // No default factory
  161. return false;
  162. }
  163. }
  164. // If the object type is not garbage collected then the array also doesn't need to be
  165. if( !(flags & asOBJ_GC) )
  166. dontGarbageCollect = true;
  167. }
  168. else if( !(typeId & asTYPEID_OBJHANDLE) )
  169. {
  170. // Arrays with primitives cannot form circular references,
  171. // thus there is no need to garbage collect them
  172. dontGarbageCollect = true;
  173. }
  174. // The type is ok
  175. return true;
  176. }
  177. CScriptArray &CScriptArray::operator=(const CScriptArray &other)
  178. {
  179. // Only perform the copy if the array types are the same
  180. if( &other != this &&
  181. other.GetArrayObjectType() == GetArrayObjectType() )
  182. {
  183. // Make sure the arrays are of the same size
  184. Resize(other.buffer->numElements);
  185. // Copy the value of each element
  186. CopyBuffer(buffer, other.buffer);
  187. }
  188. return *this;
  189. }
  190. CScriptArray::CScriptArray(asIObjectType *ot, void *buf)
  191. {
  192. refCount = 1;
  193. gcFlag = false;
  194. objType = ot;
  195. objType->AddRef();
  196. buffer = 0;
  197. Precache();
  198. asIScriptEngine *engine = ot->GetEngine();
  199. // Determine element size
  200. if( subTypeId & asTYPEID_MASK_OBJECT )
  201. elementSize = sizeof(asPWORD);
  202. else
  203. elementSize = engine->GetSizeOfPrimitiveType(subTypeId);
  204. // Determine the initial size from the buffer
  205. asUINT length = *(asUINT*)buf;
  206. // Make sure the array size isn't too large for us to handle
  207. if( !CheckMaxSize(length) )
  208. {
  209. // Don't continue with the initialization
  210. return;
  211. }
  212. // Copy the values of the array elements from the buffer
  213. if( (ot->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 )
  214. {
  215. CreateBuffer(&buffer, length);
  216. // Copy the values of the primitive type into the internal buffer
  217. memcpy(At(0), (((asUINT*)buf)+1), length * elementSize);
  218. }
  219. else if( ot->GetSubTypeId() & asTYPEID_OBJHANDLE )
  220. {
  221. CreateBuffer(&buffer, length);
  222. // Copy the handles into the internal buffer
  223. memcpy(At(0), (((asUINT*)buf)+1), length * elementSize);
  224. // With object handles it is safe to clear the memory in the received buffer
  225. // instead of increasing the ref count. It will save time both by avoiding the
  226. // call the increase ref, and also relieve the engine from having to release
  227. // its references too
  228. memset((((asUINT*)buf)+1), 0, length * elementSize);
  229. }
  230. else if( ot->GetSubType()->GetFlags() & asOBJ_REF )
  231. {
  232. // Only allocate the buffer, but not the objects
  233. subTypeId |= asTYPEID_OBJHANDLE;
  234. CreateBuffer(&buffer, length);
  235. subTypeId &= ~asTYPEID_OBJHANDLE;
  236. // Copy the handles into the internal buffer
  237. memcpy(buffer->data, (((asUINT*)buf)+1), length * elementSize);
  238. // For ref types we can do the same as for handles, as they are
  239. // implicitly stored as handles.
  240. memset((((asUINT*)buf)+1), 0, length * elementSize);
  241. }
  242. else
  243. {
  244. // TODO: Optimize by calling the copy constructor of the object instead of
  245. // constructing with the default constructor and then assigning the value
  246. // TODO: With C++11 ideally we should be calling the move constructor, instead
  247. // of the copy constructor as the engine will just discard the objects in the
  248. // buffer afterwards.
  249. CreateBuffer(&buffer, length);
  250. // For value types we need to call the opAssign for each individual object
  251. for( asUINT n = 0; n < length; n++ )
  252. {
  253. void *obj = At(n);
  254. asBYTE *srcObj = (asBYTE*)buf;
  255. srcObj += 4 + n*ot->GetSubType()->GetSize();
  256. engine->AssignScriptObject(obj, srcObj, ot->GetSubType());
  257. }
  258. }
  259. // Urho3D: garbage collection disabled
  260. /*
  261. // Notify the GC of the successful creation
  262. if( objType->GetFlags() & asOBJ_GC )
  263. objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType);
  264. */
  265. }
  266. CScriptArray::CScriptArray(asUINT length, asIObjectType *ot)
  267. {
  268. refCount = 1;
  269. gcFlag = false;
  270. objType = ot;
  271. objType->AddRef();
  272. buffer = 0;
  273. Precache();
  274. // Determine element size
  275. if( subTypeId & asTYPEID_MASK_OBJECT )
  276. elementSize = sizeof(asPWORD);
  277. else
  278. elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId);
  279. // Make sure the array size isn't too large for us to handle
  280. if( !CheckMaxSize(length) )
  281. {
  282. // Don't continue with the initialization
  283. return;
  284. }
  285. CreateBuffer(&buffer, length);
  286. // Urho3D: garbage collection disabled
  287. /*
  288. // Notify the GC of the successful creation
  289. if( objType->GetFlags() & asOBJ_GC )
  290. objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType);
  291. */
  292. }
  293. CScriptArray::CScriptArray(const CScriptArray &other)
  294. {
  295. refCount = 1;
  296. gcFlag = false;
  297. objType = other.objType;
  298. objType->AddRef();
  299. buffer = 0;
  300. Precache();
  301. elementSize = other.elementSize;
  302. if( objType->GetFlags() & asOBJ_GC )
  303. objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType);
  304. CreateBuffer(&buffer, 0);
  305. // Copy the content
  306. *this = other;
  307. }
  308. CScriptArray::CScriptArray(asUINT length, void *defVal, asIObjectType *ot)
  309. {
  310. refCount = 1;
  311. gcFlag = false;
  312. objType = ot;
  313. objType->AddRef();
  314. buffer = 0;
  315. Precache();
  316. // Determine element size
  317. if( subTypeId & asTYPEID_MASK_OBJECT )
  318. elementSize = sizeof(asPWORD);
  319. else
  320. elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId);
  321. // Make sure the array size isn't too large for us to handle
  322. if( !CheckMaxSize(length) )
  323. {
  324. // Don't continue with the initialization
  325. return;
  326. }
  327. CreateBuffer(&buffer, length);
  328. // Notify the GC of the successful creation
  329. if( objType->GetFlags() & asOBJ_GC )
  330. objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType);
  331. // Initialize the elements with the default value
  332. for( asUINT n = 0; n < GetSize(); n++ )
  333. SetValue(n, defVal);
  334. }
  335. void CScriptArray::SetValue(asUINT index, void *value)
  336. {
  337. // At() will take care of the out-of-bounds checking, though
  338. // if called from the application then nothing will be done
  339. void *ptr = At(index);
  340. if( ptr == 0 ) return;
  341. if( (subTypeId & ~asTYPEID_MASK_SEQNBR) && !(subTypeId & asTYPEID_OBJHANDLE) )
  342. objType->GetEngine()->AssignScriptObject(ptr, value, objType->GetSubType());
  343. else if( subTypeId & asTYPEID_OBJHANDLE )
  344. {
  345. void *tmp = *(void**)ptr;
  346. *(void**)ptr = *(void**)value;
  347. objType->GetEngine()->AddRefScriptObject(*(void**)value, objType->GetSubType());
  348. if( tmp )
  349. objType->GetEngine()->ReleaseScriptObject(tmp, objType->GetSubType());
  350. }
  351. else if( subTypeId == asTYPEID_BOOL ||
  352. subTypeId == asTYPEID_INT8 ||
  353. subTypeId == asTYPEID_UINT8 )
  354. *(char*)ptr = *(char*)value;
  355. else if( subTypeId == asTYPEID_INT16 ||
  356. subTypeId == asTYPEID_UINT16 )
  357. *(short*)ptr = *(short*)value;
  358. else if( subTypeId == asTYPEID_INT32 ||
  359. subTypeId == asTYPEID_UINT32 ||
  360. subTypeId == asTYPEID_FLOAT ||
  361. subTypeId > asTYPEID_DOUBLE ) // enums have a type id larger than doubles
  362. *(int*)ptr = *(int*)value;
  363. else if( subTypeId == asTYPEID_INT64 ||
  364. subTypeId == asTYPEID_UINT64 ||
  365. subTypeId == asTYPEID_DOUBLE )
  366. *(double*)ptr = *(double*)value;
  367. }
  368. CScriptArray::~CScriptArray()
  369. {
  370. if( buffer )
  371. {
  372. DeleteBuffer(buffer);
  373. buffer = 0;
  374. }
  375. if( objType ) objType->Release();
  376. }
  377. asUINT CScriptArray::GetSize() const
  378. {
  379. return buffer->numElements;
  380. }
  381. bool CScriptArray::IsEmpty() const
  382. {
  383. return buffer->numElements == 0;
  384. }
  385. void CScriptArray::Reserve(asUINT maxElements)
  386. {
  387. if( maxElements <= buffer->maxElements )
  388. return;
  389. // Allocate memory for the buffer
  390. SArrayBuffer *newBuffer;
  391. #if defined(__S3E__) // Marmalade doesn't understand (nothrow)
  392. newBuffer = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1 + elementSize*maxElements];
  393. #else
  394. newBuffer = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1 + elementSize*maxElements];
  395. #endif
  396. if( newBuffer )
  397. {
  398. newBuffer->numElements = buffer->numElements;
  399. newBuffer->maxElements = maxElements;
  400. }
  401. else
  402. {
  403. // Out of memory
  404. asIScriptContext *ctx = asGetActiveContext();
  405. if( ctx )
  406. ctx->SetException("Out of memory");
  407. return;
  408. }
  409. memcpy(newBuffer->data, buffer->data, buffer->numElements*elementSize);
  410. // Release the old buffer
  411. delete[] (asBYTE*)buffer;
  412. buffer = newBuffer;
  413. }
  414. void CScriptArray::Resize(asUINT numElements)
  415. {
  416. if( numElements & 0x80000000 )
  417. {
  418. CheckMaxSize(numElements);
  419. return;
  420. }
  421. Resize((int)numElements - (int)buffer->numElements, (asUINT)-1);
  422. }
  423. // Internal
  424. void CScriptArray::Resize(int delta, asUINT at)
  425. {
  426. if( delta < 0 )
  427. {
  428. if( -delta > (int)buffer->numElements )
  429. delta = -(int)buffer->numElements;
  430. if( at > buffer->numElements + delta )
  431. at = buffer->numElements + delta;
  432. }
  433. else if( delta > 0 )
  434. {
  435. // Make sure the array size isn't too large for us to handle
  436. if( delta > 0 && !CheckMaxSize(buffer->numElements + delta) )
  437. return;
  438. if( at > buffer->numElements )
  439. at = buffer->numElements;
  440. }
  441. if( delta == 0 ) return;
  442. if( buffer->maxElements < buffer->numElements + delta )
  443. {
  444. // Allocate memory for the buffer
  445. SArrayBuffer *newBuffer;
  446. #if defined(__S3E__) // Marmalade doesn't understand (nothrow)
  447. newBuffer = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta)];
  448. #else
  449. newBuffer = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta)];
  450. #endif
  451. if( newBuffer )
  452. {
  453. newBuffer->numElements = buffer->numElements + delta;
  454. newBuffer->maxElements = newBuffer->numElements;
  455. }
  456. else
  457. {
  458. // Out of memory
  459. asIScriptContext *ctx = asGetActiveContext();
  460. if( ctx )
  461. ctx->SetException("Out of memory");
  462. return;
  463. }
  464. memcpy(newBuffer->data, buffer->data, at*elementSize);
  465. if( at < buffer->numElements )
  466. memcpy(newBuffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements-at)*elementSize);
  467. if( subTypeId & asTYPEID_MASK_OBJECT )
  468. Construct(newBuffer, at, at+delta);
  469. // Release the old buffer
  470. delete[] (asBYTE*)buffer;
  471. buffer = newBuffer;
  472. }
  473. else if( delta < 0 )
  474. {
  475. Destruct(buffer, at, at-delta);
  476. memmove(buffer->data + at*elementSize, buffer->data + (at-delta)*elementSize, (buffer->numElements - (at-delta))*elementSize);
  477. buffer->numElements += delta;
  478. }
  479. else
  480. {
  481. memmove(buffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements - at)*elementSize);
  482. Construct(buffer, at, at+delta);
  483. buffer->numElements += delta;
  484. }
  485. }
  486. // internal
  487. bool CScriptArray::CheckMaxSize(asUINT numElements)
  488. {
  489. // This code makes sure the size of the buffer that is allocated
  490. // for the array doesn't overflow and becomes smaller than requested
  491. asUINT maxSize = 0xFFFFFFFFul - sizeof(SArrayBuffer) + 1;
  492. if( subTypeId & asTYPEID_MASK_OBJECT )
  493. maxSize /= sizeof(void*);
  494. else if( elementSize > 0 )
  495. maxSize /= elementSize;
  496. if( numElements > maxSize )
  497. {
  498. asIScriptContext *ctx = asGetActiveContext();
  499. if( ctx )
  500. {
  501. // Set a script exception
  502. ctx->SetException("Too large array size");
  503. }
  504. return false;
  505. }
  506. // OK
  507. return true;
  508. }
  509. asIObjectType *CScriptArray::GetArrayObjectType() const
  510. {
  511. return objType;
  512. }
  513. int CScriptArray::GetArrayTypeId() const
  514. {
  515. return objType->GetTypeId();
  516. }
  517. int CScriptArray::GetElementTypeId() const
  518. {
  519. return subTypeId;
  520. }
  521. void CScriptArray::InsertAt(asUINT index, void *value)
  522. {
  523. if( index > buffer->numElements )
  524. {
  525. // If this is called from a script we raise a script exception
  526. asIScriptContext *ctx = asGetActiveContext();
  527. if( ctx )
  528. ctx->SetException("Index out of bounds");
  529. return;
  530. }
  531. // Make room for the new element
  532. Resize(1, index);
  533. // Set the value of the new element
  534. SetValue(index, value);
  535. }
  536. void CScriptArray::InsertLast(void *value)
  537. {
  538. InsertAt(buffer->numElements, value);
  539. }
  540. void CScriptArray::RemoveAt(asUINT index)
  541. {
  542. if( index >= buffer->numElements )
  543. {
  544. // If this is called from a script we raise a script exception
  545. asIScriptContext *ctx = asGetActiveContext();
  546. if( ctx )
  547. ctx->SetException("Index out of bounds");
  548. return;
  549. }
  550. // Remove the element
  551. Resize(-1, index);
  552. }
  553. void CScriptArray::RemoveLast()
  554. {
  555. RemoveAt(buffer->numElements-1);
  556. }
  557. // Return a pointer to the array element. Returns 0 if the index is out of bounds
  558. const void *CScriptArray::At(asUINT index) const
  559. {
  560. if( buffer == 0 || index >= buffer->numElements )
  561. {
  562. // If this is called from a script we raise a script exception
  563. asIScriptContext *ctx = asGetActiveContext();
  564. if( ctx )
  565. ctx->SetException("Index out of bounds");
  566. return 0;
  567. }
  568. if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) )
  569. return (void*)((size_t*)buffer->data)[index];
  570. else
  571. return buffer->data + elementSize*index;
  572. }
  573. void *CScriptArray::At(asUINT index)
  574. {
  575. return const_cast<void*>(const_cast<const CScriptArray *>(this)->At(index));
  576. }
  577. // internal
  578. void CScriptArray::CreateBuffer(SArrayBuffer **buf, asUINT numElements)
  579. {
  580. if( subTypeId & asTYPEID_MASK_OBJECT )
  581. {
  582. #if defined(__S3E__) // Marmalade doesn't understand (nothrow)
  583. *buf = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1+sizeof(void*)*numElements];
  584. #else
  585. *buf = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1+sizeof(void*)*numElements];
  586. #endif
  587. }
  588. else
  589. {
  590. #if defined(__S3E__)
  591. *buf = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1+elementSize*numElements];
  592. #else
  593. *buf = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1+elementSize*numElements];
  594. #endif
  595. }
  596. if( *buf )
  597. {
  598. (*buf)->numElements = numElements;
  599. (*buf)->maxElements = numElements;
  600. Construct(*buf, 0, numElements);
  601. }
  602. else
  603. {
  604. // Oops, out of memory
  605. asIScriptContext *ctx = asGetActiveContext();
  606. if( ctx )
  607. ctx->SetException("Out of memory");
  608. }
  609. }
  610. // internal
  611. void CScriptArray::DeleteBuffer(SArrayBuffer *buf)
  612. {
  613. Destruct(buf, 0, buf->numElements);
  614. // Free the buffer
  615. delete[] (asBYTE*)buf;
  616. }
  617. // internal
  618. void CScriptArray::Construct(SArrayBuffer *buf, asUINT start, asUINT end)
  619. {
  620. if( subTypeId & asTYPEID_OBJHANDLE )
  621. {
  622. // Set all object handles to null
  623. void *d = (void*)(buf->data + start * sizeof(void*));
  624. memset(d, 0, (end-start)*sizeof(void*));
  625. }
  626. else if( subTypeId & asTYPEID_MASK_OBJECT )
  627. {
  628. void **max = (void**)(buf->data + end * sizeof(void*));
  629. void **d = (void**)(buf->data + start * sizeof(void*));
  630. asIScriptEngine *engine = objType->GetEngine();
  631. asIObjectType *subType = objType->GetSubType();
  632. for( ; d < max; d++ )
  633. *d = (void*)engine->CreateScriptObject(subType);
  634. }
  635. }
  636. // internal
  637. void CScriptArray::Destruct(SArrayBuffer *buf, asUINT start, asUINT end)
  638. {
  639. if( subTypeId & asTYPEID_MASK_OBJECT )
  640. {
  641. asIScriptEngine *engine = objType->GetEngine();
  642. void **max = (void**)(buf->data + end * sizeof(void*));
  643. void **d = (void**)(buf->data + start * sizeof(void*));
  644. for( ; d < max; d++ )
  645. {
  646. if( *d )
  647. engine->ReleaseScriptObject(*d, objType->GetSubType());
  648. }
  649. }
  650. }
  651. // internal
  652. bool CScriptArray::Less(const void *a, const void *b, bool asc, asIScriptContext *ctx, SArrayCache *cache)
  653. {
  654. if( !asc )
  655. {
  656. // Swap items
  657. const void *TEMP = a;
  658. a = b;
  659. b = TEMP;
  660. }
  661. if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) )
  662. {
  663. // Simple compare of values
  664. switch( subTypeId )
  665. {
  666. #define COMPARE(T) *((T*)a) < *((T*)b)
  667. case asTYPEID_BOOL: return COMPARE(bool);
  668. case asTYPEID_INT8: return COMPARE(signed char);
  669. case asTYPEID_UINT8: return COMPARE(unsigned char);
  670. case asTYPEID_INT16: return COMPARE(signed short);
  671. case asTYPEID_UINT16: return COMPARE(unsigned short);
  672. case asTYPEID_INT32: return COMPARE(signed int);
  673. case asTYPEID_UINT32: return COMPARE(unsigned int);
  674. case asTYPEID_FLOAT: return COMPARE(float);
  675. case asTYPEID_DOUBLE: return COMPARE(double);
  676. default: return COMPARE(signed int); // All enums fall in this case
  677. #undef COMPARE
  678. }
  679. }
  680. else
  681. {
  682. int r = 0;
  683. if( subTypeId & asTYPEID_OBJHANDLE )
  684. {
  685. // Allow sort to work even if the array contains null handles
  686. if( *(void**)a == 0 ) return true;
  687. if( *(void**)b == 0 ) return false;
  688. }
  689. // Execute object opCmp
  690. if( cache && cache->cmpFunc )
  691. {
  692. // TODO: Add proper error handling
  693. r = ctx->Prepare(cache->cmpFunc); assert(r >= 0);
  694. if( subTypeId & asTYPEID_OBJHANDLE )
  695. {
  696. r = ctx->SetObject(*((void**)a)); assert(r >= 0);
  697. r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0);
  698. }
  699. else
  700. {
  701. r = ctx->SetObject((void*)a); assert(r >= 0);
  702. r = ctx->SetArgObject(0, (void*)b); assert(r >= 0);
  703. }
  704. r = ctx->Execute();
  705. if( r == asEXECUTION_FINISHED )
  706. {
  707. return (int)ctx->GetReturnDWord() < 0;
  708. }
  709. }
  710. }
  711. return false;
  712. }
  713. void CScriptArray::Reverse()
  714. {
  715. asUINT size = GetSize();
  716. if( size >= 2 )
  717. {
  718. asBYTE TEMP[16];
  719. for( asUINT i = 0; i < size / 2; i++ )
  720. {
  721. Copy(TEMP, GetArrayItemPointer(i));
  722. Copy(GetArrayItemPointer(i), GetArrayItemPointer(size - i - 1));
  723. Copy(GetArrayItemPointer(size - i - 1), TEMP);
  724. }
  725. }
  726. }
  727. bool CScriptArray::operator==(const CScriptArray &other) const
  728. {
  729. if( objType != other.objType )
  730. return false;
  731. if( GetSize() != other.GetSize() )
  732. return false;
  733. asIScriptContext *cmpContext = 0;
  734. bool isNested = false;
  735. if( subTypeId & ~asTYPEID_MASK_SEQNBR )
  736. {
  737. // Try to reuse the active context
  738. cmpContext = asGetActiveContext();
  739. if( cmpContext )
  740. {
  741. if( cmpContext->PushState() >= 0 )
  742. isNested = true;
  743. else
  744. cmpContext = 0;
  745. }
  746. if( cmpContext == 0 )
  747. {
  748. // TODO: Ideally this context would be retrieved from a pool, so we don't have to
  749. // create a new one everytime. We could keep a context with the array object
  750. // but that would consume a lot of resources as each context is quite heavy.
  751. cmpContext = objType->GetEngine()->CreateContext();
  752. }
  753. }
  754. // Check if all elements are equal
  755. bool isEqual = true;
  756. SArrayCache *cache = reinterpret_cast<SArrayCache*>(objType->GetUserData(ARRAY_CACHE));
  757. for( asUINT n = 0; n < GetSize(); n++ )
  758. if( !Equals(At(n), other.At(n), cmpContext, cache) )
  759. {
  760. isEqual = false;
  761. break;
  762. }
  763. if( cmpContext )
  764. if( isNested )
  765. {
  766. asEContextState state = cmpContext->GetState();
  767. cmpContext->PopState();
  768. if( state == asEXECUTION_ABORTED )
  769. cmpContext->Abort();
  770. }
  771. else
  772. cmpContext->Release();
  773. return isEqual;
  774. }
  775. // internal
  776. bool CScriptArray::Equals(const void *a, const void *b, asIScriptContext *ctx, SArrayCache *cache) const
  777. {
  778. if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) )
  779. {
  780. // Simple compare of values
  781. switch( subTypeId )
  782. {
  783. #define COMPARE(T) *((T*)a) == *((T*)b)
  784. case asTYPEID_BOOL: return COMPARE(bool);
  785. case asTYPEID_INT8: return COMPARE(signed char);
  786. case asTYPEID_UINT8: return COMPARE(unsigned char);
  787. case asTYPEID_INT16: return COMPARE(signed short);
  788. case asTYPEID_UINT16: return COMPARE(unsigned short);
  789. case asTYPEID_INT32: return COMPARE(signed int);
  790. case asTYPEID_UINT32: return COMPARE(unsigned int);
  791. case asTYPEID_FLOAT: return COMPARE(float);
  792. case asTYPEID_DOUBLE: return COMPARE(double);
  793. default: return COMPARE(signed int); // All enums fall here
  794. #undef COMPARE
  795. }
  796. }
  797. else
  798. {
  799. int r = 0;
  800. if( subTypeId & asTYPEID_OBJHANDLE )
  801. {
  802. // Allow the find to work even if the array contains null handles
  803. if( *(void**)a == *(void**)b ) return true;
  804. }
  805. // Execute object opEquals if available
  806. if( cache && cache->eqFunc )
  807. {
  808. // TODO: Add proper error handling
  809. r = ctx->Prepare(cache->eqFunc); assert(r >= 0);
  810. if( subTypeId & asTYPEID_OBJHANDLE )
  811. {
  812. r = ctx->SetObject(*((void**)a)); assert(r >= 0);
  813. r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0);
  814. }
  815. else
  816. {
  817. r = ctx->SetObject((void*)a); assert(r >= 0);
  818. r = ctx->SetArgObject(0, (void*)b); assert(r >= 0);
  819. }
  820. r = ctx->Execute();
  821. if( r == asEXECUTION_FINISHED )
  822. return ctx->GetReturnByte() != 0;
  823. return false;
  824. }
  825. // Execute object opCmp if available
  826. if( cache && cache->cmpFunc )
  827. {
  828. // TODO: Add proper error handling
  829. r = ctx->Prepare(cache->cmpFunc); assert(r >= 0);
  830. if( subTypeId & asTYPEID_OBJHANDLE )
  831. {
  832. r = ctx->SetObject(*((void**)a)); assert(r >= 0);
  833. r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0);
  834. }
  835. else
  836. {
  837. r = ctx->SetObject((void*)a); assert(r >= 0);
  838. r = ctx->SetArgObject(0, (void*)b); assert(r >= 0);
  839. }
  840. r = ctx->Execute();
  841. if( r == asEXECUTION_FINISHED )
  842. return (int)ctx->GetReturnDWord() == 0;
  843. return false;
  844. }
  845. }
  846. return false;
  847. }
  848. int CScriptArray::Find(void *value) const
  849. {
  850. return Find(0, value);
  851. }
  852. int CScriptArray::Find(asUINT index, void *value) const
  853. {
  854. // Check if the subtype really supports find()
  855. // TODO: Can't this be done at compile time too by the template callback
  856. SArrayCache *cache = 0;
  857. if( subTypeId & ~asTYPEID_MASK_SEQNBR )
  858. {
  859. cache = reinterpret_cast<SArrayCache*>(objType->GetUserData(ARRAY_CACHE));
  860. if( !cache || (cache->cmpFunc == 0 && cache->eqFunc == 0) )
  861. {
  862. asIScriptContext *ctx = asGetActiveContext();
  863. asIObjectType* subType = objType->GetEngine()->GetObjectTypeById(subTypeId);
  864. // Throw an exception
  865. if( ctx )
  866. {
  867. char tmp[512];
  868. if( cache && cache->eqFuncReturnCode == asMULTIPLE_FUNCTIONS )
  869. #if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__)
  870. sprintf_s(tmp, 512, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName());
  871. #else
  872. sprintf(tmp, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName());
  873. #endif
  874. else
  875. #if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__)
  876. sprintf_s(tmp, 512, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName());
  877. #else
  878. sprintf(tmp, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName());
  879. #endif
  880. ctx->SetException(tmp);
  881. }
  882. return -1;
  883. }
  884. }
  885. asIScriptContext *cmpContext = 0;
  886. bool isNested = false;
  887. if( subTypeId & ~asTYPEID_MASK_SEQNBR )
  888. {
  889. // Try to reuse the active context
  890. cmpContext = asGetActiveContext();
  891. if( cmpContext )
  892. {
  893. if( cmpContext->PushState() >= 0 )
  894. isNested = true;
  895. else
  896. cmpContext = 0;
  897. }
  898. if( cmpContext == 0 )
  899. {
  900. // TODO: Ideally this context would be retrieved from a pool, so we don't have to
  901. // create a new one everytime. We could keep a context with the array object
  902. // but that would consume a lot of resources as each context is quite heavy.
  903. cmpContext = objType->GetEngine()->CreateContext();
  904. }
  905. }
  906. // Find the matching element
  907. int ret = -1;
  908. asUINT size = GetSize();
  909. if( index < size )
  910. {
  911. for( asUINT i = index; i < size; i++ )
  912. {
  913. // value passed by reference
  914. if( Equals(At(i), (value), cmpContext, cache) )
  915. {
  916. ret = (int)i;
  917. break;
  918. }
  919. }
  920. }
  921. if( cmpContext )
  922. if( isNested )
  923. {
  924. asEContextState state = cmpContext->GetState();
  925. cmpContext->PopState();
  926. if( state == asEXECUTION_ABORTED )
  927. cmpContext->Abort();
  928. }
  929. else
  930. cmpContext->Release();
  931. return ret;
  932. }
  933. // internal
  934. // Copy object handle or primitive value
  935. void CScriptArray::Copy(void *dst, void *src)
  936. {
  937. memcpy(dst, src, elementSize);
  938. }
  939. // internal
  940. // Return pointer to array item (object handle or primitive value)
  941. void *CScriptArray::GetArrayItemPointer(int index)
  942. {
  943. return buffer->data + index * elementSize;
  944. }
  945. // internal
  946. // Return pointer to data in buffer (object or primitive)
  947. void *CScriptArray::GetDataPointer(void *buffer)
  948. {
  949. if ((subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) )
  950. {
  951. // Real address of object
  952. return reinterpret_cast<void*>(*(size_t*)buffer);
  953. }
  954. else
  955. {
  956. // Primitive is just a raw data
  957. return buffer;
  958. }
  959. }
  960. // Sort ascending
  961. void CScriptArray::SortAsc()
  962. {
  963. Sort(0, GetSize(), true);
  964. }
  965. // Sort ascending
  966. void CScriptArray::SortAsc(asUINT index, asUINT count)
  967. {
  968. Sort(index, count, true);
  969. }
  970. // Sort descending
  971. void CScriptArray::SortDesc()
  972. {
  973. Sort(0, GetSize(), false);
  974. }
  975. // Sort descending
  976. void CScriptArray::SortDesc(asUINT index, asUINT count)
  977. {
  978. Sort(index, count, false);
  979. }
  980. // internal
  981. void CScriptArray::Sort(asUINT index, asUINT count, bool asc)
  982. {
  983. // Subtype isn't primitive and doesn't have opCmp
  984. SArrayCache *cache = reinterpret_cast<SArrayCache*>(objType->GetUserData(ARRAY_CACHE));
  985. if( subTypeId & ~asTYPEID_MASK_SEQNBR )
  986. {
  987. if( !cache || cache->cmpFunc == 0 )
  988. {
  989. asIScriptContext *ctx = asGetActiveContext();
  990. asIObjectType* subType = objType->GetEngine()->GetObjectTypeById(subTypeId);
  991. // Throw an exception
  992. if( ctx )
  993. {
  994. char tmp[512];
  995. if( cache && cache->cmpFuncReturnCode == asMULTIPLE_FUNCTIONS )
  996. #if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__)
  997. sprintf_s(tmp, 512, "Type '%s' has multiple matching opCmp methods", subType->GetName());
  998. #else
  999. sprintf(tmp, "Type '%s' has multiple matching opCmp methods", subType->GetName());
  1000. #endif
  1001. else
  1002. #if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__)
  1003. sprintf_s(tmp, 512, "Type '%s' does not have a matching opCmp method", subType->GetName());
  1004. #else
  1005. sprintf(tmp, "Type '%s' does not have a matching opCmp method", subType->GetName());
  1006. #endif
  1007. ctx->SetException(tmp);
  1008. }
  1009. return;
  1010. }
  1011. }
  1012. // No need to sort
  1013. if( count < 2 )
  1014. {
  1015. return;
  1016. }
  1017. int start = index;
  1018. int end = index + count;
  1019. // Check if we could access invalid item while sorting
  1020. if( start >= (int)buffer->numElements || end > (int)buffer->numElements )
  1021. {
  1022. asIScriptContext *ctx = asGetActiveContext();
  1023. // Throw an exception
  1024. if( ctx )
  1025. {
  1026. ctx->SetException("Index out of bounds");
  1027. }
  1028. return;
  1029. }
  1030. asBYTE tmp[16];
  1031. asIScriptContext *cmpContext = 0;
  1032. bool isNested = false;
  1033. if( subTypeId & ~asTYPEID_MASK_SEQNBR )
  1034. {
  1035. // Try to reuse the active context
  1036. cmpContext = asGetActiveContext();
  1037. if( cmpContext )
  1038. {
  1039. if( cmpContext->PushState() >= 0 )
  1040. isNested = true;
  1041. else
  1042. cmpContext = 0;
  1043. }
  1044. if( cmpContext == 0 )
  1045. {
  1046. // TODO: Ideally this context would be retrieved from a pool, so we don't have to
  1047. // create a new one everytime. We could keep a context with the array object
  1048. // but that would consume a lot of resources as each context is quite heavy.
  1049. cmpContext = objType->GetEngine()->CreateContext();
  1050. }
  1051. }
  1052. // Insertion sort
  1053. for( int i = start + 1; i < end; i++ )
  1054. {
  1055. Copy(tmp, GetArrayItemPointer(i));
  1056. int j = i - 1;
  1057. while( j >= start && Less(GetDataPointer(tmp), At(j), asc, cmpContext, cache) )
  1058. {
  1059. Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j));
  1060. j--;
  1061. }
  1062. Copy(GetArrayItemPointer(j + 1), tmp);
  1063. }
  1064. if( cmpContext )
  1065. if( isNested )
  1066. {
  1067. asEContextState state = cmpContext->GetState();
  1068. cmpContext->PopState();
  1069. if( state == asEXECUTION_ABORTED )
  1070. cmpContext->Abort();
  1071. }
  1072. else
  1073. cmpContext->Release();
  1074. }
  1075. // internal
  1076. void CScriptArray::CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src)
  1077. {
  1078. asIScriptEngine *engine = objType->GetEngine();
  1079. if( subTypeId & asTYPEID_OBJHANDLE )
  1080. {
  1081. // Copy the references and increase the reference counters
  1082. if( dst->numElements > 0 && src->numElements > 0 )
  1083. {
  1084. int count = dst->numElements > src->numElements ? src->numElements : dst->numElements;
  1085. void **max = (void**)(dst->data + count * sizeof(void*));
  1086. void **d = (void**)dst->data;
  1087. void **s = (void**)src->data;
  1088. for( ; d < max; d++, s++ )
  1089. {
  1090. void *tmp = *d;
  1091. *d = *s;
  1092. if( *d )
  1093. engine->AddRefScriptObject(*d, objType->GetSubType());
  1094. // Release the old ref after incrementing the new to avoid problem incase it is the same ref
  1095. if( tmp )
  1096. engine->ReleaseScriptObject(tmp, objType->GetSubType());
  1097. }
  1098. }
  1099. }
  1100. else
  1101. {
  1102. if( dst->numElements > 0 && src->numElements > 0 )
  1103. {
  1104. int count = dst->numElements > src->numElements ? src->numElements : dst->numElements;
  1105. if( subTypeId & asTYPEID_MASK_OBJECT )
  1106. {
  1107. // Call the assignment operator on all of the objects
  1108. void **max = (void**)(dst->data + count * sizeof(void*));
  1109. void **d = (void**)dst->data;
  1110. void **s = (void**)src->data;
  1111. asIObjectType *subType = objType->GetSubType();
  1112. for( ; d < max; d++, s++ )
  1113. engine->AssignScriptObject(*d, *s, subType);
  1114. }
  1115. else
  1116. {
  1117. // Primitives are copied byte for byte
  1118. memcpy(dst->data, src->data, count*elementSize);
  1119. }
  1120. }
  1121. }
  1122. }
  1123. // internal
  1124. // Precache some info
  1125. void CScriptArray::Precache()
  1126. {
  1127. subTypeId = objType->GetSubTypeId();
  1128. // Check if it is an array of objects. Only for these do we need to cache anything
  1129. // Type ids for primitives and enums only has the sequence number part
  1130. if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) )
  1131. return;
  1132. // The opCmp and opEquals methods are cached because the searching for the
  1133. // methods is quite time consuming if a lot of array objects are created.
  1134. // First check if a cache already exists for this array type
  1135. SArrayCache *cache = reinterpret_cast<SArrayCache*>(objType->GetUserData(ARRAY_CACHE));
  1136. if( cache ) return;
  1137. // We need to make sure the cache is created only once, even
  1138. // if multiple threads reach the same point at the same time
  1139. asAcquireExclusiveLock();
  1140. // Now that we got the lock, we need to check again to make sure the
  1141. // cache wasn't created while we were waiting for the lock
  1142. cache = reinterpret_cast<SArrayCache*>(objType->GetUserData(ARRAY_CACHE));
  1143. if( cache )
  1144. {
  1145. asReleaseExclusiveLock();
  1146. return;
  1147. }
  1148. // Create the cache
  1149. cache = new SArrayCache();
  1150. memset(cache, 0, sizeof(SArrayCache));
  1151. // If the sub type is a handle to const, then the methods must be const too
  1152. bool mustBeConst = (subTypeId & asTYPEID_HANDLETOCONST) ? true : false;
  1153. asIObjectType *subType = objType->GetEngine()->GetObjectTypeById(subTypeId);
  1154. if( subType )
  1155. {
  1156. for( asUINT i = 0; i < subType->GetMethodCount(); i++ )
  1157. {
  1158. asIScriptFunction *func = subType->GetMethodByIndex(i);
  1159. if( func->GetParamCount() == 1 && (!mustBeConst || func->IsReadOnly()) )
  1160. {
  1161. asDWORD flags = 0;
  1162. int returnTypeId = func->GetReturnTypeId(&flags);
  1163. // The method must not return a reference
  1164. if( flags != asTM_NONE )
  1165. continue;
  1166. // opCmp returns an int and opEquals returns a bool
  1167. bool isCmp = false, isEq = false;
  1168. if( returnTypeId == asTYPEID_INT32 && strcmp(func->GetName(), "opCmp") == 0 )
  1169. isCmp = true;
  1170. if( returnTypeId == asTYPEID_BOOL && strcmp(func->GetName(), "opEquals") == 0 )
  1171. isEq = true;
  1172. if( !isCmp && !isEq )
  1173. continue;
  1174. // The parameter must either be a reference to the subtype or a handle to the subtype
  1175. int paramTypeId = func->GetParamTypeId(0, &flags);
  1176. if( (paramTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) != (subTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) )
  1177. continue;
  1178. if( (flags & asTM_INREF) )
  1179. {
  1180. if( (paramTypeId & asTYPEID_OBJHANDLE) || mustBeConst && !(flags & asTM_CONST) )
  1181. continue;
  1182. }
  1183. else if( paramTypeId & asTYPEID_OBJHANDLE )
  1184. {
  1185. if( mustBeConst && !(paramTypeId & asTYPEID_HANDLETOCONST) )
  1186. continue;
  1187. }
  1188. else
  1189. continue;
  1190. if( isCmp )
  1191. {
  1192. if( cache->cmpFunc || cache->cmpFuncReturnCode )
  1193. {
  1194. cache->cmpFunc = 0;
  1195. cache->cmpFuncReturnCode = asMULTIPLE_FUNCTIONS;
  1196. }
  1197. else
  1198. cache->cmpFunc = func;
  1199. }
  1200. else if( isEq )
  1201. {
  1202. if( cache->eqFunc || cache->eqFuncReturnCode )
  1203. {
  1204. cache->eqFunc = 0;
  1205. cache->eqFuncReturnCode = asMULTIPLE_FUNCTIONS;
  1206. }
  1207. else
  1208. cache->eqFunc = func;
  1209. }
  1210. }
  1211. }
  1212. }
  1213. if( cache->eqFunc == 0 && cache->eqFuncReturnCode == 0 )
  1214. cache->eqFuncReturnCode = asNO_FUNCTION;
  1215. if( cache->cmpFunc == 0 && cache->cmpFuncReturnCode == 0 )
  1216. cache->cmpFuncReturnCode = asNO_FUNCTION;
  1217. // Set the user data only at the end so others that retrieve it will know it is complete
  1218. objType->SetUserData(cache, ARRAY_CACHE);
  1219. asReleaseExclusiveLock();
  1220. }
  1221. // GC behaviour
  1222. void CScriptArray::EnumReferences(asIScriptEngine *engine)
  1223. {
  1224. // If the array is holding handles, then we need to notify the GC of them
  1225. if( subTypeId & asTYPEID_MASK_OBJECT )
  1226. {
  1227. void **d = (void**)buffer->data;
  1228. for( asUINT n = 0; n < buffer->numElements; n++ )
  1229. {
  1230. if( d[n] )
  1231. engine->GCEnumCallback(d[n]);
  1232. }
  1233. }
  1234. }
  1235. // GC behaviour
  1236. void CScriptArray::ReleaseAllHandles(asIScriptEngine *engine)
  1237. {
  1238. // Resizing to zero will release everything
  1239. Resize(0);
  1240. }
  1241. void CScriptArray::AddRef() const
  1242. {
  1243. // Clear the GC flag then increase the counter
  1244. gcFlag = false;
  1245. asAtomicInc(refCount);
  1246. }
  1247. void CScriptArray::Release() const
  1248. {
  1249. // Clearing the GC flag then descrease the counter
  1250. gcFlag = false;
  1251. if( asAtomicDec(refCount) == 0 )
  1252. {
  1253. // When reaching 0 no more references to this instance
  1254. // exists and the object should be destroyed
  1255. delete this;
  1256. }
  1257. }
  1258. // GC behaviour
  1259. int CScriptArray::GetRefCount()
  1260. {
  1261. return refCount;
  1262. }
  1263. // GC behaviour
  1264. void CScriptArray::SetFlag()
  1265. {
  1266. gcFlag = true;
  1267. }
  1268. // GC behaviour
  1269. bool CScriptArray::GetFlag()
  1270. {
  1271. return gcFlag;
  1272. }
  1273. static void ScriptArrayClear(CScriptArray* ptr)
  1274. {
  1275. ptr->Resize(0);
  1276. }
  1277. void RegisterArray(asIScriptEngine* engine)
  1278. {
  1279. // Register the object type user data clean up
  1280. engine->SetObjectTypeUserDataCleanupCallback(CleanupObjectTypeArrayCache, ARRAY_CACHE);
  1281. engine->RegisterObjectType("Array<class T>", 0, asOBJ_REF | asOBJ_TEMPLATE);
  1282. engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback), asCALL_CDECL);
  1283. engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_FACTORY, "Array<T>@ f(int& in)", asFUNCTIONPR(ScriptArrayFactory, (asIObjectType*), CScriptArray*), asCALL_CDECL);
  1284. engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_FACTORY, "Array<T>@ f(int& in, uint)", asFUNCTIONPR(ScriptArrayFactory2, (asIObjectType*, asUINT), CScriptArray*), asCALL_CDECL);
  1285. engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_FACTORY, "Array<T>@ f(int& in, uint, const T& in)", asFUNCTIONPR(ScriptArrayFactoryDefVal, (asIObjectType*, asUINT, void *), CScriptArray*), asCALL_CDECL);
  1286. engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_LIST_FACTORY, "Array<T>@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(ScriptArrayListFactory, (asIObjectType*, void*), CScriptArray*), asCALL_CDECL);
  1287. engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptArray,AddRef), asCALL_THISCALL);
  1288. engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptArray,Release), asCALL_THISCALL);
  1289. engine->RegisterObjectMethod("Array<T>", "T& opIndex(uint)", asMETHODPR(CScriptArray, At, (unsigned), void*), asCALL_THISCALL);
  1290. engine->RegisterObjectMethod("Array<T>", "const T& opIndex(uint) const", asMETHODPR(CScriptArray, At, (unsigned), void*), asCALL_THISCALL);
  1291. engine->RegisterObjectMethod("Array<T>", "Array<T>& opAssign(const Array<T>& in)", asMETHOD(CScriptArray, operator=), asCALL_THISCALL);
  1292. engine->RegisterObjectMethod("Array<T>", "void Insert(uint, const T& in)", asMETHOD(CScriptArray, InsertAt), asCALL_THISCALL);
  1293. engine->RegisterObjectMethod("Array<T>", "void Erase(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL);
  1294. engine->RegisterObjectMethod("Array<T>", "void Push(const T& in)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL);
  1295. engine->RegisterObjectMethod("Array<T>", "void Pop()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL);
  1296. engine->RegisterObjectMethod("Array<T>", "void Resize(uint)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL);
  1297. engine->RegisterObjectMethod("Array<T>", "void Clear()", asFUNCTION(ScriptArrayClear), asCALL_CDECL_OBJLAST);
  1298. engine->RegisterObjectMethod("Array<T>", "void Sort()", asMETHODPR(CScriptArray, SortAsc, (), void), asCALL_THISCALL);
  1299. engine->RegisterObjectMethod("Array<T>", "void Sort(uint, uint)", asMETHODPR(CScriptArray, SortAsc, (asUINT, asUINT), void), asCALL_THISCALL);
  1300. engine->RegisterObjectMethod("Array<T>", "void SortReverse()", asMETHODPR(CScriptArray, SortDesc, (), void), asCALL_THISCALL);
  1301. engine->RegisterObjectMethod("Array<T>", "void SortReverse(uint, uint)", asMETHODPR(CScriptArray, SortDesc, (asUINT, asUINT), void), asCALL_THISCALL);
  1302. engine->RegisterObjectMethod("Array<T>", "void Reverse()", asMETHOD(CScriptArray, Reverse), asCALL_THISCALL);
  1303. engine->RegisterObjectMethod("Array<T>", "int Find(const T&in) const", asMETHODPR(CScriptArray, Find, (void*) const, int), asCALL_THISCALL);
  1304. engine->RegisterObjectMethod("Array<T>", "int Find(uint, const T&in) const", asMETHODPR(CScriptArray, Find, (asUINT, void*) const, int), asCALL_THISCALL);
  1305. engine->RegisterObjectMethod("Array<T>", "bool opEquals(const Array<T>&in) const", asMETHOD(CScriptArray, operator==), asCALL_THISCALL);
  1306. engine->RegisterObjectMethod("Array<T>", "uint get_length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL);
  1307. engine->RegisterObjectMethod("Array<T>", "void set_length(uint)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL);
  1308. engine->RegisterObjectMethod("Array<T>", "bool get_empty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL);
  1309. engine->RegisterDefaultArrayType("Array<T>");
  1310. }
  1311. static String StringFactory(asUINT length, const char* s)
  1312. {
  1313. return String(s, length);
  1314. }
  1315. static void ConstructString(String* ptr)
  1316. {
  1317. new(ptr) String();
  1318. }
  1319. static void ConstructStringCopy(const String& str, String* ptr)
  1320. {
  1321. new(ptr) String(str);
  1322. }
  1323. static void DestructString(String* ptr)
  1324. {
  1325. ptr->~String();
  1326. }
  1327. static char* StringCharAt(unsigned int i, String& str)
  1328. {
  1329. if (i >= str.Length())
  1330. {
  1331. asIScriptContext* context = asGetActiveContext();
  1332. if (context)
  1333. context->SetException("Index out of bounds");
  1334. return 0;
  1335. }
  1336. return &str[i];
  1337. }
  1338. static int StringCmp(const String& lhs, const String& rhs)
  1339. {
  1340. int cmp = 0;
  1341. if (lhs < rhs)
  1342. cmp = -1;
  1343. else if (lhs > rhs)
  1344. cmp = 1;
  1345. return cmp;
  1346. }
  1347. void StringResize(unsigned newSize, String& str)
  1348. {
  1349. unsigned oldSize = str.Length();
  1350. str.Resize(newSize);
  1351. for (unsigned i = oldSize; i < newSize; ++i)
  1352. str[i] = ' ';
  1353. }
  1354. static void ConstructStringInt(int value, String* ptr)
  1355. {
  1356. new(ptr) String(value);
  1357. }
  1358. static void ConstructStringUInt(unsigned value, String* ptr)
  1359. {
  1360. new(ptr) String(value);
  1361. }
  1362. static void ConstructStringFloat(float value, String* ptr)
  1363. {
  1364. new(ptr) String(value);
  1365. }
  1366. static void ConstructStringBool(bool value, String* ptr)
  1367. {
  1368. new(ptr) String(value);
  1369. }
  1370. static String& StringAssignInt(int value, String& str)
  1371. {
  1372. str = String(value);
  1373. return str;
  1374. }
  1375. static String& StringAddAssignInt(int value, String& str)
  1376. {
  1377. str += String(value);
  1378. return str;
  1379. }
  1380. static String StringAddInt(int value, const String& str)
  1381. {
  1382. return str + String(value);
  1383. }
  1384. static String StringAddIntReverse(int value, const String& str)
  1385. {
  1386. return String(value) + str;
  1387. }
  1388. static String& StringAssignUInt(unsigned value, String& str)
  1389. {
  1390. str = String(value);
  1391. return str;
  1392. }
  1393. static String& StringAddAssignUInt(unsigned value, String& str)
  1394. {
  1395. str += String(value);
  1396. return str;
  1397. }
  1398. static String StringAddUInt(unsigned value, const String& str)
  1399. {
  1400. return str + String(value);
  1401. }
  1402. static String StringAddUIntReverse(unsigned value, const String& str)
  1403. {
  1404. return String(value) + str;
  1405. }
  1406. static String& StringAssignFloat(float value, String& str)
  1407. {
  1408. str = String(value);
  1409. return str;
  1410. }
  1411. static String& StringAddAssignFloat(float value, String& str)
  1412. {
  1413. str += String(value);
  1414. return str;
  1415. }
  1416. static String StringAddFloat(float value, const String& str)
  1417. {
  1418. return str + String(value);
  1419. }
  1420. static String StringAddFloatReverse(float value, const String& str)
  1421. {
  1422. return String(value) + str;
  1423. }
  1424. static String& StringAssignBool(bool value, String& str)
  1425. {
  1426. str = String(value);
  1427. return str;
  1428. }
  1429. static String& StringAddAssignBool(bool value, String& str)
  1430. {
  1431. str += String(value);
  1432. return str;
  1433. }
  1434. static String StringAddBool(bool value, const String& str)
  1435. {
  1436. return str + String(value);
  1437. }
  1438. static String StringAddBoolReverse(bool value, const String& str)
  1439. {
  1440. return String(value) + str;
  1441. }
  1442. static void StringSetUTF8FromLatin1(const String& src, String& str)
  1443. {
  1444. str.SetUTF8FromLatin1(src.CString());
  1445. }
  1446. void RegisterString(asIScriptEngine *engine)
  1447. {
  1448. engine->RegisterObjectType("String", sizeof(String), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK);
  1449. engine->RegisterStringFactory("String", asFUNCTION(StringFactory), asCALL_CDECL);
  1450. engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST);
  1451. engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(const String&in)", asFUNCTION(ConstructStringCopy), asCALL_CDECL_OBJLAST);
  1452. engine->RegisterObjectBehaviour("String", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST);
  1453. engine->RegisterObjectMethod("String", "String& opAssign(const String&in)", asMETHODPR(String, operator =, (const String&), String&), asCALL_THISCALL);
  1454. engine->RegisterObjectMethod("String", "String& opAddAssign(const String&in)", asMETHODPR(String, operator +=, (const String&), String&), asCALL_THISCALL);
  1455. engine->RegisterObjectMethod("String", "bool opEquals(const String&in) const", asMETHODPR(String, operator ==, (const String&) const, bool), asCALL_THISCALL);
  1456. engine->RegisterObjectMethod("String", "int opCmp(const String&in) const", asFUNCTION(StringCmp), asCALL_CDECL_OBJFIRST);
  1457. engine->RegisterObjectMethod("String", "String opAdd(const String&in) const", asMETHODPR(String, operator +, (const String&) const, String), asCALL_THISCALL);
  1458. engine->RegisterObjectMethod("String", "uint8 &opIndex(uint)", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST);
  1459. engine->RegisterObjectMethod("String", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST);
  1460. engine->RegisterObjectMethod("String", "void Replace(uint8, uint8, bool caseSensitive = true)", asMETHODPR(String, Replace, (char, char, bool), void), asCALL_THISCALL);
  1461. engine->RegisterObjectMethod("String", "void Replace(const String&in, const String&in, bool caseSensitive = true)", asMETHODPR(String, Replace, (const String&, const String&, bool), void), asCALL_THISCALL);
  1462. engine->RegisterObjectMethod("String", "String Replaced(uint8, uint8, bool caseSensitive = true) const", asMETHODPR(String, Replaced, (char, char, bool) const, String), asCALL_THISCALL);
  1463. engine->RegisterObjectMethod("String", "String Replaced(const String&in, const String&in, bool caseSensitive = true) const", asMETHODPR(String, Replaced, (const String&, const String&, bool) const, String), asCALL_THISCALL);
  1464. engine->RegisterObjectMethod("String", "void Resize(uint)", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST);
  1465. engine->RegisterObjectMethod("String", "uint Find(const String&in, uint start = 0, bool caseSensitive = true) const", asMETHODPR(String, Find, (const String&, unsigned, bool) const, unsigned), asCALL_THISCALL);
  1466. engine->RegisterObjectMethod("String", "uint Find(uint8, uint start = 0, bool caseSensitive = true) const", asMETHODPR(String, Find, (char, unsigned, bool) const, unsigned), asCALL_THISCALL);
  1467. engine->RegisterObjectMethod("String", "uint FindLast(const String&in, uint start = 0xffffffff, bool caseSensitive = true) const", asMETHODPR(String, FindLast, (const String&, unsigned, bool) const, unsigned), asCALL_THISCALL);
  1468. engine->RegisterObjectMethod("String", "uint FindLast(uint8, uint start = 0xffffffff, bool caseSensitive = true) const", asMETHODPR(String, FindLast, (char, unsigned, bool) const, unsigned), asCALL_THISCALL);
  1469. engine->RegisterObjectMethod("String", "bool StartsWith(const String&in, bool caseSensitive = true) const", asMETHOD(String, StartsWith), asCALL_THISCALL);
  1470. engine->RegisterObjectMethod("String", "bool EndsWith(const String&in, bool caseSensitive = true) const", asMETHOD(String, EndsWith), asCALL_THISCALL);
  1471. engine->RegisterObjectMethod("String", "String Substring(uint) const", asMETHODPR(String, Substring, (unsigned) const, String), asCALL_THISCALL);
  1472. engine->RegisterObjectMethod("String", "String Substring(uint, uint) const", asMETHODPR(String, Substring, (unsigned, unsigned) const, String), asCALL_THISCALL);
  1473. engine->RegisterObjectMethod("String", "String ToUpper() const", asMETHOD(String, ToUpper), asCALL_THISCALL);
  1474. engine->RegisterObjectMethod("String", "String ToLower() const", asMETHOD(String, ToLower), asCALL_THISCALL);
  1475. engine->RegisterObjectMethod("String", "String Trimmed() const", asMETHOD(String, Trimmed), asCALL_THISCALL);
  1476. engine->RegisterObjectMethod("String", "void SetUTF8FromLatin1(const String& in)", asFUNCTION(StringSetUTF8FromLatin1), asCALL_CDECL_OBJLAST);
  1477. engine->RegisterObjectMethod("String", "uint get_utf8Length() const", asMETHOD(String, LengthUTF8), asCALL_THISCALL);
  1478. engine->RegisterObjectMethod("String", "uint ByteOffsetUTF8(uint) const", asMETHOD(String, ByteOffsetUTF8), asCALL_THISCALL);
  1479. engine->RegisterObjectMethod("String", "uint NextUTF8Char(uint&) const", asMETHOD(String, NextUTF8Char), asCALL_THISCALL);
  1480. engine->RegisterObjectMethod("String", "uint AtUTF8(uint) const", asMETHOD(String, AtUTF8), asCALL_THISCALL);
  1481. engine->RegisterObjectMethod("String", "void ReplaceUTF8(uint, uint)", asMETHOD(String, ReplaceUTF8), asCALL_THISCALL);
  1482. engine->RegisterObjectMethod("String", "void AppendUTF8(uint)", asMETHOD(String, AppendUTF8), asCALL_THISCALL);
  1483. engine->RegisterObjectMethod("String", "String SubstringUTF8(uint) const", asMETHODPR(String, SubstringUTF8, (unsigned) const, String), asCALL_THISCALL);
  1484. engine->RegisterObjectMethod("String", "String SubstringUTF8(uint, uint) const", asMETHODPR(String, SubstringUTF8, (unsigned, unsigned) const, String), asCALL_THISCALL);
  1485. engine->RegisterObjectMethod("String", "uint get_length() const", asMETHOD(String, Length), asCALL_THISCALL);
  1486. engine->RegisterObjectMethod("String", "bool get_empty() const", asMETHOD(String, Empty), asCALL_THISCALL);
  1487. engine->RegisterObjectMethod("String", "int Compare(const String&in, bool caseSensitive = true) const", asMETHODPR(String, Compare, (const String&, bool) const, int), asCALL_THISCALL);
  1488. engine->RegisterObjectMethod("String", "bool Contains(const String&in) const", asMETHODPR(String, Contains, (const String&) const, bool), asCALL_THISCALL);
  1489. engine->RegisterObjectMethod("String", "bool Contains(uint8) const", asMETHODPR(String, Contains, (char) const, bool), asCALL_THISCALL);
  1490. engine->RegisterObjectMethod("String", "void Clear()", asMETHOD(String, Clear), asCALL_THISCALL);
  1491. // Register automatic conversion functions for convenience
  1492. engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTION(ConstructStringInt), asCALL_CDECL_OBJLAST);
  1493. engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(uint)", asFUNCTION(ConstructStringUInt), asCALL_CDECL_OBJLAST);
  1494. engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(float)", asFUNCTION(ConstructStringFloat), asCALL_CDECL_OBJLAST);
  1495. engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(bool)", asFUNCTION(ConstructStringBool), asCALL_CDECL_OBJLAST);
  1496. engine->RegisterObjectMethod("String", "String& opAssign(int)", asFUNCTION(StringAssignInt), asCALL_CDECL_OBJLAST);
  1497. engine->RegisterObjectMethod("String", "String& opAddAssign(int)", asFUNCTION(StringAddAssignInt), asCALL_CDECL_OBJLAST);
  1498. engine->RegisterObjectMethod("String", "String opAdd(int) const", asFUNCTION(StringAddInt), asCALL_CDECL_OBJLAST);
  1499. engine->RegisterObjectMethod("String", "String opAdd_r(int) const", asFUNCTION(StringAddIntReverse), asCALL_CDECL_OBJLAST);
  1500. engine->RegisterObjectMethod("String", "String& opAssign(uint)", asFUNCTION(StringAssignUInt), asCALL_CDECL_OBJLAST);
  1501. engine->RegisterObjectMethod("String", "String& opAddAssign(uint)", asFUNCTION(StringAddAssignUInt), asCALL_CDECL_OBJLAST);
  1502. engine->RegisterObjectMethod("String", "String opAdd(uint) const", asFUNCTION(StringAddUInt), asCALL_CDECL_OBJLAST);
  1503. engine->RegisterObjectMethod("String", "String opAdd_r(uint) const", asFUNCTION(StringAddUIntReverse), asCALL_CDECL_OBJLAST);
  1504. engine->RegisterObjectMethod("String", "String& opAssign(float)", asFUNCTION(StringAssignFloat), asCALL_CDECL_OBJLAST);
  1505. engine->RegisterObjectMethod("String", "String& opAddAssign(float)", asFUNCTION(StringAddAssignFloat), asCALL_CDECL_OBJLAST);
  1506. engine->RegisterObjectMethod("String", "String opAdd(float) const", asFUNCTION(StringAddFloat), asCALL_CDECL_OBJLAST);
  1507. engine->RegisterObjectMethod("String", "String opAdd_r(float) const", asFUNCTION(StringAddFloatReverse), asCALL_CDECL_OBJLAST);
  1508. engine->RegisterObjectMethod("String", "String& opAssign(bool)", asFUNCTION(StringAssignBool), asCALL_CDECL_OBJLAST);
  1509. engine->RegisterObjectMethod("String", "String& opAddAssign(bool)", asFUNCTION(StringAddAssignBool), asCALL_CDECL_OBJLAST);
  1510. engine->RegisterObjectMethod("String", "String opAdd(bool) const", asFUNCTION(StringAddBool), asCALL_CDECL_OBJLAST);
  1511. engine->RegisterObjectMethod("String", "String opAdd_r(bool) const", asFUNCTION(StringAddBoolReverse), asCALL_CDECL_OBJLAST);
  1512. }
  1513. }