test_oa_hash_map.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*************************************************************************/
  2. /* test_oa_hash_map.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "test_oa_hash_map.h"
  31. #include "core/os/os.h"
  32. #include "core/templates/oa_hash_map.h"
  33. namespace TestOAHashMap {
  34. struct CountedItem {
  35. static int count;
  36. int id = -1;
  37. bool destroyed = false;
  38. CountedItem() {
  39. count++;
  40. }
  41. CountedItem(int p_id) :
  42. id(p_id) {
  43. count++;
  44. }
  45. CountedItem(const CountedItem &p_other) :
  46. id(p_other.id) {
  47. count++;
  48. }
  49. CountedItem &operator=(const CountedItem &p_other) = default;
  50. ~CountedItem() {
  51. CRASH_COND(destroyed);
  52. count--;
  53. destroyed = true;
  54. }
  55. };
  56. int CountedItem::count;
  57. MainLoop *test() {
  58. OS::get_singleton()->print("\n\n\nHello from test\n");
  59. // test element tracking.
  60. {
  61. OAHashMap<int, int> map;
  62. map.set(42, 1337);
  63. map.set(1337, 21);
  64. map.set(42, 11880);
  65. int value = 0;
  66. map.lookup(42, value);
  67. OS::get_singleton()->print("capacity %d\n", map.get_capacity());
  68. OS::get_singleton()->print("elements %d\n", map.get_num_elements());
  69. OS::get_singleton()->print("map[42] = %d\n", value);
  70. }
  71. // rehashing and deletion
  72. {
  73. OAHashMap<int, int> map;
  74. for (int i = 0; i < 500; i++) {
  75. map.set(i, i * 2);
  76. }
  77. for (int i = 0; i < 500; i += 2) {
  78. map.remove(i);
  79. }
  80. uint32_t num_elems = 0;
  81. for (int i = 0; i < 500; i++) {
  82. int tmp;
  83. if (map.lookup(i, tmp) && tmp == i * 2) {
  84. num_elems++;
  85. }
  86. }
  87. OS::get_singleton()->print("elements %d == %d.\n", map.get_num_elements(), num_elems);
  88. }
  89. // iteration
  90. {
  91. OAHashMap<String, int> map;
  92. map.set("Hello", 1);
  93. map.set("World", 2);
  94. map.set("Godot rocks", 42);
  95. for (OAHashMap<String, int>::Iterator it = map.iter(); it.valid; it = map.next_iter(it)) {
  96. OS::get_singleton()->print("map[\"%s\"] = %d\n", it.key->utf8().get_data(), *it.value);
  97. }
  98. }
  99. // stress test / test for issue #22928
  100. {
  101. OAHashMap<int, int> map;
  102. int dummy = 0;
  103. const int N = 1000;
  104. uint32_t *keys = new uint32_t[N];
  105. Math::seed(0);
  106. // insert a couple of random keys (with a dummy value, which is ignored)
  107. for (int i = 0; i < N; i++) {
  108. keys[i] = Math::rand();
  109. map.set(keys[i], dummy);
  110. if (!map.lookup(keys[i], dummy)) {
  111. OS::get_singleton()->print("could not find 0x%X despite it was just inserted!\n", unsigned(keys[i]));
  112. }
  113. }
  114. // check whether the keys are still present
  115. for (int i = 0; i < N; i++) {
  116. if (!map.lookup(keys[i], dummy)) {
  117. OS::get_singleton()->print("could not find 0x%X despite it has been inserted previously! (not checking the other keys, breaking...)\n", unsigned(keys[i]));
  118. break;
  119. }
  120. }
  121. delete[] keys;
  122. }
  123. // regression test / test for issue related to #31402
  124. {
  125. OS::get_singleton()->print("test for issue #31402 started...\n");
  126. const int num_test_values = 12;
  127. int test_values[num_test_values] = { 0, 24, 48, 72, 96, 120, 144, 168, 192, 216, 240, 264 };
  128. int dummy = 0;
  129. OAHashMap<int, int> map;
  130. map.clear();
  131. for (int i = 0; i < num_test_values; ++i) {
  132. map.set(test_values[i], dummy);
  133. }
  134. OS::get_singleton()->print("test for issue #31402 passed.\n");
  135. }
  136. // test collision resolution, should not crash or run indefinitely
  137. {
  138. OAHashMap<int, int> map(4);
  139. map.set(1, 1);
  140. map.set(5, 1);
  141. map.set(9, 1);
  142. map.set(13, 1);
  143. map.remove(5);
  144. map.remove(9);
  145. map.remove(13);
  146. map.set(5, 1);
  147. }
  148. // test memory management of items, should not crash or leak items
  149. {
  150. // Exercise different patterns of removal
  151. for (int i = 0; i < 4; ++i) {
  152. {
  153. OAHashMap<String, CountedItem> map;
  154. int id = 0;
  155. for (int j = 0; j < 100; ++j) {
  156. map.insert(itos(j), CountedItem(id));
  157. }
  158. if (i <= 1) {
  159. for (int j = 0; j < 100; ++j) {
  160. map.remove(itos(j));
  161. }
  162. }
  163. if (i % 2 == 0) {
  164. map.clear();
  165. }
  166. }
  167. if (CountedItem::count != 0) {
  168. OS::get_singleton()->print("%d != 0 (not performing the other test sub-cases, breaking...)\n", CountedItem::count);
  169. break;
  170. }
  171. }
  172. }
  173. // Test map with 0 capacity.
  174. {
  175. OAHashMap<int, String> original_map(0);
  176. original_map.set(1, "1");
  177. OS::get_singleton()->print("OAHashMap 0 capacity initialization passed.\n");
  178. }
  179. // Test copy constructor.
  180. {
  181. OAHashMap<int, String> original_map;
  182. original_map.set(1, "1");
  183. original_map.set(2, "2");
  184. original_map.set(3, "3");
  185. original_map.set(4, "4");
  186. original_map.set(5, "5");
  187. OAHashMap<int, String> map_copy(original_map);
  188. bool pass = true;
  189. for (
  190. OAHashMap<int, String>::Iterator it = original_map.iter();
  191. it.valid;
  192. it = original_map.next_iter(it)) {
  193. if (map_copy.lookup_ptr(*it.key) == nullptr) {
  194. pass = false;
  195. }
  196. if (*it.value != *map_copy.lookup_ptr(*it.key)) {
  197. pass = false;
  198. }
  199. }
  200. if (pass) {
  201. OS::get_singleton()->print("OAHashMap copy constructor test passed.\n");
  202. } else {
  203. OS::get_singleton()->print("OAHashMap copy constructor test FAILED.\n");
  204. }
  205. map_copy.set(1, "Random String");
  206. if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) {
  207. OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test FAILED.\n");
  208. } else {
  209. OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test passed.\n");
  210. }
  211. }
  212. // Test assign operator.
  213. {
  214. OAHashMap<int, String> original_map;
  215. original_map.set(1, "1");
  216. original_map.set(2, "2");
  217. original_map.set(3, "3");
  218. original_map.set(4, "4");
  219. original_map.set(5, "5");
  220. OAHashMap<int, String> map_copy(100000);
  221. map_copy.set(1, "Just a string.");
  222. map_copy = original_map;
  223. bool pass = true;
  224. for (
  225. OAHashMap<int, String>::Iterator it = map_copy.iter();
  226. it.valid;
  227. it = map_copy.next_iter(it)) {
  228. if (original_map.lookup_ptr(*it.key) == nullptr) {
  229. pass = false;
  230. }
  231. if (*it.value != *original_map.lookup_ptr(*it.key)) {
  232. pass = false;
  233. }
  234. }
  235. if (pass) {
  236. OS::get_singleton()->print("OAHashMap assign operation test passed.\n");
  237. } else {
  238. OS::get_singleton()->print("OAHashMap assign operation test FAILED.\n");
  239. }
  240. map_copy.set(1, "Random String");
  241. if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) {
  242. OS::get_singleton()->print("OAHashMap assign operation atomic copy test FAILED.\n");
  243. } else {
  244. OS::get_singleton()->print("OAHashMap assign operation atomic copy test passed.\n");
  245. }
  246. }
  247. return nullptr;
  248. }
  249. } // namespace TestOAHashMap