BAN: Remove unstable hash map and set
These can now be implemented safely with new linked list api
This commit is contained in:
parent
5da59c9151
commit
40e341b0ee
|
@ -7,7 +7,7 @@
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>, bool STABLE = true>
|
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
||||||
class HashMap
|
class HashMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -32,12 +32,12 @@ namespace BAN
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HashMap() = default;
|
HashMap() = default;
|
||||||
HashMap(const HashMap<Key, T, HASH, STABLE>&);
|
HashMap(const HashMap<Key, T, HASH>&);
|
||||||
HashMap(HashMap<Key, T, HASH, STABLE>&&);
|
HashMap(HashMap<Key, T, HASH>&&);
|
||||||
~HashMap();
|
~HashMap();
|
||||||
|
|
||||||
HashMap<Key, T, HASH, STABLE>& operator=(const HashMap<Key, T, HASH, STABLE>&);
|
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
|
||||||
HashMap<Key, T, HASH, STABLE>& operator=(HashMap<Key, T, HASH, STABLE>&&);
|
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
|
||||||
|
|
||||||
ErrorOr<void> insert(const Key&, const T&);
|
ErrorOr<void> insert(const Key&, const T&);
|
||||||
ErrorOr<void> insert(const Key&, T&&);
|
ErrorOr<void> insert(const Key&, T&&);
|
||||||
|
@ -74,26 +74,26 @@ namespace BAN
|
||||||
friend iterator;
|
friend iterator;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap<Key, T, HASH, STABLE>::HashMap(const HashMap<Key, T, HASH, STABLE>& other)
|
HashMap<Key, T, HASH>::HashMap(const HashMap<Key, T, HASH>& other)
|
||||||
{
|
{
|
||||||
*this = other;
|
*this = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap<Key, T, HASH, STABLE>::HashMap(HashMap<Key, T, HASH, STABLE>&& other)
|
HashMap<Key, T, HASH>::HashMap(HashMap<Key, T, HASH>&& other)
|
||||||
{
|
{
|
||||||
*this = move(other);
|
*this = move(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap<Key, T, HASH, STABLE>::~HashMap()
|
HashMap<Key, T, HASH>::~HashMap()
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap<Key, T, HASH, STABLE>& HashMap<Key, T, HASH, STABLE>::operator=(const HashMap<Key, T, HASH, STABLE>& other)
|
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(const HashMap<Key, T, HASH>& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_buckets = other.m_buckets;
|
m_buckets = other.m_buckets;
|
||||||
|
@ -101,8 +101,8 @@ namespace BAN
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap<Key, T, HASH, STABLE>& HashMap<Key, T, HASH, STABLE>::operator=(HashMap<Key, T, HASH, STABLE>&& other)
|
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(HashMap<Key, T, HASH>&& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_buckets = move(other.m_buckets);
|
m_buckets = move(other.m_buckets);
|
||||||
|
@ -111,21 +111,21 @@ namespace BAN
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::insert(const Key& key, const T& value)
|
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, const T& value)
|
||||||
{
|
{
|
||||||
return insert(key, move(T(value)));
|
return insert(key, move(T(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::insert(const Key& key, T&& value)
|
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, T&& value)
|
||||||
{
|
{
|
||||||
return emplace(key, move(value));
|
return emplace(key, move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::emplace(const Key& key, Args&&... args)
|
ErrorOr<void> HashMap<Key, T, HASH>::emplace(const Key& key, Args&&... args)
|
||||||
{
|
{
|
||||||
ASSERT(!contains(key));
|
ASSERT(!contains(key));
|
||||||
TRY(rebucket(m_size + 1));
|
TRY(rebucket(m_size + 1));
|
||||||
|
@ -135,15 +135,15 @@ namespace BAN
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::reserve(size_type size)
|
ErrorOr<void> HashMap<Key, T, HASH>::reserve(size_type size)
|
||||||
{
|
{
|
||||||
TRY(rebucket(size));
|
TRY(rebucket(size));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
void HashMap<Key, T, HASH, STABLE>::remove(const Key& key)
|
void HashMap<Key, T, HASH>::remove(const Key& key)
|
||||||
{
|
{
|
||||||
if (empty()) return;
|
if (empty()) return;
|
||||||
auto& bucket = get_bucket(key);
|
auto& bucket = get_bucket(key);
|
||||||
|
@ -158,15 +158,15 @@ namespace BAN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
void HashMap<Key, T, HASH, STABLE>::clear()
|
void HashMap<Key, T, HASH>::clear()
|
||||||
{
|
{
|
||||||
m_buckets.clear();
|
m_buckets.clear();
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
T& HashMap<Key, T, HASH, STABLE>::operator[](const Key& key)
|
T& HashMap<Key, T, HASH>::operator[](const Key& key)
|
||||||
{
|
{
|
||||||
ASSERT(!empty());
|
ASSERT(!empty());
|
||||||
auto& bucket = get_bucket(key);
|
auto& bucket = get_bucket(key);
|
||||||
|
@ -176,8 +176,8 @@ namespace BAN
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
const T& HashMap<Key, T, HASH, STABLE>::operator[](const Key& key) const
|
const T& HashMap<Key, T, HASH>::operator[](const Key& key) const
|
||||||
{
|
{
|
||||||
ASSERT(!empty());
|
ASSERT(!empty());
|
||||||
const auto& bucket = get_bucket(key);
|
const auto& bucket = get_bucket(key);
|
||||||
|
@ -187,8 +187,8 @@ namespace BAN
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
bool HashMap<Key, T, HASH, STABLE>::contains(const Key& key) const
|
bool HashMap<Key, T, HASH>::contains(const Key& key) const
|
||||||
{
|
{
|
||||||
if (empty()) return false;
|
if (empty()) return false;
|
||||||
const auto& bucket = get_bucket(key);
|
const auto& bucket = get_bucket(key);
|
||||||
|
@ -198,20 +198,20 @@ namespace BAN
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
bool HashMap<Key, T, HASH, STABLE>::empty() const
|
bool HashMap<Key, T, HASH>::empty() const
|
||||||
{
|
{
|
||||||
return m_size == 0;
|
return m_size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
typename HashMap<Key, T, HASH, STABLE>::size_type HashMap<Key, T, HASH, STABLE>::size() const
|
typename HashMap<Key, T, HASH>::size_type HashMap<Key, T, HASH>::size() const
|
||||||
{
|
{
|
||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::rebucket(size_type bucket_count)
|
ErrorOr<void> HashMap<Key, T, HASH>::rebucket(size_type bucket_count)
|
||||||
{
|
{
|
||||||
if (m_buckets.size() >= bucket_count)
|
if (m_buckets.size() >= bucket_count)
|
||||||
return {};
|
return {};
|
||||||
|
@ -222,13 +222,10 @@ namespace BAN
|
||||||
|
|
||||||
for (auto& bucket : m_buckets)
|
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();
|
size_type new_bucket_index = HASH()(it->key) % new_buckets.size();
|
||||||
if constexpr(STABLE)
|
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
||||||
TRY(new_buckets[bucket_index].push_back(entry));
|
|
||||||
else
|
|
||||||
TRY(new_buckets[bucket_index].push_back(move(entry)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,27 +233,20 @@ namespace BAN
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
LinkedList<typename HashMap<Key, T, HASH, STABLE>::Entry>& HashMap<Key, T, HASH, STABLE>::get_bucket(const Key& key)
|
LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key)
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
ASSERT(!m_buckets.empty());
|
||||||
auto index = HASH()(key) % m_buckets.size();
|
auto index = HASH()(key) % m_buckets.size();
|
||||||
return m_buckets[index];
|
return m_buckets[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
const LinkedList<typename HashMap<Key, T, HASH, STABLE>::Entry>& HashMap<Key, T, HASH, STABLE>::get_bucket(const Key& key) const
|
const LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key) const
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
ASSERT(!m_buckets.empty());
|
||||||
auto index = HASH()(key) % m_buckets.size();
|
auto index = HASH()(key) % m_buckets.size();
|
||||||
return m_buckets[index];
|
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<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
|
||||||
using HashMapUnstable = HashMap<Key, T, HASH, false>;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T, typename HASH = hash<T>, bool STABLE = true>
|
template<typename T, typename HASH = hash<T>>
|
||||||
class HashSet
|
class HashSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -55,23 +55,23 @@ namespace BAN
|
||||||
size_type m_size = 0;
|
size_type m_size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
HashSet<T, HASH, STABLE>::HashSet(const HashSet& other)
|
HashSet<T, HASH>::HashSet(const HashSet& other)
|
||||||
: m_buckets(other.m_buckets)
|
: m_buckets(other.m_buckets)
|
||||||
, m_size(other.m_size)
|
, m_size(other.m_size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
HashSet<T, HASH, STABLE>::HashSet(HashSet&& other)
|
HashSet<T, HASH>::HashSet(HashSet&& other)
|
||||||
: m_buckets(move(other.m_buckets))
|
: m_buckets(move(other.m_buckets))
|
||||||
, m_size(other.m_size)
|
, m_size(other.m_size)
|
||||||
{
|
{
|
||||||
other.clear();
|
other.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
HashSet<T, HASH, STABLE>& HashSet<T, HASH, STABLE>::operator=(const HashSet& other)
|
HashSet<T, HASH>& HashSet<T, HASH>::operator=(const HashSet& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_buckets = other.m_buckets;
|
m_buckets = other.m_buckets;
|
||||||
|
@ -79,8 +79,8 @@ namespace BAN
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
HashSet<T, HASH, STABLE>& HashSet<T, HASH, STABLE>::operator=(HashSet&& other)
|
HashSet<T, HASH>& HashSet<T, HASH>::operator=(HashSet&& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_buckets = move(other.m_buckets);
|
m_buckets = move(other.m_buckets);
|
||||||
|
@ -89,14 +89,14 @@ namespace BAN
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
ErrorOr<void> HashSet<T, HASH, STABLE>::insert(const T& key)
|
ErrorOr<void> HashSet<T, HASH>::insert(const T& key)
|
||||||
{
|
{
|
||||||
return insert(move(T(key)));
|
return insert(move(T(key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
ErrorOr<void> HashSet<T, HASH, STABLE>::insert(T&& key)
|
ErrorOr<void> HashSet<T, HASH>::insert(T&& key)
|
||||||
{
|
{
|
||||||
if (!empty() && get_bucket(key).contains(key))
|
if (!empty() && get_bucket(key).contains(key))
|
||||||
return {};
|
return {};
|
||||||
|
@ -107,8 +107,8 @@ namespace BAN
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
void HashSet<T, HASH, STABLE>::remove(const T& key)
|
void HashSet<T, HASH>::remove(const T& key)
|
||||||
{
|
{
|
||||||
if (empty()) return;
|
if (empty()) return;
|
||||||
auto& bucket = get_bucket(key);
|
auto& bucket = get_bucket(key);
|
||||||
|
@ -123,41 +123,41 @@ namespace BAN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
void HashSet<T, HASH, STABLE>::clear()
|
void HashSet<T, HASH>::clear()
|
||||||
{
|
{
|
||||||
m_buckets.clear();
|
m_buckets.clear();
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
ErrorOr<void> HashSet<T, HASH, STABLE>::reserve(size_type size)
|
ErrorOr<void> HashSet<T, HASH>::reserve(size_type size)
|
||||||
{
|
{
|
||||||
TRY(rebucket(size));
|
TRY(rebucket(size));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
bool HashSet<T, HASH, STABLE>::contains(const T& key) const
|
bool HashSet<T, HASH>::contains(const T& key) const
|
||||||
{
|
{
|
||||||
if (empty()) return false;
|
if (empty()) return false;
|
||||||
return get_bucket(key).contains(key);
|
return get_bucket(key).contains(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
typename HashSet<T, HASH, STABLE>::size_type HashSet<T, HASH, STABLE>::size() const
|
typename HashSet<T, HASH>::size_type HashSet<T, HASH>::size() const
|
||||||
{
|
{
|
||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
bool HashSet<T, HASH, STABLE>::empty() const
|
bool HashSet<T, HASH>::empty() const
|
||||||
{
|
{
|
||||||
return m_size == 0;
|
return m_size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
ErrorOr<void> HashSet<T, HASH, STABLE>::rebucket(size_type bucket_count)
|
ErrorOr<void> HashSet<T, HASH>::rebucket(size_type bucket_count)
|
||||||
{
|
{
|
||||||
if (m_buckets.size() >= bucket_count)
|
if (m_buckets.size() >= bucket_count)
|
||||||
return {};
|
return {};
|
||||||
|
@ -169,13 +169,10 @@ namespace BAN
|
||||||
|
|
||||||
for (auto& bucket : m_buckets)
|
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();
|
size_type new_bucket_index = HASH()(*it) % new_buckets.size();
|
||||||
if constexpr(STABLE)
|
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
||||||
TRY(new_buckets[bucket_index].push_back(key));
|
|
||||||
else
|
|
||||||
TRY(new_buckets[bucket_index].push_back(move(key)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,27 +180,20 @@ namespace BAN
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
LinkedList<T>& HashSet<T, HASH, STABLE>::get_bucket(const T& key)
|
LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key)
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
ASSERT(!m_buckets.empty());
|
||||||
size_type index = HASH()(key) % m_buckets.size();
|
size_type index = HASH()(key) % m_buckets.size();
|
||||||
return m_buckets[index];
|
return m_buckets[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<typename T, typename HASH>
|
||||||
const LinkedList<T>& HashSet<T, HASH, STABLE>::get_bucket(const T& key) const
|
const LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key) const
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
ASSERT(!m_buckets.empty());
|
||||||
size_type index = HASH()(key) % m_buckets.size();
|
size_type index = HASH()(key) % m_buckets.size();
|
||||||
return m_buckets[index];
|
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<typename T, typename HASH = hash<T>>
|
|
||||||
using HashSetUnstable = HashSet<T, HASH, false>;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,9 +72,9 @@ static constexpr Position s_dir_offset[] {
|
||||||
|
|
||||||
i64 solve_general(FILE* fp, auto parse_dir, auto parse_count)
|
i64 solve_general(FILE* fp, auto parse_dir, auto parse_count)
|
||||||
{
|
{
|
||||||
BAN::HashSetUnstable<Position, PositionHash> path;
|
BAN::HashSet<Position, PositionHash> path;
|
||||||
BAN::HashSetUnstable<Position, PositionHash> lpath;
|
BAN::HashSet<Position, PositionHash> lpath;
|
||||||
BAN::HashSetUnstable<Position, PositionHash> rpath;
|
BAN::HashSet<Position, PositionHash> rpath;
|
||||||
|
|
||||||
Position current_pos { 0, 0 };
|
Position current_pos { 0, 0 };
|
||||||
MUST(path.insert(current_pos));
|
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);
|
ASSERT(lmin_x != rmin_x);
|
||||||
auto& expand = (lmin_x < rmin_x) ? rpath : lpath;
|
auto& expand = (lmin_x < rmin_x) ? rpath : lpath;
|
||||||
|
|
||||||
BAN::HashSetUnstable<Position, PositionHash> visited;
|
BAN::HashSet<Position, PositionHash> visited;
|
||||||
BAN::HashSetUnstable<Position, PositionHash> inner_area;
|
BAN::HashSet<Position, PositionHash> inner_area;
|
||||||
|
|
||||||
while (!expand.empty())
|
while (!expand.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,7 +33,7 @@ struct Rule
|
||||||
BAN::String target;
|
BAN::String target;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Workflows = BAN::HashMapUnstable<BAN::String, BAN::Vector<Rule>>;
|
using Workflows = BAN::HashMap<BAN::String, BAN::Vector<Rule>>;
|
||||||
|
|
||||||
struct Item
|
struct Item
|
||||||
{
|
{
|
||||||
|
|
|
@ -72,9 +72,9 @@ struct ConjunctionModule : public Module
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BAN::HashMapUnstable<BAN::String, BAN::UniqPtr<Module>> parse_modules(FILE* fp)
|
BAN::HashMap<BAN::String, BAN::UniqPtr<Module>> parse_modules(FILE* fp)
|
||||||
{
|
{
|
||||||
BAN::HashMapUnstable<BAN::String, BAN::UniqPtr<Module>> modules;
|
BAN::HashMap<BAN::String, BAN::UniqPtr<Module>> modules;
|
||||||
|
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
while (fgets(buffer, sizeof(buffer), fp))
|
while (fgets(buffer, sizeof(buffer), fp))
|
||||||
|
|
|
@ -88,13 +88,13 @@ i64 puzzle1(FILE* fp)
|
||||||
{
|
{
|
||||||
auto garden = parse_garden(fp);
|
auto garden = parse_garden(fp);
|
||||||
|
|
||||||
BAN::HashSetUnstable<Position> visited, reachable, pending;
|
BAN::HashSet<Position> visited, reachable, pending;
|
||||||
MUST(pending.insert(garden.start));
|
MUST(pending.insert(garden.start));
|
||||||
|
|
||||||
for (i32 i = 0; i <= 64; i++)
|
for (i32 i = 0; i <= 64; i++)
|
||||||
{
|
{
|
||||||
auto temp = BAN::move(pending);
|
auto temp = BAN::move(pending);
|
||||||
pending = BAN::HashSetUnstable<Position>();
|
pending = BAN::HashSet<Position>();
|
||||||
|
|
||||||
while (!temp.empty())
|
while (!temp.empty())
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue