diff --git a/src/hashing.h b/src/hashing.h index 3551d6862151aab80ea1600dabeecb5d74f655b9..5773504962e0a61c523cb366de12cb76dba66c53 100644 --- a/src/hashing.h +++ b/src/hashing.h @@ -8,56 +8,58 @@ * hashing by division */ template<typename T> -struct DivHashing { - const size_t m; - DivHashing(size_t table_size) : m(table_size) {} - - size_t operator()(T key) { return key % m; } +class DivHashing { + public: + DivHashing(size_t table_size) : m(table_size) {} + size_t operator()(T key) const { return key % m; } + private: + size_t m; }; /* * hashing by multiplication */ template<typename T> -struct MulHashing { - const double gratio = 0.61803; - const size_t m; - MulHashing(size_t table_size) : m(table_size) {} - - size_t operator()(T key) { return m * (gratio*key - std::floor(gratio*key)); } +class MulHashing { + public: + MulHashing(size_t table_size) : m(table_size) {} + size_t operator()(T key) { return m * (gratio*key - std::floor(gratio*key)); } + private: + double gratio = 0.61803; + size_t m; }; /* * linear probing */ -struct LinearProbing { - const size_t h; - const size_t m; - LinearProbing(size_t hash, size_t table_size) : h(hash), m(table_size) {} - - size_t operator()(size_t i) { return (h+i) % m; } +class LinearProbing { + public: + LinearProbing(size_t table_size) : m(table_size) {} + size_t operator()(size_t h, size_t i) const { return (h+i) % m; } + private: + size_t m; }; /* * quadratic probing */ -struct QuadraticProbing { - const size_t h; - const size_t m; - QuadraticProbing(size_t hash, size_t table_size) : h(hash), m(table_size) {} - - size_t operator()(size_t i) { return (h + i*i) % m; } +class QuadraticProbing { + public: + QuadraticProbing(size_t table_size) : m(table_size) {} + size_t operator()(size_t h, size_t i) { return (h + i*i) % m; } + private: + size_t m; }; /* * double hashing */ -struct DoubleHashing { - const size_t h; - const size_t m; - DoubleHashing(size_t hash, size_t table_size) : h(hash), m(table_size) {} - - size_t operator()(size_t i) { return (h + i*(h+1)) % m; } +class DoubleHashing { + public: + DoubleHashing(size_t table_size) : m(table_size) {} + size_t operator()(size_t h, size_t i) { return (h + i*(2*h+1)) % m; } + private: + size_t m; }; #endif diff --git a/src/hashtable.cpp b/src/hashtable.cpp index 55c47d839ebbc669ad76481f924f198869785e0d..ea7d00acd5fa24c8a5db6134219f7285447873a7 100644 --- a/src/hashtable.cpp +++ b/src/hashtable.cpp @@ -1,26 +1,23 @@ #include <cmath> -#include <cassert> -#include <iostream> #include <stdexcept> #include "hashtable.h" -template <typename T> -Hashtable<T>::Hashtable(size_t m, float alpha, float s): - slot_count(m), max_loadfactor(alpha), growfactor(s), table(new Slot<T>[m]) +template <typename T, typename H, typename P> +Hashtable<T,H,P>::Hashtable(size_t m, float alpha, float s): + slot_count(m), max_loadfactor(alpha), growfactor(s), table(new Slot<T>[m]), + hash(H(m)), probe(P(m)) { - if (!(0 < alpha && alpha < 1)) throw std::invalid_argument("load factor alpha must be in range (0;1)"); if (!(s > 1)) throw std::invalid_argument("grow factor s must be greater 1"); } -template <typename T> -bool Hashtable<T>::insert(T key) { +template <typename T, typename H, typename P> +bool Hashtable<T,H,P>::insert(T key) { // Grow the table if inserting would exceed the load factor. - // If the key is already in the table this could grow the table unnecessarily once. if (slot_count == 0 || (element_count+1.0f)/slot_count > max_loadfactor) grow(); @@ -42,13 +39,15 @@ bool Hashtable<T>::insert(T key) { } } - // If the probing strategy permutates {0,...,m-1} the for-loop - // visits every slot and will find an empty one eventually. - throw std::logic_error("will we ever reach here?"); + // If we did not reach a "return" during the for-loop, we could not find a + // slot for the key. Grow the table and try again. + grow(); + return insert(key); } -template <typename T> -bool Hashtable<T>::remove(T key) { + +template <typename T, typename H, typename P> +bool Hashtable<T,H,P>::remove(T key) { if (slot_count == 0) return false; // table is empty @@ -58,6 +57,7 @@ bool Hashtable<T>::remove(T key) { if (slot.label == Slot<T>::vacant) { // found a vacant slot: key is not in table + return false; break; } @@ -72,8 +72,8 @@ bool Hashtable<T>::remove(T key) { return false; } -template <typename T> -bool Hashtable<T>::contains(T key) { +template <typename T, typename H, typename P> +bool Hashtable<T,H,P>::contains(T key) { if (slot_count == 0) return false; // table is empty @@ -87,6 +87,7 @@ bool Hashtable<T>::contains(T key) { } if (slot.label == Slot<T>::used && slot.key == key) { + // found the key return true; } } @@ -94,73 +95,96 @@ bool Hashtable<T>::contains(T key) { return false; } -template <typename T> -float Hashtable<T>::load_factor() const { +template <typename T, typename H, typename P> +float Hashtable<T,H,P>::load_factor() const { return slot_count == 0 ? 0 : static_cast<float>(element_count)/slot_count; } -template <typename T> -inline size_t Hashtable<T>::hash(T key) { - assert(slot_count != 0); - return key % slot_count; -} +template <typename T, typename H, typename P> +void Hashtable<T,H,P>::grow() { + size_t new_capacity = std::ceil(growfactor * (slot_count==0 ? 1 : slot_count)); -template <typename T> -inline size_t Hashtable<T>::probe(size_t h, size_t i) { - assert(slot_count != 0); - return (h+i) % slot_count; -} + while (true) { + // allocate space for new table + Slot<T> *new_table = new Slot<T>[new_capacity]; + + // new table, new hash/probe functions + auto new_hash = H(new_capacity); + auto new_probe = P(new_capacity); -template <typename T> -void Hashtable<T>::grow() { - size_t old_capacity = slot_count; - slot_count = std::ceil(growfactor * (slot_count==0 ? 1 : slot_count)); - Slot<T> *const new_table = new Slot<T>[slot_count]; + // keeps track of the number of inserts into the new table + size_t insert_count = 0; - // for all slots in the old table ... - for (size_t i=0; i<old_capacity; i++) { - Slot<T> &os = table[i]; + // for all slots in the old table ... + for (size_t i=0; i<slot_count; i++) { + Slot<T> &os = table[i]; - // that store a key ... - if (os.label == Slot<T>::used) { - unsigned hk = hash(os.key); + // that currently store a key ... + if (os.label == Slot<T>::used) { + size_t hk = new_hash(os.key); - // find a slot in the new table - for (size_t j=0; j<slot_count; j++) { - Slot<T> &ns = new_table[probe(hk, j)]; + // find a slot in the new table ... + for (size_t j=0; j<new_capacity; j++) { + Slot<T> &ns = new_table[new_probe(hk, j)]; - if (ns.label == Slot<T>::vacant) { - ns.key = os.key; - ns.label = Slot<T>::used; - break; + // and insert the key + if (ns.label == Slot<T>::vacant) { + ns.key = os.key; + ns.label = Slot<T>::used; + insert_count++; + break; + } } } } - } - table.reset(new_table); // smart_ptr frees the old table + // It is possible that not all keys were transferred into the new table. + // This can happen if the probing strategy does not try all/enough slots + // (e.g. quadratic/double hashing with bad table sizes (not prime) or + // high load factor/small grow factor combinations). + // In such a case we grow the table again. + if (insert_count != element_count) { + new_capacity = std::ceil(growfactor*new_capacity); + delete[] new_table; + continue; + } + + slot_count = new_capacity; + hash = new_hash; + probe = new_probe; + table.reset(new_table); // smart_ptr frees the old table + return; + } } -template <typename T> -void Hashtable<T>::info() const { - std::cerr << "size: " << size() << ", capacity: " << capacity() - << ", alpha (current/max): " << load_factor() << "/" << max_loadfactor << std::endl; - std::cerr << "array size: " << slot_count*sizeof(Slot<T>)/1024 << "kB, start: " - << table.get() << ", end: " << table.get()+slot_count << std::endl; +template <typename T, typename H, typename P> +std::string Hashtable<T,H,P>::info() const { + std::string s; + s += "size: " + std::to_string(size()); + s += ", capacity: " + std::to_string(capacity()); + s += ", alpha: " + std::to_string(load_factor()); + + return s; } -template <typename T> -void Hashtable<T>::print() const { +template <typename T, typename H, typename P> +std::string Hashtable<T,H,P>::print() const { + std::string s; + for (size_t i=0; i<slot_count; i+=10) { - std::cerr << i << ": "; + s += std::to_string(i) + ": "; + for (size_t j=i; j<i+10 && j<slot_count; j++) { - const Slot<T> &s = table[j]; std::string repr; - if (s.label == Slot<T>::vacant) repr = "F"; - else if(s.label == Slot<T>::deleted) repr = "D"; - else repr = std::to_string(s.key); - std::cerr << repr << " "; + + if (table[j].label == Slot<T>::vacant) repr = "F "; + else if(table[j].label == Slot<T>::deleted) repr = "D "; + else repr = std::to_string(table[j].key) + " "; + s += repr; } - std::cerr << std::endl; + + s += "\n"; } + + return s; } diff --git a/src/hashtable.h b/src/hashtable.h index a61e90191699c9e8de1a28fddbde264d6cc4c24c..1d394a99bae945f7f904c00cab22eaf31365016d 100644 --- a/src/hashtable.h +++ b/src/hashtable.h @@ -1,21 +1,17 @@ #ifndef HASHTABLE_H #define HASHTABLE_H +#include <string> #include <memory> +#include "hashing.h" -template<typename T> class Hashtable; -/* a bucket of size 1 */ -template <typename T> -class Slot { - T key; - enum: char { vacant, deleted, used } label = vacant; +template<typename T, typename H, typename P> class Hashtable; +template<typename T> class Slot; - friend Hashtable<T>; -}; -template <typename T> +template <typename T, typename H = DivHashing<T>, typename P = LinearProbing> class Hashtable { public: Hashtable(size_t m=8, float alpha=0.75, float s=2.0); @@ -27,8 +23,8 @@ class Hashtable { size_t capacity() const { return slot_count; } float load_factor() const; - void info() const; - void print() const; + std::string info() const; + std::string print() const; private: size_t element_count = 0; size_t slot_count; @@ -36,16 +32,28 @@ class Hashtable { const float growfactor; std::unique_ptr<Slot<T>[]> table; - size_t hash(T key); - size_t probe(size_t h, size_t i); + H hash; + P probe; + void grow(); }; +/* a bucket of size 1 */ +template <typename T> +class Slot { + T key; + enum: char { vacant, deleted, used } label = vacant; + + template <typename TT, typename H, typename P> friend class Hashtable; +}; + // declare some template instantiations explicitly // so they are included in the shared library -template class Hashtable<unsigned int>; -template class Hashtable<unsigned long>; -template class Hashtable<unsigned short>; -template class Hashtable<unsigned char>; +template class Hashtable<unsigned int, DivHashing<unsigned int>, LinearProbing>; +template class Hashtable<unsigned int, DivHashing<unsigned int>, QuadraticProbing>; +template class Hashtable<unsigned int, DivHashing<unsigned int>, DoubleHashing>; +template class Hashtable<unsigned int, MulHashing<unsigned int>, LinearProbing>; +template class Hashtable<unsigned int, MulHashing<unsigned int>, QuadraticProbing>; +template class Hashtable<unsigned int, MulHashing<unsigned int>, DoubleHashing>; #endif diff --git a/tests/test_hashing.cpp b/tests/test_hashing.cpp index 719b9588e121fe9102b4ddb0e3ebd6d6d340c0b4..45f17104df280e8b9b678c852c3cefeb0451660a 100644 --- a/tests/test_hashing.cpp +++ b/tests/test_hashing.cpp @@ -39,64 +39,64 @@ TEST(hashing, MulHashing) { } TEST(hashing, LinearProbing) { - LinearProbing p0(2, 1); - LinearProbing p1(4, 512); - LinearProbing p2(0, 8); - LinearProbing p3(7, 32); - LinearProbing p4(16, 6899); + LinearProbing p0(1); + LinearProbing p1(512); + LinearProbing p2(8); + LinearProbing p3(32); + LinearProbing p4(6899); for (unsigned i=0; i<10000; i++) { - EXPECT_LT(p0(i), 1); - EXPECT_EQ(p0(i), (2+i)%1); - EXPECT_LT(p1(i), 512); - EXPECT_EQ(p1(i), (4+i)%512); - EXPECT_LT(p2(i), 8); - EXPECT_EQ(p2(i), (0+i)%8); - EXPECT_LT(p3(i), 32); - EXPECT_EQ(p3(i), (7+i)%32); - EXPECT_LT(p4(i), 6899); - EXPECT_EQ(p4(i), (16+i)%6899); + EXPECT_LT(p0(2,i), 1); + EXPECT_EQ(p0(2,i), (2+i)%1); + EXPECT_LT(p1(4,i), 512); + EXPECT_EQ(p1(4,i), (4+i)%512); + EXPECT_LT(p2(0,i), 8); + EXPECT_EQ(p2(0,i), (0+i)%8); + EXPECT_LT(p3(7,i), 32); + EXPECT_EQ(p3(7,i), (7+i)%32); + EXPECT_LT(p4(16,i), 6899); + EXPECT_EQ(p4(16,i), (16+i)%6899); } } TEST(hashing, QuadraticProbing) { - QuadraticProbing p0(2, 1); - QuadraticProbing p1(4, 512); - QuadraticProbing p2(0, 8); - QuadraticProbing p3(7, 32); - QuadraticProbing p4(16, 6899); + QuadraticProbing p0(1); + QuadraticProbing p1(512); + QuadraticProbing p2(8); + QuadraticProbing p3(32); + QuadraticProbing p4(6899); for (unsigned i=0; i<10000; i++) { - EXPECT_LT(p0(i), 1); - EXPECT_EQ(p0(i), (2+i*i)%1); - EXPECT_LT(p1(i), 512); - EXPECT_EQ(p1(i), (4+i*i)%512); - EXPECT_LT(p2(i), 8); - EXPECT_EQ(p2(i), (0+i*i)%8); - EXPECT_LT(p3(i), 32); - EXPECT_EQ(p3(i), (7+i*i)%32); - EXPECT_LT(p4(i), 6899); - EXPECT_EQ(p4(i), (16+i*i)%6899); + EXPECT_LT(p0(2,i), 1); + EXPECT_EQ(p0(2,i), (2+i*i)%1); + EXPECT_LT(p1(4,i), 512); + EXPECT_EQ(p1(4,i), (4+i*i)%512); + EXPECT_LT(p2(0,i), 8); + EXPECT_EQ(p2(0,i), (0+i*i)%8); + EXPECT_LT(p3(7,i), 32); + EXPECT_EQ(p3(7,i), (7+i*i)%32); + EXPECT_LT(p4(16,i), 6899); + EXPECT_EQ(p4(16,i), (16+i*i)%6899); } } TEST(hashing, DoubleHashing) { - DoubleHashing p0(2, 1); - DoubleHashing p1(4, 512); - DoubleHashing p2(0, 8); - DoubleHashing p3(7, 32); - DoubleHashing p4(16, 6899); + DoubleHashing p0(1); + DoubleHashing p1(512); + DoubleHashing p2(8); + DoubleHashing p3(32); + DoubleHashing p4(6899); for (unsigned i=0; i<10000; i++) { - EXPECT_LT(p0(i), 1); - EXPECT_EQ(p0(i), (2+i*(2+1))%1); - EXPECT_LT(p1(i), 512); - EXPECT_EQ(p1(i), (4+i*(4+1))%512); - EXPECT_LT(p2(i), 8); - EXPECT_EQ(p2(i), (0+i*(0+1))%8); - EXPECT_LT(p3(i), 32); - EXPECT_EQ(p3(i), (7+i*(7+1))%32); - EXPECT_LT(p4(i), 6899); - EXPECT_EQ(p4(i), (16+i*(16+1))%6899); + EXPECT_LT(p0(2,i), 1); + EXPECT_EQ(p0(2,i), (2+i*(2*2+1))%1); + EXPECT_LT(p1(4,i), 512); + EXPECT_EQ(p1(4,i), (4+i*(2*4+1))%512); + EXPECT_LT(p2(0,i), 8); + EXPECT_EQ(p2(0,i), (0+i*(2*0+1))%8); + EXPECT_LT(p3(7,i), 32); + EXPECT_EQ(p3(7,i), (7+i*(2*7+1))%32); + EXPECT_LT(p4(16,i), 6899); + EXPECT_EQ(p4(16,i), (16+i*(2*16+1))%6899); } } diff --git a/tests/test_hashtable.cpp b/tests/test_hashtable.cpp index a21c0a2b16717d589aa1a779c2136bbacc0c6ce7..ff45f8467c5fd8db01d3e059821bc121e1d918e7 100644 --- a/tests/test_hashtable.cpp +++ b/tests/test_hashtable.cpp @@ -1,63 +1,102 @@ #include <gtest/gtest.h> -#include <iostream> -#include <utility> +#include <cstdlib> +#include <tuple> #include "hashtable.h" #include "argumentTypes.h" -using std::pair; +using std::tuple; template<typename T> class HashtableTest : public testing::Test { public: - using keytype = typename T::first_type; - using argtype = typename T::second_type; + using keytype = typename std::tuple_element<0, T>::type; + using hashfunc = typename std::tuple_element<1, T>::type; + using probefunc = typename std::tuple_element<2, T>::type; + using argtype = typename std::tuple_element<3, T>::type; - Hashtable<keytype> *table; + Hashtable<keytype,hashfunc,probefunc> *table; argtype args; HashtableTest() { - table = new Hashtable<keytype>(args.m, args.a, args.s); + table = new Hashtable<keytype,hashfunc,probefunc>(args.m, args.a, args.s); } ~HashtableTest() override { delete table; } }; +/* + * run the tests against hashtables created with different combinations of + * keytype, hash function, probing strategy and constructor arguments + */ using AllTheTypes = ::testing::Types< - pair<unsigned int,DefaultTable>, - pair<unsigned int,EmptyTable>, - pair<unsigned int,BigTable>, - pair<unsigned int,SmallAlphaDefaultS>, - pair<unsigned int,SmallAlphaTinyS>, - pair<unsigned int,SmallAlphaSmallS>, - pair<unsigned int,SmallAlphaLargeS>, - pair<unsigned int,LargeAlphaDefaultS>, - pair<unsigned int,LargeAlphaTinyS>, - pair<unsigned int,LargeAlphaSmallS>, - pair<unsigned int,LargeAlphaLargeS>, - pair<unsigned short,DefaultTable>, - pair<unsigned short,EmptyTable>, - pair<unsigned short,BigTable>, - pair<unsigned short,SmallAlphaDefaultS>, - pair<unsigned short,SmallAlphaTinyS>, - pair<unsigned short,SmallAlphaSmallS>, - pair<unsigned short,SmallAlphaLargeS>, - pair<unsigned short,LargeAlphaDefaultS>, - pair<unsigned short,LargeAlphaTinyS>, - pair<unsigned short,LargeAlphaSmallS>, - pair<unsigned short,LargeAlphaLargeS>, - pair<unsigned long,DefaultTable>, - pair<unsigned long,EmptyTable>, - pair<unsigned long,BigTable>, - pair<unsigned long,SmallAlphaDefaultS>, - pair<unsigned long,SmallAlphaTinyS>, - pair<unsigned long,SmallAlphaSmallS>, - pair<unsigned long,SmallAlphaLargeS>, - pair<unsigned long,LargeAlphaDefaultS>, - pair<unsigned long,LargeAlphaTinyS>, - pair<unsigned long,LargeAlphaSmallS>, - pair<unsigned long,LargeAlphaLargeS> + tuple<unsigned,DivHashing<unsigned>,LinearProbing,DefaultTable>, + tuple<unsigned,DivHashing<unsigned>,LinearProbing,EmptyTable>, + tuple<unsigned,DivHashing<unsigned>,LinearProbing,BigTable>, + tuple<unsigned,DivHashing<unsigned>,LinearProbing,SmallAlphaDefaultS>, + tuple<unsigned,DivHashing<unsigned>,LinearProbing,SmallAlphaTinyS>, + tuple<unsigned,DivHashing<unsigned>,LinearProbing,SmallAlphaSmallS>, + tuple<unsigned,DivHashing<unsigned>,LinearProbing,SmallAlphaLargeS>, + tuple<unsigned,DivHashing<unsigned>,LinearProbing,LargeAlphaDefaultS>, + tuple<unsigned,DivHashing<unsigned>,LinearProbing,LargeAlphaTinyS>, + tuple<unsigned,DivHashing<unsigned>,LinearProbing,LargeAlphaSmallS>, + tuple<unsigned,DivHashing<unsigned>,LinearProbing,LargeAlphaLargeS>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,DefaultTable>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,EmptyTable>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,BigTable>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,SmallAlphaDefaultS>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,SmallAlphaTinyS>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,SmallAlphaSmallS>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,SmallAlphaLargeS>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,LargeAlphaDefaultS>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,LargeAlphaTinyS>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,LargeAlphaSmallS>, + tuple<unsigned,DivHashing<unsigned>,QuadraticProbing,LargeAlphaLargeS>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,DefaultTable>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,EmptyTable>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,BigTable>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,SmallAlphaDefaultS>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,SmallAlphaTinyS>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,SmallAlphaSmallS>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,SmallAlphaLargeS>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,LargeAlphaDefaultS>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,LargeAlphaTinyS>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,LargeAlphaSmallS>, + tuple<unsigned,DivHashing<unsigned>,DoubleHashing,LargeAlphaLargeS>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,DefaultTable>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,EmptyTable>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,BigTable>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,SmallAlphaDefaultS>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,SmallAlphaTinyS>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,SmallAlphaSmallS>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,SmallAlphaLargeS>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,LargeAlphaDefaultS>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,LargeAlphaTinyS>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,LargeAlphaSmallS>, + tuple<unsigned,MulHashing<unsigned>,LinearProbing,LargeAlphaLargeS>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,DefaultTable>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,EmptyTable>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,BigTable>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,SmallAlphaDefaultS>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,SmallAlphaTinyS>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,SmallAlphaSmallS>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,SmallAlphaLargeS>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,LargeAlphaDefaultS>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,LargeAlphaTinyS>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,LargeAlphaSmallS>, + tuple<unsigned,MulHashing<unsigned>,QuadraticProbing,LargeAlphaLargeS>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,DefaultTable>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,EmptyTable>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,BigTable>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,SmallAlphaDefaultS>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,SmallAlphaTinyS>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,SmallAlphaSmallS>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,SmallAlphaLargeS>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,LargeAlphaDefaultS>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,LargeAlphaTinyS>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,LargeAlphaSmallS>, + tuple<unsigned,MulHashing<unsigned>,DoubleHashing,LargeAlphaLargeS> >; TYPED_TEST_SUITE(HashtableTest, AllTheTypes); @@ -93,6 +132,35 @@ TYPED_TEST(HashtableTest, InsertExisting) { EXPECT_EQ(false, table.insert(575)); } +TYPED_TEST(HashtableTest, InsertRandom) { + auto &table = *this->table; + + std::srand(2342); + for (unsigned i=0; i<4096; i++) { + EXPECT_EQ(true, table.insert(std::rand())); + } + + std::srand(2342); + for (unsigned i=0; i<4096; i++) { + EXPECT_EQ(true, table.contains(std::rand())); + } + + std::srand(2342); + for (unsigned i=0; i<4096; i++) { + EXPECT_EQ(false, table.insert(std::rand())); + } + + std::srand(2342); + for (unsigned i=0; i<4096; i++) { + EXPECT_EQ(true, table.remove(std::rand())); + } + + std::srand(2342); + for (unsigned i=0; i<4096; i++) { + EXPECT_EQ(false, table.contains(std::rand())); + } +} + TYPED_TEST(HashtableTest, RemoveFromEmpty) { auto &table = *this->table;