| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- /*
- * Copyright (C) 2019 Intel Corporation. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- */
- #include "bh_platform.h"
- #include "test_helper.h"
- #include "gtest/gtest.h"
- #include "bh_hashmap.h"
- #include "wasm.h"
- #include "wasm_export.h"
- #include <future>
- typedef struct HashMapElem {
- void *key;
- void *value;
- struct HashMapElem *next;
- } HashMapElem;
- struct HashMap {
- /* size of element array */
- uint32 size;
- /* lock for elements */
- korp_mutex *lock;
- /* hash function of key */
- HashFunc hash_func;
- /* key equal function */
- KeyEqualFunc key_equal_func;
- KeyDestroyFunc key_destroy_func;
- ValueDestroyFunc value_destroy_func;
- HashMapElem *elements[1];
- };
- int DESTROY_NUM = 0;
- char TRAVERSE_KEY[] = "key_1";
- char TRAVERSE_VAL[] = "val_1";
- int TRAVERSE_COMP_RES = 0;
- class bh_hashmap_test_suite : public testing::Test
- {
- protected:
- // You should make the members protected s.t. they can be
- // accessed from sub-classes.
- // virtual void SetUp() will be called before each test is run. You
- // should define it if you need to initialize the variables.
- // Otherwise, this can be skipped.
- virtual void SetUp() {}
- // virtual void TearDown() will be called after each test is run.
- // You should define it if there is cleanup work to do. Otherwise,
- // you don't have to provide it.
- //
- virtual void TearDown() {}
- public:
- WAMRRuntimeRAII<512 * 1024> runtime;
- };
- TEST_F(bh_hashmap_test_suite, bh_hash_map_create)
- {
- // Normally.
- EXPECT_NE((HashMap *)nullptr,
- bh_hash_map_create(32, true, (HashFunc)wasm_string_hash,
- (KeyEqualFunc)wasm_string_equal, nullptr,
- wasm_runtime_free));
- // Illegal parameters.
- EXPECT_EQ((HashMap *)nullptr,
- bh_hash_map_create(65537, true, (HashFunc)wasm_string_hash,
- (KeyEqualFunc)wasm_string_equal, nullptr,
- wasm_runtime_free));
- EXPECT_EQ((HashMap *)nullptr,
- bh_hash_map_create(65536, true, nullptr, nullptr, nullptr,
- wasm_runtime_free));
- EXPECT_EQ((HashMap *)nullptr,
- bh_hash_map_create(65536, true, (HashFunc)wasm_string_hash,
- nullptr, nullptr, wasm_runtime_free));
- }
- TEST_F(bh_hashmap_test_suite, bh_hash_map_insert)
- {
- HashMap *test_hash_map = bh_hash_map_create(
- 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
- nullptr, wasm_runtime_free);
- int num = 0;
- void **p_old_key = nullptr;
- void **p_old_value = nullptr;
- // Normally.
- EXPECT_EQ(true, bh_hash_map_insert(test_hash_map, (void *)"key_1",
- (void *)"val_1"));
- num++;
- // Illegal parameters.
- EXPECT_EQ(false, bh_hash_map_insert(nullptr, nullptr, (void *)"val_2"));
- // Execute fail: more than 32.
- for (; num <= 32; num++) {
- bh_hash_map_insert(test_hash_map, (void *)&num, (void *)"val");
- }
- EXPECT_EQ(false,
- bh_hash_map_insert(test_hash_map, (void *)&num, (void *)"val"));
- // Remove one, insert one.
- bh_hash_map_remove(test_hash_map, (void *)"key_1", p_old_key, p_old_value);
- EXPECT_EQ(true, bh_hash_map_insert(test_hash_map, (void *)"key_1",
- (void *)"val_1"));
- }
- TEST_F(bh_hashmap_test_suite, bh_hash_map_find)
- {
- HashMap *test_hash_map = bh_hash_map_create(
- 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
- nullptr, wasm_runtime_free);
- bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
- // Normally. use_lock is false.
- EXPECT_NE((void *)nullptr,
- bh_hash_map_find(test_hash_map, (void *)"key_1"));
- // Execute fail.
- EXPECT_EQ((void *)nullptr,
- bh_hash_map_find(test_hash_map, (void *)"KEY_1"));
- // Illegal parameters.
- EXPECT_EQ((void *)nullptr, bh_hash_map_find(nullptr, nullptr));
- EXPECT_EQ((void *)nullptr, bh_hash_map_find(test_hash_map, nullptr));
- // Normally. use_lock is true.
- test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash,
- (KeyEqualFunc)wasm_string_equal, nullptr,
- wasm_runtime_free);
- bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
- EXPECT_EQ((void *)nullptr,
- bh_hash_map_find(test_hash_map, (void *)"KEY_1"));
- }
- TEST_F(bh_hashmap_test_suite, bh_hash_map_update)
- {
- char old_value[10] = { 0 };
- void **p_old_value = (void **)(&old_value);
- HashMap *test_hash_map = bh_hash_map_create(
- 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
- nullptr, wasm_runtime_free);
- bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
- // test_hash_map->lock == nullptr. Normally.
- EXPECT_EQ(true, bh_hash_map_update(test_hash_map, (void *)"key_1",
- (void *)"val_2", p_old_value));
- // test_hash_map->lock == nullptr. Illegal parameters.
- EXPECT_EQ(false, bh_hash_map_update(nullptr, nullptr, (void *)"val_2",
- p_old_value));
- EXPECT_EQ(false, bh_hash_map_update(test_hash_map, nullptr, (void *)"val_2",
- p_old_value));
- EXPECT_EQ(false,
- bh_hash_map_update(nullptr, nullptr, (void *)"val_2", nullptr));
- // test_hash_map->lock == nullptr. Update non-existent elements.
- EXPECT_EQ(false, bh_hash_map_update(test_hash_map, (void *)"key",
- (void *)"val", p_old_value));
- test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash,
- (KeyEqualFunc)wasm_string_equal, nullptr,
- wasm_runtime_free);
- bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
- // test_hash_map->lock == no nullptr. Normally.
- EXPECT_EQ(true, bh_hash_map_update(test_hash_map, (void *)"key_1",
- (void *)"val_2", p_old_value));
- // test_hash_map->lock == no nullptr. Illegal parameters.
- EXPECT_EQ(false, bh_hash_map_update(nullptr, nullptr, (void *)"val_2",
- p_old_value));
- EXPECT_EQ(false, bh_hash_map_update(test_hash_map, nullptr, (void *)"val_2",
- p_old_value));
- }
- void
- trav_callback_fun(void *key, void *value, void *user_data)
- {
- if (!strncmp(TRAVERSE_VAL, (const char *)value, 5)) {
- TRAVERSE_COMP_RES = 1;
- }
- else {
- TRAVERSE_COMP_RES = 0;
- }
- }
- TEST_F(bh_hashmap_test_suite, bh_hash_map_traverse)
- {
- void **p_old_value = nullptr;
- HashMap *test_hash_map = bh_hash_map_create(
- 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
- nullptr, wasm_runtime_free);
- // Normally: TRAVERSE_COMP_RES = 1.
- bh_hash_map_insert(test_hash_map, (void *)TRAVERSE_KEY,
- (void *)TRAVERSE_VAL);
- EXPECT_EQ(true,
- bh_hash_map_traverse(test_hash_map, trav_callback_fun, nullptr));
- EXPECT_EQ(1, TRAVERSE_COMP_RES);
- // Normally: TRAVERSE_COMP_RES = 0.
- bh_hash_map_update(test_hash_map, (void *)TRAVERSE_KEY, (void *)"val",
- p_old_value);
- EXPECT_EQ(true,
- bh_hash_map_traverse(test_hash_map, trav_callback_fun, nullptr));
- EXPECT_EQ(0, TRAVERSE_COMP_RES);
- // Illegal parameters.
- EXPECT_EQ(false, bh_hash_map_traverse(nullptr, trav_callback_fun, nullptr));
- EXPECT_EQ(false, bh_hash_map_traverse(test_hash_map, nullptr, nullptr));
- }
- TEST_F(bh_hashmap_test_suite, bh_hash_map_remove)
- {
- void **p_old_key = nullptr;
- void **p_old_value = nullptr;
- HashMap *test_hash_map = bh_hash_map_create(
- 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
- nullptr, wasm_runtime_free);
- bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
- bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2");
- // test_hash_map->lock == nullptr. Normally.
- EXPECT_EQ(true, bh_hash_map_remove(test_hash_map, (void *)"key_1",
- p_old_key, p_old_value));
- // test_hash_map->lock == nullptr. Remove non-existent elements.
- EXPECT_EQ(false, bh_hash_map_remove(test_hash_map, (void *)"key_1",
- p_old_key, p_old_value));
- // test_hash_map->lock == nullptr. Illegal parameters.
- EXPECT_EQ(false, bh_hash_map_remove(nullptr, (void *)"key_2", p_old_key,
- p_old_value));
- EXPECT_EQ(false, bh_hash_map_remove(test_hash_map, nullptr, p_old_key,
- p_old_value));
- test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash,
- (KeyEqualFunc)wasm_string_equal, nullptr,
- wasm_runtime_free);
- bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
- bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2");
- // test_hash_map->lock == no nullptr. Normally.
- EXPECT_EQ(true, bh_hash_map_remove(test_hash_map, (void *)"key_1",
- p_old_key, p_old_value));
- // test_hash_map->lock == no nullptr. Illegal parameters.
- EXPECT_EQ(false, bh_hash_map_remove(nullptr, (void *)"key_2", p_old_key,
- p_old_value));
- }
- TEST_F(bh_hashmap_test_suite, bh_hash_map_get_struct_size)
- {
- HashMap *test_hash_map = nullptr;
- uint32 size = 0;
- // No lock.
- test_hash_map = bh_hash_map_create(32, false, (HashFunc)wasm_string_hash,
- (KeyEqualFunc)wasm_string_equal, nullptr,
- wasm_runtime_free);
- bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
- size = (size_t)(&((HashMap *)0)->elements)
- + (uint32)sizeof(HashMapElem *) * test_hash_map->size;
- EXPECT_EQ(size, bh_hash_map_get_struct_size(test_hash_map));
- // Has lock.
- test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash,
- (KeyEqualFunc)wasm_string_equal, nullptr,
- wasm_runtime_free);
- bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
- size = (size_t)(&((HashMap *)0)->elements)
- + (uint32)sizeof(HashMapElem *) * test_hash_map->size;
- size += (uint32)sizeof(korp_mutex);
- EXPECT_EQ(size, bh_hash_map_get_struct_size(test_hash_map));
- }
- TEST_F(bh_hashmap_test_suite, bh_hash_map_get_elem_struct_size)
- {
- EXPECT_EQ((uint32)sizeof(HashMapElem), bh_hash_map_get_elem_struct_size());
- }
- void
- destroy_func_test(void *key)
- {
- DESTROY_NUM++;
- }
- TEST_F(bh_hashmap_test_suite, bh_hash_map_destroy)
- {
- HashMap *test_hash_map = bh_hash_map_create(
- 32, true, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal,
- destroy_func_test, wasm_runtime_free);
- bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
- bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2");
- // test_hash_map->lock == no nullptr. Normally.
- EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map));
- // key_destroy_func must be called 2 times.
- EXPECT_EQ(2, DESTROY_NUM);
- test_hash_map = bh_hash_map_create(32, false, (HashFunc)wasm_string_hash,
- (KeyEqualFunc)wasm_string_equal,
- destroy_func_test, wasm_runtime_free);
- // test_hash_map->lock == no nullptr. Illegal parameters.
- EXPECT_EQ(false, bh_hash_map_destroy(nullptr));
- // test_hash_map->lock == nullptr.
- EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map));
- // key_destroy_func and value_destroy_func is nullptr.
- test_hash_map =
- bh_hash_map_create(32, false, (HashFunc)wasm_string_hash,
- (KeyEqualFunc)wasm_string_equal, nullptr, nullptr);
- bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1");
- bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2");
- EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map));
- }
- // This fun allows inserting the same keys.
- bool
- string_equal_test(const char *s1, const char *s2)
- {
- return false;
- }
- int COUNT_ELEM = 0;
- void
- fun_count_elem(void *key, void *value, void *user_data)
- {
- COUNT_ELEM++;
- }
- TEST_F(bh_hashmap_test_suite, bh_hashmap_thread_safety)
- {
- HashMap *test_hash_map = bh_hash_map_create(
- 32, true, (HashFunc)wasm_string_hash, (KeyEqualFunc)string_equal_test,
- destroy_func_test, wasm_runtime_free);
- int32_t i = 0;
- std::vector<std::future<void>> threads;
- // Creat 8 threads. In every thread, run the codes in brackets of
- // std::async.
- for (i = 0; i < 8; i++) {
- threads.push_back(std::async([&] {
- for (int j = 0; j < 25; j++) {
- bh_hash_map_insert(test_hash_map, (void *)"key_1",
- (void *)"val_1");
- }
- }));
- }
- // Wait all 8 threads finished.
- for (auto &t : threads) {
- t.wait();
- }
- // Count hash map elements.
- bh_hash_map_traverse(test_hash_map, fun_count_elem, nullptr);
- EXPECT_EQ(200, COUNT_ELEM);
- EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map));
- }
|