|
@@ -26,27 +26,27 @@ export namespace Core {
|
|
|
return static_cast<size_t>(key);
|
|
return static_cast<size_t>(key);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- template<typename K, typename V>
|
|
|
|
|
|
|
+ template<Moveable K, Moveable V>
|
|
|
struct HashMap final {
|
|
struct HashMap final {
|
|
|
template<typename Value>
|
|
template<typename Value>
|
|
|
class Node final {
|
|
class Node final {
|
|
|
friend HashMap;
|
|
friend HashMap;
|
|
|
- friend List<Node>;
|
|
|
|
|
K key;
|
|
K key;
|
|
|
|
|
|
|
|
public:
|
|
public:
|
|
|
Value& value;
|
|
Value& value;
|
|
|
|
|
|
|
|
- const K& getKey() const {
|
|
|
|
|
|
|
+ const K& getKey() const noexcept {
|
|
|
return key;
|
|
return key;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- size_t toString(StringBase& b) const {
|
|
|
|
|
|
|
+ size_t toString(StringBase& b) const noexcept {
|
|
|
return b.addFormat("{} = {}", key, value);
|
|
return b.addFormat("{} = {}", key, value);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
private:
|
|
|
- Node(const K& key_, Value& value_) : key(key_), value(value_) {
|
|
|
|
|
|
|
+ Node(const K& key_, Value& value_) noexcept :
|
|
|
|
|
+ key(key_), value(value_) {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -61,30 +61,31 @@ export namespace Core {
|
|
|
|
|
|
|
|
public:
|
|
public:
|
|
|
Iterator(
|
|
Iterator(
|
|
|
- const K* key, const K* endKey_, Value* value, bool invalidSet) :
|
|
|
|
|
|
|
+ const K* key, const K* endKey_, Value* value,
|
|
|
|
|
+ bool invalidSet) noexcept :
|
|
|
currentKey(key), endKey(endKey_), currentValue(value) {
|
|
currentKey(key), endKey(endKey_), currentValue(value) {
|
|
|
if(!invalidSet) {
|
|
if(!invalidSet) {
|
|
|
skip();
|
|
skip();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Iterator& operator++() {
|
|
|
|
|
|
|
+ Iterator& operator++() noexcept {
|
|
|
++currentKey;
|
|
++currentKey;
|
|
|
++currentValue;
|
|
++currentValue;
|
|
|
skip();
|
|
skip();
|
|
|
return *this;
|
|
return *this;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- bool operator!=(const Iterator& other) const {
|
|
|
|
|
|
|
+ bool operator!=(const Iterator& other) const noexcept {
|
|
|
return currentKey != other.currentKey;
|
|
return currentKey != other.currentKey;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- R operator*() const {
|
|
|
|
|
|
|
+ R operator*() const noexcept {
|
|
|
return A(*currentKey, *currentValue);
|
|
return A(*currentKey, *currentValue);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
private:
|
|
|
- void skip() {
|
|
|
|
|
|
|
+ void skip() noexcept {
|
|
|
while(currentKey != endKey && *currentKey == INVALID) {
|
|
while(currentKey != endKey && *currentKey == INVALID) {
|
|
|
++currentKey;
|
|
++currentKey;
|
|
|
++currentValue;
|
|
++currentValue;
|
|
@@ -93,16 +94,16 @@ export namespace Core {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
template<typename Value>
|
|
template<typename Value>
|
|
|
- static Node<Value> access(const K& key, Value& value) {
|
|
|
|
|
|
|
+ static Node<Value> access(const K& key, Value& value) noexcept {
|
|
|
return Node<Value>(key, value);
|
|
return Node<Value>(key, value);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template<typename Value>
|
|
template<typename Value>
|
|
|
- static Value& accessValue(const K&, Value& value) {
|
|
|
|
|
|
|
+ static Value& accessValue(const K&, Value& value) noexcept {
|
|
|
return value;
|
|
return value;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- static const K& accessKey(const K& key, const V&) {
|
|
|
|
|
|
|
+ static const K& accessKey(const K& key, const V&) noexcept {
|
|
|
return key;
|
|
return key;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -122,13 +123,13 @@ export namespace Core {
|
|
|
struct IteratorAdapter final {
|
|
struct IteratorAdapter final {
|
|
|
M& map;
|
|
M& map;
|
|
|
|
|
|
|
|
- I begin() const {
|
|
|
|
|
|
|
+ I begin() const noexcept {
|
|
|
return {
|
|
return {
|
|
|
map.keys.begin(), map.keys.end(), map.values,
|
|
map.keys.begin(), map.keys.end(), map.values,
|
|
|
map.invalidSet};
|
|
map.invalidSet};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- I end() const {
|
|
|
|
|
|
|
+ I end() const noexcept {
|
|
|
return {
|
|
return {
|
|
|
map.keys.end(), map.keys.end(), nullptr, map.invalidSet};
|
|
map.keys.end(), map.keys.end(), nullptr, map.invalidSet};
|
|
|
}
|
|
}
|
|
@@ -149,9 +150,9 @@ export namespace Core {
|
|
|
bool invalidSet = false;
|
|
bool invalidSet = false;
|
|
|
|
|
|
|
|
public:
|
|
public:
|
|
|
- HashMap() = default;
|
|
|
|
|
|
|
+ HashMap() noexcept = default;
|
|
|
|
|
|
|
|
- HashMap(const HashMap& other) {
|
|
|
|
|
|
|
+ HashMap(const HashMap& other) noexcept {
|
|
|
for(const auto& e : other) {
|
|
for(const auto& e : other) {
|
|
|
add(e.getKey(), e.value);
|
|
add(e.getKey(), e.value);
|
|
|
}
|
|
}
|
|
@@ -161,7 +162,7 @@ export namespace Core {
|
|
|
swap(other);
|
|
swap(other);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ~HashMap() {
|
|
|
|
|
|
|
+ ~HashMap() noexcept {
|
|
|
size_t length = keys.getLength();
|
|
size_t length = keys.getLength();
|
|
|
if(length > 0) {
|
|
if(length > 0) {
|
|
|
for(size_t i = 1; i < length; i++) {
|
|
for(size_t i = 1; i < length; i++) {
|
|
@@ -182,7 +183,7 @@ export namespace Core {
|
|
|
return *this;
|
|
return *this;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void rehash(size_t minCapacity) {
|
|
|
|
|
|
|
+ void rehash(size_t minCapacity) noexcept {
|
|
|
if(minCapacity <= keys.getLength()) {
|
|
if(minCapacity <= keys.getLength()) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -207,7 +208,7 @@ export namespace Core {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template<typename... Args>
|
|
template<typename... Args>
|
|
|
- bool tryEmplace(V*& v, const K& key, Args&&... args) {
|
|
|
|
|
|
|
+ bool tryEmplace(V*& v, const K& key, Args&&... args) noexcept {
|
|
|
size_t index = 0;
|
|
size_t index = 0;
|
|
|
if(key == INVALID) {
|
|
if(key == INVALID) {
|
|
|
if(invalidSet) {
|
|
if(invalidSet) {
|
|
@@ -222,6 +223,8 @@ export namespace Core {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
keys[index] = key;
|
|
keys[index] = key;
|
|
|
|
|
+ static_assert(
|
|
|
|
|
+ noexcept(new(values + index) V(Core::forward<Args>(args)...)));
|
|
|
v = new(values + index) V(Core::forward<Args>(args)...);
|
|
v = new(values + index) V(Core::forward<Args>(args)...);
|
|
|
entries++;
|
|
entries++;
|
|
|
markSlot(key);
|
|
markSlot(key);
|
|
@@ -229,10 +232,12 @@ export namespace Core {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template<typename VA>
|
|
template<typename VA>
|
|
|
- V& put(const K& key, VA&& value) {
|
|
|
|
|
|
|
+ V& put(const K& key, VA&& value) noexcept {
|
|
|
size_t index = 0;
|
|
size_t index = 0;
|
|
|
if(key == INVALID) {
|
|
if(key == INVALID) {
|
|
|
if(invalidSet) {
|
|
if(invalidSet) {
|
|
|
|
|
+ static_assert(
|
|
|
|
|
+ noexcept(values[0] = Core::forward<VA>(value)));
|
|
|
return (values[0] = Core::forward<VA>(value));
|
|
return (values[0] = Core::forward<VA>(value));
|
|
|
}
|
|
}
|
|
|
rehash(1);
|
|
rehash(1);
|
|
@@ -240,9 +245,13 @@ export namespace Core {
|
|
|
} else {
|
|
} else {
|
|
|
index = searchSlot(key);
|
|
index = searchSlot(key);
|
|
|
if(keys[index] == key) {
|
|
if(keys[index] == key) {
|
|
|
|
|
+ static_assert(
|
|
|
|
|
+ noexcept(values[index] = Core::forward<VA>(value)));
|
|
|
return (values[index] = Core::forward<VA>(value));
|
|
return (values[index] = Core::forward<VA>(value));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ static_assert(
|
|
|
|
|
+ noexcept(new(values + index) V(Core::forward<VA>(value))));
|
|
|
new(values + index) V(Core::forward<VA>(value));
|
|
new(values + index) V(Core::forward<VA>(value));
|
|
|
entries++;
|
|
entries++;
|
|
|
keys[index] = key;
|
|
keys[index] = key;
|
|
@@ -251,12 +260,12 @@ export namespace Core {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template<typename VA>
|
|
template<typename VA>
|
|
|
- HashMap& add(const K& key, VA&& value) {
|
|
|
|
|
|
|
+ HashMap& add(const K& key, VA&& value) noexcept {
|
|
|
put(key, Core::forward<VA>(value));
|
|
put(key, Core::forward<VA>(value));
|
|
|
return *this;
|
|
return *this;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- bool remove(const K& key) {
|
|
|
|
|
|
|
+ bool remove(const K& key) noexcept {
|
|
|
size_t index = 0;
|
|
size_t index = 0;
|
|
|
if(key == INVALID) {
|
|
if(key == INVALID) {
|
|
|
if(!invalidSet) {
|
|
if(!invalidSet) {
|
|
@@ -276,49 +285,49 @@ export namespace Core {
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const V* search(const K& key) const {
|
|
|
|
|
|
|
+ const V* search(const K& key) const noexcept {
|
|
|
return searchValue<const V>(key);
|
|
return searchValue<const V>(key);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- V* search(const K& key) {
|
|
|
|
|
|
|
+ V* search(const K& key) noexcept {
|
|
|
return searchValue<V>(key);
|
|
return searchValue<V>(key);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- bool contains(const K& key) const {
|
|
|
|
|
|
|
+ bool contains(const K& key) const noexcept {
|
|
|
return search(key) != nullptr;
|
|
return search(key) != nullptr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- HashMap& clear() {
|
|
|
|
|
|
|
+ HashMap& clear() noexcept {
|
|
|
HashMap<K, V> map;
|
|
HashMap<K, V> map;
|
|
|
swap(map);
|
|
swap(map);
|
|
|
return *this;
|
|
return *this;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ConstKeyIteratorAdapter getKeys() const {
|
|
|
|
|
|
|
+ ConstKeyIteratorAdapter getKeys() const noexcept {
|
|
|
return {*this};
|
|
return {*this};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ValueIteratorAdapter getValues() {
|
|
|
|
|
|
|
+ ValueIteratorAdapter getValues() noexcept {
|
|
|
return {*this};
|
|
return {*this};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ConstValueIteratorAdapter getValues() const {
|
|
|
|
|
|
|
+ ConstValueIteratorAdapter getValues() const noexcept {
|
|
|
return {*this};
|
|
return {*this};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- EntryIterator begin() {
|
|
|
|
|
|
|
+ EntryIterator begin() noexcept {
|
|
|
return {keys.begin(), keys.end(), values, invalidSet};
|
|
return {keys.begin(), keys.end(), values, invalidSet};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- EntryIterator end() {
|
|
|
|
|
|
|
+ EntryIterator end() noexcept {
|
|
|
return {keys.end(), keys.end(), nullptr, invalidSet};
|
|
return {keys.end(), keys.end(), nullptr, invalidSet};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ConstEntryIterator begin() const {
|
|
|
|
|
|
|
+ ConstEntryIterator begin() const noexcept {
|
|
|
return {keys.begin(), keys.end(), values, invalidSet};
|
|
return {keys.begin(), keys.end(), values, invalidSet};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ConstEntryIterator end() const {
|
|
|
|
|
|
|
+ ConstEntryIterator end() const noexcept {
|
|
|
return {keys.end(), keys.end(), nullptr, invalidSet};
|
|
return {keys.end(), keys.end(), nullptr, invalidSet};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -343,7 +352,7 @@ export namespace Core {
|
|
|
} while(false)
|
|
} while(false)
|
|
|
// clang-format on
|
|
// clang-format on
|
|
|
|
|
|
|
|
- size_t searchSlot(const K& key) {
|
|
|
|
|
|
|
+ size_t searchSlot(const K& key) noexcept {
|
|
|
rehash(1);
|
|
rehash(1);
|
|
|
while(true) {
|
|
while(true) {
|
|
|
// rehash on bad clustering
|
|
// rehash on bad clustering
|
|
@@ -357,7 +366,7 @@ export namespace Core {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void markSlot(const K& key) {
|
|
|
|
|
|
|
+ void markSlot(const K& key) noexcept {
|
|
|
FOR_EACH_HASH_START();
|
|
FOR_EACH_HASH_START();
|
|
|
if(keys[hash] == key) {
|
|
if(keys[hash] == key) {
|
|
|
return;
|
|
return;
|
|
@@ -366,7 +375,7 @@ export namespace Core {
|
|
|
FOR_EACH_HASH_STOP();
|
|
FOR_EACH_HASH_STOP();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void demarkSlot(const K& key) {
|
|
|
|
|
|
|
+ void demarkSlot(const K& key) noexcept {
|
|
|
FOR_EACH_HASH_START();
|
|
FOR_EACH_HASH_START();
|
|
|
if(keys[hash] == key) {
|
|
if(keys[hash] == key) {
|
|
|
return;
|
|
return;
|
|
@@ -376,7 +385,7 @@ export namespace Core {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template<typename Value>
|
|
template<typename Value>
|
|
|
- Value* searchValue(const K& key) const {
|
|
|
|
|
|
|
+ Value* searchValue(const K& key) const noexcept {
|
|
|
if(keys.getLength() != 0) {
|
|
if(keys.getLength() != 0) {
|
|
|
if(key == INVALID) {
|
|
if(key == INVALID) {
|
|
|
return invalidSet ? values : nullptr;
|
|
return invalidSet ? values : nullptr;
|