37# include <gtest/gtest.h>
45using namespace testing;
55 const size_t cap =
tbl.capacity();
56 for (
size_t i = 0; i < cap; ++i)
64 for (
size_t i = 0; i <
tbl.size(); ++i)
67 auto ptr =
tbl.search(i);
72 for (
size_t i = 0, n =
tbl.size(); i < n; ++i)
74 auto ptr =
tbl.search(i);
97 return r1.key == r2.key;
115 for (
size_t i = 0; i < 100; ++i)
126 for (
size_t i = 0, n =
tbl.size(); i < n; ++i)
128 auto ptr =
tbl.search(i);
143 auto *bucket =
decltype(
tbl)::key_to_bucket(ptr);
158 const int num_elements = 50;
159 for (
int i = 0; i < num_elements; ++i)
166 for (
int i = 0; i < 10; ++i)
174 <<
"Table size should not change after failed remove attempts";
177 for (
int i = 0; i < num_elements; ++i)
179 auto ptr =
tbl.search(i * 2);
181 <<
"Element " << i * 2 <<
" should still be in the table";
187 for (
int i = 0; i < num_elements; ++i)
189 auto ptr =
tbl.search(i * 2);
204 for (
int i = 0; i < 20; ++i)
216 for (
int i = 0; i < 20; ++i)
218 if (i == 10)
continue;
219 EXPECT_NE(
tbl.search(i),
nullptr) <<
"Element " << i <<
" should still exist";
229 for (
int i = 0; i < 20; ++i)
235 auto ptr =
tbl.search(10);
249 const int num_elements = 15;
250 for (
int i = 0; i < num_elements; ++i)
256 for (
int i = 0; i < num_elements; ++i)
257 EXPECT_NE(
tbl.search(i),
nullptr) <<
"Element " << i <<
" not found";
260 for (
int i = 0; i < num_elements; i += 2)
262 auto ptr =
tbl.search(i);
268 for (
int i = 1; i < num_elements; i += 2)
269 EXPECT_NE(
tbl.search(i),
nullptr) <<
"Element " << i <<
" not found after removals";
272 for (
int i = 0; i < num_elements; i += 2)
273 EXPECT_EQ(
tbl.search(i),
nullptr) <<
"Element " << i <<
" should be removed";
282 for (
int i = 0; i < 50; ++i)
297 <<
"Capacity changed after failed remove attempts";
303 for (
int i = 0; i < 50; ++i)
304 EXPECT_NE(
tbl.search(i * 2),
nullptr) <<
"Element " << i * 2 <<
" not found";
356 catch (
const domain_error &)
358 FAIL() <<
"Remove threw for key " << key <<
" that was in oracle";
369 auto ptr =
tbl.search(key);
383 ASSERT_NE(
tbl.search(key),
nullptr) <<
"Final: key " << key <<
" missing";
390 const size_t target =
tbl.capacity() - 1;
393 for (
size_t i = 0; i <
target; ++i)
395 auto ptr =
tbl.
insert(
static_cast<int>(i));
396 ASSERT_NE(ptr,
nullptr) <<
"Insert failed at i=" << i;
402 for (
size_t i = 0; i <
target; ++i)
407 iota(keys.begin(), keys.end(), 0);
412 for (
size_t i = 0; i <
target; ++i)
425 auto bad_hash = [](
const int &) ->
size_t {
return 0; };
429 const int num_elements = 50;
430 for (
int i = 0; i < num_elements; ++i)
432 auto ptr =
tbl.insert(i);
433 ASSERT_NE(ptr,
nullptr) <<
"Insert failed at i=" << i;
439 for (
int i = 0; i < num_elements; ++i)
441 auto ptr =
tbl.search(i);
442 ASSERT_NE(ptr,
nullptr) <<
"Element " << i <<
" not found";
447 for (
int i = 0; i < num_elements; ++i)
461 const int cycles = 100;
497 auto ptr =
tbl.insert(key);
498 if (
oracle.count(key) == 0 && ptr !=
nullptr)
506 ASSERT_NE(
tbl.search(key),
nullptr) <<
"Key " << key <<
" lost after resize";
522 for (
int i = 0; i <
num_ops; ++i)
529 auto ptr =
tbl.insert(key);
542 catch (
const domain_error &)
544 FAIL() <<
"Remove threw for key " << key <<
" that was in oracle";
550 auto ptr =
tbl.search(key);
574 auto ptr =
tbl.insert(key);
583 auto ptr =
tbl.search(key);
584 ASSERT_NE(ptr,
nullptr) <<
"Key " << key <<
" lost during resize";
600template <
typename HashTable>
604 for (
size_t i = 0; i <
tbl.capacity(); ++i)
606 switch (
tbl.table[i].status)
608 case HashTable::EMPTY: ++stats.
empty;
break;
609 case HashTable::BUSY: ++stats.
busy;
break;
610 case HashTable::DELETED: ++stats.
deleted;
break;
620 auto bad_hash = [](
const int &) ->
size_t {
return 0; };
625 for (
int i = 0; i < 5; ++i)
637 EXPECT_EQ(
after.deleted, 0) <<
"Last element should become EMPTY, not DELETED";
641 for (
int i = 0; i < 4; ++i)
642 EXPECT_NE(
tbl.search(i),
nullptr) <<
"Element " << i <<
" should still exist";
651 auto bad_hash = [](
const int &) ->
size_t {
return 0; };
655 for (
int i = 0; i < 5; ++i)
685 auto bad_hash = [](
const int &) ->
size_t {
return 0; };
689 for (
int i = 0; i < 5; ++i)
697 EXPECT_EQ(stats.deleted, 1) <<
"Middle element should stay DELETED";
700 for (
int i = 0; i < 5; ++i)
715 const int cycles = 50;
716 const int elements = 30;
721 for (
int i = 0; i < elements; ++i)
725 for (
int i = 0; i < elements; ++i)
732 EXPECT_EQ(stats.deleted, 0) <<
"Should have no DELETED after complete removal";
745 return static_cast<size_t>(
k + 15);
751 for (
int i = 0; i < 5; ++i)
757 for (
int i = 4; i >= 0; --i)
763 EXPECT_EQ(stats.deleted, 0) <<
"Wrap-around cleanup should leave no DELETED";
779 for (
int i = 0; i <
num_ops; ++i)
786 auto ptr =
tbl.insert(key);
789 else if (
oracle.count(key))
802 <<
"DELETED ratio should be low with cleanup. Got "
803 << stats.deleted <<
"/" <<
tbl.capacity();
818 for (
int i = 0; i < 50; ++i)
827 for (
int i = 0; i < 50; ++i)
842 for (
int i = 0; i < 50; ++i)
854 for (
int i = 0; i < 50; ++i)
861 for (
int i = 0; i < 50; ++i)
871 for (
int i = 0; i < 50; ++i)
880 for (
int i = 0; i < 50; ++i)
892 for (
int i = 0; i < 50; ++i)
899 for (
int i = 0; i < 50; ++i)
905 for (
int i = 0; i < 50; ++i)
915 auto bad_hash = [](
const int &) ->
size_t {
return 0; };
919 for (
int i = 0; i < 5; ++i)
952 auto ptr =
tbl.search_or_insert(42);
963 auto ptr =
tbl.search_or_insert(42);
973 auto [ptr,
existed] =
tbl.contains_or_insert(42);
985 auto [ptr,
existed] =
tbl.contains_or_insert(42);
1001 for (
int i = 0; i < 50; ++i)
1008 for (
int i = 0; i < 50; i += 2)
1022 EXPECT_EQ(
after.deleted, 0) <<
"Rehash should eliminate all DELETED";
1034 for (
int i = 0; i < 30; ++i)
1043 for (
int i = 0; i < 30; ++i)
1051 for (
int i = 0; i < 30; ++i)
1058 for (
int i = 0; i < 30; ++i)
1100 auto first =
tbl.insert(42);
1104 EXPECT_EQ(
second,
nullptr) <<
"Duplicate insert should return nullptr";
1146 for (
int i = 0; i < 50; ++i)
1153 for (
auto it =
tbl.get_it(); it.has_curr(); it.next())
1163 auto it =
tbl.get_it();
1172 auto it =
tbl.get_it();
1184 for (
int i = 0; i < 10; ++i)
1188 auto it =
tbl.get_it();
1189 while (it.has_curr())
1201 auto bad_hash = [](
const int &) ->
size_t {
return 0; };
1205 for (
int i = 0; i < 10; ++i)
1213 auto stats =
tbl.stats();
1217 EXPECT_EQ(stats.num_busy + stats.num_deleted + stats.num_empty,
tbl.capacity());
1227 for (
int i = 0; i < 10; ++i)
1231 tbl.for_each([&
sum](
int x) {
sum += x; });
1239 for (
int i = 0; i < 10; ++i)
1249 for (
int i = 0; i < 10; ++i)
1259 for (
int i = 0; i < 10; ++i)
T & insert(const T &item)
Insert a new item by copy.
T remove()
Remove the first item of the list.
void empty() noexcept
empty the list
constexpr bool is_empty() const noexcept
Return true if list is empty.
size_t size() const noexcept
Count the number of elements of the list.
Open addressing hash table with linear probing collision resolution.
Aleph::DynList< T > filter(Operation &operation) const
Filter the elements of a container according to a matching criteria.
Key * insert(const Key &key)
Inserts a key into the hash table (copy version).
MapOLhash< int, Foo > tbl
Main namespace for Aleph-w library functions.
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
size_t dft_hash_fct(const Key &key) noexcept
auto shuffle(const C< T > &c)
Randomly shuffle a sequence.
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
DynList< T > maps(const C &c, Op op)
Classic map operation.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
size_t my_hash(const MyRecord &r) noexcept
BucketStats count_bucket_states(const HashTable &tbl)
bool operator()(const MyRecord &r1, const MyRecord &r2) const noexcept
bool operator==(const MyRecord &r) const noexcept
MyRecord(size_t k, const string &v)
Open addressing hash table with linear probing.