libluna: Implement hash table iteration
All checks were successful
Build and test / build (push) Successful in 1m47s
All checks were successful
Build and test / build (push) Successful in 1m47s
This commit is contained in:
parent
903dcfa52c
commit
7345a952ca
@ -154,6 +154,16 @@ template <typename K, typename V> struct HashMap
|
||||
m_table.clear();
|
||||
}
|
||||
|
||||
const HashTable<HashPair<K, V>>::HashTableIterator begin()
|
||||
{
|
||||
return m_table.begin();
|
||||
}
|
||||
|
||||
const HashTable<HashPair<K, V>>::HashTableIterator end()
|
||||
{
|
||||
return m_table.end();
|
||||
}
|
||||
|
||||
private:
|
||||
HashTable<HashPair<K, V>> m_table;
|
||||
};
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <luna/Heap.h>
|
||||
#include <luna/Option.h>
|
||||
|
||||
template <typename K, typename V> class HashMap;
|
||||
|
||||
/**
|
||||
* @brief A table of values with best-case constant time lookup.
|
||||
*
|
||||
@ -181,6 +183,77 @@ template <typename T> class HashTable
|
||||
clear();
|
||||
}
|
||||
|
||||
struct HashTableIterator
|
||||
{
|
||||
private:
|
||||
HashTableIterator(usize index, HashTable<T>& table) : m_table(table)
|
||||
{
|
||||
if (index != -1)
|
||||
{
|
||||
m_index = index;
|
||||
return;
|
||||
}
|
||||
|
||||
for (usize i = 0; i < m_table.m_capacity; i++)
|
||||
{
|
||||
auto& opt = m_table.m_buckets[i];
|
||||
if (opt.has_value())
|
||||
{
|
||||
m_index = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_index = m_table.m_capacity;
|
||||
}
|
||||
|
||||
mutable usize m_index;
|
||||
HashTable<T>& m_table;
|
||||
|
||||
public:
|
||||
T& operator*()
|
||||
{
|
||||
return *m_table.m_buckets[m_index].value_ptr();
|
||||
}
|
||||
|
||||
const T& operator*() const
|
||||
{
|
||||
return *m_table.m_buckets[m_index].value_ptr();
|
||||
}
|
||||
|
||||
void operator++() const
|
||||
{
|
||||
for (usize i = m_index + 1; i < m_table.m_capacity; i++)
|
||||
{
|
||||
auto& opt = m_table.m_buckets[i];
|
||||
if (opt.has_value())
|
||||
{
|
||||
m_index = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_index = m_table.m_capacity;
|
||||
}
|
||||
|
||||
bool operator!=(HashTableIterator& other) const
|
||||
{
|
||||
return m_index != other.m_index || &m_table != &other.m_table;
|
||||
}
|
||||
|
||||
friend class HashTable<T>;
|
||||
};
|
||||
|
||||
const HashTableIterator begin()
|
||||
{
|
||||
return { (usize)-1, *this };
|
||||
}
|
||||
|
||||
const HashTableIterator end()
|
||||
{
|
||||
return { m_capacity, *this };
|
||||
}
|
||||
|
||||
private:
|
||||
bool should_grow()
|
||||
{
|
||||
@ -223,4 +296,6 @@ template <typename T> class HashTable
|
||||
usize m_size { 0 };
|
||||
// FIXME: Randomize this to protect against hash table attacks.
|
||||
u64 m_salt { 0 };
|
||||
|
||||
friend class HashTableIterator;
|
||||
};
|
||||
|
@ -80,6 +80,24 @@ TestResult test_hash_map_set_and_get()
|
||||
test_success;
|
||||
}
|
||||
|
||||
TestResult test_hash_table_iteration()
|
||||
{
|
||||
HashTable<int> table;
|
||||
|
||||
validate(TRY(table.try_set(1)));
|
||||
validate(TRY(table.try_set(2)));
|
||||
validate(TRY(table.try_set(3)));
|
||||
validate(TRY(table.try_set(4)));
|
||||
|
||||
int sum = 0;
|
||||
|
||||
for (const int& value : table) { sum += value; }
|
||||
|
||||
validate(sum == 10);
|
||||
|
||||
test_success;
|
||||
}
|
||||
|
||||
Result<void> test_main()
|
||||
{
|
||||
test_prelude;
|
||||
@ -89,6 +107,7 @@ Result<void> test_main()
|
||||
run_test(test_hash_table_remove);
|
||||
run_test(test_hash_table_duplicates);
|
||||
run_test(test_hash_map_set_and_get);
|
||||
run_test(test_hash_table_iteration);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user