From 40f3546aca4c61703220e16686d009e313b8f43d Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 21 Apr 2026 00:18:18 +0300 Subject: [PATCH] BAN: Rewrite HashMap as a wrapper around HashSet There is really no need to have two implementation of the same thing. Only difference now is that HashMap's value type has to be movable but this wasn't an issue --- BAN/include/BAN/HashMap.h | 452 +++++++----------- .../libraries/LibInput/KeyboardLayout.cpp | 24 +- userspace/programs/resolver/main.cpp | 1 + 3 files changed, 192 insertions(+), 285 deletions(-) diff --git a/BAN/include/BAN/HashMap.h b/BAN/include/BAN/HashMap.h index ef2489db..45457962 100644 --- a/BAN/include/BAN/HashMap.h +++ b/BAN/include/BAN/HashMap.h @@ -1,49 +1,128 @@ #pragma once -#include -#include -#include +#include namespace BAN { - template> + template + class HashMapIterator + { + public: + HashMapIterator() = default; + + Entry& operator*() + { + return m_iterator.operator*(); + } + const Entry& operator*() const + { + return m_iterator.operator*(); + } + + Entry* operator->() + { + return m_iterator.operator->(); + } + const Entry* operator->() const + { + return m_iterator.operator->(); + } + + HashMapIterator& operator++() + { + ++m_iterator; + return *this; + } + HashMapIterator operator++(int) + { + auto temp = *this; + ++(*this); + return temp; + } + + bool operator==(HashMapIterator other) const + { + return m_iterator == other.m_iterator; + } + bool operator!=(HashMapIterator other) const + { + return m_iterator != other.m_iterator; + } + + private: + explicit HashMapIterator(HashSetIt it) + : m_iterator(it) + { } + + private: + HashSetIt m_iterator; + friend HashMap; + }; + + template, typename COMP = BAN::equal> class HashMap { public: struct Entry { - template - Entry(const Key& key, Args&&... args) requires is_constructible_v - : key(key) - , value(forward(args)...) - {} - - template - Entry(Key&& key, Args&&... args) requires is_constructible_v - : key(BAN::move(key)) - , value(forward(args)...) - {} - Key key; T value; }; + struct EntryHash + { + constexpr bool operator()(const Key& a) + { + return HASH()(a); + } + constexpr bool operator()(const Entry& a) + { + return HASH()(a.key); + } + }; + + struct EntryComp + { + constexpr bool operator()(const Entry& a, const Key& b) + { + return COMP()(a.key, b); + } + constexpr bool operator()(const Entry& a, const Entry& b) + { + return COMP()(a.key, b.key); + } + }; + public: - using size_type = size_t; - using key_type = Key; - using value_type = T; - using iterator = IteratorDouble; - using const_iterator = ConstIteratorDouble; + using size_type = size_t; + using key_type = Key; + using value_type = T; + using iterator = HashMapIterator::iterator, HashMap, Entry>; + using const_iterator = HashMapIterator::const_iterator, HashMap, const Entry>; public: HashMap() = default; - HashMap(const HashMap&); - HashMap(HashMap&&); - ~HashMap(); + ~HashMap() { clear(); } - HashMap& operator=(const HashMap&); - HashMap& operator=(HashMap&&); + HashMap(const HashMap& other) { *this = other; } + HashMap& operator=(const HashMap& other) + { + m_hash_set = other.m_hash_set; + return *this; + } + + HashMap(HashMap&& other) { *this = BAN::move(other); } + HashMap& operator=(HashMap&& other) + { + m_hash_set = BAN::move(other.m_hash_set); + return *this; + } + + iterator begin() { return iterator(m_hash_set.begin()); } + iterator end() { return iterator(m_hash_set.end()); } + const_iterator begin() const { return const_iterator(m_hash_set.begin()); } + const_iterator end() const { return const_iterator(m_hash_set.end()); } ErrorOr insert(const Key& key, const T& value) { return emplace(key, value); } ErrorOr insert(const Key& key, T&& value) { return emplace(key, move(value)); } @@ -57,263 +136,96 @@ namespace BAN template ErrorOr emplace(const Key& key, Args&&... args) requires is_constructible_v - { return emplace(Key(key), forward(args)...); } + { return emplace(Key(key), BAN::forward(args)...); } template - ErrorOr emplace(Key&&, Args&&...) requires is_constructible_v; + ErrorOr emplace(Key&& key, Args&&... args) requires is_constructible_v + { + ASSERT(!contains(key)); + auto it = TRY(m_hash_set.insert(Entry { BAN::move(key), T(BAN::forward(args)...) })); + return iterator(it); + } template ErrorOr emplace_or_assign(const Key& key, Args&&... args) requires is_constructible_v - { return emplace_or_assign(Key(key), forward(args)...); } + { return emplace_or_assign(Key(key), BAN::forward(args)...); } template - ErrorOr emplace_or_assign(Key&&, Args&&...) requires is_constructible_v; + ErrorOr emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v + { + if (auto it = m_hash_set.find(key); it != m_hash_set.end()) + { + it->value = T(BAN::forward(args)...); + return iterator(it); + } - iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); } - iterator end() { return iterator(m_buckets.end(), m_buckets.end()); } - const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); } - const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); } + auto it = TRY(m_hash_set.insert(Entry { BAN::move(key), T(BAN::forward(args)...) })); + return iterator(it); + } - ErrorOr reserve(size_type); + void remove(const Key& key) + { + if (auto it = find(key); it != end()) + remove(it); + } - void remove(const Key&); - void remove(iterator it); - void clear(); + iterator remove(iterator it) + { + return iterator(m_hash_set.remove(it.m_iterator)); + } - T& operator[](const Key&); - const T& operator[](const Key&) const; + template requires requires(const Key& a, const U& b) { COMP()(a, b); HASH()(b); } + iterator find(const U& key) + { + return iterator(m_hash_set.find(key)); + } - iterator find(const Key& key); - const_iterator find(const Key& key) const; - bool contains(const Key&) const; + template requires requires(const Key& a, const U& b) { COMP()(a, b); HASH()(b); } + const_iterator find(const U& key) const + { + return const_iterator(m_hash_set.find(key)); + } - bool empty() const; - size_type size() const; + void clear() + { + m_hash_set.clear(); + } + + ErrorOr reserve(size_type size) + { + return m_hash_set.reserve(size); + } + + T& operator[](const Key& key) + { + return find(key)->value; + } + + const T& operator[](const Key& key) const + { + return find(key)->value; + } + + bool contains(const Key& key) const + { + return find(key) != end(); + } + + size_type capacity() const + { + return m_hash_set.capacity(); + } + + size_type size() const + { + return m_hash_set.size(); + } + + bool empty() const + { + return m_hash_set.empty(); + } private: - ErrorOr rebucket(size_type); - LinkedList& get_bucket(const Key&); - const LinkedList& get_bucket(const Key&) const; - Vector>::iterator get_bucket_iterator(const Key&); - Vector>::const_iterator get_bucket_iterator(const Key&) const; - - private: - Vector> m_buckets; - size_type m_size = 0; - - friend iterator; + HashSet m_hash_set; }; - template - HashMap::HashMap(const HashMap& other) - { - *this = other; - } - - template - HashMap::HashMap(HashMap&& other) - { - *this = move(other); - } - - template - HashMap::~HashMap() - { - clear(); - } - - template - HashMap& HashMap::operator=(const HashMap& other) - { - clear(); - m_buckets = other.m_buckets; - m_size = other.m_size; - return *this; - } - - template - HashMap& HashMap::operator=(HashMap&& other) - { - clear(); - m_buckets = move(other.m_buckets); - m_size = other.m_size; - other.m_size = 0; - return *this; - } - - template - template - ErrorOr::iterator> HashMap::emplace(Key&& key, Args&&... args) requires is_constructible_v - { - ASSERT(!contains(key)); - TRY(rebucket(m_size + 1)); - - auto bucket_it = get_bucket_iterator(key); - TRY(bucket_it->emplace_back(move(key), forward(args)...)); - m_size++; - - return iterator(m_buckets.end(), bucket_it, prev(bucket_it->end(), 1)); - } - - template - template - ErrorOr::iterator> HashMap::emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v - { - if (empty()) - return emplace(move(key), forward(args)...); - - auto bucket_it = get_bucket_iterator(key); - for (auto entry_it = bucket_it->begin(); entry_it != bucket_it->end(); entry_it++) - { - if (entry_it->key != key) - continue; - entry_it->value = T(forward(args)...); - return iterator(m_buckets.end(), bucket_it, entry_it); - } - - return emplace(move(key), forward(args)...); - } - - template - ErrorOr HashMap::reserve(size_type size) - { - TRY(rebucket(size)); - return {}; - } - - template - void HashMap::remove(const Key& key) - { - auto it = find(key); - if (it != end()) - remove(it); - } - - template - void HashMap::remove(iterator it) - { - it.outer_current()->remove(it.inner_current()); - m_size--; - } - - template - void HashMap::clear() - { - m_buckets.clear(); - m_size = 0; - } - - template - T& HashMap::operator[](const Key& key) - { - ASSERT(!empty()); - auto& bucket = get_bucket(key); - for (Entry& entry : bucket) - if (entry.key == key) - return entry.value; - ASSERT_NOT_REACHED(); - } - - template - const T& HashMap::operator[](const Key& key) const - { - ASSERT(!empty()); - const auto& bucket = get_bucket(key); - for (const Entry& entry : bucket) - if (entry.key == key) - return entry.value; - ASSERT_NOT_REACHED(); - } - - template - typename HashMap::iterator HashMap::find(const Key& key) - { - if (empty()) - return end(); - auto bucket_it = get_bucket_iterator(key); - for (auto it = bucket_it->begin(); it != bucket_it->end(); it++) - if (it->key == key) - return iterator(m_buckets.end(), bucket_it, it); - return end(); - } - - template - typename HashMap::const_iterator HashMap::find(const Key& key) const - { - if (empty()) - return end(); - auto bucket_it = get_bucket_iterator(key); - for (auto it = bucket_it->begin(); it != bucket_it->end(); it++) - if (it->key == key) - return const_iterator(m_buckets.end(), bucket_it, it); - return end(); - } - - template - bool HashMap::contains(const Key& key) const - { - return find(key) != end(); - } - - template - bool HashMap::empty() const - { - return m_size == 0; - } - - template - typename HashMap::size_type HashMap::size() const - { - return m_size; - } - - template - ErrorOr HashMap::rebucket(size_type bucket_count) - { - if (m_buckets.size() >= bucket_count) - return {}; - - size_type new_bucket_count = BAN::Math::max(bucket_count, m_buckets.size() * 2); - Vector> new_buckets; - TRY(new_buckets.resize(new_bucket_count)); - - for (auto& bucket : m_buckets) - { - for (auto it = bucket.begin(); it != bucket.end();) - { - size_type new_bucket_index = HASH()(it->key) % new_buckets.size(); - it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it); - } - } - - m_buckets = move(new_buckets); - return {}; - } - - template - LinkedList::Entry>& HashMap::get_bucket(const Key& key) - { - return *get_bucket_iterator(key); - } - - template - const LinkedList::Entry>& HashMap::get_bucket(const Key& key) const - { - return *get_bucket_iterator(key); - } - - template - Vector::Entry>>::iterator HashMap::get_bucket_iterator(const Key& key) - { - ASSERT(!m_buckets.empty()); - auto index = HASH()(key) % m_buckets.size(); - return next(m_buckets.begin(), index); - } - - template - Vector::Entry>>::const_iterator HashMap::get_bucket_iterator(const Key& key) const - { - ASSERT(!m_buckets.empty()); - auto index = HASH()(key) % m_buckets.size(); - return next(m_buckets.begin(), index); - } - } diff --git a/userspace/libraries/LibInput/KeyboardLayout.cpp b/userspace/libraries/LibInput/KeyboardLayout.cpp index c3fa618e..55c3143a 100644 --- a/userspace/libraries/LibInput/KeyboardLayout.cpp +++ b/userspace/libraries/LibInput/KeyboardLayout.cpp @@ -19,20 +19,14 @@ namespace LibInput { - struct StringViewLower + struct StringViewLowerComp { - BAN::StringView value; - - StringViewLower(BAN::StringView sv) - : value(sv) - { } - - bool operator==(const StringViewLower& other) const + constexpr bool operator()(const BAN::StringView& a, const BAN::StringView& b) const { - if (value.size() != other.value.size()) + if (a.size() != b.size()) return false; - for (size_t i = 0; i < value.size(); i++) - if (tolower(value[i]) != tolower(other.value[i])) + for (size_t i = 0; i < a.size(); i++) + if (tolower(a[i]) != tolower(b[i])) return false; return true; } @@ -40,16 +34,16 @@ namespace LibInput struct StringViewLowerHash { - BAN::hash_t operator()(const StringViewLower& value) const + BAN::hash_t operator()(const BAN::StringView& str) const { constexpr BAN::hash_t FNV_offset_basis = 0x811c9dc5; constexpr BAN::hash_t FNV_prime = 0x01000193; BAN::hash_t hash = FNV_offset_basis; - for (size_t i = 0; i < value.value.size(); i++) + for (size_t i = 0; i < str.size(); i++) { hash *= FNV_prime; - hash ^= (uint8_t)tolower(value.value[i]); + hash ^= (uint8_t)tolower(str[i]); } return hash; @@ -113,7 +107,7 @@ namespace LibInput return keycode; } - static BAN::HashMap s_name_to_key; + static BAN::HashMap s_name_to_key; static BAN::ErrorOr initialize_name_to_key(); static BAN::Optional parse_key(BAN::StringView name) diff --git a/userspace/programs/resolver/main.cpp b/userspace/programs/resolver/main.cpp index 51ed2f12..53d1a5ce 100644 --- a/userspace/programs/resolver/main.cpp +++ b/userspace/programs/resolver/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include