512 line
15 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2012 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://sam.zoy.org/projects/COPYING.WTFPL 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_CORE_ARRAY_H__
  17. #define __LOL_CORE_ARRAY_H__
  18. #include <new>
  19. #include <stdint.h>
  20. namespace lol
  21. {
  22. /*
  23. * The base array type.
  24. *
  25. * Contains an m_data memory array of Elements, of which only the first
  26. * m_count are allocated. The rest is uninitialised memory.
  27. */
  28. template<typename T, typename ARRAY> class ArrayBase
  29. {
  30. public:
  31. typedef T Element;
  32. inline ArrayBase() : m_data(0), m_count(0), m_reserved(0)
  33. {
  34. }
  35. inline ~ArrayBase()
  36. {
  37. for (int i = 0; i < m_count; i++)
  38. m_data[i].~Element();
  39. delete[] reinterpret_cast<uint8_t *>(m_data);
  40. }
  41. ArrayBase(ArrayBase const& that) : m_data(0), m_count(0), m_reserved(0)
  42. {
  43. /* Reserve the exact number of values instead of what the other
  44. * array had reserved. Just a method for not wasting too much. */
  45. Reserve(that.m_count);
  46. for (int i = 0; i < that.m_count; i++)
  47. new(&m_data[i]) Element(that[i]);
  48. m_count = that.m_count;
  49. }
  50. ArrayBase& operator=(ArrayBase const& that)
  51. {
  52. if ((uintptr_t)this != (uintptr_t)&that)
  53. {
  54. if (m_reserved < that.m_count)
  55. {
  56. /* If not enough space, reserve memory and use placement
  57. * new directly for all elements. */
  58. Reserve(that.m_count);
  59. for (int i = 0; i < that.m_count; i++)
  60. new(&m_data[i]) Element(that[i]);
  61. }
  62. else
  63. {
  64. /* If enough space, overwrite the common elements, then
  65. * use placement new for the elements in the other array
  66. * that we do not have, and finally destroy the remaining
  67. * elements. */
  68. for (int i = 0; i < m_count && i < that.m_count; i++)
  69. m_data[i] = Element(that[i]);
  70. for (int i = m_count; i < that.m_count; i++)
  71. new(&m_data[i]) Element(that[i]);
  72. for (int i = that.m_count; i < m_count; i++)
  73. m_data[i].~Element();
  74. }
  75. m_count = that.m_count;
  76. }
  77. return *this;
  78. }
  79. ArrayBase& operator+=(ARRAY const &that)
  80. {
  81. int todo = that.m_count;
  82. Reserve(m_count + that.m_count);
  83. for (int i = 0; i < todo; i++)
  84. *this << that[i];
  85. return *this;
  86. }
  87. ARRAY operator+(ARRAY const &that) const
  88. {
  89. /* FIXME: upon return, this makes a copy of the temporary object;
  90. * use either C++11 move semantics, or add a special flag to the
  91. * object indicating we're a temporary about to be destroyed */
  92. ARRAY ret;
  93. ret.Reserve(m_count + that.m_count);
  94. for (int i = 0; i < m_count; i++)
  95. ret << (*this)[i];
  96. for (int i = 0; i < that.m_count; i++)
  97. ret << that[i];
  98. return ret;
  99. }
  100. inline Element& operator[](int n)
  101. {
  102. return m_data[n];
  103. }
  104. inline Element const& operator[](int n) const
  105. {
  106. return m_data[n];
  107. }
  108. inline Element& Last()
  109. {
  110. return m_data[m_count - 1];
  111. }
  112. inline Element const& Last() const
  113. {
  114. return m_data[m_count - 1];
  115. }
  116. inline ArrayBase& operator<<(T const &x)
  117. {
  118. if (m_count >= m_reserved)
  119. {
  120. T tmp = x;
  121. Reserve(m_count * 13 / 8 + 8);
  122. new (&m_data[m_count++]) Element(tmp);
  123. }
  124. else
  125. {
  126. new (&m_data[m_count++]) Element(x);
  127. }
  128. return *this;
  129. }
  130. inline void Push(T const &x)
  131. {
  132. *this << x;
  133. }
  134. inline void Pop()
  135. {
  136. Remove(m_count - 1, 1);
  137. }
  138. void Remove(int pos, int todelete = 1)
  139. {
  140. /* FIXME: we need to call dtors for the first
  141. * todelete elements here */
  142. for (int i = pos; i + todelete < m_count; i++)
  143. m_data[i] = m_data[i + todelete];
  144. for (int i = m_count - todelete; i < m_count; i++)
  145. m_data[i].~Element();
  146. m_count -= todelete;
  147. }
  148. void Resize(int count, Element e = Element())
  149. {
  150. Reserve(count);
  151. /* Too many elements? Remove them. */
  152. for (int i = count; i < m_count; ++i)
  153. m_data[i].~Element();
  154. /* Not enough elements? Add some. */
  155. for (int i = m_count; i < count; ++i)
  156. m_data[i] = e;
  157. m_count = count;
  158. }
  159. inline void Empty()
  160. {
  161. Remove(0, m_count);
  162. }
  163. void Reserve(int toreserve)
  164. {
  165. if (toreserve <= (int)m_reserved)
  166. return;
  167. /* This cast is not very nice, because we kill any alignment
  168. * information we could have. But until C++ gives us the proper
  169. * tools to deal with it, we assume new uint8_t[] returns properly
  170. * aligned data. */
  171. Element *tmp = reinterpret_cast<Element *>(reinterpret_cast<uintptr_t>
  172. (new uint8_t[sizeof(Element) * toreserve]));
  173. for (int i = 0; i < m_count; i++)
  174. {
  175. new(&tmp[i]) Element(m_data[i]);
  176. m_data[i].~Element();
  177. }
  178. if (m_data)
  179. delete[] reinterpret_cast<uint8_t *>(m_data);
  180. m_data = tmp;
  181. m_reserved = toreserve;
  182. }
  183. inline int Count() const { return m_count; }
  184. inline int Bytes() const { return m_count * sizeof(Element); }
  185. protected:
  186. Element *m_data;
  187. int m_count, m_reserved;
  188. };
  189. /*
  190. * Element types
  191. */
  192. template<typename T1, typename T2, typename T3 = void, typename T4 = void,
  193. typename T5 = void, typename T6 = void, typename T7 = void,
  194. typename T8 = void>
  195. class ArrayElement
  196. {
  197. public:
  198. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7; T8 m8;
  199. };
  200. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  201. typename T6, typename T7>
  202. class ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>
  203. {
  204. public:
  205. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7;
  206. };
  207. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  208. typename T6>
  209. class ArrayElement<T1, T2, T3, T4, T5, T6, void, void>
  210. {
  211. public:
  212. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6;
  213. };
  214. template<typename T1, typename T2, typename T3, typename T4, typename T5>
  215. class ArrayElement<T1, T2, T3, T4, T5, void, void, void>
  216. {
  217. public:
  218. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5;
  219. };
  220. template<typename T1, typename T2, typename T3, typename T4>
  221. class ArrayElement<T1, T2, T3, T4, void, void, void, void>
  222. {
  223. public:
  224. T1 m1; T2 m2; T3 m3; T4 m4;
  225. };
  226. template<typename T1, typename T2, typename T3>
  227. class ArrayElement<T1, T2, T3, void, void, void, void, void>
  228. {
  229. public:
  230. T1 m1; T2 m2; T3 m3;
  231. };
  232. template<typename T1, typename T2>
  233. class ArrayElement<T1, T2, void, void, void, void, void, void>
  234. {
  235. public:
  236. T1 m1; T2 m2;
  237. };
  238. /*
  239. * Array specialisations implementing specific setters
  240. */
  241. template<typename T1, typename T2 = void, typename T3 = void,
  242. typename T4 = void, typename T5 = void, typename T6 = void,
  243. typename T7 = void, typename T8 = void>
  244. class Array : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, T8>,
  245. Array<T1, T2, T3, T4, T5, T6, T7, T8> >
  246. {
  247. public:
  248. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  249. T5 const &m5, T6 const &m6, T7 const &m7, T8 const &m8)
  250. {
  251. if (this->m_count >= this->m_reserved)
  252. {
  253. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  254. T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7; T8 tmp8 = m8;
  255. this->Reserve(this->m_count * 13 / 8 + 8);
  256. this->m_data[this->m_count].m1 = tmp1;
  257. this->m_data[this->m_count].m2 = tmp2;
  258. this->m_data[this->m_count].m3 = tmp3;
  259. this->m_data[this->m_count].m4 = tmp4;
  260. this->m_data[this->m_count].m5 = tmp5;
  261. this->m_data[this->m_count].m6 = tmp6;
  262. this->m_data[this->m_count].m7 = tmp7;
  263. this->m_data[this->m_count].m8 = tmp8;
  264. }
  265. else
  266. {
  267. this->m_data[this->m_count].m1 = m1;
  268. this->m_data[this->m_count].m2 = m2;
  269. this->m_data[this->m_count].m3 = m3;
  270. this->m_data[this->m_count].m4 = m4;
  271. this->m_data[this->m_count].m5 = m5;
  272. this->m_data[this->m_count].m6 = m6;
  273. this->m_data[this->m_count].m7 = m7;
  274. this->m_data[this->m_count].m8 = m8;
  275. }
  276. ++this->m_count;
  277. }
  278. };
  279. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  280. typename T6, typename T7>
  281. class Array<T1, T2, T3, T4, T5, T6, T7, void>
  282. : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>,
  283. Array<T1, T2, T3, T4, T5, T6, T7> >
  284. {
  285. public:
  286. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  287. T5 const &m5, T6 const &m6, T7 const &m7)
  288. {
  289. if (this->m_count >= this->m_reserved)
  290. {
  291. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  292. T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7;
  293. this->Reserve(this->m_count * 13 / 8 + 8);
  294. this->m_data[this->m_count].m1 = tmp1;
  295. this->m_data[this->m_count].m2 = tmp2;
  296. this->m_data[this->m_count].m3 = tmp3;
  297. this->m_data[this->m_count].m4 = tmp4;
  298. this->m_data[this->m_count].m5 = tmp5;
  299. this->m_data[this->m_count].m6 = tmp6;
  300. this->m_data[this->m_count].m7 = tmp7;
  301. }
  302. else
  303. {
  304. this->m_data[this->m_count].m1 = m1;
  305. this->m_data[this->m_count].m2 = m2;
  306. this->m_data[this->m_count].m3 = m3;
  307. this->m_data[this->m_count].m4 = m4;
  308. this->m_data[this->m_count].m5 = m5;
  309. this->m_data[this->m_count].m6 = m6;
  310. this->m_data[this->m_count].m7 = m7;
  311. }
  312. ++this->m_count;
  313. }
  314. };
  315. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  316. typename T6>
  317. class Array<T1, T2, T3, T4, T5, T6, void, void>
  318. : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, void, void>,
  319. Array<T1, T2, T3, T4, T5, T6> >
  320. {
  321. public:
  322. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  323. T5 const &m5, T6 const &m6)
  324. {
  325. if (this->m_count >= this->m_reserved)
  326. {
  327. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  328. T5 tmp5 = m5; T6 tmp6 = m6;
  329. this->Reserve(this->m_count * 13 / 8 + 8);
  330. this->m_data[this->m_count].m1 = tmp1;
  331. this->m_data[this->m_count].m2 = tmp2;
  332. this->m_data[this->m_count].m3 = tmp3;
  333. this->m_data[this->m_count].m4 = tmp4;
  334. this->m_data[this->m_count].m5 = tmp5;
  335. this->m_data[this->m_count].m6 = tmp6;
  336. }
  337. else
  338. {
  339. this->m_data[this->m_count].m1 = m1;
  340. this->m_data[this->m_count].m2 = m2;
  341. this->m_data[this->m_count].m3 = m3;
  342. this->m_data[this->m_count].m4 = m4;
  343. this->m_data[this->m_count].m5 = m5;
  344. this->m_data[this->m_count].m6 = m6;
  345. }
  346. ++this->m_count;
  347. }
  348. };
  349. template<typename T1, typename T2, typename T3, typename T4, typename T5>
  350. class Array<T1, T2, T3, T4, T5, void, void, void>
  351. : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, void, void, void>,
  352. Array<T1, T2, T3, T4, T5> >
  353. {
  354. public:
  355. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  356. T5 const &m5)
  357. {
  358. if (this->m_count >= this->m_reserved)
  359. {
  360. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  361. T5 tmp5 = m5;
  362. this->Reserve(this->m_count * 13 / 8 + 8);
  363. this->m_data[this->m_count].m1 = tmp1;
  364. this->m_data[this->m_count].m2 = tmp2;
  365. this->m_data[this->m_count].m3 = tmp3;
  366. this->m_data[this->m_count].m4 = tmp4;
  367. this->m_data[this->m_count].m5 = tmp5;
  368. }
  369. else
  370. {
  371. this->m_data[this->m_count].m1 = m1;
  372. this->m_data[this->m_count].m2 = m2;
  373. this->m_data[this->m_count].m3 = m3;
  374. this->m_data[this->m_count].m4 = m4;
  375. this->m_data[this->m_count].m5 = m5;
  376. }
  377. ++this->m_count;
  378. }
  379. };
  380. template<typename T1, typename T2, typename T3, typename T4>
  381. class Array<T1, T2, T3, T4, void, void, void, void>
  382. : public ArrayBase<ArrayElement<T1, T2, T3, T4, void, void, void, void>,
  383. Array<T1, T2, T3, T4> >
  384. {
  385. public:
  386. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4)
  387. {
  388. if (this->m_count >= this->m_reserved)
  389. {
  390. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  391. this->Reserve(this->m_count * 13 / 8 + 8);
  392. this->m_data[this->m_count].m1 = tmp1;
  393. this->m_data[this->m_count].m2 = tmp2;
  394. this->m_data[this->m_count].m3 = tmp3;
  395. this->m_data[this->m_count].m4 = tmp4;
  396. }
  397. else
  398. {
  399. this->m_data[this->m_count].m1 = m1;
  400. this->m_data[this->m_count].m2 = m2;
  401. this->m_data[this->m_count].m3 = m3;
  402. this->m_data[this->m_count].m4 = m4;
  403. }
  404. ++this->m_count;
  405. }
  406. };
  407. template<typename T1, typename T2, typename T3>
  408. class Array<T1, T2, T3, void, void, void, void, void>
  409. : public ArrayBase<ArrayElement<T1, T2, T3, void, void, void, void, void>,
  410. Array<T1, T2, T3> >
  411. {
  412. public:
  413. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3)
  414. {
  415. if (this->m_count >= this->m_reserved)
  416. {
  417. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3;
  418. this->Reserve(this->m_count * 13 / 8 + 8);
  419. this->m_data[this->m_count].m1 = tmp1;
  420. this->m_data[this->m_count].m2 = tmp2;
  421. this->m_data[this->m_count].m3 = tmp3;
  422. }
  423. else
  424. {
  425. this->m_data[this->m_count].m1 = m1;
  426. this->m_data[this->m_count].m2 = m2;
  427. this->m_data[this->m_count].m3 = m3;
  428. }
  429. ++this->m_count;
  430. }
  431. };
  432. template<typename T1, typename T2>
  433. class Array<T1, T2, void, void, void, void, void, void>
  434. : public ArrayBase<ArrayElement<T1, T2, void, void, void, void, void, void>,
  435. Array<T1, T2> >
  436. {
  437. public:
  438. inline void Push(T1 const &m1, T2 const &m2)
  439. {
  440. if (this->m_count >= this->m_reserved)
  441. {
  442. T1 tmp1 = m1; T2 tmp2 = m2;
  443. this->Reserve(this->m_count * 13 / 8 + 8);
  444. this->m_data[this->m_count].m1 = tmp1;
  445. this->m_data[this->m_count].m2 = tmp2;
  446. }
  447. else
  448. {
  449. this->m_data[this->m_count].m1 = m1;
  450. this->m_data[this->m_count].m2 = m2;
  451. }
  452. ++this->m_count;
  453. }
  454. };
  455. template<typename T>
  456. class Array<T, void, void, void, void, void, void, void>
  457. : public ArrayBase<T,
  458. Array<T> >
  459. {
  460. };
  461. } /* namespace lol */
  462. #endif // __LOL_CORE_ARRAY_H__