Addons.cpp 51 KB

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