|
@@ -9,13 +9,14 @@
|
|
namespace Core {
|
|
namespace Core {
|
|
template<typename K, typename V>
|
|
template<typename K, typename V>
|
|
struct ProbingHashMap final {
|
|
struct ProbingHashMap final {
|
|
|
|
+ template<typename Value>
|
|
class Node final {
|
|
class Node final {
|
|
friend ProbingHashMap;
|
|
friend ProbingHashMap;
|
|
friend List<Node>;
|
|
friend List<Node>;
|
|
K key;
|
|
K key;
|
|
|
|
|
|
public:
|
|
public:
|
|
- V& value;
|
|
+ Value& value;
|
|
|
|
|
|
const K& getKey() const {
|
|
const K& getKey() const {
|
|
return key;
|
|
return key;
|
|
@@ -29,157 +30,194 @@ namespace Core {
|
|
}
|
|
}
|
|
|
|
|
|
private:
|
|
private:
|
|
- Node(const K& key_, V& value_) : key(key_), value(value_) {
|
|
+ Node(const K& key_, Value& value_) : key(key_), value(value_) {
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
private:
|
|
private:
|
|
- /*template<typename N, typename I, typename R, R& (*A)(I&)>
|
|
+ template<typename Value, typename R, R (*A)(const K&, Value&)>
|
|
class Iterator final {
|
|
class Iterator final {
|
|
- N iterator;
|
|
+ const K* currentKey;
|
|
|
|
+ const K* endKey;
|
|
|
|
+ Value* currentValue;
|
|
|
|
|
|
public:
|
|
public:
|
|
- Iterator(N iterator_) : iterator(iterator_) {
|
|
+ Iterator(const K* key, const K* endKey_, Value* value)
|
|
|
|
+ : currentKey(key), endKey(endKey_), currentValue(value) {
|
|
|
|
+ skip();
|
|
}
|
|
}
|
|
|
|
|
|
Iterator& operator++() {
|
|
Iterator& operator++() {
|
|
- ++iterator;
|
|
+ ++currentKey;
|
|
|
|
+ ++currentValue;
|
|
|
|
+ skip();
|
|
return *this;
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
|
|
bool operator!=(const Iterator& other) const {
|
|
bool operator!=(const Iterator& other) const {
|
|
- return iterator != other.iterator;
|
|
+ return currentKey != other.currentKey;
|
|
}
|
|
}
|
|
|
|
|
|
- R& operator*() const {
|
|
+ R operator*() const {
|
|
- return A(*iterator);
|
|
+ return A(*currentKey, *currentValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private:
|
|
|
|
+ void skip() {
|
|
|
|
+ while(currentKey != endKey && *currentKey == emptyValue<K>()) {
|
|
|
|
+ ++currentKey;
|
|
|
|
+ ++currentValue;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
- template<typename R>
|
|
+ template<typename Value>
|
|
- static R& access(R& node) {
|
|
+ static Node<Value> access(const K& key, Value& value) {
|
|
- return node;
|
|
+ return Node<Value>(key, value);
|
|
}
|
|
}
|
|
|
|
|
|
- template<typename I, typename R>
|
|
+ template<typename Value>
|
|
- static R& accessValue(I& node) {
|
|
+ static Value& accessValue(const K&, Value& value) {
|
|
- return node.value;
|
|
+ return value;
|
|
}
|
|
}
|
|
|
|
|
|
- static const K& accessKey(const Node& node) {
|
|
+ static const K& accessKey(const K& key, const V&) {
|
|
- return node.getKey();
|
|
+ return key;
|
|
}
|
|
}
|
|
|
|
|
|
- template<typename N, typename R>
|
|
+ template<typename Value>
|
|
- using BaseEntryIterator = Iterator<N, R, R, access<R>>;
|
|
+ using BaseEntryIterator = Iterator<Value, Node<Value>, access<Value>>;
|
|
- using EntryIterator = BaseEntryIterator<NodeIterator, Node>;
|
|
+ using EntryIterator = BaseEntryIterator<V>;
|
|
- using ConstEntryIterator =
|
|
+ using ConstEntryIterator = BaseEntryIterator<const V>;
|
|
- BaseEntryIterator<ConstNodeIterator, const Node>;
|
|
|
|
|
|
|
|
- template<typename N, typename I, typename R>
|
|
+ template<typename Value>
|
|
- using BaseValueIterator = Iterator<N, I, R, accessValue<I, R>>;
|
|
+ using BaseValueIterator = Iterator<Value, Value&, accessValue<Value>>;
|
|
- using ValueIterator = BaseValueIterator<NodeIterator, Node, V>;
|
|
+ using ValueIterator = BaseValueIterator<V>;
|
|
- using ConstValueIterator =
|
|
+ using ConstValueIterator = BaseValueIterator<const V>;
|
|
- BaseValueIterator<ConstNodeIterator, const Node, const V>;
|
|
|
|
|
|
|
|
- using ConstKeyIterator =
|
|
+ using ConstKeyIterator = Iterator<const V, const K&, accessKey>;
|
|
- Iterator<ConstNodeIterator, const Node, const K, accessKey>;
|
|
|
|
|
|
|
|
template<typename M, typename I>
|
|
template<typename M, typename I>
|
|
struct IteratorAdapter final {
|
|
struct IteratorAdapter final {
|
|
M& map;
|
|
M& map;
|
|
|
|
|
|
I begin() const {
|
|
I begin() const {
|
|
- return I(map.nodes.begin());
|
|
+ return {map.keys.begin(), map.keys.end(), map.values};
|
|
}
|
|
}
|
|
|
|
|
|
I end() const {
|
|
I end() const {
|
|
- return I(map.nodes.end());
|
|
+ return {map.keys.end(), map.keys.end(), nullptr};
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
- using EntryIteratorAdapter =
|
|
|
|
- IteratorAdapter<ProbingHashMap, EntryIterator>;
|
|
|
|
- using ConstEntryIteratorAdapter =
|
|
|
|
- IteratorAdapter<const ProbingHashMap, ConstEntryIterator>;
|
|
|
|
-
|
|
|
|
using ValueIteratorAdapter =
|
|
using ValueIteratorAdapter =
|
|
IteratorAdapter<ProbingHashMap, ValueIterator>;
|
|
IteratorAdapter<ProbingHashMap, ValueIterator>;
|
|
using ConstValueIteratorAdapter =
|
|
using ConstValueIteratorAdapter =
|
|
IteratorAdapter<const ProbingHashMap, ConstValueIterator>;
|
|
IteratorAdapter<const ProbingHashMap, ConstValueIterator>;
|
|
|
|
|
|
using ConstKeyIteratorAdapter =
|
|
using ConstKeyIteratorAdapter =
|
|
- IteratorAdapter<const ProbingHashMap, ConstKeyIterator>;*/
|
|
+ IteratorAdapter<const ProbingHashMap, ConstKeyIterator>;
|
|
|
|
|
|
private:
|
|
private:
|
|
|
|
+ struct alignas(V) AlignedValue final {
|
|
|
|
+ char data[sizeof(V)];
|
|
|
|
+ };
|
|
|
|
+
|
|
List<K> keys;
|
|
List<K> keys;
|
|
- List<V> values;
|
|
+ V* values;
|
|
- K emptyKey;
|
|
|
|
int entries;
|
|
int entries;
|
|
|
|
|
|
public:
|
|
public:
|
|
- ProbingHashMap(const K& emptyKey_) : emptyKey(emptyKey_), entries(0) {
|
|
+ ProbingHashMap() : values(nullptr), entries(0) {
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ProbingHashMap(const ProbingHashMap& other) = delete;
|
|
|
|
+
|
|
|
|
+ ProbingHashMap(ProbingHashMap&& other) : ProbingHashMap() {
|
|
|
|
+ swap(other);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ~ProbingHashMap() {
|
|
|
|
+ for(int i = 0; i < keys.getLength(); i++) {
|
|
|
|
+ if(keys[i] != emptyValue<K>()) {
|
|
|
|
+ values[i].~V();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ delete[] reinterpret_cast<AlignedValue*>(values);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ProbingHashMap& operator=(const ProbingHashMap& other) = delete;
|
|
|
|
+
|
|
|
|
+ ProbingHashMap& operator=(ProbingHashMap&& other) {
|
|
|
|
+ swap(other);
|
|
|
|
+ return *this;
|
|
}
|
|
}
|
|
|
|
|
|
- /*check_return Error copyFrom(const ProbingHashMap& other) {
|
|
+ check_return Error copyFrom(const ProbingHashMap& other) {
|
|
ProbingHashMap copy;
|
|
ProbingHashMap copy;
|
|
- for(const auto& en : other) {
|
|
+ for(const auto& e : other) {
|
|
- CORE_RETURN_ERROR(copy.add(en.getKey(), en.value));
|
|
+ CORE_RETURN_ERROR(copy.add(e.getKey(), e.value));
|
|
}
|
|
}
|
|
- swap(copy.nodes, nodes);
|
|
+ swap(copy);
|
|
- swap(copy.nodePointers, nodePointers);
|
|
|
|
return Error::NONE;
|
|
return Error::NONE;
|
|
- }*/
|
|
+ }
|
|
|
|
|
|
check_return Error rehash(int minCapacity) {
|
|
check_return Error rehash(int minCapacity) {
|
|
- minCapacity *= 2;
|
|
|
|
if(minCapacity <= keys.getLength()) {
|
|
if(minCapacity <= keys.getLength()) {
|
|
return Error::NONE;
|
|
return Error::NONE;
|
|
}
|
|
}
|
|
- ProbingHashMap<K, V> map(emptyKey);
|
|
+ ProbingHashMap<K, V> map;
|
|
- int l = 1 << Math::roundUpLog2(Core::Math::max(minCapacity, 8));
|
|
+ int l = Core::Math::max(1 << Math::roundUpLog2(minCapacity), 8);
|
|
- CORE_RETURN_ERROR(map.keys.resize(l, emptyKey));
|
|
+ CORE_RETURN_ERROR(map.keys.resize(l, emptyValue<K>()));
|
|
- CORE_RETURN_ERROR(map.values.resize(l));
|
|
+ map.values = reinterpret_cast<V*>(new AlignedValue[l]);
|
|
|
|
+ if(map.values == nullptr) {
|
|
|
|
+ return Error::OUT_OF_MEMORY;
|
|
|
|
+ }
|
|
for(int i = 0; i < keys.getLength(); i++) {
|
|
for(int i = 0; i < keys.getLength(); i++) {
|
|
- if(keys[i] != emptyKey) {
|
|
+ if(keys[i] != emptyValue<K>()) {
|
|
CORE_RETURN_ERROR(map.add(keys[i], values[i]));
|
|
CORE_RETURN_ERROR(map.add(keys[i], values[i]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- Core::swap(map.keys, keys);
|
|
+ swap(map);
|
|
- Core::swap(map.values, values);
|
|
|
|
return Error::NONE;
|
|
return Error::NONE;
|
|
}
|
|
}
|
|
|
|
|
|
- /*template<typename... Args>
|
|
+ template<typename... Args>
|
|
check_return Error tryEmplace(V*& v, const K& key, Args&&... args) {
|
|
check_return Error tryEmplace(V*& v, const K& key, Args&&... args) {
|
|
- CORE_RETURN_ERROR(rehash(nodes.getLength() + 1));
|
|
+ if(key == emptyValue<K>()) {
|
|
- int h = hashIndex(key);
|
|
+ return Error::INVALID_ARGUMENT;
|
|
- v = searchList(key, h);
|
|
|
|
- if(v != nullptr) {
|
|
|
|
- return Error::EXISTING_KEY;
|
|
|
|
}
|
|
}
|
|
- NodePointer np = nullptr;
|
|
+ CORE_RETURN_ERROR(rehash(entries * 2 + 1));
|
|
- CORE_RETURN_ERROR(nodes.put(np, key, Core::forward<Args>(args)...));
|
|
+ int index = searchSlot(key);
|
|
- Error e = Error::NONE;
|
|
+ if(index < 0) {
|
|
- if(checkError(e, nodePointers[h].add(np))) {
|
|
+ return Error::CAPACITY_REACHED;
|
|
- nodes.remove(np);
|
|
+ } else if(keys[index] == key) {
|
|
- return e;
|
|
+ return Error::EXISTING_KEY;
|
|
}
|
|
}
|
|
- v = &(np->data.value);
|
|
+ keys[index] = key;
|
|
|
|
+ v = new(values + index) V(Core::forward<Args>(args)...);
|
|
|
|
+ entries++;
|
|
return Error::NONE;
|
|
return Error::NONE;
|
|
- }*/
|
|
+ }
|
|
|
|
|
|
template<typename VA>
|
|
template<typename VA>
|
|
check_return Error put(V*& v, const K& key, VA&& value) {
|
|
check_return Error put(V*& v, const K& key, VA&& value) {
|
|
- CORE_RETURN_ERROR(rehash(entries + 1));
|
|
+ if(key == emptyValue<K>()) {
|
|
- int index = searchList(key);
|
|
+ return Error::INVALID_ARGUMENT;
|
|
|
|
+ }
|
|
|
|
+ CORE_RETURN_ERROR(rehash(entries * 2 + 1));
|
|
|
|
+ int index = searchSlot(key);
|
|
if(index < 0) {
|
|
if(index < 0) {
|
|
return Error::CAPACITY_REACHED;
|
|
return Error::CAPACITY_REACHED;
|
|
}
|
|
}
|
|
- entries += keys[index] != key;
|
|
+ if(keys[index] == key) {
|
|
|
|
+ values[index] = Core::forward<VA>(value);
|
|
|
|
+ } else {
|
|
|
|
+ new(values + index) V(Core::forward<VA>(value));
|
|
|
|
+ entries++;
|
|
|
|
+ }
|
|
keys[index] = key;
|
|
keys[index] = key;
|
|
- values[index] = Core::forward<VA>(value);
|
|
+ v = reinterpret_cast<V*>(values + index);
|
|
- v = &(values[index]);
|
|
|
|
return Error::NONE;
|
|
return Error::NONE;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -189,97 +227,91 @@ namespace Core {
|
|
return put(v, key, Core::forward<VA>(value));
|
|
return put(v, key, Core::forward<VA>(value));
|
|
}
|
|
}
|
|
|
|
|
|
- /*check_return Error remove(const K& key) {
|
|
|
|
- NodePointerList& list = nodePointers[hashIndex(key)];
|
|
|
|
- for(int i = 0; i < list.getLength(); i++) {
|
|
|
|
- if(list[i]->data.key == key) {
|
|
|
|
- nodes.remove(list[i]);
|
|
|
|
- return list.removeBySwap(i);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return Error::NOT_FOUND;
|
|
|
|
- }*/
|
|
|
|
-
|
|
|
|
const V* search(const K& key) const {
|
|
const V* search(const K& key) const {
|
|
- int i = searchList(key);
|
|
+ return searchValue<const V>(key);
|
|
- return i < 0 || keys[i] == emptyKey ? nullptr : &(values[i]);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
V* search(const K& key) {
|
|
V* search(const K& key) {
|
|
- int i = searchList(key);
|
|
+ return searchValue<V>(key);
|
|
- return i < 0 || keys[i] == emptyKey ? nullptr : &(values[i]);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
bool contains(const K& key) const {
|
|
bool contains(const K& key) const {
|
|
return search(key) != nullptr;
|
|
return search(key) != nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
- /*ProbingHashMap& clear() {
|
|
+ ProbingHashMap& clear() {
|
|
- nodes.clear();
|
|
+ ProbingHashMap<K, V> map;
|
|
- for(NodePointerList& n : nodePointers) {
|
|
+ swap(map);
|
|
- n.clear();
|
|
|
|
- }
|
|
|
|
return *this;
|
|
return *this;
|
|
- }*/
|
|
+ }
|
|
|
|
|
|
- /*EntryIteratorAdapter entries() {
|
|
+ ConstKeyIteratorAdapter getKeys() const {
|
|
return {*this};
|
|
return {*this};
|
|
}
|
|
}
|
|
|
|
|
|
- ConstEntryIteratorAdapter entries() const {
|
|
+ ValueIteratorAdapter getValues() {
|
|
return {*this};
|
|
return {*this};
|
|
- }*/
|
|
|
|
-
|
|
|
|
- /*ConstKeyIteratorAdapter keys() const {
|
|
|
|
- return keys.begin();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- ValueIteratorAdapter values() {
|
|
+ ConstValueIteratorAdapter getValues() const {
|
|
- return values.begin();
|
|
+ return {*this};
|
|
}
|
|
}
|
|
|
|
|
|
- ConstValueIteratorAdapter values() const {
|
|
+ EntryIterator begin() {
|
|
- return values.begin();
|
|
+ return {keys.begin(), keys.end(), values};
|
|
- }*/
|
|
|
|
-
|
|
|
|
- /*EntryIterator begin() {
|
|
|
|
- return EntryIterator(nodes.begin());
|
|
|
|
}
|
|
}
|
|
|
|
|
|
EntryIterator end() {
|
|
EntryIterator end() {
|
|
- return EntryIterator(nodes.end());
|
|
+ return {keys.end(), keys.end(), nullptr};
|
|
}
|
|
}
|
|
|
|
|
|
ConstEntryIterator begin() const {
|
|
ConstEntryIterator begin() const {
|
|
- return ConstEntryIterator(nodes.begin());
|
|
+ return {keys.begin(), keys.end(), values};
|
|
}
|
|
}
|
|
|
|
|
|
ConstEntryIterator end() const {
|
|
ConstEntryIterator end() const {
|
|
- return ConstEntryIterator(nodes.end());
|
|
+ return {keys.end(), keys.end(), nullptr};
|
|
}
|
|
}
|
|
|
|
|
|
template<typename String>
|
|
template<typename String>
|
|
check_return Error toString(String& s) const {
|
|
check_return Error toString(String& s) const {
|
|
return Core::toString(s, *this);
|
|
return Core::toString(s, *this);
|
|
- }*/
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void swap(ProbingHashMap& o) {
|
|
|
|
+ Core::swap(o.keys, keys);
|
|
|
|
+ Core::swap(o.values, values);
|
|
|
|
+ Core::swap(o.entries, entries);
|
|
|
|
+ }
|
|
|
|
|
|
private:
|
|
private:
|
|
- int searchList(const K& key) const {
|
|
+ int searchSlot(const K& key) const {
|
|
int baseHash = static_cast<int>(hashCode(key));
|
|
int baseHash = static_cast<int>(hashCode(key));
|
|
int end = keys.getLength() - 1;
|
|
int end = keys.getLength() - 1;
|
|
for(int i = 0; i <= end; i++) {
|
|
for(int i = 0; i <= end; i++) {
|
|
int hash = (baseHash + i) & end;
|
|
int hash = (baseHash + i) & end;
|
|
- if(keys[hash] == emptyKey || keys[hash] == key) {
|
|
+ if(keys[hash] == emptyValue<K>() || keys[hash] == key) {
|
|
return hash;
|
|
return hash;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
- /*V* searchList(const K& key, int h) {
|
|
+ template<typename Value>
|
|
- return const_cast<V*>(
|
|
+ Value* searchValue(const K& key) const {
|
|
- static_cast<const ProbingHashMap*>(this)->searchList(key, h));
|
|
+ int baseHash = static_cast<int>(hashCode(key));
|
|
- }*/
|
|
+ int end = keys.getLength() - 1;
|
|
|
|
+ for(int i = 0; i <= end; i++) {
|
|
|
|
+ int hash = (baseHash + i) & end;
|
|
|
|
+ if(keys[hash] == key) //[[likely]]
|
|
|
|
+ {
|
|
|
|
+ return values + hash;
|
|
|
|
+ } else if(keys[hash] == emptyValue<K>()) {
|
|
|
|
+ return nullptr;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return nullptr;
|
|
|
|
+ }
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|