BlockArray.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright (C) 2009-2023, 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 <Tests/Framework/TestFoo.h>
  7. #include <AnKi/Util/BlockArray.h>
  8. #include <AnKi/Util/HighRezTimer.h>
  9. #include <vector>
  10. ANKI_TEST(Util, BlockArray)
  11. {
  12. DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
  13. // Simple
  14. TestFoo::reset();
  15. {
  16. BlockArray<TestFoo> arr;
  17. for(TestFoo& f : arr) // Iterate empty
  18. {
  19. f.m_x = 1;
  20. }
  21. auto it = arr.emplace(123);
  22. ANKI_TEST_EXPECT_EQ(it->m_x, 123);
  23. auto it2 = arr.emplace(124);
  24. ANKI_TEST_EXPECT_EQ(it2->m_x, 124);
  25. auto it3 = arr.emplace(666);
  26. ANKI_TEST_EXPECT_EQ(it3->m_x, 666);
  27. arr.erase(it2);
  28. ANKI_TEST_EXPECT_EQ(arr.getSize(), 2);
  29. int sum = 0;
  30. for(auto& it : arr)
  31. {
  32. sum += it.m_x;
  33. }
  34. ANKI_TEST_EXPECT_EQ(sum, 123 + 666);
  35. }
  36. ANKI_TEST_EXPECT_EQ(TestFoo::m_constructorCount, TestFoo::m_destructorCount);
  37. ANKI_TEST_EXPECT_EQ(TestFoo::m_copyCount, 0);
  38. // Copy
  39. TestFoo::reset();
  40. {
  41. constexpr U32 kInsertionCount = 100;
  42. BlockArray<TestFoo> arr;
  43. // Add some
  44. for(U32 i = 0; i < kInsertionCount; ++i)
  45. {
  46. arr.emplace(rand());
  47. }
  48. // Remove some
  49. for(U32 i = 0; i < kInsertionCount / 2; ++i)
  50. {
  51. const U32 idx = U32(rand()) % kInsertionCount;
  52. if(arr.indexExists(idx))
  53. {
  54. arr.erase(arr.indexToIterator(idx));
  55. }
  56. arr.validate();
  57. }
  58. // Copy
  59. BlockArray<TestFoo> arr2 = arr;
  60. arr2.validate();
  61. // Test
  62. I64 sum = 0;
  63. for(auto it : arr)
  64. {
  65. sum += it.m_x;
  66. }
  67. I64 sum2 = 0;
  68. for(auto it : arr2)
  69. {
  70. sum2 += it.m_x;
  71. }
  72. ANKI_TEST_EXPECT_EQ(sum, sum2);
  73. ANKI_TEST_EXPECT_EQ(arr.getSize(), arr2.getSize());
  74. }
  75. ANKI_TEST_EXPECT_EQ(TestFoo::m_constructorCount, TestFoo::m_destructorCount);
  76. ANKI_TEST_EXPECT_EQ(TestFoo::m_copyCount, 0);
  77. // Fuzzy
  78. TestFoo::reset();
  79. {
  80. constexpr U32 kOperations = 10000;
  81. std::vector<std::pair<int, int>> vec;
  82. BlockArray<TestFoo> arr;
  83. for(U32 op = 0; op < kOperations; ++op)
  84. {
  85. const int opType = rand() % 3u;
  86. if(opType == 0 && vec.size())
  87. {
  88. // Remove something
  89. const int randPos = rand() % int(vec.size());
  90. ANKI_TEST_EXPECT_EQ(arr[vec[randPos].first].m_x, vec[randPos].second);
  91. arr.erase(arr.indexToIterator(vec[randPos].first));
  92. vec.erase(vec.begin() + randPos);
  93. }
  94. else if(op == 1)
  95. {
  96. // Add something
  97. const int randVal = rand();
  98. auto idx = arr.emplace(randVal);
  99. vec.push_back({idx.getArrayIndex(), randVal});
  100. }
  101. else if(vec.size())
  102. {
  103. // Change the value
  104. const int randPos = rand() % int(vec.size());
  105. ANKI_TEST_EXPECT_EQ(arr[vec[randPos].first].m_x, vec[randPos].second);
  106. arr[vec[randPos].first].m_x = 1234;
  107. vec[randPos].second = 1234;
  108. }
  109. arr.validate();
  110. }
  111. ANKI_TEST_EXPECT_EQ(vec.size(), arr.getSize());
  112. for(auto it : vec)
  113. {
  114. ANKI_TEST_EXPECT_EQ(arr[it.first].m_x, it.second);
  115. }
  116. }
  117. ANKI_TEST_EXPECT_EQ(TestFoo::m_constructorCount, TestFoo::m_destructorCount);
  118. ANKI_TEST_EXPECT_EQ(TestFoo::m_copyCount, 0);
  119. // Performance
  120. if(ANKI_OPTIMIZE)
  121. {
  122. // Insertion
  123. std::vector<U64> vec;
  124. BlockArray<U64> arr;
  125. constexpr U kInsertionOpCount = 5'000'000;
  126. U64 begin = HighRezTimer::getCurrentTimeUs();
  127. for(U i = 0; i < kInsertionOpCount; ++i)
  128. {
  129. arr.emplace(i);
  130. }
  131. const U64 arrInsertionTime = HighRezTimer::getCurrentTimeUs() - begin;
  132. begin = HighRezTimer::getCurrentTimeUs();
  133. for(U i = 0; i < kInsertionOpCount; ++i)
  134. {
  135. vec.emplace_back(i);
  136. }
  137. const U64 vecInsertionTime = HighRezTimer::getCurrentTimeUs() - begin;
  138. ANKI_TEST_LOGI("Insertion time: BlockArray %luus, std::vector %luus, a/b %lu", arrInsertionTime, vecInsertionTime,
  139. arrInsertionTime / vecInsertionTime);
  140. // Iterate
  141. begin = HighRezTimer::getCurrentTimeUs();
  142. U64 sum = 0;
  143. for(auto& it : arr)
  144. {
  145. sum += it;
  146. }
  147. const U64 arrIterateTime = HighRezTimer::getCurrentTimeUs() - begin;
  148. begin = HighRezTimer::getCurrentTimeUs();
  149. U64 sum2 = 0;
  150. for(auto& it : vec)
  151. {
  152. sum2 += it;
  153. }
  154. const U64 vecIterateTime = HighRezTimer::getCurrentTimeUs() - begin;
  155. ANKI_TEST_EXPECT_EQ(sum, sum2);
  156. ANKI_TEST_LOGI("Iteration time: BlockArray %luus, std::vector %luus, a/b %lu", arrIterateTime, vecIterateTime,
  157. arrIterateTime / vecIterateTime);
  158. }
  159. DefaultMemoryPool::freeSingleton();
  160. }