mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
AK: Implement reverse iterators for OrderedHashTable
This commit is contained in:
parent
d94a374001
commit
4d2af7c3d6
Notes:
sideshowbarker
2024-07-17 06:20:50 +09:00
Author: https://github.com/BertalanD Commit: https://github.com/SerenityOS/serenity/commit/4d2af7c3d6 Pull-request: https://github.com/SerenityOS/serenity/pull/21219 Reviewed-by: https://github.com/gmta ✅
2 changed files with 89 additions and 0 deletions
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <AK/Concepts.h>
|
||||
#include <AK/Error.h>
|
||||
#include <AK/ReverseIterator.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/Traits.h>
|
||||
#include <AK/Types.h>
|
||||
|
@ -92,6 +93,27 @@ private:
|
|||
BucketType* m_bucket { nullptr };
|
||||
};
|
||||
|
||||
template<typename OrderedHashTableType, typename T, typename BucketType>
|
||||
class ReverseOrderedHashTableIterator {
|
||||
friend OrderedHashTableType;
|
||||
|
||||
public:
|
||||
bool operator==(ReverseOrderedHashTableIterator const& other) const { return m_bucket == other.m_bucket; }
|
||||
bool operator!=(ReverseOrderedHashTableIterator const& other) const { return m_bucket != other.m_bucket; }
|
||||
T& operator*() { return *m_bucket->slot(); }
|
||||
T* operator->() { return m_bucket->slot(); }
|
||||
void operator++() { m_bucket = m_bucket->previous; }
|
||||
void operator--() { m_bucket = m_bucket->next; }
|
||||
|
||||
private:
|
||||
ReverseOrderedHashTableIterator(BucketType* bucket)
|
||||
: m_bucket(bucket)
|
||||
{
|
||||
}
|
||||
|
||||
BucketType* m_bucket { nullptr };
|
||||
};
|
||||
|
||||
template<typename T, typename TraitsForT, bool IsOrdered>
|
||||
class HashTable {
|
||||
static constexpr size_t grow_capacity_at_least = 8;
|
||||
|
@ -275,6 +297,42 @@ public:
|
|||
return ConstIterator(nullptr, nullptr);
|
||||
}
|
||||
|
||||
using ReverseIterator = Conditional<IsOrdered,
|
||||
ReverseOrderedHashTableIterator<HashTable, T, BucketType>,
|
||||
void>;
|
||||
|
||||
[[nodiscard]] ReverseIterator rbegin()
|
||||
requires(IsOrdered)
|
||||
{
|
||||
return ReverseIterator(m_collection_data.tail);
|
||||
}
|
||||
|
||||
[[nodiscard]] ReverseIterator rend()
|
||||
requires(IsOrdered)
|
||||
{
|
||||
return ReverseIterator(nullptr);
|
||||
}
|
||||
|
||||
auto in_reverse() { return ReverseWrapper::in_reverse(*this); }
|
||||
|
||||
using ReverseConstIterator = Conditional<IsOrdered,
|
||||
ReverseOrderedHashTableIterator<HashTable const, T const, BucketType const>,
|
||||
void>;
|
||||
|
||||
[[nodiscard]] ReverseConstIterator rbegin() const
|
||||
requires(IsOrdered)
|
||||
{
|
||||
return ReverseConstIterator(m_collection_data.tail);
|
||||
}
|
||||
|
||||
[[nodiscard]] ReverseConstIterator rend() const
|
||||
requires(IsOrdered)
|
||||
{
|
||||
return ReverseConstIterator(nullptr);
|
||||
}
|
||||
|
||||
auto in_reverse() const { return ReverseWrapper::in_reverse(*this); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
*this = HashTable();
|
||||
|
|
|
@ -70,6 +70,24 @@ TEST_CASE(range_loop)
|
|||
EXPECT_EQ(loop_counter, 3);
|
||||
}
|
||||
|
||||
TEST_CASE(range_loop_reverse)
|
||||
{
|
||||
Array strings = { "One"sv, "Two"sv, "Three"sv };
|
||||
OrderedHashTable<DeprecatedString> table;
|
||||
EXPECT_EQ(table.set(strings[0]), AK::HashSetResult::InsertedNewEntry);
|
||||
EXPECT_EQ(table.set(strings[1]), AK::HashSetResult::InsertedNewEntry);
|
||||
EXPECT_EQ(table.set(strings[2]), AK::HashSetResult::InsertedNewEntry);
|
||||
|
||||
int loop_counter = 0;
|
||||
int index = strings.size() - 1;
|
||||
for (auto& it : table.in_reverse()) {
|
||||
EXPECT_EQ(it, strings[index]);
|
||||
++loop_counter;
|
||||
--index;
|
||||
}
|
||||
EXPECT_EQ(loop_counter, 3);
|
||||
}
|
||||
|
||||
TEST_CASE(table_remove)
|
||||
{
|
||||
HashTable<DeprecatedString> strings;
|
||||
|
@ -326,6 +344,12 @@ TEST_CASE(ordered_insertion_and_deletion)
|
|||
EXPECT_EQ(*it, values[index]);
|
||||
EXPECT(table.contains(values[index]));
|
||||
}
|
||||
|
||||
index = table.size() - 1;
|
||||
for (auto it = table.rbegin(); it != table.rend(); ++it, --index) {
|
||||
EXPECT_EQ(*it, values[index]);
|
||||
EXPECT(table.contains(values[index]));
|
||||
}
|
||||
};
|
||||
|
||||
expect_table(table, Array<int, 4> { 0, 1, 2, 3 });
|
||||
|
@ -357,6 +381,13 @@ TEST_CASE(ordered_deletion_and_reinsertion)
|
|||
EXPECT_EQ(*it, 1);
|
||||
++it;
|
||||
EXPECT_EQ(it, table.end());
|
||||
|
||||
auto rit = table.rbegin();
|
||||
EXPECT_EQ(*rit, 1);
|
||||
++rit;
|
||||
EXPECT_EQ(*rit, 3);
|
||||
++rit;
|
||||
EXPECT_EQ(rit, table.rend());
|
||||
}
|
||||
|
||||
TEST_CASE(ordered_take_last)
|
||||
|
|
Loading…
Reference in a new issue