AK: Introduce AK::enumerate

Co-Authored-By: Tim Flynn <trflynn89@pm.me>
This commit is contained in:
Dan Klishch 2024-03-10 20:52:50 -04:00 committed by Tim Flynn
parent 2d11fc6d44
commit 45a0ba2167
3 changed files with 117 additions and 0 deletions

65
AK/Enumerate.h Normal file
View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/StdLibExtras.h>
namespace AK {
namespace Detail {
template<typename Iterable>
class Enumerator {
using IteratorType = decltype(declval<Iterable>().begin());
using ValueType = decltype(*declval<IteratorType>());
struct Enumeration {
size_t index { 0 };
ValueType value;
};
public:
Enumerator(Iterable&& iterable)
: m_iterable(forward<Iterable>(iterable))
, m_iterator(m_iterable.begin())
, m_end(m_iterable.end())
{
}
Enumerator const& begin() const { return *this; }
Enumerator const& end() const { return *this; }
Enumeration operator*() { return { m_index, *m_iterator }; }
Enumeration operator*() const { return { m_index, *m_iterator }; }
bool operator!=(Enumerator const&) const { return m_iterator != m_end; }
void operator++()
{
++m_index;
++m_iterator;
}
private:
Iterable m_iterable;
size_t m_index { 0 };
IteratorType m_iterator;
IteratorType const m_end;
};
}
template<typename T>
auto enumerate(T&& range)
{
return Detail::Enumerator<T> { forward<T>(range) };
}
}
#ifdef USING_AK_GLOBALLY
using AK::enumerate;
#endif

View file

@ -25,6 +25,7 @@ set(AK_TEST_SOURCES
TestDoublyLinkedList.cpp
TestEndian.cpp
TestEnumBits.cpp
TestEnumerate.cpp
TestFind.cpp
TestFixedArray.cpp
TestFixedPoint.cpp

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2024, Dan Klishch <danilklishch@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/Enumerate.h>
#include <AK/Span.h>
#include <AK/Vector.h>
struct IndexAndValue {
size_t index;
int value;
bool operator==(IndexAndValue const&) const = default;
};
TEST_CASE(enumerate)
{
{
Vector<IndexAndValue> result;
for (auto [i, value] : enumerate(Vector { 1, 2, 3, 4 })) {
result.append({ i, value });
}
EXPECT_EQ(result, (Vector<IndexAndValue> { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 } }));
}
{
Vector<IndexAndValue> result;
Vector<int> values = { 9, 8, 7, 6 };
for (auto [i, value] : enumerate(values)) {
static_assert(SameAs<decltype(value), int&>);
result.append({ i, value });
value = static_cast<int>(i);
}
EXPECT_EQ(result, (Vector<IndexAndValue> { { 0, 9 }, { 1, 8 }, { 2, 7 }, { 3, 6 } }));
EXPECT_EQ(values, (Vector<int> { 0, 1, 2, 3 }));
}
{
Vector<IndexAndValue> result;
Vector<int> const& values = { 9, 8, 7, 6 };
for (auto [i, value] : enumerate(values)) {
static_assert(SameAs<decltype(value), int const&>);
result.append({ i, value });
}
EXPECT_EQ(result, (Vector<IndexAndValue> { { 0, 9 }, { 1, 8 }, { 2, 7 }, { 3, 6 } }));
}
}