as_array.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2015 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. andreas@angelcode.com
  22. */
  23. #ifndef AS_ARRAY_H
  24. #define AS_ARRAY_H
  25. #if !defined(AS_NO_MEMORY_H)
  26. #include <memory.h>
  27. #endif
  28. #include <string.h> // some compilers declare memcpy() here
  29. #ifdef _MSC_VER
  30. #pragma warning(disable:4345) // warning about a change in how the code is handled in this version
  31. #endif
  32. BEGIN_AS_NAMESPACE
  33. template <class T> class asCArray
  34. {
  35. public:
  36. asCArray();
  37. asCArray(const asCArray<T> &);
  38. asCArray(asUINT reserve);
  39. ~asCArray();
  40. void Allocate(asUINT numElements, bool keepData);
  41. void AllocateNoConstruct(asUINT numElements, bool keepData);
  42. asUINT GetCapacity() const;
  43. void PushLast(const T &element);
  44. T PopLast();
  45. bool SetLength(asUINT numElements);
  46. bool SetLengthNoConstruct(asUINT numElements);
  47. asUINT GetLength() const;
  48. void Copy(const T*, asUINT count);
  49. asCArray<T> &operator =(const asCArray<T> &);
  50. void SwapWith(asCArray<T> &other);
  51. const T &operator [](asUINT index) const;
  52. T &operator [](asUINT index);
  53. T *AddressOf();
  54. const T *AddressOf() const;
  55. bool Concatenate(const asCArray<T> &);
  56. void Concatenate(T*, unsigned int count);
  57. bool Exists(const T &element) const;
  58. int IndexOf(const T &element) const;
  59. void RemoveIndex(asUINT index); // Removes the entry without reordering the array
  60. void RemoveValue(const T &element); // Removes the value without reordering the array
  61. void RemoveIndexUnordered(asUINT index); // Removes the entry without keeping the order
  62. bool operator==(const asCArray<T> &) const;
  63. bool operator!=(const asCArray<T> &) const;
  64. protected:
  65. T *array;
  66. asUINT length; // 32bits is enough for all uses of this array
  67. asUINT maxLength;
  68. char buf[2*4*AS_PTR_SIZE]; // Avoid dynamically allocated memory for tiny arrays
  69. };
  70. // Implementation
  71. template <class T>
  72. T *asCArray<T>::AddressOf()
  73. {
  74. return array;
  75. }
  76. template <class T>
  77. const T *asCArray<T>::AddressOf() const
  78. {
  79. return array;
  80. }
  81. template <class T>
  82. asCArray<T>::asCArray(void)
  83. {
  84. array = 0;
  85. length = 0;
  86. maxLength = 0;
  87. }
  88. template <class T>
  89. asCArray<T>::asCArray(const asCArray<T> &copy)
  90. {
  91. array = 0;
  92. length = 0;
  93. maxLength = 0;
  94. *this = copy;
  95. }
  96. template <class T>
  97. asCArray<T>::asCArray(asUINT reserve)
  98. {
  99. array = 0;
  100. length = 0;
  101. maxLength = 0;
  102. Allocate(reserve, false);
  103. }
  104. template <class T>
  105. asCArray<T>::~asCArray(void)
  106. {
  107. // Allocating a zero length array will free all memory
  108. Allocate(0,0);
  109. }
  110. template <class T>
  111. asUINT asCArray<T>::GetLength() const
  112. {
  113. return length;
  114. }
  115. template <class T>
  116. const T &asCArray<T>::operator [](asUINT index) const
  117. {
  118. asASSERT(index < length);
  119. return array[index];
  120. }
  121. template <class T>
  122. T &asCArray<T>::operator [](asUINT index)
  123. {
  124. asASSERT(index < length);
  125. return array[index];
  126. }
  127. template <class T>
  128. void asCArray<T>::PushLast(const T &element)
  129. {
  130. if( length == maxLength )
  131. {
  132. if( maxLength == 0 )
  133. Allocate(1, false);
  134. else
  135. Allocate(2*maxLength, true);
  136. if( length == maxLength )
  137. {
  138. // Out of memory. Return without doing anything
  139. return;
  140. }
  141. }
  142. array[length++] = element;
  143. }
  144. template <class T>
  145. T asCArray<T>::PopLast()
  146. {
  147. asASSERT(length > 0);
  148. return array[--length];
  149. }
  150. template <class T>
  151. void asCArray<T>::Allocate(asUINT numElements, bool keepData)
  152. {
  153. // We have 4 situations
  154. // 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller
  155. // 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes
  156. // 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller
  157. // 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes
  158. T *tmp = 0;
  159. if( numElements )
  160. {
  161. if( sizeof(T)*numElements <= sizeof(buf) )
  162. // Use the internal buffer
  163. tmp = reinterpret_cast<T*>(buf);
  164. else
  165. {
  166. // Allocate the array and construct each of the elements
  167. tmp = asNEWARRAY(T,numElements);
  168. if( tmp == 0 )
  169. {
  170. // Out of memory. Return without doing anything
  171. return;
  172. }
  173. }
  174. if( array == tmp )
  175. {
  176. // Construct only the newly allocated elements
  177. for( asUINT n = length; n < numElements; n++ )
  178. new (&tmp[n]) T();
  179. }
  180. else
  181. {
  182. // Construct all elements
  183. for( asUINT n = 0; n < numElements; n++ )
  184. new (&tmp[n]) T();
  185. }
  186. }
  187. if( array )
  188. {
  189. asUINT oldLength = length;
  190. if( array == tmp )
  191. {
  192. if( keepData )
  193. {
  194. if( length > numElements )
  195. length = numElements;
  196. }
  197. else
  198. length = 0;
  199. // Call the destructor for elements that are no longer used
  200. for( asUINT n = length; n < oldLength; n++ )
  201. array[n].~T();
  202. }
  203. else
  204. {
  205. if( keepData )
  206. {
  207. if( length > numElements )
  208. length = numElements;
  209. for( asUINT n = 0; n < length; n++ )
  210. tmp[n] = array[n];
  211. }
  212. else
  213. length = 0;
  214. // Call the destructor for all elements
  215. for( asUINT n = 0; n < oldLength; n++ )
  216. array[n].~T();
  217. if( array != reinterpret_cast<T*>(buf) )
  218. asDELETEARRAY(array);
  219. }
  220. }
  221. array = tmp;
  222. maxLength = numElements;
  223. }
  224. template <class T>
  225. void asCArray<T>::AllocateNoConstruct(asUINT numElements, bool keepData)
  226. {
  227. // We have 4 situations
  228. // 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller
  229. // 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes
  230. // 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller
  231. // 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes
  232. T *tmp = 0;
  233. if( numElements )
  234. {
  235. if( sizeof(T)*numElements <= sizeof(buf) )
  236. // Use the internal buffer
  237. tmp = reinterpret_cast<T*>(buf);
  238. else
  239. {
  240. // Allocate the array and construct each of the elements
  241. tmp = asNEWARRAY(T,numElements);
  242. if( tmp == 0 )
  243. {
  244. // Out of memory. Return without doing anything
  245. return;
  246. }
  247. }
  248. }
  249. if( array )
  250. {
  251. if( array == tmp )
  252. {
  253. if( keepData )
  254. {
  255. if( length > numElements )
  256. length = numElements;
  257. }
  258. else
  259. length = 0;
  260. }
  261. else
  262. {
  263. if( keepData )
  264. {
  265. if( length > numElements )
  266. length = numElements;
  267. memcpy(tmp, array, sizeof(T)*length);
  268. }
  269. else
  270. length = 0;
  271. if( array != reinterpret_cast<T*>(buf) )
  272. asDELETEARRAY(array);
  273. }
  274. }
  275. array = tmp;
  276. maxLength = numElements;
  277. }
  278. template <class T>
  279. asUINT asCArray<T>::GetCapacity() const
  280. {
  281. return maxLength;
  282. }
  283. template <class T>
  284. bool asCArray<T>::SetLength(asUINT numElements)
  285. {
  286. if( numElements > maxLength )
  287. {
  288. Allocate(numElements, true);
  289. if( numElements > maxLength )
  290. {
  291. // Out of memory. Return without doing anything
  292. return false;
  293. }
  294. }
  295. length = numElements;
  296. return true;
  297. }
  298. template <class T>
  299. bool asCArray<T>::SetLengthNoConstruct(asUINT numElements)
  300. {
  301. if( numElements > maxLength )
  302. {
  303. AllocateNoConstruct(numElements, true);
  304. if( numElements > maxLength )
  305. {
  306. // Out of memory. Return without doing anything
  307. return false;
  308. }
  309. }
  310. length = numElements;
  311. return true;
  312. }
  313. template <class T>
  314. void asCArray<T>::Copy(const T *data, asUINT count)
  315. {
  316. if( maxLength < count )
  317. {
  318. Allocate(count, false);
  319. if( maxLength < count )
  320. {
  321. // Out of memory. Return without doing anything
  322. return;
  323. }
  324. }
  325. for( asUINT n = 0; n < count; n++ )
  326. array[n] = data[n];
  327. length = count;
  328. }
  329. template <class T>
  330. asCArray<T> &asCArray<T>::operator =(const asCArray<T> &copy)
  331. {
  332. Copy(copy.array, copy.length);
  333. return *this;
  334. }
  335. template <class T>
  336. void asCArray<T>::SwapWith(asCArray<T> &other)
  337. {
  338. T *tmpArray = array;
  339. asUINT tmpLength = length;
  340. asUINT tmpMaxLength = maxLength;
  341. char tmpBuf[sizeof(buf)];
  342. memcpy(tmpBuf, buf, sizeof(buf));
  343. array = other.array;
  344. length = other.length;
  345. maxLength = other.maxLength;
  346. memcpy(buf, other.buf, sizeof(buf));
  347. other.array = tmpArray;
  348. other.length = tmpLength;
  349. other.maxLength = tmpMaxLength;
  350. memcpy(other.buf, tmpBuf, sizeof(buf));
  351. // If the data is in the internal buffer, then the array pointer must refer to it
  352. if( array == reinterpret_cast<T*>(other.buf) )
  353. array = reinterpret_cast<T*>(buf);
  354. if( other.array == reinterpret_cast<T*>(buf) )
  355. other.array = reinterpret_cast<T*>(other.buf);
  356. }
  357. template <class T>
  358. bool asCArray<T>::operator ==(const asCArray<T> &other) const
  359. {
  360. if( length != other.length ) return false;
  361. for( asUINT n = 0; n < length; n++ )
  362. if( array[n] != other.array[n] )
  363. return false;
  364. return true;
  365. }
  366. template <class T>
  367. bool asCArray<T>::operator !=(const asCArray<T> &other) const
  368. {
  369. return !(*this == other);
  370. }
  371. // Returns false if the concatenation wasn't successful due to out of memory
  372. template <class T>
  373. bool asCArray<T>::Concatenate(const asCArray<T> &other)
  374. {
  375. if( maxLength < length + other.length )
  376. {
  377. Allocate(length + other.length, true);
  378. if( maxLength < length + other.length )
  379. {
  380. // Out of memory
  381. return false;
  382. }
  383. }
  384. for( asUINT n = 0; n < other.length; n++ )
  385. array[length+n] = other.array[n];
  386. length += other.length;
  387. // Success
  388. return true;
  389. }
  390. template <class T>
  391. void asCArray<T>::Concatenate(T* other, unsigned int count)
  392. {
  393. for( unsigned int c = 0; c < count; c++ )
  394. PushLast(other[c]);
  395. }
  396. template <class T>
  397. bool asCArray<T>::Exists(const T &e) const
  398. {
  399. return IndexOf(e) == -1 ? false : true;
  400. }
  401. template <class T>
  402. int asCArray<T>::IndexOf(const T &e) const
  403. {
  404. for( asUINT n = 0; n < length; n++ )
  405. if( array[n] == e ) return static_cast<int>(n);
  406. return -1;
  407. }
  408. template <class T>
  409. void asCArray<T>::RemoveIndex(asUINT index)
  410. {
  411. if( index < length )
  412. {
  413. for( asUINT n = index; n < length-1; n++ )
  414. array[n] = array[n+1];
  415. PopLast();
  416. }
  417. }
  418. template <class T>
  419. void asCArray<T>::RemoveValue(const T &e)
  420. {
  421. for( asUINT n = 0; n < length; n++ )
  422. {
  423. if( array[n] == e )
  424. {
  425. RemoveIndex(n);
  426. break;
  427. }
  428. }
  429. }
  430. template <class T>
  431. void asCArray<T>::RemoveIndexUnordered(asUINT index)
  432. {
  433. if( index == length - 1 )
  434. PopLast();
  435. else if( index < length )
  436. array[index] = PopLast();
  437. }
  438. END_AS_NAMESPACE
  439. #endif