DynamicArray.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <Tests/Framework/Framework.h>
  6. #include <AnKi/Util/DynamicArray.h>
  7. #include <vector>
  8. #include <ctime>
  9. namespace anki {
  10. static I64 g_constructor0Count = 0;
  11. static I64 g_constructor1Count = 0;
  12. static I64 g_constructor2Count = 0;
  13. static I64 g_constructor3Count = 0;
  14. static I64 g_destructorCount = 0;
  15. static I64 g_copyCount = 0;
  16. static I64 g_moveCount = 0;
  17. class DynamicArrayFoo
  18. {
  19. public:
  20. static constexpr I32 WRONG_NUMBER = -1234;
  21. int m_x;
  22. DynamicArrayFoo()
  23. : m_x(0)
  24. {
  25. ++g_constructor0Count;
  26. }
  27. DynamicArrayFoo(int x)
  28. : m_x(x)
  29. {
  30. ++g_constructor1Count;
  31. if(m_x == WRONG_NUMBER)
  32. {
  33. ++m_x;
  34. }
  35. }
  36. DynamicArrayFoo(const DynamicArrayFoo& b)
  37. : m_x(b.m_x)
  38. {
  39. ANKI_TEST_EXPECT_NEQ(b.m_x, WRONG_NUMBER);
  40. ++g_constructor2Count;
  41. }
  42. DynamicArrayFoo(DynamicArrayFoo&& b)
  43. : m_x(b.m_x)
  44. {
  45. ANKI_TEST_EXPECT_NEQ(b.m_x, WRONG_NUMBER);
  46. b.m_x = 0;
  47. ++g_constructor3Count;
  48. }
  49. ~DynamicArrayFoo()
  50. {
  51. ANKI_TEST_EXPECT_NEQ(m_x, WRONG_NUMBER);
  52. m_x = WRONG_NUMBER;
  53. ++g_destructorCount;
  54. }
  55. DynamicArrayFoo& operator=(const DynamicArrayFoo& b)
  56. {
  57. ANKI_TEST_EXPECT_NEQ(m_x, WRONG_NUMBER);
  58. ANKI_TEST_EXPECT_NEQ(b.m_x, WRONG_NUMBER);
  59. m_x = b.m_x;
  60. ++g_copyCount;
  61. return *this;
  62. }
  63. DynamicArrayFoo& operator=(DynamicArrayFoo&& b)
  64. {
  65. ANKI_TEST_EXPECT_NEQ(m_x, WRONG_NUMBER);
  66. ANKI_TEST_EXPECT_NEQ(b.m_x, WRONG_NUMBER);
  67. m_x = b.m_x;
  68. b.m_x = 0;
  69. ++g_moveCount;
  70. return *this;
  71. }
  72. };
  73. } // end namespace anki
  74. ANKI_TEST(Util, DynamicArray)
  75. {
  76. {
  77. HeapAllocator<U8> alloc(allocAligned, nullptr);
  78. DynamicArrayAuto<DynamicArrayFoo> arr(alloc);
  79. arr.resize(0);
  80. arr.resize(2, 1);
  81. arr.resize(3, 2);
  82. arr.resize(4, 3);
  83. ANKI_TEST_EXPECT_EQ(arr.getSize(), 4);
  84. ANKI_TEST_EXPECT_EQ(arr[0].m_x, 1);
  85. ANKI_TEST_EXPECT_EQ(arr[1].m_x, 1);
  86. ANKI_TEST_EXPECT_EQ(arr[2].m_x, 2);
  87. ANKI_TEST_EXPECT_EQ(arr[3].m_x, 3);
  88. arr.emplaceBack(4);
  89. ANKI_TEST_EXPECT_EQ(arr.getSize(), 5);
  90. ANKI_TEST_EXPECT_EQ(arr[4].m_x, 4);
  91. arr.resize(1);
  92. arr.resize(0);
  93. }
  94. // Fuzzy
  95. {
  96. srand(U32(time(nullptr)));
  97. HeapAllocator<U8> alloc(allocAligned, nullptr);
  98. DynamicArrayAuto<DynamicArrayFoo> arr(alloc);
  99. std::vector<DynamicArrayFoo> vec;
  100. const U ITERATIONS = 1000000;
  101. for(U i = 0; i < ITERATIONS; ++i)
  102. {
  103. const Bool grow = arr.getSize() > 0 && (rand() & 1);
  104. U32 newSize;
  105. U32 value = rand();
  106. if(grow)
  107. {
  108. newSize = U32(vec.size()) * getRandomRange(1, 4);
  109. }
  110. else
  111. {
  112. newSize = U32(F32(vec.size()) * getRandomRange(0.0, 0.9));
  113. }
  114. vec.resize(newSize, value);
  115. arr.resize(newSize, value);
  116. // Validate
  117. ANKI_TEST_EXPECT_EQ(arr.getSize(), vec.size());
  118. for(U32 j = 0; j < arr.getSize(); ++j)
  119. {
  120. ANKI_TEST_EXPECT_EQ(arr[j].m_x, vec[j].m_x);
  121. }
  122. arr.validate();
  123. }
  124. arr = DynamicArrayAuto<DynamicArrayFoo>(alloc);
  125. vec = std::vector<DynamicArrayFoo>();
  126. ANKI_TEST_EXPECT_GT(g_destructorCount, 0);
  127. ANKI_TEST_EXPECT_EQ(g_constructor0Count + g_constructor1Count + g_constructor2Count + g_constructor3Count,
  128. g_destructorCount);
  129. }
  130. }
  131. ANKI_TEST(Util, DynamicArrayEmplaceAt)
  132. {
  133. HeapAllocator<U8> alloc(allocAligned, nullptr);
  134. // Empty & add to the end
  135. {
  136. DynamicArrayAuto<DynamicArrayFoo> arr(alloc);
  137. arr.emplaceAt(arr.getEnd(), 12);
  138. ANKI_TEST_EXPECT_EQ(arr[0].m_x, 12);
  139. }
  140. // 1 element & add to he end
  141. {
  142. DynamicArrayAuto<DynamicArrayFoo> arr(alloc);
  143. arr.emplaceBack(12);
  144. arr.emplaceAt(arr.getEnd(), 34);
  145. ANKI_TEST_EXPECT_EQ(arr[0].m_x, 12);
  146. ANKI_TEST_EXPECT_EQ(arr[1].m_x, 34);
  147. }
  148. // 1 element & add to 0
  149. {
  150. DynamicArrayAuto<DynamicArrayFoo> arr(alloc);
  151. arr.emplaceBack(12);
  152. arr.emplaceAt(arr.getBegin(), 34);
  153. ANKI_TEST_EXPECT_EQ(arr[0].m_x, 34);
  154. ANKI_TEST_EXPECT_EQ(arr[1].m_x, 12);
  155. }
  156. // A bit more complex
  157. {
  158. DynamicArrayAuto<DynamicArrayFoo> arr(alloc);
  159. for(I32 i = 0; i < 10; ++i)
  160. {
  161. arr.emplaceBack(i);
  162. }
  163. arr.emplaceAt(arr.getBegin() + 4, 666);
  164. for(I32 i = 0; i < 10 + 1; ++i)
  165. {
  166. if(i < 4)
  167. {
  168. ANKI_TEST_EXPECT_EQ(arr[i].m_x, i);
  169. }
  170. else if(i == 4)
  171. {
  172. ANKI_TEST_EXPECT_EQ(arr[i].m_x, 666);
  173. }
  174. else
  175. {
  176. ANKI_TEST_EXPECT_EQ(arr[i].m_x, i - 1);
  177. }
  178. }
  179. }
  180. // Fuzzy
  181. {
  182. srand(U32(time(nullptr)));
  183. DynamicArrayAuto<DynamicArrayFoo> arr(alloc);
  184. std::vector<DynamicArrayFoo> vec;
  185. const I ITERATIONS = 10000;
  186. for(I i = 0; i < ITERATIONS; ++i)
  187. {
  188. I32 randNum = rand();
  189. I32 op = rand() % 3;
  190. switch(op)
  191. {
  192. case 0:
  193. // Push back
  194. arr.emplaceBack(randNum);
  195. vec.emplace_back(randNum);
  196. break;
  197. case 1:
  198. // Insert somewhere
  199. if(!arr.isEmpty())
  200. {
  201. I pos = rand() % arr.getSize();
  202. arr.emplaceAt(arr.getBegin() + pos, randNum);
  203. vec.emplace(vec.begin() + pos, randNum);
  204. }
  205. break;
  206. default:
  207. // Insert at the end
  208. arr.emplaceAt(arr.getEnd(), randNum);
  209. vec.emplace(vec.end(), randNum);
  210. break;
  211. }
  212. }
  213. // Check
  214. ANKI_TEST_EXPECT_EQ(arr.getSize(), vec.size());
  215. for(U32 i = 0; i < arr.getSize(); ++i)
  216. {
  217. ANKI_TEST_EXPECT_EQ(arr[i].m_x, vec[i].m_x);
  218. }
  219. arr.destroy();
  220. vec.resize(0);
  221. ANKI_TEST_EXPECT_EQ(g_constructor0Count + g_constructor1Count + g_constructor2Count + g_constructor3Count,
  222. g_destructorCount);
  223. }
  224. }
  225. ANKI_TEST(Util, DynamicArrayErase)
  226. {
  227. HeapAllocator<U8> alloc(allocAligned, nullptr);
  228. // Fuzzy
  229. {
  230. srand(U32(time(nullptr)));
  231. DynamicArrayAuto<DynamicArrayFoo> arr(alloc);
  232. std::vector<DynamicArrayFoo> vec;
  233. const I ITERATIONS = 10000;
  234. for(I i = 0; i < ITERATIONS; ++i)
  235. {
  236. if(getRandom() % 2)
  237. {
  238. const I32 r = rand();
  239. arr.emplaceBack(r);
  240. vec.push_back(r);
  241. }
  242. else if(arr.getSize() > 0)
  243. {
  244. PtrSize eraseFrom = getRandom() % arr.getSize();
  245. PtrSize eraseTo = getRandom() % (arr.getSize() + 1);
  246. if(eraseTo < eraseFrom)
  247. {
  248. swapValues(eraseTo, eraseFrom);
  249. }
  250. if(eraseTo != eraseFrom)
  251. {
  252. vec.erase(vec.begin() + eraseFrom, vec.begin() + eraseTo);
  253. arr.erase(arr.getBegin() + eraseFrom, arr.getBegin() + eraseTo);
  254. }
  255. }
  256. }
  257. // Check
  258. ANKI_TEST_EXPECT_EQ(arr.getSize(), vec.size());
  259. for(U32 i = 0; i < arr.getSize(); ++i)
  260. {
  261. ANKI_TEST_EXPECT_EQ(arr[i].m_x, vec[i].m_x);
  262. }
  263. arr.destroy();
  264. vec.resize(0);
  265. ANKI_TEST_EXPECT_EQ(g_constructor0Count + g_constructor1Count + g_constructor2Count + g_constructor3Count,
  266. g_destructorCount);
  267. }
  268. }