HashMap.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Copyright (C) 2009-present, 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/Util/Foo.h>
  7. #include <AnKi/Util/HashMap.h>
  8. #include <AnKi/Util/DynamicArray.h>
  9. #include <AnKi/Util/HighRezTimer.h>
  10. #include <unordered_map>
  11. #include <algorithm>
  12. using namespace anki;
  13. class Hasher
  14. {
  15. public:
  16. U64 operator()(int x)
  17. {
  18. return x;
  19. }
  20. };
  21. ANKI_TEST(Util, HashMap)
  22. {
  23. int vals[] = {20, 15, 5, 1, 10, 0, 18, 6, 7, 11, 13, 3};
  24. U valsSize = sizeof(vals) / sizeof(vals[0]);
  25. // Simple
  26. {
  27. HashMap<int, int, Hasher> map;
  28. map.emplace(20, 1);
  29. map.emplace(21, 1);
  30. map.destroy();
  31. }
  32. // Add more and iterate
  33. {
  34. HashMap<int, int, Hasher> map;
  35. for(U i = 0; i < valsSize; ++i)
  36. {
  37. map.emplace(vals[i], vals[i] * 10);
  38. }
  39. U count = 0;
  40. auto it = map.getBegin();
  41. for(; it != map.getEnd(); ++it)
  42. {
  43. ++count;
  44. }
  45. ANKI_TEST_EXPECT_EQ(count, valsSize);
  46. map.destroy();
  47. }
  48. // Erase
  49. {
  50. HashMap<int, int, Hasher> map;
  51. for(U i = 0; i < valsSize; ++i)
  52. {
  53. map.emplace(vals[i], vals[i] * 10);
  54. }
  55. for(U i = valsSize - 1; i != 0; --i)
  56. {
  57. HashMap<int, int, Hasher>::Iterator it = map.find(vals[i]);
  58. ANKI_TEST_EXPECT_NEQ(it, map.getEnd());
  59. map.erase(it);
  60. map.emplace(vals[i], vals[i] * 10);
  61. }
  62. map.destroy();
  63. }
  64. // Find
  65. {
  66. HashMap<int, int, Hasher> map;
  67. for(U i = 0; i < valsSize; ++i)
  68. {
  69. map.emplace(vals[i], vals[i] * 10);
  70. }
  71. for(U i = valsSize - 1; i != 0; --i)
  72. {
  73. HashMap<int, int, Hasher>::Iterator it = map.find(vals[i]);
  74. ANKI_TEST_EXPECT_NEQ(it, map.getEnd());
  75. ANKI_TEST_EXPECT_EQ(*it, vals[i] * 10);
  76. }
  77. map.destroy();
  78. }
  79. // Fuzzy test
  80. {
  81. const U MAX = 1000;
  82. HashMap<int, int, Hasher> akMap;
  83. std::vector<int> numbers;
  84. // Insert random
  85. for(U i = 0; i < MAX; ++i)
  86. {
  87. I32 num;
  88. while(1)
  89. {
  90. num = rand();
  91. if(std::find(numbers.begin(), numbers.end(), num) == numbers.end())
  92. {
  93. // Not found
  94. ANKI_TEST_EXPECT_EQ(akMap.find(num), akMap.getEnd());
  95. akMap.emplace(num, num);
  96. numbers.push_back(num);
  97. break;
  98. }
  99. else
  100. {
  101. // Found
  102. ANKI_TEST_EXPECT_NEQ(akMap.find(num), akMap.getEnd());
  103. }
  104. }
  105. }
  106. // Remove randomly
  107. U count = MAX;
  108. while(count--)
  109. {
  110. U idx = rand() % (count + 1);
  111. int num = numbers[idx];
  112. numbers.erase(numbers.begin() + idx);
  113. auto it = akMap.find(num);
  114. akMap.erase(it);
  115. }
  116. akMap.destroy();
  117. }
  118. // Bench it
  119. {
  120. class Config
  121. {
  122. public:
  123. using Index = U64;
  124. static Index getInitialStorageSize()
  125. {
  126. return 128;
  127. }
  128. static U32 getLinearProbingCount()
  129. {
  130. return 32;
  131. }
  132. static F32 getMaxLoadFactor()
  133. {
  134. return 0.9f;
  135. }
  136. };
  137. using AkMap = HashMap<int, int, Hasher, SingletonMemoryPoolWrapper<DefaultMemoryPool>, Config>;
  138. AkMap akMap;
  139. using StlMap = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>>;
  140. StlMap stdMap(10, std::hash<int>(), std::equal_to<int>());
  141. std::unordered_map<int, int> tmpMap;
  142. HighRezTimer timer;
  143. // Create a huge set
  144. const U32 kCount = 1024 * 1024 * 10;
  145. DynamicArray<int> vals;
  146. vals.resize(kCount);
  147. for(U32 i = 0; i < kCount; ++i)
  148. {
  149. // Put unique keys
  150. int v;
  151. do
  152. {
  153. v = rand();
  154. } while(tmpMap.find(v) != tmpMap.end());
  155. tmpMap[v] = 1;
  156. vals[i] = v;
  157. }
  158. // Insertion
  159. {
  160. // Put the vals AnKi
  161. timer.start();
  162. for(U32 i = 0; i < kCount; ++i)
  163. {
  164. akMap.emplace(vals[i], vals[i]);
  165. }
  166. timer.stop();
  167. Second akTime = timer.getElapsedTime();
  168. // Put the vals STL
  169. timer.start();
  170. for(U32 i = 0; i < kCount; ++i)
  171. {
  172. stdMap[vals[i]] = vals[i];
  173. }
  174. timer.stop();
  175. Second stlTime = timer.getElapsedTime();
  176. ANKI_TEST_LOGI("Inserting bench: STL %f AnKi %f | %f%%", stlTime, akTime, stlTime / akTime * 100.0);
  177. }
  178. // Search
  179. {
  180. I64 count = 0; // To avoid compiler opts
  181. // Find values AnKi
  182. timer.start();
  183. for(U32 i = 0; i < kCount; ++i)
  184. {
  185. auto it = akMap.find(vals[i]);
  186. count += *it;
  187. }
  188. timer.stop();
  189. Second akTime = timer.getElapsedTime();
  190. // Find values STL
  191. timer.start();
  192. for(U32 i = 0; i < kCount; ++i)
  193. {
  194. count += stdMap[vals[i]];
  195. }
  196. timer.stop();
  197. Second stlTime = timer.getElapsedTime();
  198. ANKI_TEST_LOGI("Find bench: STL %f AnKi %f | %f%% (%ld)", stlTime, akTime, stlTime / akTime * 100.0, count);
  199. }
  200. // Delete
  201. {
  202. // Remove in random order
  203. randomShuffle(vals.begin(), vals.end());
  204. // Random delete AnKi
  205. Second akTime = 0.0;
  206. for(U32 i = 0; i < vals.getSize(); ++i)
  207. {
  208. auto it = akMap.find(vals[i]);
  209. timer.start();
  210. akMap.erase(it);
  211. timer.stop();
  212. akTime += timer.getElapsedTime();
  213. }
  214. // Random delete STL
  215. Second stlTime = 0.0;
  216. for(U32 i = 0; i < vals.getSize(); ++i)
  217. {
  218. auto it = stdMap.find(vals[i]);
  219. timer.start();
  220. stdMap.erase(it);
  221. timer.stop();
  222. stlTime += timer.getElapsedTime();
  223. }
  224. ANKI_TEST_LOGI("Deleting bench: STL %f AnKi %f | %f%%", stlTime, akTime, stlTime / akTime * 100.0);
  225. }
  226. akMap.destroy();
  227. }
  228. }