37# include <gtest/gtest.h>
46using namespace testing;
56 const size_t cap =
tbl.capacity();
57 for (
size_t i = 0; i < cap; ++i)
65 for (
size_t i = 0; i <
tbl.size(); ++i)
68 auto ptr =
tbl.search(i);
73 for (
size_t i = 0, n =
tbl.size(); i < n; ++i)
75 auto ptr =
tbl.search(i);
98 return r1.key == r2.key;
122 for (
size_t i = 0; i < 100; ++i)
133 for (
size_t i = 0, n =
tbl.size(); i < n; ++i)
135 auto ptr =
tbl.search(i);
150 auto *bucket =
decltype(
tbl)::key_to_bucket(ptr);
167 const int num_elements = 50;
168 for (
int i = 0; i < num_elements; ++i)
175 for (
int i = 0; i < 10; ++i)
183 <<
"Table size should not change after failed remove attempts";
186 for (
int i = 0; i < num_elements; ++i)
188 auto ptr =
tbl.search(i * 2);
190 <<
"Element " << i * 2 <<
" should still be in the table";
196 for (
int i = 0; i < num_elements; ++i)
198 auto ptr =
tbl.search(i * 2);
213 for (
int i = 0; i < 20; ++i)
225 for (
int i = 0; i < 20; ++i)
227 if (i == 10)
continue;
228 EXPECT_NE(
tbl.search(i),
nullptr) <<
"Element " << i <<
" should still exist";
238 for (
int i = 0; i < 20; ++i)
244 auto ptr =
tbl.search(10);
259 for (
int i = 0; i < 50; ++i)
275 <<
"Capacity changed - possible unnecessary rehash on failed remove";
281 for (
int i = 0; i < 50; ++i)
282 EXPECT_NE(
tbl.search(i * 2),
nullptr) <<
"Element " << i * 2 <<
" not found";
316 <<
" but oracle already had it";
322 <<
" but oracle didn't have it";
336 catch (
const domain_error &)
338 FAIL() <<
"Remove threw for key " << key <<
" that was in oracle";
349 auto ptr =
tbl.search(key);
352 <<
"Search mismatch for key " << key;
360 <<
"Size mismatch at operation " << i <<
", key=" << key;
366 auto ptr =
tbl.search(key);
367 ASSERT_NE(ptr,
nullptr) <<
"Final check: key " << key <<
" missing";
375 const size_t target =
tbl.capacity() - 1;
378 for (
size_t i = 0; i <
target; ++i)
380 auto ptr =
tbl.
insert(
static_cast<int>(i));
381 ASSERT_NE(ptr,
nullptr) <<
"Insert failed at i=" << i;
387 for (
size_t i = 0; i <
target; ++i)
390 <<
"Element " << i <<
" not found after fill";
395 iota(keys.begin(), keys.end(), 0);
400 for (
size_t i = 0; i <
target; ++i)
413 auto bad_hash = [](
const int &) ->
size_t {
return 42; };
418 const int num_elements = 50;
419 for (
int i = 0; i < num_elements; ++i)
421 auto ptr =
tbl.insert(i);
422 ASSERT_NE(ptr,
nullptr) <<
"Insert failed at i=" << i <<
" with bad hash";
428 for (
int i = 0; i < num_elements; ++i)
430 auto ptr =
tbl.search(i);
431 ASSERT_NE(ptr,
nullptr) <<
"Element " << i <<
" not found with collision";
436 for (
int i = num_elements - 1; i >= 0; --i)
450 const int cycles = 100;
460 ASSERT_NE(ptr,
nullptr) <<
"Insert failed at cycle " <<
cycle <<
", i=" << i;
491 auto ptr =
tbl.insert(key);
492 if (
oracle.count(key) == 0 && ptr !=
nullptr)
501 auto ptr =
tbl.search(key);
502 ASSERT_NE(ptr,
nullptr) <<
"Key " << key <<
" lost after resize";
508 for (
size_t i = 0; i <
to_remove; ++i, ++it)
519 ASSERT_NE(
tbl.search(key),
nullptr) <<
"Key " << key <<
" missing after partial remove";
536 for (
int i = 0; i <
num_ops; ++i)
543 auto ptr =
tbl.insert(key);
556 catch (
const domain_error &)
558 FAIL() <<
"Remove threw for key " << key <<
" that was in oracle";
564 auto ptr =
tbl.search(key);
567 <<
"Search mismatch for key " << key;
594 auto ptr =
tbl.insert(key);
605 auto ptr =
tbl.search(key);
606 ASSERT_NE(ptr,
nullptr) <<
"Key " << key <<
" lost during resize";
642 for (
int i = 0; i < len; ++i)
649 for (
int i = 0; i <
num_ops; ++i)
653 if (
oracle.count(key) == 0)
655 auto ptr =
tbl.insert(key);
670 for (
const auto & key :
oracle)
672 auto ptr =
tbl.search(key);
673 ASSERT_NE(ptr,
nullptr) <<
"String key missing: " << key;
683 for (
int i = 0; i < 30; ++i)
687 for (
int i = 0; i < 30; i += 2)
693 for (
int i = 1; i < 30; i += 2)
695 auto ptr =
tbl.search_or_insert(i);
702 for (
int i = 0; i < 30; i += 2)
705 auto ptr =
tbl.search_or_insert(i);
712 for (
int i = 0; i < 30; ++i)
714 auto ptr =
tbl.search(i);
715 ASSERT_NE(ptr,
nullptr) <<
"Key " << i <<
" not found";
723 auto bad_hash = [](
const int &) ->
size_t {
return 7; };
728 for (
int i = 0; i < 20; ++i)
731 for (
int i = 0; i < 20; i += 3)
735 for (
int i = 20; i < 30; ++i)
737 auto [ptr,
existed] =
tbl.contains_or_insert(i);
744 for (
int i = 20; i < 30; ++i)
746 auto [ptr,
existed] =
tbl.contains_or_insert(i);
758 std::mt19937
gen(54321);
759 std::uniform_int_distribution<>
key_dist(0, 500);
760 std::uniform_int_distribution<>
op_dist(0, 2);
769 auto ptr =
tbl.search_or_insert(key);
770 ASSERT_NE(ptr,
nullptr) <<
"search_or_insert returned nullptr for key " << key;
776 <<
"Key " << key <<
" not found immediately after search_or_insert at iter " <<
iter;
778 else if (op == 1 &&
oracle.count(key))
783 <<
"Key " << key <<
" should exist before removal at iter " <<
iter
784 <<
", oracle.count=" <<
oracle.count(key) <<
", tbl.size=" <<
tbl.
size();
790 auto ptr =
tbl.search(key);
792 ASSERT_NE(ptr,
nullptr) <<
"Key " << key <<
" should exist at iter " <<
iter;
804 auto ptr =
tbl.search(key);
805 ASSERT_NE(ptr,
nullptr) <<
"Key " << key <<
" missing";
814 std::mt19937
gen(54321);
815 std::uniform_int_distribution<>
key_dist(0, 500);
816 std::uniform_int_distribution<>
op_dist(0, 2);
827 auto p =
tbl.search(
k);
829 <<
"Pre-op check: Key " <<
k <<
" missing at iter " <<
iter
830 <<
" (about to do op " << op <<
" on key " << key <<
")";
837 auto ptr =
tbl.search_or_insert(key);
838 ASSERT_NE(ptr,
nullptr) <<
"search_or_insert returned nullptr at iter " <<
iter;
844 <<
"Size should increase for new key at iter " <<
iter;
846 else if (op == 1 &&
oracle.count(key))
853 <<
"Size mismatch at iter " <<
iter;
864 for (
int i = 0; i < 50; ++i)
872 for (
int i = 0; i < 50; ++i)
886 for (
int i = 0; i < 50; ++i)
897 for (
int i = 0; i < 50; ++i)
904 for (
int i = 0; i < 50; ++i)
914 for (
int i = 0; i < 50; ++i)
923 for (
int i = 0; i < 50; ++i)
935 for (
int i = 0; i < 50; ++i)
942 for (
int i = 0; i < 50; ++i)
948 for (
int i = 0; i < 50; ++i)
986 auto first =
tbl.insert(42);
1032 for (
int i = 0; i < 50; ++i)
1038 for (
int i = 0; i < 50; i += 2)
1056 for (
int i = 0; i < 30; ++i)
1065 for (
int i = 0; i < 30; ++i)
1073 for (
int i = 0; i < 30; ++i)
1080 for (
int i = 0; i < 30; ++i)
1093 for (
int i = 0; i < 50; ++i)
1100 for (
auto it =
tbl.get_it(); it.has_curr(); it.next())
1110 auto it =
tbl.get_it();
1119 auto it =
tbl.get_it();
1131 for (
int i = 0; i < 10; ++i)
1134 auto it =
tbl.get_it();
1135 while (it.has_curr())
1153template <
typename HashTable>
1157 for (
size_t i = 0; i <
tbl.capacity(); ++i)
1159 switch (
tbl.table[i].status)
1161 case HashTable::EMPTY: ++stats.
empty;
break;
1162 case HashTable::BUSY: ++stats.
busy;
break;
1163 case HashTable::DELETED: ++stats.
deleted;
break;
1172 auto bad_hash = [](
const int &) ->
size_t {
return 0; };
1176 for (
int i = 0; i < 5; ++i)
1189 EXPECT_EQ(
after.deleted, 0) <<
"Last element should become EMPTY via probe_counter";
1191 for (
int i = 0; i < 4; ++i)
1198 auto bad_hash = [](
const int &) ->
size_t {
return 0; };
1201 for (
int i = 0; i < 5; ++i)
1209 EXPECT_EQ(stats.deleted, 1) <<
"Middle should stay DELETED";
1211 for (
int i = 0; i < 5; ++i)
1222 auto bad_hash = [](
const int &) ->
size_t {
return 0; };
1225 for (
int i = 0; i < 5; ++i)
1229 for (
int i = 4; i >= 0; --i)
1234 EXPECT_EQ(stats.deleted, 0) <<
"All should become EMPTY when removed in reverse";
1245 for (
int i = 0; i < 10; ++i)
1249 tbl.for_each([&
sum](
int x) {
sum += x; });
1257 for (
int i = 0; i < 10; ++i)
1267 for (
int i = 0; i < 10; ++i)
1277 for (
int i = 0; i < 10; ++i)
static string random_string(std::mt19937 &rng, size_t len)
T & insert(const T &item)
Insert a new item by copy.
T remove()
Remove the first item of the list.
size_t size() const noexcept
Count the number of elements of the list.
Open addressing hash table with double hashing 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).
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
MapOLhash< int, Foo > tbl
Main namespace for Aleph-w library functions.
size_t snd_hash_fct(const Key &key) noexcept
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 snd_hash(const MyRecord &r) noexcept
size_t fst_hast(const MyRecord &r) noexcept
ODhashBucketStats count_odhash_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 double hashing.