181e3e7e5SSchrodinger ZHU Yifan //===-- Unittests for table -----------------------------------------------===// 281e3e7e5SSchrodinger ZHU Yifan // 381e3e7e5SSchrodinger ZHU Yifan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481e3e7e5SSchrodinger ZHU Yifan // See https://llvm.org/LICENSE.txt for license information. 581e3e7e5SSchrodinger ZHU Yifan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681e3e7e5SSchrodinger ZHU Yifan // 781e3e7e5SSchrodinger ZHU Yifan //===----------------------------------------------------------------------===// 881e3e7e5SSchrodinger ZHU Yifan 91d894788SGuillaume Chatelet #include "src/__support/CPP/bit.h" // bit_ceil 1081e3e7e5SSchrodinger ZHU Yifan #include "src/__support/HashTable/randomness.h" 1181e3e7e5SSchrodinger ZHU Yifan #include "src/__support/HashTable/table.h" 125ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 1381e3e7e5SSchrodinger ZHU Yifan #include "test/UnitTest/Test.h" 1481e3e7e5SSchrodinger ZHU Yifan 155ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 1681e3e7e5SSchrodinger ZHU Yifan namespace internal { 1781e3e7e5SSchrodinger ZHU Yifan TEST(LlvmLibcTableTest, AllocationAndDeallocation) { 1881e3e7e5SSchrodinger ZHU Yifan size_t caps[] = {0, 1, 2, 3, 4, 7, 11, 37, 1024, 5261, 19999}; 1981e3e7e5SSchrodinger ZHU Yifan const char *keys[] = {"", "a", "ab", "abc", 2081e3e7e5SSchrodinger ZHU Yifan "abcd", "abcde", "abcdef", "abcdefg", 2181e3e7e5SSchrodinger ZHU Yifan "abcdefgh", "abcdefghi", "abcdefghij"}; 2281e3e7e5SSchrodinger ZHU Yifan for (size_t i : caps) { 2381e3e7e5SSchrodinger ZHU Yifan HashTable *table = HashTable::allocate(i, 1); 2481e3e7e5SSchrodinger ZHU Yifan ASSERT_NE(table, static_cast<HashTable *>(nullptr)); 2581e3e7e5SSchrodinger ZHU Yifan for (const char *key : keys) { 2681e3e7e5SSchrodinger ZHU Yifan ASSERT_EQ(table->find(key), static_cast<ENTRY *>(nullptr)); 2781e3e7e5SSchrodinger ZHU Yifan } 2881e3e7e5SSchrodinger ZHU Yifan HashTable::deallocate(table); 2981e3e7e5SSchrodinger ZHU Yifan } 3081e3e7e5SSchrodinger ZHU Yifan ASSERT_EQ(HashTable::allocate(-1, 0), static_cast<HashTable *>(nullptr)); 3181e3e7e5SSchrodinger ZHU Yifan HashTable::deallocate(nullptr); 3281e3e7e5SSchrodinger ZHU Yifan } 3381e3e7e5SSchrodinger ZHU Yifan 3486e99e11SSchrodinger ZHU Yifan TEST(LlvmLibcTableTest, Iteration) { 3586e99e11SSchrodinger ZHU Yifan constexpr size_t TEST_SIZE = 512; 3686e99e11SSchrodinger ZHU Yifan size_t counter[TEST_SIZE]; 3786e99e11SSchrodinger ZHU Yifan struct key { 3886e99e11SSchrodinger ZHU Yifan uint8_t bytes[3]; 3986e99e11SSchrodinger ZHU Yifan } keys[TEST_SIZE]; 4086e99e11SSchrodinger ZHU Yifan HashTable *table = HashTable::allocate(0, 0x7f7f7f7f7f7f7f7f); 4186e99e11SSchrodinger ZHU Yifan ASSERT_NE(table, static_cast<HashTable *>(nullptr)); 4286e99e11SSchrodinger ZHU Yifan for (size_t i = 0; i < TEST_SIZE; ++i) { 4386e99e11SSchrodinger ZHU Yifan counter[i] = 0; 4486e99e11SSchrodinger ZHU Yifan if (i >= 256) { 4586e99e11SSchrodinger ZHU Yifan keys[i].bytes[0] = 2; 4686e99e11SSchrodinger ZHU Yifan keys[i].bytes[1] = i % 256; 4786e99e11SSchrodinger ZHU Yifan keys[i].bytes[2] = 0; 4886e99e11SSchrodinger ZHU Yifan } else { 4986e99e11SSchrodinger ZHU Yifan keys[i].bytes[0] = 1; 5086e99e11SSchrodinger ZHU Yifan keys[i].bytes[1] = i; 5186e99e11SSchrodinger ZHU Yifan keys[i].bytes[2] = 0; 5286e99e11SSchrodinger ZHU Yifan } 5386e99e11SSchrodinger ZHU Yifan HashTable::insert(table, {reinterpret_cast<char *>(keys[i].bytes), 5486e99e11SSchrodinger ZHU Yifan reinterpret_cast<void *>((size_t)i)}); 5586e99e11SSchrodinger ZHU Yifan } 5686e99e11SSchrodinger ZHU Yifan 5786e99e11SSchrodinger ZHU Yifan size_t count = 0; 5886e99e11SSchrodinger ZHU Yifan for (const ENTRY &e : *table) { 5986e99e11SSchrodinger ZHU Yifan size_t data = reinterpret_cast<size_t>(e.data); 6086e99e11SSchrodinger ZHU Yifan ++counter[data]; 6186e99e11SSchrodinger ZHU Yifan ++count; 6286e99e11SSchrodinger ZHU Yifan } 6386e99e11SSchrodinger ZHU Yifan ASSERT_EQ(count, TEST_SIZE); 6486e99e11SSchrodinger ZHU Yifan for (size_t i = 0; i < TEST_SIZE; ++i) { 6586e99e11SSchrodinger ZHU Yifan ASSERT_EQ(counter[i], static_cast<size_t>(1)); 6686e99e11SSchrodinger ZHU Yifan } 6786e99e11SSchrodinger ZHU Yifan HashTable::deallocate(table); 6886e99e11SSchrodinger ZHU Yifan } 6986e99e11SSchrodinger ZHU Yifan 7086e99e11SSchrodinger ZHU Yifan // Check if resize works correctly. This test actually covers two things: 7186e99e11SSchrodinger ZHU Yifan // - The sizes are indeed growing. 7286e99e11SSchrodinger ZHU Yifan // - The sizes are growing rapidly enough to reach the upper bound. 7386e99e11SSchrodinger ZHU Yifan TEST(LlvmLibcTableTest, GrowthSequence) { 7486e99e11SSchrodinger ZHU Yifan size_t cap = capacity_to_entries(0); 7586e99e11SSchrodinger ZHU Yifan // right shift 4 to avoid overflow ssize_t. 7686e99e11SSchrodinger ZHU Yifan while (cap < static_cast<size_t>(-1) >> 4u) { 7786e99e11SSchrodinger ZHU Yifan size_t hint = cap / 8 * 7 + 1; 7886e99e11SSchrodinger ZHU Yifan size_t new_cap = capacity_to_entries(hint); 7986e99e11SSchrodinger ZHU Yifan ASSERT_GT(new_cap, cap); 8086e99e11SSchrodinger ZHU Yifan cap = new_cap; 8186e99e11SSchrodinger ZHU Yifan } 8286e99e11SSchrodinger ZHU Yifan } 8386e99e11SSchrodinger ZHU Yifan 8481e3e7e5SSchrodinger ZHU Yifan TEST(LlvmLibcTableTest, Insertion) { 85*e59582b6SSchrodinger ZHU Yifan struct key { 8686e99e11SSchrodinger ZHU Yifan char bytes[2]; 8781e3e7e5SSchrodinger ZHU Yifan } keys[256]; 8881e3e7e5SSchrodinger ZHU Yifan for (size_t k = 0; k < 256; ++k) { 8986e99e11SSchrodinger ZHU Yifan keys[k].bytes[0] = static_cast<char>(k); 9086e99e11SSchrodinger ZHU Yifan keys[k].bytes[1] = 0; 9181e3e7e5SSchrodinger ZHU Yifan } 921d894788SGuillaume Chatelet constexpr size_t CAP = cpp::bit_ceil((sizeof(Group) + 1) * 8 / 7) / 8 * 7; 9381e3e7e5SSchrodinger ZHU Yifan static_assert(CAP + 1 < 256, "CAP is too large for this test."); 9481e3e7e5SSchrodinger ZHU Yifan HashTable *table = 9581e3e7e5SSchrodinger ZHU Yifan HashTable::allocate(sizeof(Group) + 1, randomness::next_random_seed()); 9681e3e7e5SSchrodinger ZHU Yifan ASSERT_NE(table, static_cast<HashTable *>(nullptr)); 9781e3e7e5SSchrodinger ZHU Yifan 9881e3e7e5SSchrodinger ZHU Yifan // insert to full capacity. 9981e3e7e5SSchrodinger ZHU Yifan for (size_t i = 0; i < CAP; ++i) { 10086e99e11SSchrodinger ZHU Yifan ASSERT_NE(HashTable::insert(table, {keys[i].bytes, keys[i].bytes}), 10181e3e7e5SSchrodinger ZHU Yifan static_cast<ENTRY *>(nullptr)); 10281e3e7e5SSchrodinger ZHU Yifan } 10381e3e7e5SSchrodinger ZHU Yifan 10486e99e11SSchrodinger ZHU Yifan // One more insert should grow the table successfully. We test the value 10586e99e11SSchrodinger ZHU Yifan // here because the grow finishes with a fastpath insertion that is different 10686e99e11SSchrodinger ZHU Yifan // from the normal insertion. 10786e99e11SSchrodinger ZHU Yifan ASSERT_EQ(HashTable::insert(table, {keys[CAP].bytes, keys[CAP].bytes})->data, 10886e99e11SSchrodinger ZHU Yifan static_cast<void *>(keys[CAP].bytes)); 10981e3e7e5SSchrodinger ZHU Yifan 11086e99e11SSchrodinger ZHU Yifan for (size_t i = 0; i <= CAP; ++i) { 11181e3e7e5SSchrodinger ZHU Yifan ASSERT_EQ(strcmp(table->find(keys[i].bytes)->key, keys[i].bytes), 0); 11281e3e7e5SSchrodinger ZHU Yifan } 11386e99e11SSchrodinger ZHU Yifan for (size_t i = CAP + 1; i < 256; ++i) { 11481e3e7e5SSchrodinger ZHU Yifan ASSERT_EQ(table->find(keys[i].bytes), static_cast<ENTRY *>(nullptr)); 11581e3e7e5SSchrodinger ZHU Yifan } 11681e3e7e5SSchrodinger ZHU Yifan 11781e3e7e5SSchrodinger ZHU Yifan // do not replace old value 11886e99e11SSchrodinger ZHU Yifan for (size_t i = 0; i <= CAP; ++i) { 11986e99e11SSchrodinger ZHU Yifan ASSERT_NE( 12086e99e11SSchrodinger ZHU Yifan HashTable::insert(table, {keys[i].bytes, reinterpret_cast<void *>(i)}), 12181e3e7e5SSchrodinger ZHU Yifan static_cast<ENTRY *>(nullptr)); 12281e3e7e5SSchrodinger ZHU Yifan } 12386e99e11SSchrodinger ZHU Yifan for (size_t i = 0; i <= CAP; ++i) { 12481e3e7e5SSchrodinger ZHU Yifan ASSERT_EQ(table->find(keys[i].bytes)->data, 12581e3e7e5SSchrodinger ZHU Yifan reinterpret_cast<void *>(keys[i].bytes)); 12681e3e7e5SSchrodinger ZHU Yifan } 12781e3e7e5SSchrodinger ZHU Yifan 12881e3e7e5SSchrodinger ZHU Yifan HashTable::deallocate(table); 12981e3e7e5SSchrodinger ZHU Yifan } 13081e3e7e5SSchrodinger ZHU Yifan 13181e3e7e5SSchrodinger ZHU Yifan } // namespace internal 1325ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 133