diff --git a/BAN/include/BAN/HashMap.h b/BAN/include/BAN/HashMap.h index 4328b2ba..4fd15354 100644 --- a/BAN/include/BAN/HashMap.h +++ b/BAN/include/BAN/HashMap.h @@ -7,7 +7,7 @@ namespace BAN { - template, bool STABLE = true> + template> class HashMap { public: @@ -32,12 +32,12 @@ namespace BAN public: HashMap() = default; - HashMap(const HashMap&); - HashMap(HashMap&&); + HashMap(const HashMap&); + HashMap(HashMap&&); ~HashMap(); - HashMap& operator=(const HashMap&); - HashMap& operator=(HashMap&&); + HashMap& operator=(const HashMap&); + HashMap& operator=(HashMap&&); ErrorOr insert(const Key&, const T&); ErrorOr insert(const Key&, T&&); @@ -74,26 +74,26 @@ namespace BAN friend iterator; }; - template - HashMap::HashMap(const HashMap& other) + template + HashMap::HashMap(const HashMap& other) { *this = other; } - template - HashMap::HashMap(HashMap&& other) + template + HashMap::HashMap(HashMap&& other) { *this = move(other); } - template - HashMap::~HashMap() + template + HashMap::~HashMap() { clear(); } - template - HashMap& HashMap::operator=(const HashMap& other) + template + HashMap& HashMap::operator=(const HashMap& other) { clear(); m_buckets = other.m_buckets; @@ -101,8 +101,8 @@ namespace BAN return *this; } - template - HashMap& HashMap::operator=(HashMap&& other) + template + HashMap& HashMap::operator=(HashMap&& other) { clear(); m_buckets = move(other.m_buckets); @@ -111,21 +111,21 @@ namespace BAN return *this; } - template - ErrorOr HashMap::insert(const Key& key, const T& value) + template + ErrorOr HashMap::insert(const Key& key, const T& value) { return insert(key, move(T(value))); } - template - ErrorOr HashMap::insert(const Key& key, T&& value) + template + ErrorOr HashMap::insert(const Key& key, T&& value) { return emplace(key, move(value)); } - template + template template - ErrorOr HashMap::emplace(const Key& key, Args&&... args) + ErrorOr HashMap::emplace(const Key& key, Args&&... args) { ASSERT(!contains(key)); TRY(rebucket(m_size + 1)); @@ -135,15 +135,15 @@ namespace BAN return {}; } - template - ErrorOr HashMap::reserve(size_type size) + template + ErrorOr HashMap::reserve(size_type size) { TRY(rebucket(size)); return {}; } - template - void HashMap::remove(const Key& key) + template + void HashMap::remove(const Key& key) { if (empty()) return; auto& bucket = get_bucket(key); @@ -158,15 +158,15 @@ namespace BAN } } - template - void HashMap::clear() + template + void HashMap::clear() { m_buckets.clear(); m_size = 0; } - template - T& HashMap::operator[](const Key& key) + template + T& HashMap::operator[](const Key& key) { ASSERT(!empty()); auto& bucket = get_bucket(key); @@ -176,8 +176,8 @@ namespace BAN ASSERT(false); } - template - const T& HashMap::operator[](const Key& key) const + template + const T& HashMap::operator[](const Key& key) const { ASSERT(!empty()); const auto& bucket = get_bucket(key); @@ -187,8 +187,8 @@ namespace BAN ASSERT(false); } - template - bool HashMap::contains(const Key& key) const + template + bool HashMap::contains(const Key& key) const { if (empty()) return false; const auto& bucket = get_bucket(key); @@ -198,20 +198,20 @@ namespace BAN return false; } - template - bool HashMap::empty() const + template + bool HashMap::empty() const { return m_size == 0; } - template - typename HashMap::size_type HashMap::size() const + template + typename HashMap::size_type HashMap::size() const { return m_size; } - template - ErrorOr HashMap::rebucket(size_type bucket_count) + template + ErrorOr HashMap::rebucket(size_type bucket_count) { if (m_buckets.size() >= bucket_count) return {}; @@ -222,13 +222,10 @@ namespace BAN for (auto& bucket : m_buckets) { - for (Entry& entry : bucket) + for (auto it = bucket.begin(); it != bucket.end();) { - size_type bucket_index = HASH()(entry.key) % new_buckets.size(); - if constexpr(STABLE) - TRY(new_buckets[bucket_index].push_back(entry)); - else - TRY(new_buckets[bucket_index].push_back(move(entry))); + 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); } } @@ -236,27 +233,20 @@ namespace BAN return {}; } - template - LinkedList::Entry>& HashMap::get_bucket(const Key& key) + template + LinkedList::Entry>& HashMap::get_bucket(const Key& key) { ASSERT(!m_buckets.empty()); auto index = HASH()(key) % m_buckets.size(); return m_buckets[index]; } - template - const LinkedList::Entry>& HashMap::get_bucket(const Key& key) const + template + const LinkedList::Entry>& HashMap::get_bucket(const Key& key) const { ASSERT(!m_buckets.empty()); auto index = HASH()(key) % m_buckets.size(); return m_buckets[index]; } - // Unstable hash map moves values between container during rebucketing. - // This means that if insertion to map fails, elements could be in invalid state - // and that container is no longer usable. This is better if either way you are - // going to stop using the hash map after insertion fails. - template> - using HashMapUnstable = HashMap; - } diff --git a/BAN/include/BAN/HashSet.h b/BAN/include/BAN/HashSet.h index ecff41ae..d8a5305e 100644 --- a/BAN/include/BAN/HashSet.h +++ b/BAN/include/BAN/HashSet.h @@ -11,7 +11,7 @@ namespace BAN { - template, bool STABLE = true> + template> class HashSet { public: @@ -55,23 +55,23 @@ namespace BAN size_type m_size = 0; }; - template - HashSet::HashSet(const HashSet& other) + template + HashSet::HashSet(const HashSet& other) : m_buckets(other.m_buckets) , m_size(other.m_size) { } - template - HashSet::HashSet(HashSet&& other) + template + HashSet::HashSet(HashSet&& other) : m_buckets(move(other.m_buckets)) , m_size(other.m_size) { other.clear(); } - template - HashSet& HashSet::operator=(const HashSet& other) + template + HashSet& HashSet::operator=(const HashSet& other) { clear(); m_buckets = other.m_buckets; @@ -79,8 +79,8 @@ namespace BAN return *this; } - template - HashSet& HashSet::operator=(HashSet&& other) + template + HashSet& HashSet::operator=(HashSet&& other) { clear(); m_buckets = move(other.m_buckets); @@ -89,14 +89,14 @@ namespace BAN return *this; } - template - ErrorOr HashSet::insert(const T& key) + template + ErrorOr HashSet::insert(const T& key) { return insert(move(T(key))); } - template - ErrorOr HashSet::insert(T&& key) + template + ErrorOr HashSet::insert(T&& key) { if (!empty() && get_bucket(key).contains(key)) return {}; @@ -107,8 +107,8 @@ namespace BAN return {}; } - template - void HashSet::remove(const T& key) + template + void HashSet::remove(const T& key) { if (empty()) return; auto& bucket = get_bucket(key); @@ -123,41 +123,41 @@ namespace BAN } } - template - void HashSet::clear() + template + void HashSet::clear() { m_buckets.clear(); m_size = 0; } - template - ErrorOr HashSet::reserve(size_type size) + template + ErrorOr HashSet::reserve(size_type size) { TRY(rebucket(size)); return {}; } - template - bool HashSet::contains(const T& key) const + template + bool HashSet::contains(const T& key) const { if (empty()) return false; return get_bucket(key).contains(key); } - template - typename HashSet::size_type HashSet::size() const + template + typename HashSet::size_type HashSet::size() const { return m_size; } - template - bool HashSet::empty() const + template + bool HashSet::empty() const { return m_size == 0; } - template - ErrorOr HashSet::rebucket(size_type bucket_count) + template + ErrorOr HashSet::rebucket(size_type bucket_count) { if (m_buckets.size() >= bucket_count) return {}; @@ -169,13 +169,10 @@ namespace BAN for (auto& bucket : m_buckets) { - for (T& key : bucket) + for (auto it = bucket.begin(); it != bucket.end();) { - size_type bucket_index = HASH()(key) % new_buckets.size(); - if constexpr(STABLE) - TRY(new_buckets[bucket_index].push_back(key)); - else - TRY(new_buckets[bucket_index].push_back(move(key))); + size_type new_bucket_index = HASH()(*it) % new_buckets.size(); + it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it); } } @@ -183,27 +180,20 @@ namespace BAN return {}; } - template - LinkedList& HashSet::get_bucket(const T& key) + template + LinkedList& HashSet::get_bucket(const T& key) { ASSERT(!m_buckets.empty()); size_type index = HASH()(key) % m_buckets.size(); return m_buckets[index]; } - template - const LinkedList& HashSet::get_bucket(const T& key) const + template + const LinkedList& HashSet::get_bucket(const T& key) const { ASSERT(!m_buckets.empty()); size_type index = HASH()(key) % m_buckets.size(); return m_buckets[index]; } - // Unstable hash set moves values between container during rebucketing. - // This means that if insertion to set fails, elements could be in invalid state - // and that container is no longer usable. This is better if either way you are - // going to stop using the hash set after insertion fails. - template> - using HashSetUnstable = HashSet; - } diff --git a/userspace/aoc2023/day18/main.cpp b/userspace/aoc2023/day18/main.cpp index 006e779f..e2481d92 100644 --- a/userspace/aoc2023/day18/main.cpp +++ b/userspace/aoc2023/day18/main.cpp @@ -72,9 +72,9 @@ static constexpr Position s_dir_offset[] { i64 solve_general(FILE* fp, auto parse_dir, auto parse_count) { - BAN::HashSetUnstable path; - BAN::HashSetUnstable lpath; - BAN::HashSetUnstable rpath; + BAN::HashSet path; + BAN::HashSet lpath; + BAN::HashSet rpath; Position current_pos { 0, 0 }; MUST(path.insert(current_pos)); @@ -157,8 +157,8 @@ i64 solve_general(FILE* fp, auto parse_dir, auto parse_count) ASSERT(lmin_x != rmin_x); auto& expand = (lmin_x < rmin_x) ? rpath : lpath; - BAN::HashSetUnstable visited; - BAN::HashSetUnstable inner_area; + BAN::HashSet visited; + BAN::HashSet inner_area; while (!expand.empty()) { diff --git a/userspace/aoc2023/day19/main.cpp b/userspace/aoc2023/day19/main.cpp index c6e70f8c..7a18fe0f 100644 --- a/userspace/aoc2023/day19/main.cpp +++ b/userspace/aoc2023/day19/main.cpp @@ -33,7 +33,7 @@ struct Rule BAN::String target; }; -using Workflows = BAN::HashMapUnstable>; +using Workflows = BAN::HashMap>; struct Item { diff --git a/userspace/aoc2023/day20/main.cpp b/userspace/aoc2023/day20/main.cpp index ec41f7ad..b1cee452 100644 --- a/userspace/aoc2023/day20/main.cpp +++ b/userspace/aoc2023/day20/main.cpp @@ -72,9 +72,9 @@ struct ConjunctionModule : public Module } }; -BAN::HashMapUnstable> parse_modules(FILE* fp) +BAN::HashMap> parse_modules(FILE* fp) { - BAN::HashMapUnstable> modules; + BAN::HashMap> modules; char buffer[128]; while (fgets(buffer, sizeof(buffer), fp)) diff --git a/userspace/aoc2023/day21/main.cpp b/userspace/aoc2023/day21/main.cpp index 2a055551..461497dd 100644 --- a/userspace/aoc2023/day21/main.cpp +++ b/userspace/aoc2023/day21/main.cpp @@ -88,13 +88,13 @@ i64 puzzle1(FILE* fp) { auto garden = parse_garden(fp); - BAN::HashSetUnstable visited, reachable, pending; + BAN::HashSet visited, reachable, pending; MUST(pending.insert(garden.start)); for (i32 i = 0; i <= 64; i++) { auto temp = BAN::move(pending); - pending = BAN::HashSetUnstable(); + pending = BAN::HashSet(); while (!temp.empty()) {