Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

574 rader
18 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://www.wtfpl.net/ for more details.
  9. //
  10. //
  11. // The Array class
  12. // ---------------
  13. // A very simple Array class not unlike the std::vector, with some nice
  14. // additional features, eg. Array<int,float> for automatic arrays of structs.
  15. //
  16. #if !defined __LOL_BASE_ARRAY_H__
  17. #define __LOL_BASE_ARRAY_H__
  18. #include <lol/base/assert.h>
  19. #include <new>
  20. #include <stdint.h>
  21. namespace lol
  22. {
  23. /*
  24. * The base array type.
  25. *
  26. * Contains an m_data memory array of Elements, of which only the first
  27. * m_count are allocated. The rest is uninitialised memory.
  28. */
  29. template<typename T, typename ARRAY> class ArrayBase
  30. {
  31. public:
  32. typedef T Element;
  33. inline ArrayBase() : m_data(0), m_count(0), m_reserved(0)
  34. {
  35. }
  36. inline ~ArrayBase()
  37. {
  38. for (int i = 0; i < m_count; i++)
  39. m_data[i].~Element();
  40. delete[] reinterpret_cast<uint8_t *>(m_data);
  41. }
  42. ArrayBase(ArrayBase const& that) : m_data(0), m_count(0), m_reserved(0)
  43. {
  44. /* Reserve the exact number of values instead of what the other
  45. * array had reserved. Just a method for not wasting too much. */
  46. Reserve(that.m_count);
  47. for (int i = 0; i < that.m_count; i++)
  48. new(&m_data[i]) Element(that[i]);
  49. m_count = that.m_count;
  50. }
  51. ArrayBase& operator=(ArrayBase const& that)
  52. {
  53. if ((uintptr_t)this != (uintptr_t)&that)
  54. {
  55. /* FIXME: there is an opportunity for optimisation here if we
  56. * find a way to ask Reserve not to create new elements, since
  57. * we're going to overwrite them anyway. */
  58. if (m_reserved < that.m_count)
  59. {
  60. /* If not enough space, reserve memory, overwrite the first
  61. * elements, then use placement new directly for the
  62. * remaining elements. */
  63. Reserve(that.m_count);
  64. for (int i = 0; i < m_count && i < that.m_count; i++)
  65. m_data[i] = Element(that[i]);
  66. for (int i = m_count; i < that.m_count; i++)
  67. new(&m_data[i]) Element(that[i]);
  68. }
  69. else
  70. {
  71. /* If enough space, overwrite the common elements, then
  72. * use placement new for the elements in the other array
  73. * that we do not have, and finally destroy the remaining
  74. * elements. */
  75. for (int i = 0; i < m_count && i < that.m_count; i++)
  76. m_data[i] = Element(that[i]);
  77. for (int i = m_count; i < that.m_count; i++)
  78. new(&m_data[i]) Element(that[i]);
  79. for (int i = that.m_count; i < m_count; i++)
  80. m_data[i].~Element();
  81. }
  82. m_count = that.m_count;
  83. }
  84. return *this;
  85. }
  86. ArrayBase& operator+=(ArrayBase const &that)
  87. {
  88. int todo = that.m_count;
  89. Reserve(m_count + that.m_count);
  90. for (int i = 0; i < todo; i++)
  91. new(&m_data[m_count + i]) Element(that[i]);
  92. m_count += todo;
  93. return *this;
  94. }
  95. ARRAY operator+(ARRAY const &that) const
  96. {
  97. ARRAY ret;
  98. ret.Reserve(m_count + that.m_count);
  99. ret += *this;
  100. ret += that;
  101. return ret;
  102. }
  103. inline Element& operator[](int n)
  104. {
  105. /* Allow array[0] even if size is zero so that people can
  106. * always use &array[0] to get a pointer to the data. */
  107. ASSERT(n >= 0);
  108. ASSERT((unsigned)n < (unsigned)m_count || (!n && !m_count));
  109. return m_data[n];
  110. }
  111. inline Element const& operator[](int n) const
  112. {
  113. ASSERT(n >= 0);
  114. ASSERT(n < m_count || (!n && !m_count));
  115. return m_data[n];
  116. }
  117. inline Element& Last()
  118. {
  119. ASSERT(m_count > 0);
  120. return m_data[m_count - 1];
  121. }
  122. inline Element *Data()
  123. {
  124. return m_data;
  125. }
  126. inline Element const *Data() const
  127. {
  128. return m_data;
  129. }
  130. inline Element const& Last() const
  131. {
  132. ASSERT(m_count > 0);
  133. return m_data[m_count - 1];
  134. }
  135. inline ArrayBase& operator<<(T const &x)
  136. {
  137. if (m_count >= m_reserved)
  138. {
  139. T tmp = x;
  140. Reserve(m_count * 13 / 8 + 8);
  141. new (&m_data[m_count++]) Element(tmp);
  142. }
  143. else
  144. {
  145. new (&m_data[m_count++]) Element(x);
  146. }
  147. return *this;
  148. }
  149. inline void Push(T const &x)
  150. {
  151. *this << x;
  152. }
  153. inline T Pop()
  154. {
  155. ASSERT(m_count > 0);
  156. Element tmp = Last();
  157. Remove(m_count - 1, 1);
  158. return tmp;
  159. }
  160. void Swap(int pos1, int pos2)
  161. {
  162. ASSERT(pos1 >= 0);
  163. ASSERT(pos2 >= 0);
  164. ASSERT(pos1 < m_count);
  165. ASSERT(pos2 < m_count);
  166. if (pos1 != pos2)
  167. {
  168. Element tmp = (*this)[pos1];
  169. (*this)[pos1] = (*this)[pos2];
  170. (*this)[pos2] = tmp;
  171. }
  172. }
  173. void Remove(int pos, int todelete = 1)
  174. {
  175. ASSERT(todelete >= 0);
  176. ASSERT(pos - todelete >= -m_count - 1);
  177. ASSERT(pos + todelete <= m_count);
  178. if (pos < 0)
  179. pos = m_count + pos;
  180. for (int i = pos; i + todelete < m_count; i++)
  181. m_data[i] = m_data[i + todelete];
  182. for (int i = m_count - todelete; i < m_count; i++)
  183. m_data[i].~Element();
  184. m_count -= todelete;
  185. }
  186. void RemoveSwap(int pos, int todelete = 1)
  187. {
  188. ASSERT(todelete >= 0);
  189. ASSERT(pos - todelete >= -m_count - 1);
  190. ASSERT(pos + todelete <= m_count);
  191. if (pos < 0)
  192. pos = m_count + pos;
  193. for (int i = 0; i < todelete; i++)
  194. {
  195. if (pos + i < m_count - 1 - i)
  196. m_data[pos + i] = m_data[m_count - 1 - i];
  197. m_data[m_count - 1 - i].~Element();
  198. }
  199. m_count -= todelete;
  200. }
  201. void Resize(int count, Element e = Element())
  202. {
  203. ASSERT(count >= 0);
  204. Reserve(count);
  205. /* Too many elements? Remove them. */
  206. for (int i = count; i < m_count; ++i)
  207. m_data[i].~Element();
  208. /* Not enough elements? Add some. */
  209. for (int i = m_count; i < count; ++i)
  210. new(&m_data[i]) Element(e);
  211. m_count = count;
  212. }
  213. inline void Empty()
  214. {
  215. Remove(0, m_count);
  216. }
  217. void Reserve(int toreserve)
  218. {
  219. if (toreserve <= (int)m_reserved)
  220. return;
  221. /* This cast is not very nice, because we kill any alignment
  222. * information we could have. But until C++ gives us the proper
  223. * tools to deal with it, we assume new uint8_t[] returns properly
  224. * aligned data. */
  225. Element *tmp = reinterpret_cast<Element *>(reinterpret_cast<uintptr_t>
  226. (new uint8_t[sizeof(Element) * toreserve]));
  227. for (int i = 0; i < m_count; i++)
  228. {
  229. new(&tmp[i]) Element(m_data[i]);
  230. m_data[i].~Element();
  231. }
  232. if (m_data)
  233. delete[] reinterpret_cast<uint8_t *>(m_data);
  234. m_data = tmp;
  235. m_reserved = toreserve;
  236. }
  237. inline int Count() const { return m_count; }
  238. inline int Bytes() const { return m_count * sizeof(Element); }
  239. protected:
  240. Element *m_data;
  241. int m_count, m_reserved;
  242. };
  243. /*
  244. * Element types
  245. */
  246. template<typename T1, typename T2, typename T3 = void, typename T4 = void,
  247. typename T5 = void, typename T6 = void, typename T7 = void,
  248. typename T8 = void>
  249. class ArrayElement
  250. {
  251. public:
  252. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7; T8 m8;
  253. };
  254. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  255. typename T6, typename T7>
  256. class ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>
  257. {
  258. public:
  259. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7;
  260. };
  261. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  262. typename T6>
  263. class ArrayElement<T1, T2, T3, T4, T5, T6, void, void>
  264. {
  265. public:
  266. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6;
  267. };
  268. template<typename T1, typename T2, typename T3, typename T4, typename T5>
  269. class ArrayElement<T1, T2, T3, T4, T5, void, void, void>
  270. {
  271. public:
  272. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5;
  273. };
  274. template<typename T1, typename T2, typename T3, typename T4>
  275. class ArrayElement<T1, T2, T3, T4, void, void, void, void>
  276. {
  277. public:
  278. T1 m1; T2 m2; T3 m3; T4 m4;
  279. };
  280. template<typename T1, typename T2, typename T3>
  281. class ArrayElement<T1, T2, T3, void, void, void, void, void>
  282. {
  283. public:
  284. T1 m1; T2 m2; T3 m3;
  285. };
  286. template<typename T1, typename T2>
  287. class ArrayElement<T1, T2, void, void, void, void, void, void>
  288. {
  289. public:
  290. T1 m1; T2 m2;
  291. };
  292. /*
  293. * Array specialisations implementing specific setters
  294. */
  295. template<typename T1, typename T2 = void, typename T3 = void,
  296. typename T4 = void, typename T5 = void, typename T6 = void,
  297. typename T7 = void, typename T8 = void>
  298. class Array : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, T8>,
  299. Array<T1, T2, T3, T4, T5, T6, T7, T8> >
  300. {
  301. public:
  302. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  303. T5 const &m5, T6 const &m6, T7 const &m7, T8 const &m8)
  304. {
  305. if (this->m_count >= this->m_reserved)
  306. {
  307. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  308. T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7; T8 tmp8 = m8;
  309. this->Reserve(this->m_count * 13 / 8 + 8);
  310. new (&this->m_data[this->m_count].m1) T1(tmp1);
  311. new (&this->m_data[this->m_count].m2) T2(tmp2);
  312. new (&this->m_data[this->m_count].m3) T3(tmp3);
  313. new (&this->m_data[this->m_count].m4) T4(tmp4);
  314. new (&this->m_data[this->m_count].m5) T5(tmp5);
  315. new (&this->m_data[this->m_count].m6) T6(tmp6);
  316. new (&this->m_data[this->m_count].m7) T7(tmp7);
  317. new (&this->m_data[this->m_count].m8) T8(tmp8);
  318. }
  319. else
  320. {
  321. new (&this->m_data[this->m_count].m1) T1(m1);
  322. new (&this->m_data[this->m_count].m2) T2(m2);
  323. new (&this->m_data[this->m_count].m3) T3(m3);
  324. new (&this->m_data[this->m_count].m4) T4(m4);
  325. new (&this->m_data[this->m_count].m5) T5(m5);
  326. new (&this->m_data[this->m_count].m6) T6(m6);
  327. new (&this->m_data[this->m_count].m7) T7(m7);
  328. new (&this->m_data[this->m_count].m8) T8(m8);
  329. }
  330. ++this->m_count;
  331. }
  332. };
  333. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  334. typename T6, typename T7>
  335. class Array<T1, T2, T3, T4, T5, T6, T7, void>
  336. : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>,
  337. Array<T1, T2, T3, T4, T5, T6, T7> >
  338. {
  339. public:
  340. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  341. T5 const &m5, T6 const &m6, T7 const &m7)
  342. {
  343. if (this->m_count >= this->m_reserved)
  344. {
  345. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  346. T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7;
  347. this->Reserve(this->m_count * 13 / 8 + 8);
  348. new (&this->m_data[this->m_count].m1) T1(tmp1);
  349. new (&this->m_data[this->m_count].m2) T2(tmp2);
  350. new (&this->m_data[this->m_count].m3) T3(tmp3);
  351. new (&this->m_data[this->m_count].m4) T4(tmp4);
  352. new (&this->m_data[this->m_count].m5) T5(tmp5);
  353. new (&this->m_data[this->m_count].m6) T6(tmp6);
  354. new (&this->m_data[this->m_count].m7) T7(tmp7);
  355. }
  356. else
  357. {
  358. new (&this->m_data[this->m_count].m1) T1(m1);
  359. new (&this->m_data[this->m_count].m2) T2(m2);
  360. new (&this->m_data[this->m_count].m3) T3(m3);
  361. new (&this->m_data[this->m_count].m4) T4(m4);
  362. new (&this->m_data[this->m_count].m5) T5(m5);
  363. new (&this->m_data[this->m_count].m6) T6(m6);
  364. new (&this->m_data[this->m_count].m7) T7(m7);
  365. }
  366. ++this->m_count;
  367. }
  368. };
  369. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  370. typename T6>
  371. class Array<T1, T2, T3, T4, T5, T6, void, void>
  372. : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, void, void>,
  373. Array<T1, T2, T3, T4, T5, T6> >
  374. {
  375. public:
  376. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  377. T5 const &m5, T6 const &m6)
  378. {
  379. if (this->m_count >= this->m_reserved)
  380. {
  381. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  382. T5 tmp5 = m5; T6 tmp6 = m6;
  383. this->Reserve(this->m_count * 13 / 8 + 8);
  384. new (&this->m_data[this->m_count].m1) T1(tmp1);
  385. new (&this->m_data[this->m_count].m2) T2(tmp2);
  386. new (&this->m_data[this->m_count].m3) T3(tmp3);
  387. new (&this->m_data[this->m_count].m4) T4(tmp4);
  388. new (&this->m_data[this->m_count].m5) T5(tmp5);
  389. new (&this->m_data[this->m_count].m6) T6(tmp6);
  390. }
  391. else
  392. {
  393. new (&this->m_data[this->m_count].m1) T1(m1);
  394. new (&this->m_data[this->m_count].m2) T2(m2);
  395. new (&this->m_data[this->m_count].m3) T3(m3);
  396. new (&this->m_data[this->m_count].m4) T4(m4);
  397. new (&this->m_data[this->m_count].m5) T5(m5);
  398. new (&this->m_data[this->m_count].m6) T6(m6);
  399. }
  400. ++this->m_count;
  401. }
  402. };
  403. template<typename T1, typename T2, typename T3, typename T4, typename T5>
  404. class Array<T1, T2, T3, T4, T5, void, void, void>
  405. : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, void, void, void>,
  406. Array<T1, T2, T3, T4, T5> >
  407. {
  408. public:
  409. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  410. T5 const &m5)
  411. {
  412. if (this->m_count >= this->m_reserved)
  413. {
  414. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  415. T5 tmp5 = m5;
  416. this->Reserve(this->m_count * 13 / 8 + 8);
  417. new (&this->m_data[this->m_count].m1) T1(tmp1);
  418. new (&this->m_data[this->m_count].m2) T2(tmp2);
  419. new (&this->m_data[this->m_count].m3) T3(tmp3);
  420. new (&this->m_data[this->m_count].m4) T4(tmp4);
  421. new (&this->m_data[this->m_count].m5) T5(tmp5);
  422. }
  423. else
  424. {
  425. new (&this->m_data[this->m_count].m1) T1(m1);
  426. new (&this->m_data[this->m_count].m2) T2(m2);
  427. new (&this->m_data[this->m_count].m3) T3(m3);
  428. new (&this->m_data[this->m_count].m4) T4(m4);
  429. new (&this->m_data[this->m_count].m5) T5(m5);
  430. }
  431. ++this->m_count;
  432. }
  433. };
  434. template<typename T1, typename T2, typename T3, typename T4>
  435. class Array<T1, T2, T3, T4, void, void, void, void>
  436. : public ArrayBase<ArrayElement<T1, T2, T3, T4, void, void, void, void>,
  437. Array<T1, T2, T3, T4> >
  438. {
  439. public:
  440. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4)
  441. {
  442. if (this->m_count >= this->m_reserved)
  443. {
  444. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  445. this->Reserve(this->m_count * 13 / 8 + 8);
  446. new (&this->m_data[this->m_count].m1) T1(tmp1);
  447. new (&this->m_data[this->m_count].m2) T2(tmp2);
  448. new (&this->m_data[this->m_count].m3) T3(tmp3);
  449. new (&this->m_data[this->m_count].m4) T4(tmp4);
  450. }
  451. else
  452. {
  453. new (&this->m_data[this->m_count].m1) T1(m1);
  454. new (&this->m_data[this->m_count].m2) T2(m2);
  455. new (&this->m_data[this->m_count].m3) T3(m3);
  456. new (&this->m_data[this->m_count].m4) T4(m4);
  457. }
  458. ++this->m_count;
  459. }
  460. };
  461. template<typename T1, typename T2, typename T3>
  462. class Array<T1, T2, T3, void, void, void, void, void>
  463. : public ArrayBase<ArrayElement<T1, T2, T3, void, void, void, void, void>,
  464. Array<T1, T2, T3> >
  465. {
  466. public:
  467. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3)
  468. {
  469. if (this->m_count >= this->m_reserved)
  470. {
  471. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3;
  472. this->Reserve(this->m_count * 13 / 8 + 8);
  473. new (&this->m_data[this->m_count].m1) T1(tmp1);
  474. new (&this->m_data[this->m_count].m2) T2(tmp2);
  475. new (&this->m_data[this->m_count].m3) T3(tmp3);
  476. }
  477. else
  478. {
  479. new (&this->m_data[this->m_count].m1) T1(m1);
  480. new (&this->m_data[this->m_count].m2) T2(m2);
  481. new (&this->m_data[this->m_count].m3) T3(m3);
  482. }
  483. ++this->m_count;
  484. }
  485. };
  486. template<typename T1, typename T2>
  487. class Array<T1, T2, void, void, void, void, void, void>
  488. : public ArrayBase<ArrayElement<T1, T2, void, void, void, void, void, void>,
  489. Array<T1, T2> >
  490. {
  491. public:
  492. inline void Push(T1 const &m1, T2 const &m2)
  493. {
  494. if (this->m_count >= this->m_reserved)
  495. {
  496. T1 tmp1 = m1; T2 tmp2 = m2;
  497. this->Reserve(this->m_count * 13 / 8 + 8);
  498. new (&this->m_data[this->m_count].m1) T1(tmp1);
  499. new (&this->m_data[this->m_count].m2) T2(tmp2);
  500. }
  501. else
  502. {
  503. new (&this->m_data[this->m_count].m1) T1(m1);
  504. new (&this->m_data[this->m_count].m2) T2(m2);
  505. }
  506. ++this->m_count;
  507. }
  508. };
  509. template<typename T>
  510. class Array<T, void, void, void, void, void, void, void>
  511. : public ArrayBase<T,
  512. Array<T> >
  513. {
  514. };
  515. } /* namespace lol */
  516. #endif // __LOL_BASE_ARRAY_H__