|
@@ -2,6 +2,7 @@
|
|
#define CORE_PROBING_HASHMAP_HPP
|
|
#define CORE_PROBING_HASHMAP_HPP
|
|
|
|
|
|
#include "core/List.hpp"
|
|
#include "core/List.hpp"
|
|
|
|
+#include "core/Logger.hpp"
|
|
#include "core/ToString.hpp"
|
|
#include "core/ToString.hpp"
|
|
#include "core/Utility.hpp"
|
|
#include "core/Utility.hpp"
|
|
|
|
|
|
@@ -141,7 +142,7 @@ namespace Core {
|
|
using ConstKeyIteratorAdapter =
|
|
using ConstKeyIteratorAdapter =
|
|
IteratorAdapter<const ProbingHashMap, ConstKeyIterator>;
|
|
IteratorAdapter<const ProbingHashMap, ConstKeyIterator>;
|
|
|
|
|
|
- public:
|
|
+ private:
|
|
List<K> keys{};
|
|
List<K> keys{};
|
|
V* values = nullptr;
|
|
V* values = nullptr;
|
|
List<int> jumps{};
|
|
List<int> jumps{};
|
|
@@ -211,7 +212,7 @@ namespace Core {
|
|
if(invalidSet) {
|
|
if(invalidSet) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
- rehash(entries * 2 + 1);
|
|
+ rehash(1);
|
|
invalidSet = true;
|
|
invalidSet = true;
|
|
} else {
|
|
} else {
|
|
index = searchSlot(key);
|
|
index = searchSlot(key);
|
|
@@ -233,7 +234,7 @@ namespace Core {
|
|
if(invalidSet) {
|
|
if(invalidSet) {
|
|
return (values[0] = Core::forward<VA>(value));
|
|
return (values[0] = Core::forward<VA>(value));
|
|
}
|
|
}
|
|
- rehash(entries * 2 + 1);
|
|
+ rehash(1);
|
|
invalidSet = true;
|
|
invalidSet = true;
|
|
} else {
|
|
} else {
|
|
index = searchSlot(key);
|
|
index = searchSlot(key);
|
|
@@ -254,6 +255,26 @@ namespace Core {
|
|
return *this;
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ bool remove(const K& key) {
|
|
|
|
+ size_t index = 0;
|
|
|
|
+ if(key == INVALID) {
|
|
|
|
+ if(!invalidSet) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ invalidSet = false;
|
|
|
|
+ } else {
|
|
|
|
+ index = searchSlot(key);
|
|
|
|
+ if(keys[index] != key) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ values[index].~V();
|
|
|
|
+ entries--;
|
|
|
|
+ demarkSlot(key);
|
|
|
|
+ keys[index] = INVALID;
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
const V* search(const K& key) const {
|
|
const V* search(const K& key) const {
|
|
return searchValue<const V>(key);
|
|
return searchValue<const V>(key);
|
|
}
|
|
}
|
|
@@ -309,27 +330,29 @@ namespace Core {
|
|
}
|
|
}
|
|
|
|
|
|
private:
|
|
private:
|
|
|
|
+ static constexpr size_t MAX_CLUSTER = 5;
|
|
|
|
+
|
|
size_t searchSlot(const K& key) {
|
|
size_t searchSlot(const K& key) {
|
|
- size_t rehashFactor = 2;
|
|
+ rehash(1);
|
|
while(true) {
|
|
while(true) {
|
|
- rehash(entries * rehashFactor + 1);
|
|
|
|
size_t baseHash = hashCode(key) * 514'685'581u;
|
|
size_t baseHash = hashCode(key) * 514'685'581u;
|
|
size_t end = keys.getLength() - 2;
|
|
size_t end = keys.getLength() - 2;
|
|
// rehash on bad clustering
|
|
// rehash on bad clustering
|
|
- for(size_t i = 0; i <= 5; i++) {
|
|
+ for(size_t i = 0; i <= MAX_CLUSTER; i++) {
|
|
size_t hash = 1 + ((baseHash + i) & end);
|
|
size_t hash = 1 + ((baseHash + i) & end);
|
|
- if(keys[hash] == INVALID || keys[hash] == key) {
|
|
+ if((keys[hash] == INVALID && jumps[hash] == 0) ||
|
|
|
|
+ keys[hash] == key) {
|
|
return hash;
|
|
return hash;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- rehashFactor *= 2;
|
|
+ rehash(keys.getLength() + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void markSlot(const K& key) {
|
|
void markSlot(const K& key) {
|
|
size_t baseHash = hashCode(key) * 514'685'581u;
|
|
size_t baseHash = hashCode(key) * 514'685'581u;
|
|
size_t end = keys.getLength() - 2;
|
|
size_t end = keys.getLength() - 2;
|
|
- for(size_t i = 0; i <= 5; i++) {
|
|
+ for(size_t i = 0; i <= MAX_CLUSTER; i++) {
|
|
size_t hash = 1 + ((baseHash + i) & end);
|
|
size_t hash = 1 + ((baseHash + i) & end);
|
|
if(keys[hash] == key) {
|
|
if(keys[hash] == key) {
|
|
return;
|
|
return;
|
|
@@ -338,6 +361,18 @@ namespace Core {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ void demarkSlot(const K& key) {
|
|
|
|
+ size_t baseHash = hashCode(key) * 514'685'581u;
|
|
|
|
+ size_t end = keys.getLength() - 2;
|
|
|
|
+ for(size_t i = 0; i <= MAX_CLUSTER; i++) {
|
|
|
|
+ size_t hash = 1 + ((baseHash + i) & end);
|
|
|
|
+ if(keys[hash] == key) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ jumps[hash]--;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
template<typename Value>
|
|
template<typename Value>
|
|
Value* searchValue(const K& key) const {
|
|
Value* searchValue(const K& key) const {
|
|
if(keys.getLength() != 0) {
|
|
if(keys.getLength() != 0) {
|
|
@@ -350,7 +385,7 @@ namespace Core {
|
|
size_t hash = 1 + ((baseHash + i) & end);
|
|
size_t hash = 1 + ((baseHash + i) & end);
|
|
if(keys[hash] == key) [[likely]] {
|
|
if(keys[hash] == key) [[likely]] {
|
|
return values + hash;
|
|
return values + hash;
|
|
- } else if(keys[hash] == INVALID) {
|
|
+ } else if(jumps[hash] == 0) {
|
|
return nullptr;
|
|
return nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|