From 756ef2c7226b654648d28780382ce3fee57a85a3 Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Mon, 5 Aug 2024 23:45:36 -0600 Subject: [PATCH] AK: Conform SimpleIterator to the random access iterator requirements This requires pulling in some of the STL, but the result is that our iterator is now STL Approved :tm: and our containers can be auto-conformed to Swift protocols. --- AK/Iterator.h | 90 ++++++++++++++++++++++++++----------- Tests/AK/TestArray.cpp | 6 +++ Tests/AK/TestFixedArray.cpp | 8 ++++ Tests/AK/TestSpan.cpp | 13 ++++++ Tests/AK/TestStringView.cpp | 5 +++ Tests/AK/TestVector.cpp | 13 ++++++ 6 files changed, 109 insertions(+), 26 deletions(-) diff --git a/AK/Iterator.h b/AK/Iterator.h index d09cbeaf261..6c7a6fd2464 100644 --- a/AK/Iterator.h +++ b/AK/Iterator.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, the SerenityOS developers. + * Copyright (c) 2024, Andrew Kaster * * SPDX-License-Identifier: BSD-2-Clause */ @@ -7,6 +8,7 @@ #pragma once #include +#include namespace AK { @@ -15,22 +17,44 @@ class SimpleIterator { public: friend Container; - constexpr bool is_end() const { return m_index == SimpleIterator::end(m_container).m_index; } + using value_type = ValueType; + using iterator_category = std::random_access_iterator_tag; + + constexpr bool is_end() const { return m_index == SimpleIterator::end(*m_container).m_index; } constexpr size_t index() const { return m_index; } - constexpr bool operator==(SimpleIterator other) const { return m_index == other.m_index; } - constexpr bool operator!=(SimpleIterator other) const { return m_index != other.m_index; } - constexpr bool operator<(SimpleIterator other) const { return m_index < other.m_index; } - constexpr bool operator>(SimpleIterator other) const { return m_index > other.m_index; } - constexpr bool operator<=(SimpleIterator other) const { return m_index <= other.m_index; } - constexpr bool operator>=(SimpleIterator other) const { return m_index >= other.m_index; } + constexpr bool operator==(SimpleIterator const& other) const = default; + constexpr auto operator<=>(SimpleIterator const& other) const = default; - constexpr SimpleIterator operator+(ptrdiff_t delta) const { return SimpleIterator { m_container, m_index + delta }; } - constexpr SimpleIterator operator-(ptrdiff_t delta) const { return SimpleIterator { m_container, m_index - delta }; } + constexpr SimpleIterator operator+(ptrdiff_t delta) const { return SimpleIterator { *m_container, m_index + delta }; } + friend constexpr SimpleIterator operator+(ptrdiff_t delta, SimpleIterator const& it) { return it + delta; } + constexpr SimpleIterator& operator+=(ptrdiff_t delta) + { + m_index += delta; + return *this; + } + constexpr SimpleIterator operator-(ptrdiff_t delta) const { return SimpleIterator { *m_container, m_index - delta }; } + friend constexpr SimpleIterator operator-(ptrdiff_t delta, SimpleIterator const& it) { return it - delta; } + constexpr SimpleIterator& operator-=(ptrdiff_t delta) + { + m_index -= delta; + return *this; + } + + constexpr ValueType& operator[](ptrdiff_t delta) const + requires(!IsConst) + { + return (*m_container)[m_index + delta]; + } + constexpr ValueType const& operator[](ptrdiff_t delta) const + requires(IsConst) + { + return (*m_container)[m_index + delta]; + } constexpr ptrdiff_t operator-(SimpleIterator other) const { return static_cast(m_index) - other.m_index; } - constexpr SimpleIterator operator++() + constexpr SimpleIterator& operator++() { ++m_index; return *this; @@ -38,10 +62,10 @@ public: constexpr SimpleIterator operator++(int) { ++m_index; - return SimpleIterator { m_container, m_index - 1 }; + return SimpleIterator { *m_container, m_index - 1 }; } - constexpr SimpleIterator operator--() + constexpr SimpleIterator& operator--() { --m_index; return *this; @@ -49,21 +73,35 @@ public: constexpr SimpleIterator operator--(int) { --m_index; - return SimpleIterator { m_container, m_index + 1 }; + return SimpleIterator { *m_container, m_index + 1 }; } - ALWAYS_INLINE constexpr ValueType const& operator*() const { return m_container[m_index]; } - ALWAYS_INLINE constexpr ValueType& operator*() { return m_container[m_index]; } - - ALWAYS_INLINE constexpr ValueType const* operator->() const { return &m_container[m_index]; } - ALWAYS_INLINE constexpr ValueType* operator->() { return &m_container[m_index]; } - - SimpleIterator& operator=(SimpleIterator const& other) + ALWAYS_INLINE constexpr ValueType const& operator*() const + requires(IsConst) { - m_index = other.m_index; - return *this; + return (*m_container)[m_index]; } - SimpleIterator(SimpleIterator const& obj) = default; + ALWAYS_INLINE constexpr ValueType& operator*() const + requires(!IsConst) + { + return (*m_container)[m_index]; + } + + ALWAYS_INLINE constexpr ValueType const* operator->() const + requires(IsConst) + { + return &(*m_container)[m_index]; + } + ALWAYS_INLINE constexpr ValueType* operator->() const + requires(!IsConst) + { + return &(*m_container)[m_index]; + } + + constexpr SimpleIterator& operator=(SimpleIterator const& other) = default; + constexpr SimpleIterator(SimpleIterator const& obj) = default; + + constexpr SimpleIterator() = default; private: static constexpr SimpleIterator begin(Container& container) { return { container, 0 }; } @@ -78,13 +116,13 @@ private: } constexpr SimpleIterator(Container& container, size_t index) - : m_container(container) + : m_container(&container) , m_index(index) { } - Container& m_container; - size_t m_index; + Container* m_container = nullptr; + size_t m_index = 0; }; } diff --git a/Tests/AK/TestArray.cpp b/Tests/AK/TestArray.cpp index 6a71d324fb8..afcde1c61c6 100644 --- a/Tests/AK/TestArray.cpp +++ b/Tests/AK/TestArray.cpp @@ -23,6 +23,12 @@ TEST_CASE(compile_time_constructible) static_assert(array.size() == 4); } +TEST_CASE(conforms_to_iterator_protocol) +{ + static_assert(std::random_access_iterator::Iterator>); + static_assert(std::random_access_iterator::ConstIterator>); +} + TEST_CASE(compile_time_iterable) { constexpr Array array = { 0, 1, 2, 3, 4, 5, 6, 7 }; diff --git a/Tests/AK/TestFixedArray.cpp b/Tests/AK/TestFixedArray.cpp index 85e878791d7..c4fae1a05e3 100644 --- a/Tests/AK/TestFixedArray.cpp +++ b/Tests/AK/TestFixedArray.cpp @@ -27,6 +27,14 @@ TEST_CASE(ints) EXPECT_EQ(ints[2], 2); } +TEST_CASE(conforms_to_iterator_procotol) +{ + static_assert(std::random_access_iterator::Iterator>); + static_assert(std::random_access_iterator::ConstIterator>); + static_assert(std::random_access_iterator::Iterator>); + static_assert(std::random_access_iterator::ConstIterator>); +} + TEST_CASE(swap) { FixedArray first = FixedArray::must_create_but_fixme_should_propagate_errors(4); diff --git a/Tests/AK/TestSpan.cpp b/Tests/AK/TestSpan.cpp index 407f8ca407a..6644d78d651 100644 --- a/Tests/AK/TestSpan.cpp +++ b/Tests/AK/TestSpan.cpp @@ -16,6 +16,19 @@ TEST_CASE(constexpr_default_constructor_is_empty) static_assert(span.is_empty(), "Default constructed span should be empty."); } +TEST_CASE(conforms_to_iterator_protocol) +{ + static_assert(std::random_access_iterator::Iterator>); + static_assert(std::random_access_iterator::ConstIterator>); + static_assert(std::random_access_iterator::Iterator>); + static_assert(std::random_access_iterator::ConstIterator>); + + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); +} + TEST_CASE(implicit_conversion_to_const) { constexpr Bytes bytes0; diff --git a/Tests/AK/TestStringView.cpp b/Tests/AK/TestStringView.cpp index 63523b863b5..ce0fcc5687c 100644 --- a/Tests/AK/TestStringView.cpp +++ b/Tests/AK/TestStringView.cpp @@ -40,6 +40,11 @@ TEST_CASE(compare_views) EXPECT_EQ(view1, "foo"); } +TEST_CASE(conforms_to_iterator_protocol) +{ + static_assert(std::random_access_iterator); +} + TEST_CASE(string_view_literal_operator) { StringView literal_view = "foo"sv; diff --git a/Tests/AK/TestVector.cpp b/Tests/AK/TestVector.cpp index 4250f29356d..e0171412e98 100644 --- a/Tests/AK/TestVector.cpp +++ b/Tests/AK/TestVector.cpp @@ -56,6 +56,19 @@ TEST_CASE(strings) EXPECT_EQ(loop_counter, 2); } +TEST_CASE(conforms_to_iterator_protocol) +{ + static_assert(std::random_access_iterator::Iterator>); + static_assert(std::random_access_iterator::ConstIterator>); + static_assert(std::random_access_iterator::Iterator>); + static_assert(std::random_access_iterator::ConstIterator>); + + static_assert(std::random_access_iterator::Iterator>); + static_assert(std::random_access_iterator::ConstIterator>); + static_assert(std::random_access_iterator::Iterator>); + static_assert(std::random_access_iterator::ConstIterator>); +} + TEST_CASE(strings_insert_ordered) { Vector strings;