Skip to content
Permalink
Browse files

Use separate lists for Hashtable buckets and entries

  • Loading branch information...
bobbymcr committed Jun 8, 2019
1 parent a2913f1 commit efa79c657bae6dfea28e5d13db5379b487617b41
Showing with 87 additions and 80 deletions.
  1. +87 −80 src/Words.Native.Core/Hashtable.h
@@ -6,7 +6,7 @@


namespace namespace
{ {
static int nextSize(int current, float loadFactor) static int next_size(int current, float loadFactor)
{ {
static const int sizes[] = static const int sizes[] =
{ {
@@ -33,138 +33,145 @@ namespace Words
class Hashtable class Hashtable
{ {
private: private:
struct Entry typedef std::pair<TKey, TValue> Entry;
{
Entry()
: key_(),
value_(),
occupied_(false)
{
}

TKey key_;
TValue value_;
bool occupied_;
};


public: public:
Hashtable(float loadFactor = 1.0f) Hashtable(float loadFactor = 1.0f)
: eq_(), : eq_(),
hash_(), hash_(),
buckets_(nextSize(0, loadFactor)),
loadFactor_(loadFactor), loadFactor_(loadFactor),
size_(0) buckets_(next_size(0, loadFactor)),
entries_(1)
{ {
} }


bool get(const TKey& key, TValue& value) const bool get(const TKey& key, TValue& value) const
{ {
const Entry* e = find(key); int index = idx(key);
if (!e) int n = static_cast<int>(buckets_.size());
for (int i = 0; i < n; ++i)
{ {
return false; int b = buckets_[index];
} if (b == 0)
{
break;
}


if (e->occupied_) const Entry& e = entries_[b];
{ const TKey& k = e.first;
value = e->value_; if (eq_(k, key))
return true; {
value = e.second;
return true;
}

next_index(index);
} }


return false; return false;
} }


bool insert(const TKey& key, const TValue& value, TValue* previous = nullptr) bool insert(const TKey& key, const TValue& value, TValue* previous = nullptr)
{ {
bool inserted = false; int index = idx(key);
Entry& e = find(key); int n = static_cast<int>(buckets_.size());
if (!e.occupied_) for (int i = 0; i < n; ++i)
{ {
e.occupied_ = true; int b = buckets_[index];
e.key_ = key; if (b == 0)
inserted = true; {
++size_; break;
} }


if (previous) Entry& e = entries_[b];
{ const TKey& k = e.first;
*previous = e.value_; if (eq_(k, key))
{
if (previous)
{
*previous = e.second;
}

e.second = value;
return false;
}

next_index(index);
} }


e.value_ = value; insert_new(index, key, value);
return inserted; return true;
} }


private: private:
TEq eq_; TEq eq_;
THash hash_; THash hash_;
std::vector<Entry> buckets_;
float loadFactor_; float loadFactor_;
int size_; int size_;
std::vector<int> buckets_;
std::vector<Entry> entries_;


size_t idx(const TKey& key) const int idx(const TKey& key) const
{ {
size_t hashcode = hash_(key); size_t hashcode = hash_(key);
return hashcode % buckets_.size(); return static_cast<int>(hashcode % buckets_.size());
} }


const Entry* find(const TKey& key) const void resize()
{ {
size_t index = idx(key); std::vector<int> original(next_size(static_cast<int>(buckets_.size()), loadFactor_));
for (int i = 0; i < size_; ++i) std::swap(buckets_, original);
size_ = 0;
size_t n = entries_.size();
for (int x = 1; x < n; ++x)
{ {
const Entry& e = buckets_[index]; const Entry& e = entries_[x];
if (!e.occupied_ || eq_(e.key_, key)) const TKey& k = e.first;
{ put_bucket(-1, k, x);
return &e; }
} }


++index; void insert_new(int index, const TKey& key, const TValue& value)
if (index == buckets_.size()) {
{ int maxSize = static_cast<int>(loadFactor_ * buckets_.size());
index = 0; if (entries_.size() > maxSize)
} {
resize();
index = -1;
} }


return nullptr; put_bucket(index, key, static_cast<int>(entries_.size()));
entries_.push_back(std::make_pair(key, value));
} }


Entry& find(const TKey& key) void put_bucket(int index, const TKey& key, int x)
{ {
size_t index = idx(key); if (index == -1)
while (true)
{ {
Entry& e = buckets_[index]; index = idx(key);
if (!e.occupied_ || eq_(e.key_, key)) }
{
return e;
}


int maxSize = static_cast<int>(loadFactor_ * buckets_.size()); int n = static_cast<int>(buckets_.size());
if (size_ >= maxSize) for (int i = 0; i < n; ++i)
{
int& b = buckets_[index];
if (b == 0)
{ {
resize(); b = x;
index = idx(key); return;
}
else
{
++index;
if (index == buckets_.size())
{
index = 0;
}
} }

next_index(index);
} }
} }


void resize() void next_index(int& index) const
{ {
std::vector<Entry> original(nextSize(static_cast<int>(buckets_.size()), loadFactor_)); ++index;
std::swap(buckets_, original); int n = static_cast<int>(buckets_.size());
size_ = 0; if (index == n)
for (const Entry& e : original)
{ {
insert(e.key_, e.value_); index = 0;
} }
} }
}; };

0 comments on commit efa79c6

Please sign in to comment.
You can’t perform that action at this time.