BlockArray.cpp 4.2 KB

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