491 wiersze
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_ARRAY_H__
  17. #define __LOL_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. for (int i = pos; i + todelete < m_count; i++)
  141. m_data[i] = m_data[i + todelete];
  142. for (int i = m_count - todelete; i < m_count; i++)
  143. m_data[i].~Element();
  144. m_count -= todelete;
  145. }
  146. inline void Empty()
  147. {
  148. Remove(0, m_count);
  149. }
  150. void Reserve(int toreserve)
  151. {
  152. if (toreserve <= (int)m_reserved)
  153. return;
  154. Element *tmp = reinterpret_cast<Element *>
  155. (new uint8_t [sizeof(Element) * toreserve]);
  156. for (int i = 0; i < m_count; i++)
  157. {
  158. new(&tmp[i]) Element(m_data[i]);
  159. m_data[i].~Element();
  160. }
  161. if (m_data)
  162. delete[] reinterpret_cast<uint8_t *>(m_data);
  163. m_data = tmp;
  164. m_reserved = toreserve;
  165. }
  166. inline int Count() const { return m_count; }
  167. inline int Bytes() const { return m_count * sizeof(Element); }
  168. protected:
  169. Element *m_data;
  170. int m_count, m_reserved;
  171. };
  172. /*
  173. * Element types
  174. */
  175. template<typename T1, typename T2, typename T3 = void, typename T4 = void,
  176. typename T5 = void, typename T6 = void, typename T7 = void,
  177. typename T8 = void>
  178. class ArrayElement
  179. {
  180. public:
  181. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7; T8 m8;
  182. };
  183. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  184. typename T6, typename T7>
  185. class ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>
  186. {
  187. public:
  188. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7;
  189. };
  190. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  191. typename T6>
  192. class ArrayElement<T1, T2, T3, T4, T5, T6, void, void>
  193. {
  194. public:
  195. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6;
  196. };
  197. template<typename T1, typename T2, typename T3, typename T4, typename T5>
  198. class ArrayElement<T1, T2, T3, T4, T5, void, void, void>
  199. {
  200. public:
  201. T1 m1; T2 m2; T3 m3; T4 m4; T5 m5;
  202. };
  203. template<typename T1, typename T2, typename T3, typename T4>
  204. class ArrayElement<T1, T2, T3, T4, void, void, void, void>
  205. {
  206. public:
  207. T1 m1; T2 m2; T3 m3; T4 m4;
  208. };
  209. template<typename T1, typename T2, typename T3>
  210. class ArrayElement<T1, T2, T3, void, void, void, void, void>
  211. {
  212. public:
  213. T1 m1; T2 m2; T3 m3;
  214. };
  215. template<typename T1, typename T2>
  216. class ArrayElement<T1, T2, void, void, void, void, void, void>
  217. {
  218. public:
  219. T1 m1; T2 m2;
  220. };
  221. /*
  222. * Array specialisations implementing specific setters
  223. */
  224. template<typename T1, typename T2 = void, typename T3 = void,
  225. typename T4 = void, typename T5 = void, typename T6 = void,
  226. typename T7 = void, typename T8 = void>
  227. class Array : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, T8>,
  228. Array<T1, T2, T3, T4, T5, T6, T7, T8> >
  229. {
  230. public:
  231. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  232. T5 const &m5, T6 const &m6, T7 const &m7, T8 const &m8)
  233. {
  234. if (this->m_count >= this->m_reserved)
  235. {
  236. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  237. T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7; T8 tmp8 = m8;
  238. Reserve(this->m_count * 13 / 8 + 8);
  239. this->m_data[this->m_count].m1 = tmp1;
  240. this->m_data[this->m_count].m2 = tmp2;
  241. this->m_data[this->m_count].m3 = tmp3;
  242. this->m_data[this->m_count].m4 = tmp4;
  243. this->m_data[this->m_count].m5 = tmp5;
  244. this->m_data[this->m_count].m6 = tmp6;
  245. this->m_data[this->m_count].m7 = tmp7;
  246. this->m_data[this->m_count].m8 = tmp8;
  247. }
  248. else
  249. {
  250. this->m_data[this->m_count].m1 = m1;
  251. this->m_data[this->m_count].m2 = m2;
  252. this->m_data[this->m_count].m3 = m3;
  253. this->m_data[this->m_count].m4 = m4;
  254. this->m_data[this->m_count].m5 = m5;
  255. this->m_data[this->m_count].m6 = m6;
  256. this->m_data[this->m_count].m7 = m7;
  257. this->m_data[this->m_count].m8 = m8;
  258. }
  259. ++this->m_count;
  260. }
  261. };
  262. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  263. typename T6, typename T7>
  264. class Array<T1, T2, T3, T4, T5, T6, T7, void>
  265. : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>,
  266. Array<T1, T2, T3, T4, T5, T6, T7> >
  267. {
  268. public:
  269. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  270. T5 const &m5, T6 const &m6, T7 const &m7)
  271. {
  272. if (this->m_count >= this->m_reserved)
  273. {
  274. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  275. T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7;
  276. Reserve(this->m_count * 13 / 8 + 8);
  277. this->m_data[this->m_count].m1 = tmp1;
  278. this->m_data[this->m_count].m2 = tmp2;
  279. this->m_data[this->m_count].m3 = tmp3;
  280. this->m_data[this->m_count].m4 = tmp4;
  281. this->m_data[this->m_count].m5 = tmp5;
  282. this->m_data[this->m_count].m6 = tmp6;
  283. this->m_data[this->m_count].m7 = tmp7;
  284. }
  285. else
  286. {
  287. this->m_data[this->m_count].m1 = m1;
  288. this->m_data[this->m_count].m2 = m2;
  289. this->m_data[this->m_count].m3 = m3;
  290. this->m_data[this->m_count].m4 = m4;
  291. this->m_data[this->m_count].m5 = m5;
  292. this->m_data[this->m_count].m6 = m6;
  293. this->m_data[this->m_count].m7 = m7;
  294. }
  295. ++this->m_count;
  296. }
  297. };
  298. template<typename T1, typename T2, typename T3, typename T4, typename T5,
  299. typename T6>
  300. class Array<T1, T2, T3, T4, T5, T6, void, void>
  301. : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, void, void>,
  302. Array<T1, T2, T3, T4, T5, T6> >
  303. {
  304. public:
  305. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  306. T5 const &m5, T6 const &m6)
  307. {
  308. if (this->m_count >= this->m_reserved)
  309. {
  310. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  311. T5 tmp5 = m5; T6 tmp6 = m6;
  312. Reserve(this->m_count * 13 / 8 + 8);
  313. this->m_data[this->m_count].m1 = tmp1;
  314. this->m_data[this->m_count].m2 = tmp2;
  315. this->m_data[this->m_count].m3 = tmp3;
  316. this->m_data[this->m_count].m4 = tmp4;
  317. this->m_data[this->m_count].m5 = tmp5;
  318. this->m_data[this->m_count].m6 = tmp6;
  319. }
  320. else
  321. {
  322. this->m_data[this->m_count].m1 = m1;
  323. this->m_data[this->m_count].m2 = m2;
  324. this->m_data[this->m_count].m3 = m3;
  325. this->m_data[this->m_count].m4 = m4;
  326. this->m_data[this->m_count].m5 = m5;
  327. this->m_data[this->m_count].m6 = m6;
  328. }
  329. ++this->m_count;
  330. }
  331. };
  332. template<typename T1, typename T2, typename T3, typename T4, typename T5>
  333. class Array<T1, T2, T3, T4, T5, void, void, void>
  334. : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, void, void, void>,
  335. Array<T1, T2, T3, T4, T5> >
  336. {
  337. public:
  338. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
  339. T5 const &m5)
  340. {
  341. if (this->m_count >= this->m_reserved)
  342. {
  343. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  344. T5 tmp5 = m5;
  345. Reserve(this->m_count * 13 / 8 + 8);
  346. this->m_data[this->m_count].m1 = tmp1;
  347. this->m_data[this->m_count].m2 = tmp2;
  348. this->m_data[this->m_count].m3 = tmp3;
  349. this->m_data[this->m_count].m4 = tmp4;
  350. this->m_data[this->m_count].m5 = tmp5;
  351. }
  352. else
  353. {
  354. this->m_data[this->m_count].m1 = m1;
  355. this->m_data[this->m_count].m2 = m2;
  356. this->m_data[this->m_count].m3 = m3;
  357. this->m_data[this->m_count].m4 = m4;
  358. this->m_data[this->m_count].m5 = m5;
  359. }
  360. ++this->m_count;
  361. }
  362. };
  363. template<typename T1, typename T2, typename T3, typename T4>
  364. class Array<T1, T2, T3, T4, void, void, void, void>
  365. : public ArrayBase<ArrayElement<T1, T2, T3, T4, void, void, void, void>,
  366. Array<T1, T2, T3, T4> >
  367. {
  368. public:
  369. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4)
  370. {
  371. if (this->m_count >= this->m_reserved)
  372. {
  373. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
  374. Reserve(this->m_count * 13 / 8 + 8);
  375. this->m_data[this->m_count].m1 = tmp1;
  376. this->m_data[this->m_count].m2 = tmp2;
  377. this->m_data[this->m_count].m3 = tmp3;
  378. this->m_data[this->m_count].m4 = tmp4;
  379. }
  380. else
  381. {
  382. this->m_data[this->m_count].m1 = m1;
  383. this->m_data[this->m_count].m2 = m2;
  384. this->m_data[this->m_count].m3 = m3;
  385. this->m_data[this->m_count].m4 = m4;
  386. }
  387. ++this->m_count;
  388. }
  389. };
  390. template<typename T1, typename T2, typename T3>
  391. class Array<T1, T2, T3, void, void, void, void, void>
  392. : public ArrayBase<ArrayElement<T1, T2, T3, void, void, void, void, void>,
  393. Array<T1, T2, T3> >
  394. {
  395. public:
  396. inline void Push(T1 const &m1, T2 const &m2, T3 const &m3)
  397. {
  398. if (this->m_count >= this->m_reserved)
  399. {
  400. T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3;
  401. Reserve(this->m_count * 13 / 8 + 8);
  402. this->m_data[this->m_count].m1 = tmp1;
  403. this->m_data[this->m_count].m2 = tmp2;
  404. this->m_data[this->m_count].m3 = tmp3;
  405. }
  406. else
  407. {
  408. this->m_data[this->m_count].m1 = m1;
  409. this->m_data[this->m_count].m2 = m2;
  410. this->m_data[this->m_count].m3 = m3;
  411. }
  412. ++this->m_count;
  413. }
  414. };
  415. template<typename T1, typename T2>
  416. class Array<T1, T2, void, void, void, void, void, void>
  417. : public ArrayBase<ArrayElement<T1, T2, void, void, void, void, void, void>,
  418. Array<T1, T2> >
  419. {
  420. public:
  421. inline void Push(T1 const &m1, T2 const &m2)
  422. {
  423. if (this->m_count >= this->m_reserved)
  424. {
  425. T1 tmp1 = m1; T2 tmp2 = m2;
  426. Reserve(this->m_count * 13 / 8 + 8);
  427. this->m_data[this->m_count].m1 = tmp1;
  428. this->m_data[this->m_count].m2 = tmp2;
  429. }
  430. else
  431. {
  432. this->m_data[this->m_count].m1 = m1;
  433. this->m_data[this->m_count].m2 = m2;
  434. }
  435. ++this->m_count;
  436. }
  437. };
  438. template<typename T>
  439. class Array<T, void, void, void, void, void, void, void>
  440. : public ArrayBase<T,
  441. Array<T> >
  442. {
  443. };
  444. } /* namespace lol */
  445. #endif // __LOL_ARRAY_H__