xref: /llvm-project/libc/test/src/__support/HashTable/table_test.cpp (revision e59582b6f8f1be3e675866f6a5d661eb4c8ed448)
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