|
@@ -11,13 +11,18 @@
|
|
|
|
|
|
template<typename K, typename V>
|
|
|
struct HashMap final {
|
|
|
- struct Node {
|
|
|
+ class Node {
|
|
|
friend HashMap;
|
|
|
friend List<Node>;
|
|
|
+ K key;
|
|
|
|
|
|
- const K key;
|
|
|
+ public:
|
|
|
V value;
|
|
|
|
|
|
+ const K& getKey() const {
|
|
|
+ return key;
|
|
|
+ }
|
|
|
+
|
|
|
private:
|
|
|
int next;
|
|
|
|
|
@@ -35,58 +40,70 @@ struct HashMap final {
|
|
|
};
|
|
|
|
|
|
private:
|
|
|
- List<int> nodePointers;
|
|
|
- List<Node> nodes;
|
|
|
+ List<List<Node>> nodes;
|
|
|
+ int elements;
|
|
|
|
|
|
public:
|
|
|
- HashMap(int minCapacity = 8) {
|
|
|
- nodePointers.resize(1 << Utils::roundUpLog2(minCapacity), -1);
|
|
|
+ HashMap(int minCapacity = 8) : elements(0) {
|
|
|
+ nodes.resize(1 << Utils::roundUpLog2(minCapacity));
|
|
|
}
|
|
|
|
|
|
template<typename... Args>
|
|
|
bool tryEmplace(const K& key, Args&&... args) {
|
|
|
- int pointer = prepareAdd(key);
|
|
|
- if(pointer == -1) {
|
|
|
- nodes.add(key, std::forward<Args>(args)...);
|
|
|
+ rehash();
|
|
|
+ Hash h = hash(key);
|
|
|
+ V* v = searchList(key, h);
|
|
|
+ if(v == nullptr) {
|
|
|
+ nodes[h].add(key, std::forward<Args>(args)...);
|
|
|
+ elements++;
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
HashMap& add(const K& key, const V& value) {
|
|
|
- int pointer = prepareAdd(key);
|
|
|
- if(pointer != -1) {
|
|
|
- nodes[pointer].value = value;
|
|
|
+ rehash();
|
|
|
+ Hash h = hash(key);
|
|
|
+ V* v = searchList(key, h);
|
|
|
+ if(v == nullptr) {
|
|
|
+ nodes[h].add(key, value);
|
|
|
+ elements++;
|
|
|
} else {
|
|
|
- nodes.add(key, value);
|
|
|
+ *v = value;
|
|
|
}
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
HashMap& add(const K& key, V&& value) {
|
|
|
- int pointer = prepareAdd(key);
|
|
|
- if(pointer != -1) {
|
|
|
- nodes[pointer].value = std::move(value);
|
|
|
+ rehash();
|
|
|
+ Hash h = hash(key);
|
|
|
+ V* v = searchList(key, h);
|
|
|
+ if(v == nullptr) {
|
|
|
+ nodes[h].add(key, std::move(value));
|
|
|
+ elements++;
|
|
|
} else {
|
|
|
- nodes.add(key, std::move(value));
|
|
|
+ *v = std::move(value);
|
|
|
}
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
- const V* search(const K& key) const {
|
|
|
- Hash h = hash(key);
|
|
|
- int pointer = nodePointers[h];
|
|
|
- while(pointer != -1) {
|
|
|
- if(nodes[pointer].key == key) {
|
|
|
- return &(nodes[pointer].value);
|
|
|
+ bool remove(const K& key) {
|
|
|
+ List<Node>& list = nodes[hash(key)];
|
|
|
+ for(int i = 0; i < list.getLength(); i++) {
|
|
|
+ if(list[i].key == key) {
|
|
|
+ list.remove(i);
|
|
|
+ return true;
|
|
|
}
|
|
|
- pointer = nodes[pointer].next;
|
|
|
}
|
|
|
- return nullptr;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ const V* search(const K& key) const {
|
|
|
+ return searchList(key, hash(key));
|
|
|
}
|
|
|
|
|
|
V* search(const K& key) {
|
|
|
- return const_cast<V*>(static_cast<const HashMap*>(this)->search(key));
|
|
|
+ return searchList(key, hash(key));
|
|
|
}
|
|
|
|
|
|
bool contains(const K& key) const {
|
|
@@ -94,10 +111,10 @@ public:
|
|
|
}
|
|
|
|
|
|
HashMap& clear() {
|
|
|
- for(int& pointer : nodePointers) {
|
|
|
- pointer = -1;
|
|
|
+ for(List<Node>& n : nodes) {
|
|
|
+ n.clear();
|
|
|
}
|
|
|
- nodes.clear();
|
|
|
+ elements = 0;
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
@@ -121,12 +138,14 @@ public:
|
|
|
void toString(StringBuffer<L>& s) const {
|
|
|
s.append("[");
|
|
|
bool c = false;
|
|
|
- for(const Node& n : nodes) {
|
|
|
- if(c) {
|
|
|
- s.append(", ");
|
|
|
+ for(const List<Node>& list : nodes) {
|
|
|
+ for(const Node& n : list) {
|
|
|
+ if(c) {
|
|
|
+ s.append(", ");
|
|
|
+ }
|
|
|
+ s.append(n.key).append(" = ").append(n.value);
|
|
|
+ c = true;
|
|
|
}
|
|
|
- s.append(n.key).append(" = ").append(n.value);
|
|
|
- c = true;
|
|
|
}
|
|
|
s.append("]");
|
|
|
}
|
|
@@ -134,7 +153,7 @@ public:
|
|
|
private:
|
|
|
template<typename H>
|
|
|
Hash hash(const H& key) const {
|
|
|
- return fullHash(key) & (nodePointers.getLength() - 1);
|
|
|
+ return fullHash(key) & (nodes.getLength() - 1);
|
|
|
}
|
|
|
|
|
|
template<typename H>
|
|
@@ -147,33 +166,30 @@ private:
|
|
|
}
|
|
|
|
|
|
void rehash() {
|
|
|
- if(nodes.getLength() < nodePointers.getLength()) {
|
|
|
+ if(elements < nodes.getLength()) {
|
|
|
return;
|
|
|
}
|
|
|
- HashMap<K, V> map(nodePointers.getLength() * 2);
|
|
|
- for(const Node& n : nodes) {
|
|
|
- map.add(n.key, std::move(n.value));
|
|
|
+ HashMap<K, V> map(nodes.getLength() * 2);
|
|
|
+ for(List<Node>& list : nodes) {
|
|
|
+ for(Node& n : list) {
|
|
|
+ map.tryEmplace(n.key, std::move(n.value));
|
|
|
+ }
|
|
|
}
|
|
|
*this = std::move(map);
|
|
|
}
|
|
|
|
|
|
- int prepareAdd(const K& key) {
|
|
|
- rehash();
|
|
|
- Hash h = hash(key);
|
|
|
- int pointer = nodePointers[h];
|
|
|
- if(pointer == -1) {
|
|
|
- nodePointers[h] = nodes.getLength();
|
|
|
- return -1;
|
|
|
- }
|
|
|
- while(true) {
|
|
|
- if(nodes[pointer].key == key) {
|
|
|
- return pointer;
|
|
|
- } else if(nodes[pointer].next == -1) {
|
|
|
- nodes[pointer].next = nodes.getLength();
|
|
|
- return -1;
|
|
|
+ const V* searchList(const K& key, Hash h) const {
|
|
|
+ for(const Node& n : nodes[h]) {
|
|
|
+ if(n.key == key) {
|
|
|
+ return &n.value;
|
|
|
}
|
|
|
- pointer = nodes[pointer].next;
|
|
|
}
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ V* searchList(const K& key, Hash h) {
|
|
|
+ return const_cast<V*>(
|
|
|
+ static_cast<const HashMap*>(this)->searchList(key, h));
|
|
|
}
|
|
|
};
|
|
|
|