diff --git a/AK/Enumerate.h b/AK/Enumerate.h index eadb30f677..841e3fc94e 100644 --- a/AK/Enumerate.h +++ b/AK/Enumerate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Tim Flynn + * Copyright (c) 2024-2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -13,7 +13,7 @@ namespace AK { namespace Detail { template -class Enumerator { +struct Enumerator { using IteratorType = decltype(declval().begin()); using ValueType = decltype(*declval()); @@ -22,34 +22,26 @@ class Enumerator { ValueType value; }; -public: - Enumerator(Iterable&& iterable) - : m_iterable(forward(iterable)) - , m_iterator(m_iterable.begin()) - , m_end(m_iterable.end()) - { - } + struct Iterator { + Enumeration operator*() { return { index, *iterator }; } + Enumeration operator*() const { return { index, *iterator }; } - Enumerator const& begin() const { return *this; } - Enumerator const& end() const { return *this; } + bool operator!=(Iterator const& other) const { return iterator != other.iterator; } - Enumeration operator*() { return { m_index, *m_iterator }; } - Enumeration operator*() const { return { m_index, *m_iterator }; } + void operator++() + { + ++index; + ++iterator; + } - bool operator!=(Enumerator const&) const { return m_iterator != m_end; } + size_t index { 0 }; + IteratorType iterator; + }; - void operator++() - { - ++m_index; - ++m_iterator; - } + Iterator begin() { return { 0, iterable.begin() }; } + Iterator end() { return { 0, iterable.end() }; } -private: - Iterable m_iterable; - - size_t m_index { 0 }; - IteratorType m_iterator; - IteratorType const m_end; + Iterable iterable; }; } diff --git a/Tests/AK/TestEnumerate.cpp b/Tests/AK/TestEnumerate.cpp index dffc2869b6..728962aeab 100644 --- a/Tests/AK/TestEnumerate.cpp +++ b/Tests/AK/TestEnumerate.cpp @@ -49,3 +49,43 @@ TEST_CASE(enumerate) EXPECT_EQ(result, (Vector { { 0, 9 }, { 1, 8 }, { 2, 7 }, { 3, 6 } })); } } + +class CopyCounter { +public: + static inline size_t copy_count = 0; + + CopyCounter() = default; + CopyCounter(CopyCounter const&) { ++copy_count; } + CopyCounter(CopyCounter&&) { } + + auto begin() const { return m_vec.begin(); } + auto end() const { return m_vec.end(); } + +private: + Vector m_vec { 1, 2, 3, 4 }; +}; + +TEST_CASE(do_not_copy) +{ + { + Vector result; + CopyCounter::copy_count = 0; + CopyCounter counter {}; + + for (auto [i, value] : enumerate(counter)) + result.append({ i, value }); + + EXPECT_EQ(result, (Vector { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 } })); + EXPECT_EQ(CopyCounter::copy_count, 0uz); + } + { + Vector result; + CopyCounter::copy_count = 0; + + for (auto [i, value] : enumerate(CopyCounter {})) + result.append({ i, value }); + + EXPECT_EQ(result, (Vector { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 } })); + EXPECT_EQ(CopyCounter::copy_count, 0uz); + } +}