RegisterArray.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  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 "Exception.h"
  25. #include "RegisterArray.h"
  26. #include <cstring>
  27. #include "DebugNew.h"
  28. // Adapted from Angelscript's scriptarray add-on
  29. //! Script array buffer
  30. struct SArrayBuffer
  31. {
  32. asDWORD numElements;
  33. asBYTE data[1];
  34. };
  35. static CScriptArray* ScriptArrayFactory2(asIObjectType* ot, asUINT length)
  36. {
  37. CScriptArray* a = new CScriptArray(length, ot);
  38. // It's possible the constructor raised a script exception, in which case we
  39. // need to free the memory and return null instead, else we get a memory leak.
  40. asIScriptContext* context = asGetActiveContext();
  41. if (context && context->GetState() == asEXECUTION_EXCEPTION)
  42. {
  43. delete a;
  44. return 0;
  45. }
  46. return a;
  47. }
  48. static CScriptArray* ScriptArrayFactoryDefVal(asIObjectType* ot, asUINT length, void* defVal)
  49. {
  50. CScriptArray* a = new CScriptArray(length, defVal, ot);
  51. // It's possible the constructor raised a script exception, in which case we
  52. // need to free the memory and return null instead, else we get a memory leak.
  53. asIScriptContext* context = asGetActiveContext();
  54. if (context && context->GetState() == asEXECUTION_EXCEPTION)
  55. {
  56. delete a;
  57. return 0;
  58. }
  59. return a;
  60. }
  61. static CScriptArray* ScriptArrayFactory(asIObjectType* ot)
  62. {
  63. return ScriptArrayFactory2(ot, 0);
  64. }
  65. // This optional callback is called when the template type is first used by the compiler.
  66. // It allows the application to validate if the template can be instanciated for the requested
  67. // subtype at compile time, instead of at runtime.
  68. static bool ScriptArrayTemplateCallback(asIObjectType* ot)
  69. {
  70. // Make sure the subtype can be instanciated with a default factory/constructor,
  71. // otherwise we won't be able to instanciate the elements. Script classes always
  72. // have default factories, so we don't have to worry about those.
  73. int typeId = ot->GetSubTypeId();
  74. if ((typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) && !(typeId & asTYPEID_SCRIPTOBJECT))
  75. {
  76. asIObjectType *subtype = ot->GetEngine()->GetObjectTypeById(typeId);
  77. asDWORD flags = subtype->GetFlags();
  78. if ((flags & asOBJ_VALUE) && !(flags & asOBJ_POD))
  79. {
  80. // Verify that there is a default constructor
  81. for (int n = 0; n < subtype->GetBehaviourCount(); ++n)
  82. {
  83. asEBehaviours beh;
  84. int funcId = subtype->GetBehaviourByIndex(n, &beh);
  85. if (beh != asBEHAVE_CONSTRUCT)
  86. continue;
  87. asIScriptFunction* func = ot->GetEngine()->GetFunctionDescriptorById(funcId);
  88. if (func->GetParamCount() == 0)
  89. {
  90. // Found the default constructor
  91. return true;
  92. }
  93. }
  94. // There is no default constructor
  95. return false;
  96. }
  97. else if ((flags & asOBJ_REF))
  98. {
  99. // Verify that there is a default factory
  100. for (int n = 0; n < subtype->GetFactoryCount(); ++n)
  101. {
  102. int funcId = subtype->GetFactoryIdByIndex(n);
  103. asIScriptFunction* func = ot->GetEngine()->GetFunctionDescriptorById(funcId);
  104. if (func->GetParamCount() == 0)
  105. {
  106. // Found the default factory
  107. return true;
  108. }
  109. }
  110. // No default factory
  111. return false;
  112. }
  113. }
  114. // The type is ok
  115. return true;
  116. }
  117. CScriptArray& CScriptArray::operator = (const CScriptArray &other)
  118. {
  119. // Only perform the copy if the array types are the same
  120. if (&other != this && other.GetArrayObjectType() == GetArrayObjectType())
  121. {
  122. if (buffer)
  123. {
  124. DeleteBuffer(buffer);
  125. buffer = 0;
  126. }
  127. // Copy all elements from the other array
  128. CreateBuffer(&buffer, other.buffer->numElements);
  129. CopyBuffer(buffer, other.buffer);
  130. }
  131. return *this;
  132. }
  133. CScriptArray::CScriptArray(asUINT length, asIObjectType* ot)
  134. {
  135. refCount = 1;
  136. gcFlag = false;
  137. objType = ot;
  138. objType->AddRef();
  139. buffer = 0;
  140. // Determine element size
  141. // TODO: Should probably store the template sub type id as well
  142. int typeId = objType->GetSubTypeId();
  143. if (typeId & asTYPEID_MASK_OBJECT)
  144. elementSize = sizeof(asPWORD);
  145. else
  146. elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(typeId);
  147. isArrayOfHandles = typeId & asTYPEID_OBJHANDLE ? true : false;
  148. // Make sure the array size isn't too large for us to handle
  149. if (!CheckMaxSize(length))
  150. {
  151. // Don't continue with the initialization
  152. return;
  153. }
  154. CreateBuffer(&buffer, length);
  155. // Notify the GC of the successful creation
  156. //if (objType->GetFlags() & asOBJ_GC)
  157. // objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType->GetTypeId());
  158. }
  159. CScriptArray::CScriptArray(asUINT length, void *defVal, asIObjectType *ot)
  160. {
  161. refCount = 1;
  162. gcFlag = false;
  163. objType = ot;
  164. objType->AddRef();
  165. buffer = 0;
  166. // Determine element size
  167. // TODO: Should probably store the template sub type id as well
  168. int typeId = objType->GetSubTypeId();
  169. if (typeId & asTYPEID_MASK_OBJECT)
  170. elementSize = sizeof(asPWORD);
  171. else
  172. elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(typeId);
  173. isArrayOfHandles = typeId & asTYPEID_OBJHANDLE ? true : false;
  174. // Make sure the array size isn't too large for us to handle
  175. if (!CheckMaxSize(length))
  176. {
  177. // Don't continue with the initialization
  178. return;
  179. }
  180. CreateBuffer(&buffer, length);
  181. // Notify the GC of the successful creation
  182. //if (objType->GetFlags() & asOBJ_GC)
  183. // objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType->GetTypeId());
  184. // Initialize the elements with the default value
  185. for (asUINT n = 0; n < GetSize(); ++n)
  186. SetValue(n, defVal);
  187. }
  188. // Internal
  189. void CScriptArray::SetValue(asUINT index, void *value)
  190. {
  191. int typeId = objType->GetSubTypeId();
  192. if ((typeId & ~0x03FFFFFF) && !(typeId & asTYPEID_OBJHANDLE))
  193. objType->GetEngine()->CopyScriptObject(At(index), value, typeId);
  194. else if (typeId & asTYPEID_OBJHANDLE)
  195. {
  196. *(void**)At(index) = *(void**)value;
  197. objType->GetEngine()->AddRefScriptObject(*(void**)value, typeId);
  198. }
  199. else if (typeId == asTYPEID_BOOL || typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
  200. *(char*)At(index) = *(char*)value;
  201. else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
  202. *(short*)At(index) = *(short*)value;
  203. else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32 || typeId == asTYPEID_FLOAT)
  204. *(int*)At(index) = *(int*)value;
  205. else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64 || typeId == asTYPEID_DOUBLE)
  206. *(double*)At(index) = *(double*)value;
  207. }
  208. CScriptArray::~CScriptArray()
  209. {
  210. if (buffer)
  211. {
  212. DeleteBuffer(buffer);
  213. buffer = 0;
  214. }
  215. if (objType)
  216. objType->Release();
  217. }
  218. asUINT CScriptArray::GetSize() const
  219. {
  220. return buffer->numElements;
  221. }
  222. void CScriptArray::Resize(asUINT numElements)
  223. {
  224. if (numElements & 0x80000000)
  225. {
  226. CheckMaxSize(numElements);
  227. return;
  228. }
  229. Resize((int)numElements - (int)buffer->numElements, -1);
  230. }
  231. // Internal
  232. void CScriptArray::Resize(int delta, asUINT at)
  233. {
  234. if (delta < 0)
  235. {
  236. if (-delta > (int)buffer->numElements)
  237. delta = -(int)buffer->numElements;
  238. if (at > buffer->numElements + delta)
  239. at = buffer->numElements + delta;
  240. }
  241. else if (delta > 0)
  242. {
  243. // Make sure the array size isn't too large for us to handle
  244. if (delta > 0 && !CheckMaxSize(buffer->numElements + delta))
  245. return;
  246. if (at > buffer->numElements)
  247. at = buffer->numElements;
  248. }
  249. if (delta == 0)
  250. return;
  251. // Allocate memory for the buffer
  252. SArrayBuffer *newBuffer;
  253. newBuffer = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta)];
  254. newBuffer->numElements = buffer->numElements + delta;
  255. int c = newBuffer->numElements > buffer->numElements ? buffer->numElements : newBuffer->numElements;
  256. memcpy(newBuffer->data, buffer->data, at*elementSize);
  257. if (delta > 0 && at < buffer->numElements)
  258. memcpy(newBuffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements-at)*elementSize);
  259. else if (delta < 0 && at < buffer->numElements)
  260. memcpy(newBuffer->data + at*elementSize, buffer->data + (at-delta)*elementSize, (buffer->numElements-at+delta)*elementSize);
  261. int typeId = objType->GetSubTypeId();
  262. if (typeId & asTYPEID_MASK_OBJECT)
  263. {
  264. if (delta > 0)
  265. Construct(newBuffer, at, at+delta);
  266. else if (delta < 0)
  267. Destruct(buffer, at, at-delta);
  268. }
  269. // Release the old buffer
  270. delete[] (asBYTE*)buffer;
  271. buffer = newBuffer;
  272. }
  273. // internal
  274. bool CScriptArray::CheckMaxSize(asUINT numElements)
  275. {
  276. // This code makes sure the size of the buffer that is allocated
  277. // for the array doesn't overflow and becomes smaller than requested
  278. asUINT maxSize = 0xFFFFFFFFul - sizeof(SArrayBuffer) + 1;
  279. if (objType->GetSubTypeId() & asTYPEID_MASK_OBJECT)
  280. maxSize /= sizeof(void*);
  281. else
  282. maxSize /= elementSize;
  283. if (numElements > maxSize)
  284. SAFE_EXCEPTION_RET("Too large array size", false);
  285. // OK
  286. return true;
  287. }
  288. asIObjectType *CScriptArray::GetArrayObjectType() const
  289. {
  290. return objType;
  291. }
  292. int CScriptArray::GetArrayTypeId() const
  293. {
  294. return objType->GetTypeId();
  295. }
  296. int CScriptArray::GetElementTypeId() const
  297. {
  298. return objType->GetSubTypeId();
  299. }
  300. void CScriptArray::InsertAt(asUINT index, void *value)
  301. {
  302. if (index > buffer->numElements)
  303. SAFE_EXCEPTION("Index out of bounds");
  304. // Make room for the new element
  305. Resize(1, index);
  306. // Set the value of the new element
  307. SetValue(index, value);
  308. }
  309. void CScriptArray::InsertLast(void *value)
  310. {
  311. InsertAt(buffer->numElements, value);
  312. }
  313. void CScriptArray::RemoveAt(asUINT index)
  314. {
  315. if (index >= buffer->numElements)
  316. SAFE_EXCEPTION("Index out of bounds");
  317. // Remove the element
  318. Resize(-1, index);
  319. }
  320. void CScriptArray::RemoveLast()
  321. {
  322. RemoveAt(buffer->numElements-1);
  323. }
  324. // Return a pointer to the array element. Returns 0 if the index is out of bounds
  325. void *CScriptArray::At(asUINT index)
  326. {
  327. if (index >= buffer->numElements)
  328. {
  329. SAFE_EXCEPTION_RET("Index out of bounds", 0);
  330. }
  331. else
  332. {
  333. int typeId = objType->GetSubTypeId();
  334. if ((typeId & asTYPEID_MASK_OBJECT) && !isArrayOfHandles)
  335. return (void*)((size_t*)buffer->data)[index];
  336. else
  337. return buffer->data + elementSize*index;
  338. }
  339. }
  340. // internal
  341. void CScriptArray::CreateBuffer(SArrayBuffer **buf, asUINT numElements)
  342. {
  343. int typeId = objType->GetSubTypeId();
  344. if (typeId & asTYPEID_MASK_OBJECT)
  345. {
  346. *buf = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1+sizeof(void*)*numElements];
  347. (*buf)->numElements = numElements;
  348. }
  349. else
  350. {
  351. *buf = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1+elementSize*numElements];
  352. (*buf)->numElements = numElements;
  353. }
  354. Construct(*buf, 0, numElements);
  355. }
  356. // internal
  357. void CScriptArray::DeleteBuffer(SArrayBuffer *buf)
  358. {
  359. Destruct(buf, 0, buf->numElements);
  360. // Free the buffer
  361. delete[] (asBYTE*)buf;
  362. }
  363. // internal
  364. void CScriptArray::Construct(SArrayBuffer *buf, asUINT start, asUINT end)
  365. {
  366. int typeId = objType->GetSubTypeId();
  367. if (isArrayOfHandles)
  368. {
  369. // Set all object handles to null
  370. void* d = (void*)(buf->data + start * sizeof(void*));
  371. memset(d, 0, (end-start)*sizeof(void*));
  372. }
  373. else if (typeId & asTYPEID_MASK_OBJECT)
  374. {
  375. void** max = (void**)(buf->data + end * sizeof(void*));
  376. void** d = (void**)(buf->data + start * sizeof(void*));
  377. asIScriptEngine* engine = objType->GetEngine();
  378. for (; d < max; d++)
  379. *d = (void*)engine->CreateScriptObject(typeId);
  380. }
  381. }
  382. // internal
  383. void CScriptArray::Destruct(SArrayBuffer *buf, asUINT start, asUINT end)
  384. {
  385. int typeId = objType->GetSubTypeId();
  386. if (typeId & asTYPEID_MASK_OBJECT)
  387. {
  388. asIScriptEngine* engine = objType->GetEngine();
  389. void** max = (void**)(buf->data + end * sizeof(void*));
  390. void** d = (void**)(buf->data + start * sizeof(void*));
  391. for(; d < max; d++ )
  392. {
  393. if( *d )
  394. engine->ReleaseScriptObject(*d, typeId);
  395. }
  396. }
  397. }
  398. // internal
  399. void CScriptArray::CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src)
  400. {
  401. asIScriptEngine* engine = objType->GetEngine();
  402. if(isArrayOfHandles)
  403. {
  404. // Copy the references and increase the reference counters
  405. if (dst->numElements > 0 && src->numElements > 0)
  406. {
  407. int typeId = objType->GetSubTypeId();
  408. int count = dst->numElements > src->numElements ? src->numElements : dst->numElements;
  409. void** max = (void**)(dst->data + count * sizeof(void*));
  410. void** d = (void**)dst->data;
  411. void** s = (void**)src->data;
  412. for (; d < max; d++, s++)
  413. {
  414. *d = *s;
  415. if (*d)
  416. engine->AddRefScriptObject(*d, typeId);
  417. }
  418. }
  419. }
  420. else
  421. {
  422. int typeId = objType->GetSubTypeId();
  423. if (dst->numElements > 0 && src->numElements > 0)
  424. {
  425. int count = dst->numElements > src->numElements ? src->numElements : dst->numElements;
  426. if (typeId & asTYPEID_MASK_OBJECT)
  427. {
  428. // Call the assignment operator on all of the objects
  429. void** max = (void**)(dst->data + count * sizeof(void*));
  430. void** d = (void**)dst->data;
  431. void** s = (void**)src->data;
  432. for(; d < max; d++, s++)
  433. engine->CopyScriptObject(*d, *s, typeId);
  434. }
  435. else
  436. {
  437. // Primitives are copied byte for byte
  438. memcpy(dst->data, src->data, count*elementSize);
  439. }
  440. }
  441. }
  442. }
  443. // GC behaviour
  444. //void CScriptArray::EnumReferences(asIScriptEngine* engine)
  445. //{
  446. // // If the array is holding handles, then we need to notify the GC of them
  447. // int typeId = objType->GetSubTypeId();
  448. // if (typeId & asTYPEID_MASK_OBJECT)
  449. // {
  450. // void** d = (void**)buffer->data;
  451. // for (asUINT n = 0; n < buffer->numElements; ++n)
  452. // {
  453. // if (d[n])
  454. // engine->GCEnumCallback(d[n]);
  455. // }
  456. // }
  457. //}
  458. // GC behaviour
  459. //void CScriptArray::ReleaseAllHandles(asIScriptEngine* engine)
  460. //{
  461. // // Resizing to zero will release everything
  462. // Resize(0);
  463. //}
  464. void CScriptArray::AddRef() const
  465. {
  466. // Clear the GC flag then increase the counter
  467. gcFlag = false;
  468. refCount++;
  469. }
  470. void CScriptArray::Release() const
  471. {
  472. // Now do the actual releasing (clearing the flag set by GC)
  473. gcFlag = false;
  474. if (--refCount == 0)
  475. delete this;
  476. }
  477. // GC behaviour
  478. //int CScriptArray::GetRefCount()
  479. //{
  480. // return refCount;
  481. //}
  482. // GC behaviour
  483. //void CScriptArray::SetFlag()
  484. //{
  485. // gcFlag = true;
  486. //}
  487. // GC behaviour
  488. //bool CScriptArray::GetFlag()
  489. //{
  490. // return gcFlag;
  491. //}
  492. // Registers the template array type
  493. void registerArray(asIScriptEngine* engine)
  494. {
  495. engine->RegisterObjectType("array<class T>", 0, asOBJ_REF | asOBJ_TEMPLATE);
  496. engine->RegisterObjectBehaviour("array<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in)", asFUNCTION(ScriptArrayTemplateCallback), asCALL_CDECL);
  497. engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int& in)", asFUNCTIONPR(ScriptArrayFactory, (asIObjectType*), CScriptArray*), asCALL_CDECL);
  498. engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int& in, uint)", asFUNCTIONPR(ScriptArrayFactory2, (asIObjectType*, asUINT), CScriptArray*), asCALL_CDECL);
  499. engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int& in, uint, const T& in)", asFUNCTIONPR(ScriptArrayFactoryDefVal, (asIObjectType*, asUINT, void *), CScriptArray*), asCALL_CDECL);
  500. engine->RegisterObjectBehaviour("array<T>", asBEHAVE_LIST_FACTORY, "array<T>@ f(int& in, uint)", asFUNCTIONPR(ScriptArrayFactory2, (asIObjectType*, asUINT), CScriptArray*), asCALL_CDECL);
  501. engine->RegisterObjectBehaviour("array<T>", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptArray,AddRef), asCALL_THISCALL);
  502. engine->RegisterObjectBehaviour("array<T>", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptArray,Release), asCALL_THISCALL);
  503. engine->RegisterObjectMethod("array<T>", "T& opIndex(uint)", asMETHOD(CScriptArray, At), asCALL_THISCALL);
  504. engine->RegisterObjectMethod("array<T>", "const T& opIndex(uint) const", asMETHOD(CScriptArray, At), asCALL_THISCALL);
  505. engine->RegisterObjectMethod("array<T>", "array<T> &opAssign(const array<T>& in)", asMETHOD(CScriptArray, operator=), asCALL_THISCALL);
  506. engine->RegisterObjectMethod("array<T>", "void insertAt(uint, const T& in)", asMETHOD(CScriptArray, InsertAt), asCALL_THISCALL);
  507. engine->RegisterObjectMethod("array<T>", "void removeAt(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL);
  508. engine->RegisterObjectMethod("array<T>", "void insertLast(const T& in)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL);
  509. engine->RegisterObjectMethod("array<T>", "void removeLast()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL);
  510. engine->RegisterObjectMethod("array<T>", "uint length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL);
  511. engine->RegisterObjectMethod("array<T>", "void resize(uint)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL);
  512. //engine->RegisterObjectBehaviour("array<T>", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptArray, GetRefCount), asCALL_THISCALL);
  513. //engine->RegisterObjectBehaviour("array<T>", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptArray, SetFlag), asCALL_THISCALL);
  514. //engine->RegisterObjectBehaviour("array<T>", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptArray, GetFlag), asCALL_THISCALL);
  515. //engine->RegisterObjectBehaviour("array<T>", asBEHAVE_ENUMREFS, "void f(int& in)", asMETHOD(CScriptArray, EnumReferences), asCALL_THISCALL);
  516. //engine->RegisterObjectBehaviour("array<T>", asBEHAVE_RELEASEREFS, "void f(int& in)", asMETHOD(CScriptArray, ReleaseAllHandles), asCALL_THISCALL);
  517. engine->RegisterDefaultArrayType("array<T>");
  518. }