From 3d410c41e93dc36e3664fb4f388b02feaa3a239c Mon Sep 17 00:00:00 2001 From: lenamonj Date: Sun, 6 Sep 2026 02:33:01 -0400 Subject: [PATCH 1/3] Complete the random access iterator interface of dyn_array_iterator --- include/gsl/dyn_array | 33 +++++++++++++++++++++++++++++++-- tests/dyn_array_tests.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/include/gsl/dyn_array b/include/gsl/dyn_array index 10a43eb1..91a96cca 100644 --- a/include/gsl/dyn_array +++ b/include/gsl/dyn_array @@ -177,9 +177,7 @@ namespace details using const_reference = const T&; using iterator_category = std::random_access_iterator_tag; -#if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) constexpr dyn_array_iterator() = default; -#endif /* __cpp_lib_ranges >= 201911L */ constexpr operator dyn_array_iterator() const { return {_ptr, _pos, _end_pos}; } @@ -199,6 +197,25 @@ namespace details return !(*this == other); } + constexpr auto operator<(const dyn_array_iterator& other) const + { + Expects(_ptr == other._ptr); + Expects(_end_pos == other._end_pos); + return _pos < other._pos; + } + + constexpr auto operator>(const dyn_array_iterator& other) const { return other < *this; } + + constexpr auto operator<=(const dyn_array_iterator& other) const + { + return !(other < *this); + } + + constexpr auto operator>=(const dyn_array_iterator& other) const + { + return !(*this < other); + } + constexpr auto operator*() const -> reference { Expects(_ptr != nullptr); @@ -206,6 +223,13 @@ namespace details return _ptr[_pos]; } + constexpr auto operator->() const -> pointer + { + Expects(_ptr != nullptr); + Expects(_pos < _end_pos); + return _ptr + _pos; + } + constexpr auto operator++() -> dyn_array_iterator& { Expects(_pos < _end_pos); @@ -256,6 +280,11 @@ namespace details return dyn_array_iterator{_ptr, gsl::narrow(new_pos), _end_pos}; } + friend constexpr auto operator+(difference_type diff, const dyn_array_iterator& it) + { + return it + diff; + } + constexpr auto operator-(difference_type diff) const { return *this + (-diff); } constexpr auto operator-(const dyn_array_iterator& other) const diff --git a/tests/dyn_array_tests.cpp b/tests/dyn_array_tests.cpp index 51e7fb08..8e75040d 100644 --- a/tests/dyn_array_tests.cpp +++ b/tests/dyn_array_tests.cpp @@ -2,6 +2,7 @@ #include "deathTestCommon.h" #include "gsl/dyn_array" +#include #include #include #include @@ -9,6 +10,7 @@ #include #include #include +#include // Despite using and utilities in this test, they // are not being included directly by this file as a test to ensure @@ -631,6 +633,39 @@ TEST(dyn_array_tests, random_access_iterator_arithmetic_accepts_negative_offsets EXPECT_EQ(next, 'd'); } +TEST(dyn_array_tests, random_access_iterator_comparisons) +{ + gsl::dyn_array giants{'c', 'a', 'b'}; + + const auto first = giants.begin(); + const auto last = giants.end(); + + EXPECT_TRUE(first < last); + EXPECT_TRUE(last > first); + EXPECT_TRUE(first <= first); + EXPECT_TRUE(first >= first); + EXPECT_FALSE(last <= first); + EXPECT_EQ(2 + first, last - 1); + EXPECT_EQ(*(1 + first), 'a'); + + std::sort(giants.begin(), giants.end()); + EXPECT_EQ(giants[0], 'a'); + EXPECT_EQ(giants[1], 'b'); + EXPECT_EQ(giants[2], 'c'); +} + +TEST(dyn_array_tests, iterator_member_access_and_default_construction) +{ + gsl::dyn_array> rockies{{'a', 1}, {'b', 2}}; + EXPECT_EQ(rockies.begin()->second, 1); + EXPECT_EQ((rockies.begin() + 1)->first, 'b'); + + gsl::dyn_array::iterator it{}; + gsl::dyn_array::const_iterator cit{}; + EXPECT_TRUE(it == gsl::dyn_array::iterator{}); + EXPECT_TRUE(cit == gsl::dyn_array::const_iterator{}); +} + TEST(dyn_array_tests, input_iterator_constructor) { std::istringstream stream{"n a t s"}; From 550dfcb970502c9b0e0cf453d8a5527dda69ad3e Mon Sep 17 00:00:00 2001 From: lenamonj Date: Thu, 10 Sep 2026 21:17:12 -0400 Subject: [PATCH 2/3] Remove the direct include; the test checks transitive inclusion --- tests/dyn_array_tests.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/dyn_array_tests.cpp b/tests/dyn_array_tests.cpp index 8e75040d..2c147889 100644 --- a/tests/dyn_array_tests.cpp +++ b/tests/dyn_array_tests.cpp @@ -2,7 +2,6 @@ #include "deathTestCommon.h" #include "gsl/dyn_array" -#include #include #include #include From 0d03ab78da318f9351d2e682eff5b196d1efc444 Mon Sep 17 00:00:00 2001 From: lenamonj Date: Thu, 10 Sep 2026 21:17:12 -0400 Subject: [PATCH 3/3] Satisfy the random_access_iterator and contiguous_iterator concepts --- include/gsl/dyn_array | 29 +++++++++++++++++++---------- tests/dyn_array_tests.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/include/gsl/dyn_array b/include/gsl/dyn_array index 91a96cca..8d2e6257 100644 --- a/include/gsl/dyn_array +++ b/include/gsl/dyn_array @@ -176,6 +176,9 @@ namespace details using reference = T&; using const_reference = const T&; using iterator_category = std::random_access_iterator_tag; +#if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts)) + using iterator_concept = std::contiguous_iterator_tag; +#endif /* __cpp_lib_ranges || (_MSVC_STL_VERSION && __cpp_lib_concepts) */ constexpr dyn_array_iterator() = default; @@ -294,16 +297,7 @@ namespace details return gsl::narrow(_pos) - gsl::narrow(other._pos); } - constexpr auto operator[](size_type pos) -> reference - { - Expects(_pos + pos < _end_pos); - return _ptr[_pos + pos]; - } - - constexpr auto operator[](size_type pos) const -> const_reference - { - return const_cast(*this).operator[](pos); - } + constexpr auto operator[](difference_type pos) const -> reference { return *(*this + pos); } private: constexpr dyn_array_iterator(pointer ptr, size_type pos, size_type end_pos) @@ -321,6 +315,8 @@ namespace details friend class dyn_array_iterator; template friend class ::gsl::dyn_array; + template + friend struct std::pointer_traits; }; } // namespace details @@ -474,4 +470,17 @@ dyn_array(std::from_range_t, InputRg&&, Alloc = {}) #endif /* __cpp_deduction_guides >= 201703L */ } // namespace gsl +namespace std +{ +template +struct pointer_traits<::gsl::details::dyn_array_iterator> +{ + using pointer = ::gsl::details::dyn_array_iterator; + using element_type = Type; + using difference_type = ptrdiff_t; + + static constexpr element_type* to_address(const pointer i) noexcept { return i._ptr + i._pos; } +}; +} // namespace std + #endif /* defined(GSL_DYN_ARRAY_H) */ diff --git a/tests/dyn_array_tests.cpp b/tests/dyn_array_tests.cpp index 2c147889..a5cc5092 100644 --- a/tests/dyn_array_tests.cpp +++ b/tests/dyn_array_tests.cpp @@ -10,6 +10,9 @@ #include #include #include +#if defined(__cplusplus) && __cplusplus >= 202002L +#include +#endif /* __cplusplus >= 202002L */ // Despite using and utilities in this test, they // are not being included directly by this file as a test to ensure @@ -38,11 +41,21 @@ static_assert(std::is_copy_constructible::iterator>::value, #if defined(__cpp_lib_concepts) && (__cpp_lib_concepts >= 202002L) static_assert(std::input_iterator::iterator>, "gsl::dyn_array should expose a valid input_iterator"); +static_assert(std::random_access_iterator::iterator>, + "gsl::dyn_array should expose a valid random_access_iterator"); +static_assert(std::random_access_iterator::const_iterator>, + "gsl::dyn_array should expose a valid random_access const_iterator"); +static_assert(std::contiguous_iterator::iterator>, + "gsl::dyn_array should expose a valid contiguous_iterator"); +static_assert(std::contiguous_iterator::const_iterator>, + "gsl::dyn_array should expose a valid contiguous const_iterator"); #endif /* __cpp_lib_concepts >= 202002L */ #if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) static_assert(std::ranges::input_range>, "gsl::dyn_array should be a valid input range"); +static_assert(std::ranges::contiguous_range>, + "gsl::dyn_array should be a valid contiguous range"); #endif /* __cpp_lib_ranges >= 201911L */ TEST(dyn_array_tests, default_ctor) @@ -665,6 +678,18 @@ TEST(dyn_array_tests, iterator_member_access_and_default_construction) EXPECT_TRUE(cit == gsl::dyn_array::const_iterator{}); } +#if defined(__cpp_lib_span) && (__cpp_lib_span >= 202002L) +TEST(dyn_array_tests, converts_to_a_span) +{ + gsl::dyn_array giants{'a', 'b', 'c'}; + const std::span span{giants}; + + EXPECT_EQ(span.size(), giants.size()); + EXPECT_EQ(span.data(), giants.data()); + EXPECT_EQ(std::to_address(giants.end()), giants.data() + giants.size()); +} +#endif /* __cpp_lib_span >= 202002L */ + TEST(dyn_array_tests, input_iterator_constructor) { std::istringstream stream{"n a t s"};