Skip to content
Snippets Groups Projects
Commit b56a1130 authored by David Nieder's avatar David Nieder
Browse files

hashtable as template class + tests

parent ac0b3d15
No related branches found
No related tags found
No related merge requests found
......@@ -8,56 +8,58 @@
* hashing by division
*/
template<typename T>
struct DivHashing {
const size_t m;
class DivHashing {
public:
DivHashing(size_t table_size) : m(table_size) {}
size_t operator()(T key) { return key % m; }
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;
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
#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++) {
for (size_t i=0; i<slot_count; i++) {
Slot<T> &os = table[i];
// that store a key ...
// that currently store a key ...
if (os.label == Slot<T>::used) {
unsigned hk = hash(os.key);
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)];
// and insert the key
if (ns.label == Slot<T>::vacant) {
ns.key = os.key;
ns.label = Slot<T>::used;
insert_count++;
break;
}
}
}
}
// 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;
}
#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
......@@ -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);
}
}
#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;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment