bh_hashmap_test.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "bh_platform.h"
  6. #include "test_helper.h"
  7. #include "gtest/gtest.h"
  8. #include "bh_hashmap.h"
  9. #include "wasm.h"
  10. #include "wasm_export.h"
  11. #include <future>
  12. typedef struct HashMapElem {
  13. void *key;
  14. void *value;
  15. struct HashMapElem *next;
  16. } HashMapElem;
  17. struct HashMap {
  18. /* size of element array */
  19. uint32 size;
  20. /* lock for elements */
  21. korp_mutex *lock;
  22. /* hash function of key */
  23. HashFunc hash_func;
  24. /* key equal function */
  25. KeyEqualFunc key_equal_func;
  26. KeyDestroyFunc key_destroy_func;
  27. ValueDestroyFunc value_destroy_func;
  28. HashMapElem *elements[1];
  29. };
  30. int DESTROY_NUM = 0;
  31. char TRAVERSE_KEY[] = "key_1";
  32. char TRAVERSE_VAL[] = "val_1";
  33. int TRAVERSE_COMP_RES = 0;
  34. class bh_hashmap_test_suite : public testing::Test
  35. {
  36. protected:
  37. // You should make the members protected s.t. they can be
  38. // accessed from sub-classes.
  39. // virtual void SetUp() will be called before each test is run. You
  40. // should define it if you need to initialize the variables.
  41. // Otherwise, this can be skipped.
  42. virtual void SetUp() {}
  43. // virtual void TearDown() will be called after each test is run.
  44. // You should define it if there is cleanup work to do. Otherwise,
  45. // you don't have to provide it.
  46. //
  47. virtual void TearDown() {}
  48. public:
  49. WAMRRuntimeRAII<512 * 1024> runtime;
  50. };
  51. TEST_F(bh_hashmap_test_suite, bh_hash_map_create)
  52. {
  53. // Normally.
  54. EXPECT_NE((HashMap *)nullptr,
  55. bh_hash_map_create(32, true, (HashFunc)wasm_string_hash,
  56. (KeyEqualFunc)wasm_string_equal, nullptr,
  57. wasm_runtime_free));
  58. // Illegal parameters.
  59. EXPECT_EQ((HashMap *)nullptr,
  60. bh_hash_map_create(65537, true, (HashFunc)wasm_string_hash,
  61. (KeyEqualFunc)wasm_string_equal, nullptr,
  62. wasm_runtime_free));
  63. EXPECT_EQ((HashMap *)nullptr,
  64. bh_hash_map_create(65536, true, nullptr, nullptr, nullptr,
  65. wasm_runtime_free));
  66. EXPECT_EQ((HashMap *)nullptr,
  67. bh_hash_map_create(65536, true, (HashFunc)wasm_string_hash,
  68. nullptr, nullptr, wasm_runtime_free));
  69. }
  70. TEST_F(bh_hashmap_test_suite, bh_hash_map_insert)
  71. {
  72. HashMap *test_hash_map = bh_hash_map_create(
  73. 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
  74. nullptr, wasm_runtime_free);
  75. int num = 0;
  76. void **p_old_key = nullptr;
  77. void **p_old_value = nullptr;
  78. // Normally.
  79. EXPECT_EQ(true, bh_hash_map_insert(test_hash_map, (void *)"key_1",
  80. (void *)"val_1"));
  81. num++;
  82. // Illegal parameters.
  83. EXPECT_EQ(false, bh_hash_map_insert(nullptr, nullptr, (void *)"val_2"));
  84. // Execute fail: more than 32.
  85. for (; num <= 32; num++) {
  86. bh_hash_map_insert(test_hash_map, (void *)&num, (void *)"val");
  87. }
  88. EXPECT_EQ(false,
  89. bh_hash_map_insert(test_hash_map, (void *)&num, (void *)"val"));
  90. // Remove one, insert one.
  91. bh_hash_map_remove(test_hash_map, (void *)"key_1", p_old_key, p_old_value);
  92. EXPECT_EQ(true, bh_hash_map_insert(test_hash_map, (void *)"key_1",
  93. (void *)"val_1"));
  94. }
  95. TEST_F(bh_hashmap_test_suite, bh_hash_map_find)
  96. {
  97. HashMap *test_hash_map = bh_hash_map_create(
  98. 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
  99. nullptr, wasm_runtime_free);
  100. bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
  101. // Normally. use_lock is false.
  102. EXPECT_NE((void *)nullptr,
  103. bh_hash_map_find(test_hash_map, (void *)"key_1"));
  104. // Execute fail.
  105. EXPECT_EQ((void *)nullptr,
  106. bh_hash_map_find(test_hash_map, (void *)"KEY_1"));
  107. // Illegal parameters.
  108. EXPECT_EQ((void *)nullptr, bh_hash_map_find(nullptr, nullptr));
  109. EXPECT_EQ((void *)nullptr, bh_hash_map_find(test_hash_map, nullptr));
  110. // Normally. use_lock is true.
  111. test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash,
  112. (KeyEqualFunc)wasm_string_equal, nullptr,
  113. wasm_runtime_free);
  114. bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
  115. EXPECT_EQ((void *)nullptr,
  116. bh_hash_map_find(test_hash_map, (void *)"KEY_1"));
  117. }
  118. TEST_F(bh_hashmap_test_suite, bh_hash_map_update)
  119. {
  120. char old_value[10] = { 0 };
  121. void **p_old_value = (void **)(&old_value);
  122. HashMap *test_hash_map = bh_hash_map_create(
  123. 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
  124. nullptr, wasm_runtime_free);
  125. bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
  126. // test_hash_map->lock == nullptr. Normally.
  127. EXPECT_EQ(true, bh_hash_map_update(test_hash_map, (void *)"key_1",
  128. (void *)"val_2", p_old_value));
  129. // test_hash_map->lock == nullptr. Illegal parameters.
  130. EXPECT_EQ(false, bh_hash_map_update(nullptr, nullptr, (void *)"val_2",
  131. p_old_value));
  132. EXPECT_EQ(false, bh_hash_map_update(test_hash_map, nullptr, (void *)"val_2",
  133. p_old_value));
  134. EXPECT_EQ(false,
  135. bh_hash_map_update(nullptr, nullptr, (void *)"val_2", nullptr));
  136. // test_hash_map->lock == nullptr. Update non-existent elements.
  137. EXPECT_EQ(false, bh_hash_map_update(test_hash_map, (void *)"key",
  138. (void *)"val", p_old_value));
  139. test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash,
  140. (KeyEqualFunc)wasm_string_equal, nullptr,
  141. wasm_runtime_free);
  142. bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
  143. // test_hash_map->lock == no nullptr. Normally.
  144. EXPECT_EQ(true, bh_hash_map_update(test_hash_map, (void *)"key_1",
  145. (void *)"val_2", p_old_value));
  146. // test_hash_map->lock == no nullptr. Illegal parameters.
  147. EXPECT_EQ(false, bh_hash_map_update(nullptr, nullptr, (void *)"val_2",
  148. p_old_value));
  149. EXPECT_EQ(false, bh_hash_map_update(test_hash_map, nullptr, (void *)"val_2",
  150. p_old_value));
  151. }
  152. void
  153. trav_callback_fun(void *key, void *value, void *user_data)
  154. {
  155. if (!strncmp(TRAVERSE_VAL, (const char *)value, 5)) {
  156. TRAVERSE_COMP_RES = 1;
  157. }
  158. else {
  159. TRAVERSE_COMP_RES = 0;
  160. }
  161. }
  162. TEST_F(bh_hashmap_test_suite, bh_hash_map_traverse)
  163. {
  164. void **p_old_value = nullptr;
  165. HashMap *test_hash_map = bh_hash_map_create(
  166. 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
  167. nullptr, wasm_runtime_free);
  168. // Normally: TRAVERSE_COMP_RES = 1.
  169. bh_hash_map_insert(test_hash_map, (void *)TRAVERSE_KEY,
  170. (void *)TRAVERSE_VAL);
  171. EXPECT_EQ(true,
  172. bh_hash_map_traverse(test_hash_map, trav_callback_fun, nullptr));
  173. EXPECT_EQ(1, TRAVERSE_COMP_RES);
  174. // Normally: TRAVERSE_COMP_RES = 0.
  175. bh_hash_map_update(test_hash_map, (void *)TRAVERSE_KEY, (void *)"val",
  176. p_old_value);
  177. EXPECT_EQ(true,
  178. bh_hash_map_traverse(test_hash_map, trav_callback_fun, nullptr));
  179. EXPECT_EQ(0, TRAVERSE_COMP_RES);
  180. // Illegal parameters.
  181. EXPECT_EQ(false, bh_hash_map_traverse(nullptr, trav_callback_fun, nullptr));
  182. EXPECT_EQ(false, bh_hash_map_traverse(test_hash_map, nullptr, nullptr));
  183. }
  184. TEST_F(bh_hashmap_test_suite, bh_hash_map_remove)
  185. {
  186. void **p_old_key = nullptr;
  187. void **p_old_value = nullptr;
  188. HashMap *test_hash_map = bh_hash_map_create(
  189. 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
  190. nullptr, wasm_runtime_free);
  191. bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
  192. bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2");
  193. // test_hash_map->lock == nullptr. Normally.
  194. EXPECT_EQ(true, bh_hash_map_remove(test_hash_map, (void *)"key_1",
  195. p_old_key, p_old_value));
  196. // test_hash_map->lock == nullptr. Remove non-existent elements.
  197. EXPECT_EQ(false, bh_hash_map_remove(test_hash_map, (void *)"key_1",
  198. p_old_key, p_old_value));
  199. // test_hash_map->lock == nullptr. Illegal parameters.
  200. EXPECT_EQ(false, bh_hash_map_remove(nullptr, (void *)"key_2", p_old_key,
  201. p_old_value));
  202. EXPECT_EQ(false, bh_hash_map_remove(test_hash_map, nullptr, p_old_key,
  203. p_old_value));
  204. test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash,
  205. (KeyEqualFunc)wasm_string_equal, nullptr,
  206. wasm_runtime_free);
  207. bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
  208. bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2");
  209. // test_hash_map->lock == no nullptr. Normally.
  210. EXPECT_EQ(true, bh_hash_map_remove(test_hash_map, (void *)"key_1",
  211. p_old_key, p_old_value));
  212. // test_hash_map->lock == no nullptr. Illegal parameters.
  213. EXPECT_EQ(false, bh_hash_map_remove(nullptr, (void *)"key_2", p_old_key,
  214. p_old_value));
  215. }
  216. TEST_F(bh_hashmap_test_suite, bh_hash_map_get_struct_size)
  217. {
  218. HashMap *test_hash_map = nullptr;
  219. uint32 size = 0;
  220. // No lock.
  221. test_hash_map = bh_hash_map_create(32, false, (HashFunc)wasm_string_hash,
  222. (KeyEqualFunc)wasm_string_equal, nullptr,
  223. wasm_runtime_free);
  224. bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
  225. size = (size_t)(&((HashMap *)0)->elements)
  226. + (uint32)sizeof(HashMapElem *) * test_hash_map->size;
  227. EXPECT_EQ(size, bh_hash_map_get_struct_size(test_hash_map));
  228. // Has lock.
  229. test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash,
  230. (KeyEqualFunc)wasm_string_equal, nullptr,
  231. wasm_runtime_free);
  232. bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
  233. size = (size_t)(&((HashMap *)0)->elements)
  234. + (uint32)sizeof(HashMapElem *) * test_hash_map->size;
  235. size += (uint32)sizeof(korp_mutex);
  236. EXPECT_EQ(size, bh_hash_map_get_struct_size(test_hash_map));
  237. }
  238. TEST_F(bh_hashmap_test_suite, bh_hash_map_get_elem_struct_size)
  239. {
  240. EXPECT_EQ((uint32)sizeof(HashMapElem), bh_hash_map_get_elem_struct_size());
  241. }
  242. void
  243. destroy_func_test(void *key)
  244. {
  245. DESTROY_NUM++;
  246. }
  247. TEST_F(bh_hashmap_test_suite, bh_hash_map_destroy)
  248. {
  249. HashMap *test_hash_map = bh_hash_map_create(
  250. 32, true, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
  251. destroy_func_test, wasm_runtime_free);
  252. bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
  253. bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2");
  254. // test_hash_map->lock == no nullptr. Normally.
  255. EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map));
  256. // key_destroy_func must be called 2 times.
  257. EXPECT_EQ(2, DESTROY_NUM);
  258. test_hash_map = bh_hash_map_create(32, false, (HashFunc)wasm_string_hash,
  259. (KeyEqualFunc)wasm_string_equal,
  260. destroy_func_test, wasm_runtime_free);
  261. // test_hash_map->lock == no nullptr. Illegal parameters.
  262. EXPECT_EQ(false, bh_hash_map_destroy(nullptr));
  263. // test_hash_map->lock == nullptr.
  264. EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map));
  265. // key_destroy_func and value_destroy_func is nullptr.
  266. test_hash_map =
  267. bh_hash_map_create(32, false, (HashFunc)wasm_string_hash,
  268. (KeyEqualFunc)wasm_string_equal, nullptr, nullptr);
  269. bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
  270. bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2");
  271. EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map));
  272. }
  273. // This fun allows inserting the same keys.
  274. bool
  275. string_equal_test(const char *s1, const char *s2)
  276. {
  277. return false;
  278. }
  279. int COUNT_ELEM = 0;
  280. void
  281. fun_count_elem(void *key, void *value, void *user_data)
  282. {
  283. COUNT_ELEM++;
  284. }
  285. TEST_F(bh_hashmap_test_suite, bh_hashmap_thread_safety)
  286. {
  287. HashMap *test_hash_map = bh_hash_map_create(
  288. 32, true, (HashFunc)wasm_string_hash, (KeyEqualFunc)string_equal_test,
  289. destroy_func_test, wasm_runtime_free);
  290. int32_t i = 0;
  291. std::vector<std::future<void>> threads;
  292. // Creat 8 threads. In every thread, run the codes in brackets of
  293. // std::async.
  294. for (i = 0; i < 8; i++) {
  295. threads.push_back(std::async([&] {
  296. for (int j = 0; j < 25; j++) {
  297. bh_hash_map_insert(test_hash_map, (void *)"key_1",
  298. (void *)"val_1");
  299. }
  300. }));
  301. }
  302. // Wait all 8 threads finished.
  303. for (auto &t : threads) {
  304. t.wait();
  305. }
  306. // Count hash map elements.
  307. bh_hash_map_traverse(test_hash_map, fun_count_elem, nullptr);
  308. EXPECT_EQ(200, COUNT_ELEM);
  309. EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map));
  310. }