[libcxx-commits] [libcxx] [libc++][ranges] P2116R9: Implements `views::enumerate` (PR #73617)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jul 24 23:52:18 PDT 2024
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/73617
>From 75fe088c9f38887553bd359353b11a863ca6f7e6 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Thu, 15 Jun 2023 01:59:18 +0300
Subject: [PATCH 01/33] [libc++][ranges] P2116R9: Implements `views::enumerate`
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +
libcxx/docs/Status/Cxx23Papers.csv | 2 +-
libcxx/docs/Status/Cxx2cIssues.csv | 4 +-
libcxx/docs/Status/RangesViews.csv | 2 +-
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__ranges/enumerate_view.h | 333 ++++++++++++++++++
libcxx/include/module.modulemap.in | 1 +
libcxx/include/ranges | 12 +
libcxx/include/version | 2 +
libcxx/modules/std/ranges.inc | 13 +-
.../ranges.version.compile.pass.cpp | 31 ++
.../version.version.compile.pass.cpp | 31 ++
...erator_robust_against_adl.compile.pass.cpp | 1 +
.../range.enumerate/adaptor.pass.cpp | 128 +++++++
.../range.enumerate/base.pass.cpp | 85 +++++
.../range.enumerate/begin.pass.cpp | 129 +++++++
.../range.enumerate/ctad.compile.pass.cpp | 46 +++
.../range.enumerate/ctor.base.pass.cpp | 55 +++
.../range.enumerate/ctor.default.pass.cpp | 81 +++++
.../enable_borrowed_range.compile.pass.cpp | 35 ++
.../range.enumerate/end.pass.cpp | 114 ++++++
.../iterator/arithmetic.pass.cpp | 127 +++++++
.../range.enumerate/iterator/base.pass.cpp | 81 +++++
.../iterator/compare.three_way.pass.cpp | 107 ++++++
.../iterator/ctor.convert.pass.cpp | 84 +++++
.../iterator/ctor.default.pass.cpp | 69 ++++
.../range.enumerate/iterator/deref.pass.cpp | 101 ++++++
.../range.enumerate/iterator/equal.pass.cpp | 97 +++++
.../range.enumerate/iterator/index.pass.cpp | 95 +++++
.../iterator/iter_move.pass.cpp | 75 ++++
.../iterator/subscript.pass.cpp | 77 ++++
.../iterator/types.compile.pass.cpp | 112 ++++++
.../range.enumerate/sentinel/base.pass.cpp | 62 ++++
.../sentinel/ctor.convert.pass.cpp | 75 ++++
.../sentinel/ctor.default.pass.cpp | 76 ++++
.../range.enumerate/sentinel/equal.pass.cpp | 71 ++++
.../range.enumerate/sentinel/minus.pass.cpp | 253 +++++++++++++
.../range.enumerate/size.pass.cpp | 54 +++
.../range.adaptors/range.enumerate/types.h | 136 +++++++
.../range.enumerate/types_iterators.h | 109 ++++++
.../generate_feature_test_macro_components.py | 5 +
41 files changed, 2967 insertions(+), 7 deletions(-)
create mode 100644 libcxx/include/__ranges/enumerate_view.h
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.base.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.default.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/enable_borrowed_range.compile.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.convert.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/size.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/types_iterators.h
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 3b2dff3108b0f..cd1190e25bfe1 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -354,6 +354,8 @@ Status
--------------------------------------------------- -----------------
``__cpp_lib_ranges_chunk_by`` ``202202L``
--------------------------------------------------- -----------------
+ ``__cpp_lib_ranges_enumerate`` ``202302L``
+ --------------------------------------------------- -----------------
``__cpp_lib_ranges_iota`` *unimplemented*
--------------------------------------------------- -----------------
``__cpp_lib_ranges_join_with`` *unimplemented*
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 5cc9e488297b9..5083a26e4d21b 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -105,7 +105,7 @@
"","","","","","",""
"`P0290R4 <https://wg21.link/P0290R4>`__","LWG", "``apply()`` for ``synchronized_value<T>``","February 2023","","","|concurrency TS|"
"`P2770R0 <https://wg21.link/P2770R0>`__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|In Progress|","","|ranges|"
-"`P2164R9 <https://wg21.link/P2164R9>`__","LWG", "``views::enumerate``","February 2023","","","|ranges|"
+"`P2164R9 <https://wg21.link/P2164R9>`__","LWG", "``views::enumerate``","February 2023","|Complete|","18.0","|ranges|"
"`P2711R1 <https://wg21.link/P2711R1>`__","LWG", "Making multi-param constructors of ``views`` ``explicit``","February 2023","|In Progress| [#note-P2711R1]_","","|ranges|"
"`P2609R3 <https://wg21.link/P2609R3>`__","LWG", "Relaxing Ranges Just A Smidge","February 2023","","","|ranges|"
"`P2713R1 <https://wg21.link/P2713R1>`__","LWG", "Escaping improvements in ``std::format``","February 2023","","","|format|"
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index fe0f13f6e8cb2..d12dc23cb4a8c 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -8,8 +8,8 @@
"`3903 <https://wg21.link/LWG3903>`__","span destructor is redundantly noexcept","Varna June 2023","|Complete|","7.0",""
"`3904 <https://wg21.link/LWG3904>`__","``lazy_split_view::outer-iterator``'s const-converting constructor isn't setting ``trailing_empty_``","Varna June 2023","","","|ranges|"
"`3905 <https://wg21.link/LWG3905>`__","Type of ``std::fexcept_t``","Varna June 2023","|Complete|","3.4",""
-"`3912 <https://wg21.link/LWG3912>`__","``enumerate_view::iterator::operator-`` should be ``noexcept``","Varna June 2023","","","|ranges|"
-"`3914 <https://wg21.link/LWG3914>`__","Inconsistent template-head of ``ranges::enumerate_view``","Varna June 2023","","","|ranges|"
+"`3912 <https://wg21.link/LWG3912>`__","``enumerate_view::iterator::operator-`` should be ``noexcept``","Varna June 2023","|Complete|","18.0","|ranges|"
+"`3914 <https://wg21.link/LWG3914>`__","Inconsistent template-head of ``ranges::enumerate_view``","Varna June 2023","|Complete|","18.0","|ranges|"
"`3915 <https://wg21.link/LWG3915>`__","Redundant paragraph about expression variations","Varna June 2023","","","|ranges|"
"`3925 <https://wg21.link/LWG3925>`__","Concept ``formattable``'s definition is incorrect","Varna June 2023","|Complete|","17.0","|format|"
"`3927 <https://wg21.link/LWG3927>`__","Unclear preconditions for ``operator[]`` for sequence containers","Varna June 2023","|Nothing To Do|","",""
diff --git a/libcxx/docs/Status/RangesViews.csv b/libcxx/docs/Status/RangesViews.csv
index f141656eb131a..581596724878b 100644
--- a/libcxx/docs/Status/RangesViews.csv
+++ b/libcxx/docs/Status/RangesViews.csv
@@ -35,4 +35,4 @@ C++23,`chunk_by <https://wg21.link/P2443R1>`_,Jakub Mazurkiewicz,`D144767 <https
C++23,`as_const <https://wg21.link/P2278R4>`_,Unassigned,No patch yet,Not started
C++23,`as_rvalue <https://wg21.link/P2446R2>`_,Nikolas Klauser,`D137637 <https://llvm.org/D137637>`_,✅
C++23,`stride <https://wg21.link/P1899R3>`_,Hristo Hristov and Will Hawkins,`D156924 <https://llvm.org/D156924>`_,In Progress
-C++23,`enumerate <https://wg21.link/P2164R9>`_,Hristo Hristov,`D157193 <https://reviews.llvm.org/D157193>`_,In Progress
+C++23,`enumerate <https://wg21.link/P2164R9>`_,Hristo Hristov,`D157193 <https://reviews.llvm.org/D157193>`_,✅
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index b0bc3718576f6..eca80630bb1c1 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -622,6 +622,7 @@ set(files
__ranges/empty_view.h
__ranges/enable_borrowed_range.h
__ranges/enable_view.h
+ __ranges/enumerate_view.h
__ranges/filter_view.h
__ranges/from_range.h
__ranges/iota_view.h
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
new file mode 100644
index 0000000000000..77b29837ba546
--- /dev/null
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -0,0 +1,333 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___RANGES_ENUMERATE_VIEW_H
+#define _LIBCPP___RANGES_ENUMERATE_VIEW_H
+
+#include <__concepts/convertible_to.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/distance.h>
+#include <__iterator/iter_move.h>
+#include <__iterator/iterator_traits.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/range_adaptor.h>
+#include <__ranges/size.h>
+#include <__ranges/view_interface.h>
+#include <__type_traits/maybe_const.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
+#include <tuple>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+
+// [concept.object]
+
+template <class _Rp>
+concept __range_with_movable_references =
+ ranges::input_range<_Rp> && std::move_constructible<ranges::range_reference_t<_Rp>> &&
+ std::move_constructible<ranges::range_rvalue_reference_t<_Rp>>;
+
+// [range.enumerate.view]
+
+template <view _View>
+ requires __range_with_movable_references<_View>
+class enumerate_view : public view_interface<enumerate_view<_View>> {
+ _View __base_ = _View();
+
+ // [range.enumerate.iterator]
+ template <bool _Const>
+ class __iterator;
+
+ // [range.enumerate.sentinel]
+ template <bool _Const>
+ class __sentinel;
+
+ template <bool _AnyConst>
+ _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __get_current(const __iterator<_AnyConst>& __iter) {
+ return (__iter.__current_);
+ }
+
+public:
+ _LIBCPP_HIDE_FROM_ABI constexpr enumerate_view()
+ requires(default_initializable<_View>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit enumerate_view(_View __base) : __base_(std::move(__base)){};
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+ requires(!__simple_view<_View>)
+ {
+ return __iterator<false>(ranges::begin(__base_), 0);
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+ requires __range_with_movable_references<const _View>
+ {
+ return __iterator<true>(ranges::begin(__base_), 0);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+ requires(!__simple_view<_View>)
+ {
+ if constexpr (common_range<_View> && sized_range<_View>)
+ return __iterator<false>(ranges::end(__base_), ranges::distance(__base_));
+ else
+ return __sentinel<false>(ranges::end(__base_));
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+ requires __range_with_movable_references<const _View>
+ {
+ if constexpr (common_range<const _View> && sized_range<const _View>)
+ return __iterator<true>(ranges::end(__base_), ranges::distance(__base_));
+ else
+ return __sentinel<true>(ranges::end(__base_));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+ requires sized_range<_View>
+ {
+ return ranges::size(__base_);
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+ requires sized_range<const _View>
+ {
+ return ranges::size(__base_);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
+ requires copy_constructible<_View>
+ {
+ return __base_;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
+};
+
+template <class _Range>
+enumerate_view(_Range&&) -> enumerate_view<views::all_t<_Range>>;
+
+// [range.enumerate.iterator]
+
+template <view _View>
+ requires __range_with_movable_references<_View>
+template <bool _Const>
+class enumerate_view<_View>::__iterator {
+ using _Base = __maybe_const<_Const, _View>;
+
+ static consteval auto __get_iterator_concept() {
+ if constexpr (random_access_range<_Base>) {
+ return random_access_iterator_tag{};
+ } else if constexpr (bidirectional_range<_Base>) {
+ return bidirectional_iterator_tag{};
+ } else if constexpr (forward_range<_Base>) {
+ return forward_iterator_tag{};
+ } else {
+ return input_iterator_tag{};
+ }
+ }
+
+ friend class enumerate_view<_View>;
+
+public:
+ using iterator_category = input_iterator_tag;
+ using iterator_concept = decltype(__get_iterator_concept());
+ using difference_type = range_difference_t<_Base>;
+ using value_type = tuple<difference_type, range_value_t<_Base>>;
+
+private:
+ using __reference_type = tuple<difference_type, range_reference_t<_Base>>;
+ iterator_t<_Base> __current_ = iterator_t<_Base>();
+ difference_type __pos_ = 0;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(iterator_t<_Base> __current, difference_type __pos)
+ : __current_(std::move(__current)), __pos_(__pos) {}
+
+public:
+ _LIBCPP_HIDE_FROM_ABI __iterator()
+ requires(default_initializable<iterator_t<_Base>>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
+ requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
+ : __current_(std::move(__i.__current_)), __pos_(__i.__pos_) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_Base>& base() const& noexcept { return __current_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() && { return std::move(__current_); }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr difference_type index() const noexcept { return __pos_; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { return __reference_type(__pos_, *__current_); }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+ ++__current_;
+ ++__pos_;
+ return *this;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { return ++*this; }
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
+ requires forward_range<_Base>
+ {
+ auto __temp = *this;
+ ++*this;
+ return __temp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
+ requires bidirectional_range<_Base>
+ {
+ --__current_;
+ --__pos_;
+ return *this;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
+ requires bidirectional_range<_Base>
+ {
+ auto __temp = *this;
+ --*this;
+ return *__temp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n)
+ requires random_access_range<_Base>
+ {
+ __current_ += __n;
+ __pos_ += __n;
+ return *this;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
+ requires random_access_range<_Base>
+ {
+ __current_ -= __n;
+ __pos_ -= __n;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const
+ requires random_access_range<_Base>
+ {
+ return __reference_type(__pos_ + __n, __current_[__n]);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) noexcept {
+ return __x.__pos_ == __y.__pos_;
+ }
+ _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering
+ operator<=>(const __iterator& __x, const __iterator& __y) noexcept {
+ return __x.__pos_ <=> __y.__pos_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
+ requires random_access_range<_Base>
+ {
+ auto __temp = __i;
+ __temp += __n;
+ return __temp;
+ }
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
+ requires random_access_range<_Base>
+ {
+ return __i + __n;
+ }
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
+ requires random_access_range<_Base>
+ {
+ auto __temp = __i;
+ __temp -= __n;
+ return __temp;
+ }
+ _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+ operator-(const __iterator& __x, const __iterator& __y) noexcept {
+ return __x.__pos_ - __y.__pos_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto iter_move(const __iterator& __i) noexcept(
+ noexcept(ranges::iter_move(__i.__current_)) && is_nothrow_move_constructible_v<range_rvalue_reference_t<_Base>>) {
+ return tuple<difference_type, range_rvalue_reference_t<_Base>>(__i.__pos_, ranges::iter_move(__i.__current_));
+ }
+};
+
+// [range.enumerate.sentinel]
+
+template <view _View>
+ requires __range_with_movable_references<_View>
+template <bool _Const>
+class enumerate_view<_View>::__sentinel {
+ using _Base = __maybe_const<_Const, _View>;
+ sentinel_t<_Base> __end_ = sentinel_t<_Base>();
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {}
+
+ friend class enumerate_view<_View>;
+
+public:
+ _LIBCPP_HIDE_FROM_ABI __sentinel() = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __other)
+ requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
+ : __end_(std::move(__other.__end_)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Base> base() const { return __end_; }
+
+ template <bool _OtherConst>
+ requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
+ return __get_current(__x) == __y.__end_;
+ }
+
+ template <bool _OtherConst>
+ requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
+ operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
+ return __get_current(__x) - __y.__end_;
+ }
+
+ template <bool _OtherConst>
+ requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
+ operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) {
+ return __x.__end_ - __get_current(__y);
+ }
+};
+
+template <class _View>
+constexpr bool enable_borrowed_range<enumerate_view<_View>> = enable_borrowed_range<_View>;
+
+namespace views {
+namespace __enumerate {
+
+struct __fn : __range_adaptor_closure<__fn> {
+ template <class _Range>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
+ noexcept(noexcept(/**/ enumerate_view(std::forward<_Range>(__range))))
+ -> decltype(/*--*/ enumerate_view(std::forward<_Range>(__range))) {
+ return /*-------------*/ enumerate_view(std::forward<_Range>(__range));
+ }
+};
+
+} // namespace __enumerate
+
+inline namespace __cpo {
+
+inline constexpr auto enumerate = __enumerate::__fn{};
+
+} // namespace __cpo
+} // namespace views
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___RANGES_ENUMERATE_VIEW_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 90381f4f7f720..c0949a28b278b 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1663,6 +1663,7 @@ module std_private_ranges_empty [system] { header "__ranges
module std_private_ranges_empty_view [system] { header "__ranges/empty_view.h" }
module std_private_ranges_enable_borrowed_range [system] { header "__ranges/enable_borrowed_range.h" }
module std_private_ranges_enable_view [system] { header "__ranges/enable_view.h" }
+module std_private_ranges_enumerate_view [system] { header "__ranges/enumerate_view.h" }
module std_private_ranges_filter_view [system] {
header "__ranges/filter_view.h"
export std_private_ranges_range_adaptor
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index f71a92f8a660b..56b3c82daa118 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -314,6 +314,17 @@ namespace std::ranges {
namespace views { template<class T> inline constexpr unspecified istream = unspecified; }
+ // [range.enumerate], enumerate view
+ template<view View>
+ requires see below
+ class enumerate_view; // since C++23
+
+ template<class View>
+ constexpr bool enable_borrowed_range<enumerate_view<View>> = // since C++23
+ enable_borrowed_range<View>;
+
+ namespace views { inline constexpr unspecified enumerate = unspecified; } // since C++23
+
// [range.zip], zip view
template<input_range... Views>
requires (view<Views> && ...) && (sizeof...(Views) > 0)
@@ -393,6 +404,7 @@ namespace std {
#include <__ranges/empty_view.h>
#include <__ranges/enable_borrowed_range.h>
#include <__ranges/enable_view.h>
+#include <__ranges/enumerate_view.h>
#include <__ranges/filter_view.h>
#include <__ranges/from_range.h>
#include <__ranges/iota_view.h>
diff --git a/libcxx/include/version b/libcxx/include/version
index ef01af7532982..ed6c2aa9fcd42 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -170,6 +170,7 @@ __cpp_lib_ranges_as_const 202207L <ranges>
__cpp_lib_ranges_as_rvalue 202207L <ranges>
__cpp_lib_ranges_chunk 202202L <ranges>
__cpp_lib_ranges_chunk_by 202202L <ranges>
+__cpp_lib_ranges_enumerate 202302L <ranges>
__cpp_lib_ranges_iota 202202L <numeric>
__cpp_lib_ranges_join_with 202202L <ranges>
__cpp_lib_ranges_repeat 202207L <ranges>
@@ -461,6 +462,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
# define __cpp_lib_ranges_as_rvalue 202207L
// # define __cpp_lib_ranges_chunk 202202L
# define __cpp_lib_ranges_chunk_by 202202L
+# define __cpp_lib_ranges_enumerate 202302L
// # define __cpp_lib_ranges_iota 202202L
// # define __cpp_lib_ranges_join_with 202202L
# define __cpp_lib_ranges_repeat 202207L
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index a883103d81258..5b97f02c56a49 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -320,9 +320,8 @@ export namespace std {
namespace views {
using std::ranges::views::chunk_by;
}
-#endif // _LIBCPP_STD_VER >= 23
-#if 0
+# if 0
// [range.stride], stride view
using std::ranges::stride_view;
@@ -335,7 +334,15 @@ export namespace std {
namespace views {
using std::ranges::views::cartesian_product;
}
-#endif
+# endif
+
+ // [range.enumerate]
+ using std::ranges::enumerate_view;
+
+ namespace views {
+ using std::ranges::views::enumerate;
+ }
+#endif // _LIBCPP_STD_VER >= 23
} // namespace ranges
namespace views = ranges::views;
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
index aa3a4964ad492..0d5bf118892a4 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
@@ -21,6 +21,7 @@
__cpp_lib_ranges_as_rvalue 202207L [C++23]
__cpp_lib_ranges_chunk 202202L [C++23]
__cpp_lib_ranges_chunk_by 202202L [C++23]
+ __cpp_lib_ranges_enumerate 202302L [C++23]
__cpp_lib_ranges_join_with 202202L [C++23]
__cpp_lib_ranges_repeat 202207L [C++23]
__cpp_lib_ranges_slide 202202L [C++23]
@@ -53,6 +54,10 @@
# error "__cpp_lib_ranges_chunk_by should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
@@ -95,6 +100,10 @@
# error "__cpp_lib_ranges_chunk_by should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
@@ -137,6 +146,10 @@
# error "__cpp_lib_ranges_chunk_by should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
@@ -182,6 +195,10 @@
# error "__cpp_lib_ranges_chunk_by should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
@@ -251,6 +268,13 @@
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++23"
# endif
+# ifndef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should be defined in c++23"
+# endif
+# if __cpp_lib_ranges_enumerate != 202302L
+# error "__cpp_lib_ranges_enumerate should have the value 202302L in c++23"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should be defined in c++23"
@@ -353,6 +377,13 @@
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++26"
# endif
+# ifndef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should be defined in c++26"
+# endif
+# if __cpp_lib_ranges_enumerate != 202302L
+# error "__cpp_lib_ranges_enumerate should have the value 202302L in c++26"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should be defined in c++26"
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index d7adf2941b62c..334541501045d 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -158,6 +158,7 @@
__cpp_lib_ranges_as_rvalue 202207L [C++23]
__cpp_lib_ranges_chunk 202202L [C++23]
__cpp_lib_ranges_chunk_by 202202L [C++23]
+ __cpp_lib_ranges_enumerate 202302L [C++23]
__cpp_lib_ranges_iota 202202L [C++23]
__cpp_lib_ranges_join_with 202202L [C++23]
__cpp_lib_ranges_repeat 202207L [C++23]
@@ -771,6 +772,10 @@
# error "__cpp_lib_ranges_chunk_by should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_iota
# error "__cpp_lib_ranges_iota should not be defined before c++23"
# endif
@@ -1593,6 +1598,10 @@
# error "__cpp_lib_ranges_chunk_by should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_iota
# error "__cpp_lib_ranges_iota should not be defined before c++23"
# endif
@@ -2586,6 +2595,10 @@
# error "__cpp_lib_ranges_chunk_by should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_iota
# error "__cpp_lib_ranges_iota should not be defined before c++23"
# endif
@@ -3858,6 +3871,10 @@
# error "__cpp_lib_ranges_chunk_by should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_iota
# error "__cpp_lib_ranges_iota should not be defined before c++23"
# endif
@@ -5328,6 +5345,13 @@
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++23"
# endif
+# ifndef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should be defined in c++23"
+# endif
+# if __cpp_lib_ranges_enumerate != 202302L
+# error "__cpp_lib_ranges_enumerate should have the value 202302L in c++23"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_iota
# error "__cpp_lib_ranges_iota should be defined in c++23"
@@ -7047,6 +7071,13 @@
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++26"
# endif
+# ifndef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should be defined in c++26"
+# endif
+# if __cpp_lib_ranges_enumerate != 202302L
+# error "__cpp_lib_ranges_enumerate should have the value 202302L in c++26"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_iota
# error "__cpp_lib_ranges_iota should be defined in c++26"
diff --git a/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp b/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp
index 09b77c0901a22..2dfd4efaded35 100644
--- a/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp
+++ b/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp
@@ -76,4 +76,5 @@ static_assert(!CanFindADLFunc<std::ranges::transform_view<adl::BaseView, adl::Pr
#if TEST_STD_VER >= 23
static_assert(!CanFindADLFunc<std::ranges::zip_view<adl::BaseView>>);
+static_assert(!CanFindADLFunc<std::ranges::enumerate_view<adl::BaseView>>);
#endif
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp
new file mode 100644
index 0000000000000..edc58536d68dc
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp
@@ -0,0 +1,128 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// std::views::enumerate;
+
+#include <algorithm>
+#include <cassert>
+#include <ranges>
+#include <string_view>
+
+#include "types.h"
+
+// Concepts
+
+template <class View, class T>
+concept CanBePiped = requires(View&& view, T&& t) {
+ { std::forward<View>(view) | std::forward<T>(t) };
+};
+
+template <class Range>
+concept CanEnumerate = requires(Range&& range) { std::views::enumerate(std::forward<Range>(range)); };
+
+// Helpers
+
+struct ImmovableReference {
+ ImmovableReference(ImmovableReference&&) = delete;
+
+ operator int();
+};
+
+struct IteratorWithImmovableReferences {
+ using value_type = int;
+ using difference_type = std::ptrdiff_t;
+
+ ImmovableReference operator*() const;
+ IteratorWithImmovableReferences& operator++();
+ void operator++(int);
+ bool operator==(std::default_sentinel_t) const;
+};
+
+static_assert(std::input_iterator<IteratorWithImmovableReferences>);
+
+using NonEnumeratableRangeWithImmmovabaleReferences =
+ std::ranges::subrange<IteratorWithImmovableReferences, std::default_sentinel_t>;
+
+static_assert(std::ranges::input_range<NonEnumeratableRangeWithImmmovabaleReferences>);
+static_assert(!CanEnumerate<NonEnumeratableRangeWithImmmovabaleReferences>);
+
+template <typename View, typename T>
+using ExpectedViewElement = std::tuple<typename std::ranges::iterator_t<View>::difference_type, T>;
+
+// Helpers
+
+template <typename View, typename T = int>
+constexpr void compareViews(View v, std::initializer_list<ExpectedViewElement<View, T>> list) {
+ assert(std::ranges::equal(v, list));
+}
+
+// Test SFINAE friendliness
+
+static_assert(CanBePiped<RangeView, decltype(std::views::enumerate)>);
+
+static_assert(CanEnumerate<RangeView>);
+
+static_assert(!std::is_invocable_v<decltype(std::views::enumerate)>);
+static_assert(std::is_invocable_v<decltype(std::views::enumerate), RangeView>);
+static_assert(!std::is_invocable_v<decltype(std::views::enumerate), NotAView>);
+static_assert(!std::is_invocable_v<decltype(std::views::enumerate), NotInvocable>);
+
+static_assert(std::is_same_v<decltype(std::ranges::views::enumerate), decltype(std::views::enumerate)>);
+
+constexpr bool test() {
+ // Test `views::enumerate_view(v)`
+ {
+ int buff[] = {0, 1, 2, 3};
+
+ using Result = std::ranges::enumerate_view<RangeView>;
+ RangeView const range(buff, buff + 4);
+
+ std::same_as<Result> decltype(auto) result = std::views::enumerate(range);
+ compareViews(result, {{0, 0}, {1, 1}, {2, 2}, {3, 3}});
+ }
+ {
+ std::string_view sv{"babazmt"};
+ using Result = std::ranges::enumerate_view<std::string_view>;
+
+ std::same_as<Result> decltype(auto) result = std::views::enumerate(sv);
+ compareViews(result, {{0, 'b'}, {1, 'a'}, {2, 'b'}, {3, 'a'}, {4, 'z'}, {5, 'm'}, {6, 't'}});
+ }
+
+ // Test `adaptor | views::enumerate`
+ {
+ int buff[] = {0, 1, 2, 3};
+
+ using Result = std::ranges::enumerate_view<RangeView>;
+ RangeView const range(buff, buff + 4);
+
+ std::same_as<Result> decltype(auto) result = range | std::views::enumerate;
+ compareViews(result, {{0, 0}, {1, 1}, {2, 2}, {3, 3}});
+ }
+ {
+ std::string_view sv{"babazmt"};
+ using Result = std::ranges::enumerate_view<std::string_view>;
+
+ std::same_as<Result> decltype(auto) result = sv | std::views::enumerate;
+ compareViews(result, {{0, 'b'}, {1, 'a'}, {2, 'b'}, {3, 'a'}, {4, 'z'}, {5, 'm'}, {6, 't'}});
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp
new file mode 100644
index 0000000000000..86d8a9e88cb99
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// constexpr V base() const & requires copy_constructible<V>;
+// constexpr V base() &&;
+
+#include <cassert>
+#include <ranges>
+
+#include "MoveOnly.h"
+#include "types.h"
+
+template <class T>
+concept HasBase = requires(T&& t) { std::forward<T>(t).base(); };
+
+// SFINAE
+
+static_assert(HasBase<std::ranges::enumerate_view<RangeView> const&>);
+static_assert(HasBase<std::ranges::enumerate_view<RangeView>&&>);
+
+struct MoveOnlyView : RangeView {
+ MoveOnly mo;
+};
+
+static_assert(!HasBase<std::ranges::enumerate_view<MoveOnlyView> const&>);
+static_assert(HasBase<std::ranges::enumerate_view<MoveOnlyView>&&>);
+
+constexpr bool test() {
+ // Check the const& overload
+ {
+ int buff[] = {0, 1, 2, 3};
+
+ RangeView range(buff, buff + 4);
+
+ std::ranges::enumerate_view<RangeView> view{range};
+ std::same_as<RangeView> decltype(auto) result = view.base();
+ assert(result.wasCopyInitialized);
+ assert(range.begin() == result.begin());
+ assert(range.end() == result.end());
+ }
+ {
+ int buff[] = {0, 1, 2, 3};
+
+ RangeView const range(buff, buff + 4);
+
+ std::ranges::enumerate_view<RangeView> const view{range};
+ std::same_as<RangeView> decltype(auto) result = view.base();
+ assert(result.wasCopyInitialized);
+ assert(range.begin() == result.begin());
+ assert(range.end() == result.end());
+ }
+
+ // Check the && overload
+ {
+ int buff[] = {0, 1, 2, 3};
+
+ RangeView const range(buff, buff + 4);
+
+ std::ranges::enumerate_view<RangeView> view{range};
+ std::same_as<RangeView> decltype(auto) result = std::move(view).base();
+ assert(result.wasMoveInitialized);
+ assert(range.begin() == result.begin());
+ assert(range.end() == result.end());
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
new file mode 100644
index 0000000000000..64876ed71355f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
@@ -0,0 +1,129 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// constexpr auto begin() requires (!simple-view<V>);
+// constexpr auto begin() const requires range-with-movable-references<const V>;
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "types.h"
+
+// Helpers
+
+template <class T>
+concept HasConstBegin = requires(const T ct) { ct.begin(); };
+
+template <class T>
+concept HasBegin = requires(T t) { t.begin(); };
+
+template <class T>
+concept HasConstAndNonConstBegin =
+ HasConstBegin<T> &&
+ // Because const begin() and non-const begin() returns different types: iterator<true> vs. iterator<false>
+ requires(T t, const T ct) { requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>; };
+
+template <class T>
+concept HasOnlyNonConstBegin = HasBegin<T> && !HasConstBegin<T>;
+
+template <class T>
+concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
+
+// Types
+
+template <bool Simple>
+struct CommonView : std::ranges::view_base {
+ constexpr std::tuple<std::ptrdiff_t, int>* begin()
+ requires(!Simple)
+ {
+ return nullptr;
+ }
+ constexpr const std::tuple<std::ptrdiff_t, int>* begin() const { return nullptr; }
+ constexpr std::tuple<std::ptrdiff_t, int>* end()
+ requires(!Simple)
+ {
+ return nullptr;
+ }
+ constexpr const std::tuple<std::ptrdiff_t, int>* end() const { return nullptr; }
+};
+using SimpleCommonView = CommonView<true>;
+using NonSimpleCommonView = CommonView<false>;
+
+struct NoConstBeginView : std::ranges::view_base {
+ constexpr std::tuple<std::ptrdiff_t, int>* begin() { return nullptr; }
+ constexpr std::tuple<std::ptrdiff_t, int>* end() { return nullptr; }
+};
+
+// SFINAE
+
+// simple-view<V>
+static_assert(HasOnlyConstBegin<std::ranges::enumerate_view<SimpleCommonView>>);
+
+// !simple-view<V> && range<const V>
+static_assert(HasConstAndNonConstBegin<std::ranges::enumerate_view<NonSimpleCommonView>>);
+
+// !range<const V>
+static_assert(HasOnlyNonConstBegin<std::ranges::enumerate_view<NoConstBeginView>>);
+
+constexpr bool test() {
+ int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ // Check the return type of begin()
+ {
+ RangeView range(buff, buff + 1);
+
+ std::ranges::enumerate_view view(range);
+ using Iterator = std::ranges::iterator_t<decltype(view)>;
+ static_assert(std::same_as<Iterator, decltype(view.begin())>);
+ }
+
+ // begin() over an empty range
+ {
+ RangeView range(buff, buff);
+
+ std::ranges::enumerate_view view(range);
+ auto it = view.begin();
+ assert(base(it.base()) == buff);
+ assert(it == view.end());
+ }
+
+ // begin() over an 1-element range
+ {
+ RangeView range(buff, buff + 1);
+
+ std::ranges::enumerate_view view(range);
+ auto it = view.begin();
+ assert(base(it.base()) == buff);
+ }
+
+ // begin() over an N-element range
+ {
+ RangeView range(buff, buff + 8);
+
+ std::ranges::enumerate_view view(range);
+ auto it = view.begin();
+ assert(base(it.base()) == buff);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp
new file mode 100644
index 0000000000000..fb6b26c1fd9a5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// template<class R>
+// enumerate_view(R&&) -> enumerate_view<views::all_t<R>>;
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "types.h"
+
+constexpr bool test() {
+ {
+ MinimalDefaultConstructedView jv;
+ std::ranges::enumerate_view view(jv);
+ static_assert(std::is_same_v<decltype(view), std::ranges::enumerate_view<MinimalDefaultConstructedView>>);
+ }
+
+ // Test with a range that isn't a view, to make sure we properly use views::all_t in the implementation.
+ {
+ NotAViewRange range;
+ std::ranges::enumerate_view view(range);
+ static_assert(std::is_same_v<decltype(view), std::ranges::enumerate_view<std::ranges::ref_view<NotAViewRange>>>);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.base.pass.cpp
new file mode 100644
index 0000000000000..ab33ace0cee18
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.base.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// constexpr explicit enumerate_view(V base);
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <tuple>
+#include <type_traits>
+
+#include "types.h"
+
+constexpr bool test() {
+ using EnumerateView = std::ranges::enumerate_view<RangeView>;
+
+ {
+ std::array base = {0, 1, 2, 3, 84};
+
+ RangeView range(base.begin(), base.end());
+ EnumerateView view{range};
+
+ auto baseIt = base.begin();
+ auto viewIt = view.begin();
+ for (std::size_t index = 0; index != base.size(); ++index) {
+ auto [vi, vv] = *viewIt;
+ assert(std::cmp_equal(index, vi));
+ assert(*baseIt == vv);
+
+ ++baseIt;
+ ++viewIt;
+ }
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..8d1c985dbfd33
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.default.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// constexpr enumerate_view() requires default_initializable<V>;
+
+#include <ranges>
+
+#include <cassert>
+#include <tuple>
+#include <type_traits>
+
+constexpr int buff[] = {0, 1};
+
+template <bool DefaultConstructible>
+struct DefaultConstructibleView : std::ranges::view_base {
+ constexpr DefaultConstructibleView()
+ requires DefaultConstructible
+ : begin_(buff), end_(buff + 1) {}
+
+ constexpr int const* begin() const { return begin_; }
+ constexpr int const* end() const { return end_; }
+
+ int const* begin_;
+ int const* end_;
+};
+
+static_assert(std::is_default_constructible_v<std::ranges::enumerate_view<DefaultConstructibleView<true>>>);
+static_assert(!std::is_default_constructible_v<std::ranges::enumerate_view<DefaultConstructibleView<false>>>);
+
+constexpr bool test() {
+ using EnumerateView = std::ranges::enumerate_view<DefaultConstructibleView<true>>;
+
+ {
+ EnumerateView view;
+
+ assert((*view.begin() == std::tuple<std::ranges::iterator_t<EnumerateView>::difference_type, int>{0, 0}));
+ assert((*view.end() == std::tuple<std::ranges::iterator_t<EnumerateView>::difference_type, int>{1, 1}));
+
+ auto [bi, bv] = *view.begin();
+ assert(bi == 0);
+ assert(bv == 0);
+
+ auto [ei, ev] = *view.end();
+ assert(ei == 1);
+ assert(ev == 1);
+ }
+ {
+ EnumerateView view = {};
+
+ assert((*view.begin() == std::tuple<std::ranges::iterator_t<EnumerateView>::difference_type, int>{0, 0}));
+ assert((*view.end() == std::tuple<std::ranges::iterator_t<EnumerateView>::difference_type, int>{1, 1}));
+
+ auto [bi, bv] = *view.begin();
+ assert(bi == 0);
+ assert(bv == 0);
+
+ auto [ei, ev] = *view.end();
+ assert(ei == 1);
+ assert(ev == 1);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/enable_borrowed_range.compile.pass.cpp
new file mode 100644
index 0000000000000..303f5ac063d15
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/enable_borrowed_range.compile.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// template<class View>
+// constexpr bool enable_borrowed_range<enumerate_view<View>>;
+
+#include <cassert>
+#include <ranges>
+
+struct NonBorrowedRange : std::ranges::view_base {
+ int* begin();
+ int* end();
+};
+
+struct BorrowedRange : std::ranges::view_base {
+ int* begin();
+ int* end();
+};
+
+template <>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
+
+static_assert(!std::ranges::borrowed_range<std::ranges::enumerate_view<NonBorrowedRange>>);
+static_assert(std::ranges::borrowed_range<std::ranges::enumerate_view<BorrowedRange>>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp
new file mode 100644
index 0000000000000..744e33d4e33b7
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp
@@ -0,0 +1,114 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// constexpr auto end() requires (!simple-view<V>);
+// constexpr auto end() const requires range-with-movable-references<const V>;
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "types.h"
+
+constexpr bool test() {
+ int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ // Check the return type of .end()
+ {
+ RangeView range(buff, buff + 1);
+
+ std::ranges::enumerate_view view(range);
+ using Iterator = std::ranges::iterator_t<decltype(view)>;
+ static_assert(std::same_as<Iterator, decltype(view.end())>);
+ using Sentinel = std::ranges::sentinel_t<decltype(view)>;
+ static_assert(std::same_as<Sentinel, decltype(view.end())>);
+ }
+
+ // Check the return type of .end() const
+ {
+ RangeView range(buff, buff + 1);
+
+ const std::ranges::enumerate_view view(range);
+ using Iterator = std::ranges::iterator_t<decltype(view)>;
+ static_assert(std::same_as<Iterator, decltype(view.end())>);
+ using Sentinel = std::ranges::sentinel_t<decltype(view)>;
+ static_assert(std::same_as<Sentinel, decltype(view.end())>);
+ }
+
+ // end() over an empty range
+ {
+ RangeView range(buff, buff);
+
+ std::ranges::enumerate_view view(range);
+
+ auto it = view.end();
+ assert(base(it.base()) == buff);
+ assert(it == view.end());
+
+ auto constIt = std::as_const(view).end();
+ assert(base(constIt.base()) == buff);
+ assert(constIt == std::as_const(view).end());
+ }
+
+ // end() const over an empty range
+ {
+ RangeView range(buff, buff);
+
+ const std::ranges::enumerate_view view(range);
+
+ auto it = view.end();
+ assert(base(it.base()) == buff);
+ assert(it == view.end());
+
+ auto constIt = std::as_const(view).end();
+ assert(base(constIt.base()) == buff);
+ assert(constIt == std::as_const(view).end());
+ }
+
+ // end() over an 1-element range
+ {
+ RangeView range(buff, buff + 1);
+
+ std::ranges::enumerate_view view(range);
+
+ auto it = view.end();
+ assert(base(it.base()) == buff + 1);
+
+ auto constIt = std::as_const(view).end();
+ assert(base(constIt.base()) == buff + 1);
+ }
+
+ // end() over an N-element range
+ {
+ RangeView range(buff, buff + 8);
+
+ std::ranges::enumerate_view view(range);
+
+ auto it = view.end();
+ assert(base(it.base()) == buff + 8);
+
+ auto constIt = std::as_const(view).end();
+ assert(base(constIt.base()) == buff + 8);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp
new file mode 100644
index 0000000000000..031605a7aacd8
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp
@@ -0,0 +1,127 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// constexpr iterator& operator+=(difference_type x)
+// requires random_access_range<Base>;
+// constexpr iterator& operator-=(difference_type x)
+// requires random_access_range<Base>;
+
+// friend constexpr iterator operator+(const iterator& x, difference_type y)
+// requires random_access_range<Base>;
+// friend constexpr iterator operator+(difference_type x, const iterator& y)
+// requires random_access_range<Base>;
+// friend constexpr iterator operator-(const iterator& x, difference_type y)
+// requires random_access_range<Base>;
+// friend constexpr difference_type operator-(const iterator& x, const iterator& y);
+
+#include <ranges>
+
+#include "test_iterators.h"
+
+// Concepts
+
+template <class T, class U>
+concept CanPlus = requires(T t, U u) { t + u; };
+
+template <class T, class U>
+concept CanPlusEqual = requires(T t, U u) { t += u; };
+
+template <class T, class U>
+concept CanMinus = requires(T t, U u) { t - u; };
+
+template <class T, class U>
+concept CanMinusEqual = requires(T t, U u) { t -= u; };
+
+template <class BaseRange>
+using EnumerateIter = std::ranges::iterator_t<std::ranges::enumerate_view<BaseRange>>;
+
+using RandomAccessRange = std::ranges::subrange<int*>;
+
+// SFINAE.
+
+static_assert(std::ranges::random_access_range<RandomAccessRange>);
+static_assert(
+ std::sized_sentinel_for<std::ranges::iterator_t<RandomAccessRange>, std::ranges::iterator_t<RandomAccessRange>>);
+
+static_assert(CanPlus<EnumerateIter<RandomAccessRange>, int>);
+static_assert(CanPlus<int, EnumerateIter<RandomAccessRange>>);
+static_assert(CanPlusEqual<EnumerateIter<RandomAccessRange>, int>);
+static_assert(CanMinus<EnumerateIter<RandomAccessRange>, int>);
+static_assert(CanMinus<EnumerateIter<RandomAccessRange>, EnumerateIter<RandomAccessRange>>);
+static_assert(CanMinusEqual<EnumerateIter<RandomAccessRange>, int>);
+
+using BidirectionalRange = std::ranges::subrange<bidirectional_iterator<int*>>;
+static_assert(!std::ranges::random_access_range<BidirectionalRange>);
+static_assert(
+ !std::sized_sentinel_for<std::ranges::iterator_t<BidirectionalRange>, std::ranges::iterator_t<BidirectionalRange>>);
+
+static_assert(!CanPlus<EnumerateIter<BidirectionalRange>, int>);
+static_assert(!CanPlus<int, EnumerateIter<BidirectionalRange>>);
+static_assert(!CanPlusEqual<EnumerateIter<BidirectionalRange>, int>);
+static_assert(!CanMinus<EnumerateIter<BidirectionalRange>, int>);
+static_assert(!CanMinusEqual<EnumerateIter<BidirectionalRange>, int>);
+
+constexpr bool test() {
+ int ts[] = {1, 2, 3, 4, 5};
+
+ RandomAccessRange r{ts, ts + 5};
+ auto ev = r | std::views::enumerate;
+
+ // operator+(x, n), operator+(n,x) and operator+=
+ {
+ auto it1 = ev.begin();
+
+ auto it2 = it1 + 3;
+ assert(it2.base() == &ts[3]);
+
+ auto it3 = 3 + it1;
+ assert(it3.base() == &ts[3]);
+
+ it1 += 3;
+ assert(it1 == it2);
+ assert(it1.base() == &ts[3]);
+ }
+
+ // operator-(x, n) and operator-=
+ {
+ auto it1 = ev.end();
+
+ auto it2 = it1 - 4;
+ assert(it2.base() == &ts[1]);
+
+ it1 -= 4;
+ assert(it1 == it2);
+ assert(it1.base() == &ts[1]);
+ }
+
+ // operator-(x, y)
+ {
+ assert((ev.end() - ev.begin()) == 5);
+
+ auto it1 = ev.begin() + 2;
+ auto it2 = ev.end() - 2;
+ assert((it1 - it2) == -1);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
new file mode 100644
index 0000000000000..b29d504a81515
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// constexpr const iterator_t<Base>& base() const & noexcept;
+// constexpr iterator_t<Base> base() &&;
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <utility>
+#include <tuple>
+
+#include "test_iterators.h"
+#include "../types.h"
+
+template <class Iterator>
+constexpr void testBase() {
+ using Sentinel = sentinel_wrapper<Iterator>;
+ using View = MinimalView<Iterator, Sentinel>;
+ using EnumerateView = std::ranges::enumerate_view<View>;
+ using EnumerateIterator = std::ranges::iterator_t<EnumerateView>;
+
+ auto make_enumerate_view = [](auto begin, auto end) {
+ View view{Iterator(begin), Sentinel(Iterator(end))};
+
+ return EnumerateView(std::move(view));
+ };
+
+ std::array array{0, 1, 2, 3, 84};
+ const auto view = make_enumerate_view(array.begin(), array.end());
+
+ // Test the const& version
+ {
+ EnumerateIterator const it = view.begin();
+ std::same_as<const Iterator&> decltype(auto) result = it.base();
+ ASSERT_NOEXCEPT(it.base());
+ assert(base(result) == array.begin());
+ }
+
+ // Test the && version
+ {
+ EnumerateIterator it = view.begin();
+ std::same_as<Iterator> decltype(auto) result = std::move(it).base();
+ assert(base(result) == array.begin());
+ }
+}
+
+constexpr bool test() {
+ testBase<cpp17_input_iterator<int*>>();
+ testBase<cpp20_input_iterator<int*>>();
+ testBase<forward_iterator<int*>>();
+ testBase<bidirectional_iterator<int*>>();
+ testBase<random_access_iterator<int*>>();
+ testBase<contiguous_iterator<int*>>();
+ testBase<int*>();
+ testBase<int const*>();
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp
new file mode 100644
index 0000000000000..7cc00decebcab
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp
@@ -0,0 +1,107 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// friend constexpr strong_ordering operator<=>(const iterator& x, const iterator& y) noexcept;
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "../types.h"
+
+constexpr void compareOperatorTest(const auto& iter1, const auto& iter2) {
+ assert(!(iter1 < iter1));
+ assert(iter1 < iter2);
+ assert(!(iter2 < iter1));
+
+ assert(iter1 <= iter1);
+ assert(iter1 <= iter2);
+ assert(!(iter2 <= iter1));
+
+ assert(!(iter1 > iter1));
+ assert(!(iter1 > iter2));
+ assert(iter2 > iter1);
+
+ assert(iter1 >= iter1);
+ assert(!(iter1 >= iter2));
+ assert(iter2 >= iter1);
+
+ assert(iter1 == iter1);
+ assert(!(iter1 == iter2));
+ assert(iter2 == iter2);
+
+ assert(!(iter1 != iter1));
+ assert(iter1 != iter2);
+ assert(!(iter2 != iter2));
+}
+
+constexpr bool test() {
+ int buff[] = {0, 1, 2, 3};
+ {
+ using View = std::ranges::enumerate_view<RangeView>;
+
+ using Iterator = std::ranges::iterator_t<View>;
+ static_assert(std::three_way_comparable<Iterator>);
+ using Subrange = std::ranges::subrange<Iterator>;
+ static_assert(std::three_way_comparable<std::ranges::iterator_t<Subrange>>);
+ using EnumerateView = std::ranges::enumerate_view<Subrange>;
+ static_assert(std::three_way_comparable<std::ranges::iterator_t<EnumerateView>>);
+
+ RangeView const range(buff, buff + 4);
+
+ std::same_as<View> decltype(auto) ev = std::views::enumerate(range);
+
+ auto it1 = ev.begin();
+ auto it2 = it1 + 1;
+
+ compareOperatorTest(it1, it2);
+
+ assert((it1 <=> it2) == std::strong_ordering::less);
+ assert((it1 <=> it1) == std::strong_ordering::equal);
+ assert((it2 <=> it2) == std::strong_ordering::equal);
+ assert((it2 <=> it1) == std::strong_ordering::greater);
+ }
+
+ // Test an old-school iterator with no operator<=>
+ {
+ using Iterator = random_access_iterator<int*>;
+ static_assert(!std::three_way_comparable<Iterator>);
+ using Subrange = std::ranges::subrange<Iterator>;
+ static_assert(!std::three_way_comparable<std::ranges::iterator_t<Subrange>>);
+ using EnumerateView = std::ranges::enumerate_view<Subrange>;
+ static_assert(std::three_way_comparable<std::ranges::iterator_t<EnumerateView>>);
+
+ auto ev = Subrange{Iterator{buff}, Iterator{buff + 3}} | std::views::enumerate;
+ auto it1 = ev.begin();
+ auto it2 = it1 + 1;
+
+ compareOperatorTest(it1, it2);
+
+ assert((it1 <=> it2) == std::strong_ordering::less);
+ assert((it1 <=> it1) == std::strong_ordering::equal);
+ assert((it2 <=> it2) == std::strong_ordering::equal);
+ assert((it2 <=> it1) == std::strong_ordering::greater);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.convert.pass.cpp
new file mode 100644
index 0000000000000..668686884a910
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.convert.pass.cpp
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// constexpr iterator(iterator<!Const> i)
+// requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>;
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <utility>
+
+#include "test_iterators.h"
+#include "../types.h"
+
+template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
+constexpr void test() {
+ using View = MinimalView<Iterator, Sentinel>;
+ using EnumerateView = std::ranges::enumerate_view<View>;
+ using EnumerateIterator = std::ranges::iterator_t<EnumerateView>;
+ using EnumerateConstIterator = std::ranges::iterator_t<const EnumerateView>;
+
+ auto make_enumerate_view = [](auto begin, auto end) {
+ View view{Iterator(begin), Sentinel(Iterator(end))};
+
+ return EnumerateView(std::move(view));
+ };
+
+ static_assert(std::is_convertible_v<EnumerateIterator, EnumerateConstIterator>);
+
+ std::array array{0, 84, 2, 3, 4};
+ auto view = make_enumerate_view(array.begin(), array.end());
+ {
+ std::same_as<EnumerateIterator> decltype(auto) it = view.begin();
+ std::same_as<const Iterator&> decltype(auto) itResult = it.base();
+ assert(base(base(itResult)) == array.begin());
+
+ auto [index, value] = *(++it);
+ assert(index == 1);
+ assert(value == 84);
+ }
+ {
+ std::same_as<EnumerateConstIterator> decltype(auto) it = view.begin();
+ std::same_as<const Iterator&> decltype(auto) itResult = it.base();
+ assert(base(base(itResult)) == array.begin());
+
+ auto [index, value] = *(++it);
+ assert(index == 1);
+ assert(value == 84);
+ }
+}
+
+constexpr bool tests() {
+ test<cpp17_input_iterator<int*>>();
+ test<cpp20_input_iterator<int*>>();
+ test<forward_iterator<int*>>();
+ test<bidirectional_iterator<int*>>();
+ test<random_access_iterator<int*>>();
+ test<contiguous_iterator<int*>>();
+ test<int*>();
+
+ return true;
+}
+
+int main(int, char**) {
+ tests();
+ static_assert(tests());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..1108025de0103
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// iterator() requires default_initializable<iterator_t<Base>>;
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "../types.h"
+
+template <class Iterator, bool IsNoexcept = true>
+constexpr void test_default_constructible() {
+ using View = MinimalView<Iterator, sentinel_wrapper<Iterator>>;
+ using EnumerateView = std::ranges::enumerate_view<View>;
+ using EnumerateIterator = std::ranges::iterator_t<EnumerateView>;
+
+ EnumerateIterator it1;
+ EnumerateIterator it2{};
+
+ assert(it1 == it2);
+
+ static_assert(noexcept(EnumerateIterator()) == IsNoexcept);
+}
+
+template <class Iterator>
+constexpr void test_not_default_constructible() {
+ // Make sure the iterator is *not* default constructible when the underlying iterator isn't.
+ using Sentinel = sentinel_wrapper<Iterator>;
+ using View = MinimalView<Iterator, Sentinel>;
+ using EnumerateView = std::ranges::enumerate_view<View>;
+ using EnumerateIterator = std::ranges::iterator_t<EnumerateView>;
+
+ static_assert(!std::is_default_constructible_v<EnumerateIterator>);
+}
+
+constexpr bool tests() {
+ // clang-format off
+ test_not_default_constructible<cpp17_input_iterator<int*>>();
+ test_not_default_constructible<cpp20_input_iterator<int*>>();
+ test_default_constructible<forward_iterator<int*>, /* noexcept */ false>();
+ test_default_constructible<bidirectional_iterator<int*>, /* noexcept */ false>();
+ test_default_constructible<random_access_iterator<int*>, /* noexcept */ false>();
+ test_default_constructible<contiguous_iterator<int*>, /* noexcept */ false>();
+ test_default_constructible<int*, /* noexcept */ true>();
+ // clang-format on
+
+ return true;
+}
+
+int main(int, char**) {
+ tests();
+ static_assert(tests());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp
new file mode 100644
index 0000000000000..d8e75e1634617
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// constexpr auto operator*() const;
+
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <cstddef>
+#include <utility>
+#include <tuple>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "../types.h"
+
+template <class Iterator, class ValueType = int, class Sentinel = sentinel_wrapper<Iterator>>
+constexpr void test() {
+ using View = MinimalView<Iterator, Sentinel>;
+ using EnumerateView = std::ranges::enumerate_view<View>;
+ using EnumerateIterator = std::ranges::iterator_t<EnumerateView>;
+
+ using Result = std::tuple<typename EnumerateIterator::difference_type,
+ std::ranges::range_reference_t<MinimalView<Iterator, Sentinel>>>;
+
+ std::array array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+ View view{Iterator(array.begin()), Sentinel(Iterator(array.end()))};
+ EnumerateView ev{std::move(view)};
+
+ {
+ auto it = ev.begin();
+ for (std::size_t index = 0; index < array.size(); ++index) {
+ std::same_as<Result> decltype(auto) result = *it;
+
+ auto [resultIndex, resultValue] = result;
+ assert(std::cmp_equal(index, resultIndex));
+ assert(array[index] == resultValue);
+
+ ++it;
+ }
+
+ assert(it == ev.end());
+ }
+
+ // const
+ {
+ auto constIt = std::as_const(ev).begin();
+ for (std::size_t index = 0; index < array.size(); ++index) {
+ std::same_as<Result> decltype(auto) result = *constIt;
+
+ auto [resultIndex, resultValue] = result;
+ assert(std::cmp_equal(index, resultIndex));
+ assert(array[index] == resultValue);
+
+ ++constIt;
+ }
+
+ assert(constIt == ev.end());
+ }
+}
+
+constexpr bool tests() {
+ test<cpp17_input_iterator<int*>>();
+ test<cpp20_input_iterator<int*>>();
+ test<forward_iterator<int*>>();
+ test<bidirectional_iterator<int*>>();
+ test<random_access_iterator<int*>>();
+ test<contiguous_iterator<int*>>();
+ test<int*>();
+
+ test<cpp17_input_iterator<int const*>, int const>();
+ test<cpp20_input_iterator<int const*>, int const>();
+ test<forward_iterator<int const*>, int const>();
+ test<bidirectional_iterator<int const*>, int const>();
+ test<random_access_iterator<int const*>, int const>();
+ test<contiguous_iterator<int const*>, int const>();
+ test<int const*, int const>();
+
+ return true;
+}
+
+int main(int, char**) {
+ tests();
+ static_assert(tests());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
new file mode 100644
index 0000000000000..6bf131d356d9c
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// friend constexpr bool operator==(const iterator& x, const iterator& y) noexcept;
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "../types.h"
+#include "../types_iterators.h"
+
+
+// template <bool Const>
+// struct Iterator {
+// using value_type = int
+// using difference_type = std::std::ptrdiff_t;
+// using iterator_concept = std::input_iterator_tag;
+
+// constexpr decltype(auto) operator*() const { return *it_; }
+// constexpr Iterator& operator++() {
+// ++it_;
+
+// return *this;
+// }
+// constexpr void operator++(int) { ++it_; }
+
+// std::tuple<std::ptrdiff_t, int>* it_;
+// };
+
+// template <bool Const>
+// struct Sentinel {
+// constexpr bool operator==(const Iterator<Const>& i) const { return i.it_ == end_; }
+
+// std::tuple<std::ptrdiff_t, int>* end_;
+// };
+
+// template <bool Const>
+// struct CrossComparableSentinel {
+// template <bool C>
+// constexpr bool operator==(const Iterator<C>& i) const {
+// return i.it_ == end_;
+// }
+
+// std::tuple<std::ptrdiff_t, int>* end_;
+// };
+
+constexpr bool test() {
+ int buff[] = {0, 1, 2, 3, 5};
+ {
+ using View = std::ranges::enumerate_view<RangeView>;
+ RangeView const range(buff, buff + 5);
+
+ std::same_as<View> decltype(auto) ev = std::views::enumerate(range);
+
+ auto it1 = ev.begin();
+ auto it2 = it1 + 5;
+
+ assert(it1 == it1);
+ ASSERT_NOEXCEPT(it1 == it1);
+ assert(it1 != it2);
+ ASSERT_NOEXCEPT(it1 != it2);
+ assert(it2 != it1);
+ ASSERT_NOEXCEPT(it2 != it1);
+ assert(it2 == ev.end());
+ assert(ev.end() == it2);
+
+ for (std::size_t index = 0; index != 5; ++index) {
+ ++it1;
+ }
+
+ assert(it1 == it2);
+ assert(it2 == it1);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp
new file mode 100644
index 0000000000000..0256115f4a6a9
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// constexpr difference_type index() const noexcept;
+
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <cstdint>
+#include <utility>
+#include <tuple>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "../types.h"
+
+template <class Iterator, class ValueType = int, class Sentinel = sentinel_wrapper<Iterator>>
+constexpr void test() {
+ using View = MinimalView<Iterator, Sentinel>;
+ using EnumerateView = std::ranges::enumerate_view<View>;
+
+ std::array array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+ View view{Iterator(array.begin()), Sentinel(Iterator(array.end()))};
+ EnumerateView ev(std::move(view));
+
+ {
+ auto it = ev.begin();
+ ASSERT_NOEXCEPT(it.index());
+
+ static_assert(std::same_as<typename decltype(it)::difference_type, decltype(it.index())>);
+ for (std::size_t index = 0; index < array.size(); ++index) {
+ assert(std::cmp_equal(index, it.index()));
+
+ ++it;
+ }
+
+ assert(it == ev.end());
+ }
+
+ // const
+ {
+ auto constIt = std::as_const(ev).begin();
+ ASSERT_NOEXCEPT(constIt.index());
+
+ static_assert(std::same_as<typename decltype(constIt)::difference_type, decltype(constIt.index())>);
+ for (std::size_t index = 0; index < array.size(); ++index) {
+ assert(std::cmp_equal(index, constIt.index()));
+
+ ++constIt;
+ }
+
+ assert(constIt == ev.end());
+ }
+}
+
+constexpr bool tests() {
+ test<cpp17_input_iterator<int*>>();
+ test<cpp20_input_iterator<int*>>();
+ test<forward_iterator<int*>>();
+ test<bidirectional_iterator<int*>>();
+ test<random_access_iterator<int*>>();
+ test<contiguous_iterator<int*>>();
+ test<int*>();
+
+ test<cpp17_input_iterator<int const*>, int const>();
+ test<cpp20_input_iterator<int const*>, int const>();
+ test<forward_iterator<int const*>, int const>();
+ test<bidirectional_iterator<int const*>, int const>();
+ test<random_access_iterator<int const*>, int const>();
+ test<contiguous_iterator<int const*>, int const>();
+ test<int const*, int const>();
+
+ return true;
+}
+
+int main(int, char**) {
+ tests();
+ static_assert(tests());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp
new file mode 100644
index 0000000000000..c023d58bd859b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// friend constexpr auto iter_move(const iterator& i)
+// noexcept(noexcept(ranges::iter_move(i.current_)) &&
+// is_nothrow_move_constructible_v<range_rvalue_reference_t<Base>>);
+
+#include <array>
+#include <cassert>
+#include <ranges>
+#include <type_traits>
+#include <utility>
+
+#include "test_iterators.h"
+#include "../types.h"
+
+template <class Iterator, bool HasNoexceptIterMove>
+constexpr void test() {
+ using Sentinel = sentinel_wrapper<Iterator>;
+ using View = MinimalView<Iterator, Sentinel>;
+ using EnumerateView = std::ranges::enumerate_view<View>;
+ using EnumerateIterator = std::ranges::iterator_t<EnumerateView>;
+
+ std::array array{0, 1, 2, 3, 4};
+
+ View view{Iterator(array.begin()), Sentinel(Iterator(array.end()))};
+ EnumerateView ev{std::move(view)};
+ EnumerateIterator const it = ev.begin();
+
+ auto&& result = iter_move(it);
+
+ static_assert(std::is_same_v<decltype(result),
+ std::tuple<typename std::ranges::iterator_t<EnumerateView>::difference_type, int&&>&&>);
+ static_assert(std::is_same_v<decltype(result), std::tuple<typename decltype(it)::difference_type, int&&>&&>);
+
+ assert(get<0>(result) == 0);
+ assert(&get<1>(result) == array.begin());
+
+ static_assert(noexcept(iter_move(it)) == HasNoexceptIterMove);
+}
+
+constexpr bool tests() {
+ // clang-format off
+ test<cpp17_input_iterator<int*>, /* noexcept */ false>();
+ test<cpp20_input_iterator<int*>, /* noexcept */ false>();
+ test<forward_iterator<int*>, /* noexcept */ false>();
+ test<bidirectional_iterator<int*>, /* noexcept */ false>();
+ test<random_access_iterator<int*>, /* noexcept */ false>();
+ test<contiguous_iterator<int*>, /* noexcept */ false>();
+ test<int*, /* noexcept */ true>();
+ test<MaybeNoexceptIterMoveInputIterator<true>, /* noexcept */ true>();
+ test<MaybeNoexceptIterMoveInputIterator<false>, /* noexcept */ false>();
+ // clang-format on
+
+ return true;
+}
+
+int main(int, char**) {
+ tests();
+ static_assert(tests());
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp
new file mode 100644
index 0000000000000..d6f9d4beda938
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// constexpr auto operator[](difference_type n) const
+// requires random_access_range<Base>;
+
+#include <array>
+#include <cassert>
+#include <ranges>
+#include <tuple>
+
+#include "test_iterators.h"
+
+template <class T, class U>
+concept HasSubscriptOperator = requires(T t, U u) { t[u]; };
+
+template <class BaseRange>
+using EnumerateIterator = std::ranges::iterator_t<std::ranges::enumerate_view<BaseRange>>;
+
+using RandomAccessRange = std::ranges::subrange<int*>;
+static_assert(std::ranges::random_access_range<RandomAccessRange>);
+
+static_assert(HasSubscriptOperator<EnumerateIterator<RandomAccessRange>, int>);
+
+using BidirectionalRange = std::ranges::subrange<bidirectional_iterator<int*>>;
+static_assert(!std::ranges::random_access_range<BidirectionalRange>);
+
+static_assert(!HasSubscriptOperator<EnumerateIterator<BidirectionalRange>, int>);
+
+constexpr bool test() {
+ // Reference
+ {
+ std::array ts = {0, 1, 2, 3, 84};
+ auto view = ts | std::views::enumerate;
+ auto it = view.begin();
+
+ for (std::size_t index = 0; index != ts.size(); ++index) {
+ assert(it[index] == *(it + index));
+ }
+
+ static_assert(std::is_same_v<decltype(it[2]), std::tuple<decltype(it)::difference_type, int&>>);
+ }
+
+ // Value
+ {
+ auto view = std::views::iota(0, 5) | std::views::enumerate;
+ auto it = view.begin();
+
+ for (std::size_t index = 0; index != 5; ++index) {
+ assert(it[index] == *(it + index));
+ }
+
+ static_assert(std::is_same_v<decltype(it[2]), std::tuple<decltype(it)::difference_type, int>>);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
new file mode 100644
index 0000000000000..a800e362befb0
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
@@ -0,0 +1,112 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::iterator
+
+// std::enumerate_view::<iterator>::difference_type;
+// std::enumerate_view::<iterator>::value_type;
+// std::enumerate_view::<iterator>::iterator_category;
+// std::enumerate_view::<iterator>::iterator_concept;
+
+#include <ranges>
+
+#include <type_traits>
+#include "test_iterators.h"
+#include "../types.h"
+
+template <typename T>
+concept HasIteratorCategory = requires { typename T::iterator_category; };
+
+template <class Iterator>
+using EnumerateViewFor = std::ranges::enumerate_view< MinimalView<Iterator, sentinel_wrapper<Iterator>>>;
+
+template <class Iterator>
+using EnumerateIteratorFor = std::ranges::iterator_t<EnumerateViewFor<Iterator>>;
+
+struct ForwardIteratorWithInputCategory {
+ using difference_type = int;
+ using value_type = int;
+ using iterator_category = std::input_iterator_tag;
+ using iterator_concept = std::forward_iterator_tag;
+ ForwardIteratorWithInputCategory();
+ ForwardIteratorWithInputCategory& operator++();
+ ForwardIteratorWithInputCategory operator++(int);
+ int& operator*() const;
+ friend bool operator==(ForwardIteratorWithInputCategory, ForwardIteratorWithInputCategory);
+};
+static_assert(std::forward_iterator<ForwardIteratorWithInputCategory>);
+
+constexpr bool test() {
+ // Check that value_type is range_value_t and difference_type is range_difference_t
+ {
+ auto test = []<class Iterator> {
+ using EnumerateView = EnumerateViewFor<Iterator>;
+ using EnumerateIterator = EnumerateIteratorFor<Iterator>;
+ static_assert(std::is_same_v<typename EnumerateIterator::value_type, std::ranges::range_value_t<EnumerateView>>);
+ static_assert(
+ std::is_same_v<typename EnumerateIterator::difference_type, std::ranges::range_difference_t<EnumerateView>>);
+ };
+ test.operator()<cpp17_input_iterator<int*>>();
+ test.operator()<cpp20_input_iterator<int*>>();
+ test.operator()<forward_iterator<int*>>();
+ test.operator()<bidirectional_iterator<int*>>();
+ test.operator()<random_access_iterator<int*>>();
+ test.operator()<contiguous_iterator<int*>>();
+ test.operator()<int*>();
+ }
+ // Check iterator_concept for various categories of ranges
+ {
+ static_assert(
+ std::is_same_v<EnumerateIteratorFor<cpp17_input_iterator<int*>>::iterator_concept, std::input_iterator_tag>);
+ static_assert(
+ std::is_same_v<EnumerateIteratorFor<cpp20_input_iterator<int*>>::iterator_concept, std::input_iterator_tag>);
+ static_assert(std::is_same_v<EnumerateIteratorFor<ForwardIteratorWithInputCategory>::iterator_concept,
+ std::forward_iterator_tag>);
+ static_assert(
+ std::is_same_v<EnumerateIteratorFor<forward_iterator<int*>>::iterator_concept, std::forward_iterator_tag>);
+ static_assert(std::is_same_v<EnumerateIteratorFor<bidirectional_iterator<int*>>::iterator_concept,
+ std::bidirectional_iterator_tag>);
+ static_assert(std::is_same_v<EnumerateIteratorFor<random_access_iterator<int*>>::iterator_concept,
+ std::random_access_iterator_tag>);
+ static_assert(std::is_same_v<EnumerateIteratorFor<contiguous_iterator<int*>>::iterator_concept,
+ std::random_access_iterator_tag>);
+ static_assert(std::is_same_v<EnumerateIteratorFor<int*>::iterator_concept, std::random_access_iterator_tag>);
+ }
+
+ // Check iterator_category for various categories of ranges
+ {
+ static_assert(HasIteratorCategory<EnumerateIteratorFor<cpp17_input_iterator<int*>>>);
+ static_assert(HasIteratorCategory<EnumerateIteratorFor<cpp20_input_iterator<int*>>>);
+ static_assert(std::is_same_v<EnumerateIteratorFor<ForwardIteratorWithInputCategory>::iterator_category,
+ std::input_iterator_tag>);
+ static_assert(
+ std::is_same_v<EnumerateIteratorFor<forward_iterator<int*>>::iterator_category, std::input_iterator_tag>);
+ static_assert(
+ std::is_same_v<EnumerateIteratorFor<bidirectional_iterator<int*>>::iterator_category, std::input_iterator_tag>);
+ static_assert(
+ std::is_same_v<EnumerateIteratorFor<random_access_iterator<int*>>::iterator_category, std::input_iterator_tag>);
+ static_assert(
+ std::is_same_v<EnumerateIteratorFor<contiguous_iterator<int*>>::iterator_category, std::input_iterator_tag>);
+ static_assert(std::is_same_v<EnumerateIteratorFor<int*>::iterator_category, std::input_iterator_tag>);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.pass.cpp
new file mode 100644
index 0000000000000..28a93decfddb8
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.pass.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::sentinel
+
+// constexpr sentinel_t<Base> base() const;
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <utility>
+
+#include "test_iterators.h"
+#include "../types.h"
+
+template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
+constexpr void test() {
+ using View = MinimalView<Iterator, Sentinel>;
+ using EnumerateView = std::ranges::enumerate_view<View>;
+ using EnumerateSentinel = std::ranges::sentinel_t<EnumerateView>;
+
+ std::array<int, 5> array{0, 1, 2, 3, 84};
+
+ View mv{Iterator{array.begin()}, Sentinel{Iterator{array.end()}}};
+ EnumerateView ev{std::move(mv)};
+
+ EnumerateSentinel const s = ev.end();
+ std::same_as<Sentinel> decltype(auto) result = s.base();
+ assert(base(base(result)) == array.end());
+}
+
+constexpr bool tests() {
+ test<cpp17_input_iterator<int*>>();
+ test<cpp20_input_iterator<int*>>();
+ test<forward_iterator<int*>>();
+ test<bidirectional_iterator<int*>>();
+ test<random_access_iterator<int*>>();
+ test<contiguous_iterator<int*>>();
+ test<int*>();
+
+ return true;
+}
+
+int main(int, char**) {
+ tests();
+ static_assert(tests());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
new file mode 100644
index 0000000000000..3cdf52db41650
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::sentinel
+
+// constexpr sentinel(sentinel<!Const> other)
+// requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <utility>
+
+#include "test_iterators.h"
+#include "../types.h"
+
+template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
+constexpr void test() {
+ using View = MinimalView<Iterator, Sentinel>;
+ using EnumerateView = std::ranges::enumerate_view<View>;
+ using EnumerateSentinel = std::ranges::sentinel_t<EnumerateView>;
+ using EnumerateConstSentinel = std::ranges::sentinel_t<const EnumerateView>;
+
+ auto make_enumerate_view = [](auto begin, auto end) {
+ View view{Iterator(begin), Sentinel(Iterator(end))};
+
+ return EnumerateView(std::move(view));
+ };
+
+ static_assert(std::is_convertible_v<EnumerateSentinel, EnumerateConstSentinel>);
+
+ std::array array{0, 1, 2, 3, 84};
+ auto view = make_enumerate_view(array.begin(), array.end());
+
+ std::same_as<EnumerateSentinel> decltype(auto) s = view.end();
+ std::same_as<Sentinel> decltype(auto) sResult = s.base();
+ assert(base(base(sResult)) == array.end());
+
+ // Test assignment
+ EnumerateConstSentinel cs = s;
+ std::same_as<Sentinel> decltype(auto) csResult = cs.base();
+ assert(base(base(csResult)) == array.end());
+}
+
+constexpr bool tests() {
+ test<cpp17_input_iterator<int*>>();
+ test<cpp20_input_iterator<int*>>();
+ test<forward_iterator<int*>>();
+ test<bidirectional_iterator<int*>>();
+ test<random_access_iterator<int*>>();
+ test<contiguous_iterator<int*>>();
+ test<int*>();
+
+ return true;
+}
+
+int main(int, char**) {
+ tests();
+ static_assert(tests());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..9206441d5ccf3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::sentinel
+
+// sentinel() = default;
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "../types.h"
+
+struct PODSentinel {
+ int i; // deliberately uninitialised
+
+ friend constexpr bool operator==(std::tuple<int>*, const PODSentinel&) { return true; }
+};
+
+template <typename Iterator, typename Sentinel>
+struct PODSentinelView : MinimalView<Iterator, Sentinel> {
+ std::tuple<int>* begin() const;
+ PODSentinel end();
+};
+
+template <class Iterator>
+constexpr void test() {
+ using Sentinel = sentinel_wrapper<Iterator>;
+ using View = PODSentinelView<Iterator, Sentinel>;
+ using EnumerateView = std::ranges::enumerate_view<View>;
+ using EnumerateSentinel = std::ranges::sentinel_t<EnumerateView>;
+
+ {
+ EnumerateSentinel s;
+
+ assert(s.base().i == 0);
+ }
+
+ {
+ EnumerateSentinel s = {};
+
+ assert(s.base().i == 0);
+ }
+
+ static_assert(noexcept(EnumerateSentinel()));
+}
+
+constexpr bool tests() {
+ test<cpp17_input_iterator<int*>>();
+ test<cpp20_input_iterator<int*>>();
+ test<forward_iterator<int*>>();
+ test<bidirectional_iterator<int*>>();
+ test<random_access_iterator<int*>>();
+ test<contiguous_iterator<int*>>();
+ test<int*>();
+
+ return true;
+}
+
+int main(int, char**) {
+ tests();
+ static_assert(tests());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
new file mode 100644
index 0000000000000..2a502564b4a45
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::sentinel
+
+// template<bool OtherConst>
+// requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
+// friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <utility>
+
+#include "test_iterators.h"
+#include "../types.h"
+
+template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
+constexpr void test() {
+ using View = MinimalView<Iterator, Sentinel>;
+
+ std::array array{0, 1, 2, 3, 84};
+
+ View v(Iterator(array.begin()), Sentinel(Iterator(array.end())));
+ std::ranges::enumerate_view view(std::move(v));
+
+ auto const it = view.begin();
+ auto const s = view.end();
+
+ std::same_as<bool> decltype(auto) eqItSResult = (it == s);
+ assert(!eqItSResult);
+ std::same_as<bool> decltype(auto) eqSItResult = (s == it);
+ assert(!eqSItResult);
+
+ std::same_as<bool> decltype(auto) neqItSResult = (it != s);
+ assert(neqItSResult);
+ std::same_as<bool> decltype(auto) neqSItResult = (s != it);
+ assert(neqSItResult);
+}
+
+constexpr bool tests() {
+ test<cpp17_input_iterator<int*>>();
+ test<cpp20_input_iterator<int*>>();
+ test<forward_iterator<int*>>();
+ test<bidirectional_iterator<int*>>();
+ test<random_access_iterator<int*>>();
+ test<contiguous_iterator<int*>>();
+ test<int*>();
+
+ return true;
+}
+
+int main(int, char**) {
+ tests();
+ static_assert(tests());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
new file mode 100644
index 0000000000000..274829668c7c1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
@@ -0,0 +1,253 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// class enumerate_view::sentinel
+
+// template<bool OtherConst>
+// requires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
+// friend constexpr range_difference_t<maybe-const<OtherConst, V>>
+// operator-(const iterator<OtherConst>& x, const sentinel& y);
+
+// template<bool OtherConst>
+// requires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
+// friend constexpr range_difference_t<maybe-const<OtherConst, V>>
+// operator-(const sentinel& x, const iterator<OtherConst>& y);
+
+#include <array>
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "../types.h"
+#include "../types_iterators.h"
+
+// template <bool Const>
+// struct Iter {
+// int* it_;
+
+// using value_type = int;
+// using difference_type = std::ptrdiff_t;
+// using iterator_concept = std::input_iterator_tag;
+
+// constexpr decltype(auto) operator*() const { return *it_; }
+// constexpr Iter& operator++() {
+// ++it_;
+// return *this;
+// }
+// constexpr void operator++(int) { ++it_; }
+// };
+
+// template <bool Const>
+// struct Sent {
+// int* end_;
+
+// constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
+// };
+
+// template <bool Const>
+// struct SizedSent {
+// int* end_;
+
+// constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
+
+// friend constexpr auto operator-(const SizedSent& st, const Iter<Const>& it) { return st.end_ - it.it_; }
+
+// friend constexpr auto operator-(const Iter<Const>& it, const SizedSent& st) { return it.it_ - st.end_; }
+// };
+
+// template <bool Const>
+// struct CrossSizedSent {
+// int* end_;
+
+// template <bool C>
+// constexpr bool operator==(const Iter<C>& i) const {
+// return i.it_ == end_;
+// }
+
+// template <bool C>
+// friend constexpr auto operator-(const CrossSizedSent& st, const Iter<C>& it) {
+// return st.end_ - it.it_;
+// }
+
+// template <bool C>
+// friend constexpr auto operator-(const Iter<C>& it, const CrossSizedSent& st) {
+// return it.it_ - st.end_;
+// }
+// };
+
+// template <template <bool> class It, template <bool> class St>
+// struct BufferView : std::ranges::view_base {
+// template <std::size_t N>
+// constexpr BufferView(int (&b)[N]) : buffer_(b), size_(N) {}
+
+// template <std::size_t N>
+// constexpr BufferView(std::array<int, N>& arr) : buffer_(arr.data()), size_(N) {}
+
+// using iterator = It<false>;
+// using sentinel = St<false>;
+// using const_iterator = It<true>;
+// using const_sentinel = St<true>;
+
+// constexpr iterator begin() { return {buffer_}; }
+// constexpr const_iterator begin() const { return {buffer_}; }
+// constexpr sentinel end() { return sentinel{buffer_ + size_}; }
+// constexpr const_sentinel end() const { return const_sentinel{buffer_ + size_}; }
+
+// int* buffer_;
+// std::size_t size_;
+// };
+
+template <template <bool> class It, template <bool> class St>
+struct SizedBufferView : BufferView<It, St> {
+ constexpr std::size_t size() { return BufferView<It, St>::size_; }
+};
+
+template <class T, class U>
+concept HasMinus = requires(const T t, const U u) { t - u; };
+
+template <class BaseView>
+using EnumerateView = std::ranges::enumerate_view<BaseView>;
+
+template <class BaseView>
+using EnumerateIter = std::ranges::iterator_t<EnumerateView<BaseView>>;
+
+template <class BaseView>
+using EnumerateConstIter = std::ranges::iterator_t<const EnumerateView<BaseView>>;
+
+template <class BaseView>
+using EnumerateSentinel = std::ranges::sentinel_t<EnumerateView<BaseView>>;
+
+template <class BaseView>
+using EnumerateConstSentinel = std::ranges::sentinel_t<const EnumerateView<BaseView>>;
+
+constexpr void testConstraints() {
+ // Base is not sized
+ {
+ using Base = BufferView<Iterator, Sentinel>;
+
+ static_assert(!HasSize<Base>);
+ static_assert(!std::ranges::sized_range<Base>);
+
+ static_assert(!HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
+
+ static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
+ }
+
+ // Base is sized but not cross const
+ {
+ using Base = SizedBufferView<Iterator, SizedSentinel>;
+
+ static_assert(HasSize<Base>);
+ static_assert(std::ranges::sized_range<Base>);
+
+ static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
+
+ static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
+ }
+
+ // Base is cross const sized
+ {
+ using Base = BufferView<Iterator, CrossSizedSentinel>;
+
+ static_assert(!HasSize<Base>);
+ static_assert(!std::ranges::sized_range<Base>);
+
+ static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
+
+ static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
+ }
+}
+
+constexpr bool test() {
+ int buffer[] = {1, 2, 3, 4, 5};
+
+ // Base is sized but not cross const
+ {
+ using Base = SizedBufferView<Iterator, SizedSentinel>;
+
+ static_assert(HasSize<Base>);
+ static_assert(std::ranges::sized_range<Base>);
+
+ Base base{buffer};
+ auto ev = base | std::views::enumerate;
+ auto iter = ev.begin();
+ auto const_iter = std::as_const(ev).begin();
+ auto sent = ev.end();
+ auto const_sent = std::as_const(ev).end();
+
+ // Asssert difference
+ assert(iter - sent == -5);
+ assert(sent - iter == 5);
+ assert(const_iter - const_sent == -5);
+ assert(const_sent - const_iter == 5);
+ }
+
+ // Base is cross const sized
+ {
+ using Base = BufferView<Iterator, CrossSizedSentinel>;
+
+ static_assert(!HasSize<Base>);
+ static_assert(!std::ranges::sized_range<Base>);
+
+ Base base{buffer};
+ auto ev = base | std::views::enumerate;
+ auto iter = ev.begin();
+ auto const_iter = std::as_const(ev).begin();
+ auto sent = ev.end();
+ auto const_sent = std::as_const(ev).end();
+
+ // Assert difference
+ assert(iter - sent == -5);
+ assert(sent - iter == 5);
+ assert(iter - const_sent == -5);
+ assert(const_sent - iter == 5);
+ assert(const_iter - sent == -5);
+ assert(sent - const_iter == 5);
+ assert(const_iter - const_sent == -5);
+ assert(const_sent - const_iter == 5);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/size.pass.cpp
new file mode 100644
index 0000000000000..9be911c34959a
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/size.pass.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <ranges>
+
+// class enumerate_view
+
+// constexpr auto size() requires sized_range<V>;
+// constexpr auto size() const requires sized_range<const V>;
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "types.h"
+
+struct NonSizedRangeView : std::ranges::view_base {
+ using iterator = forward_iterator<int*>;
+ iterator begin() const;
+ iterator end() const;
+};
+
+static_assert(!std::ranges::sized_range<NonSizedRangeView>);
+static_assert(!std::ranges::sized_range<const NonSizedRangeView>);
+
+static_assert(!HasSize<std::ranges::enumerate_view<NonSizedRangeView>>);
+static_assert(!HasSize<const std::ranges::enumerate_view<NonSizedRangeView>>);
+
+constexpr bool test() {
+ int buffer[] = {1, 2, 3};
+
+ // Non-const and const are sized
+ {
+ auto view = std::views::enumerate(buffer);
+ assert(view.size() == 3);
+ assert(std::as_const(view).size() == 3);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
new file mode 100644
index 0000000000000..1d55107df98cd
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
@@ -0,0 +1,136 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_TYPES_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_TYPES_H
+
+#include <ranges>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+// Types
+
+struct RangeView : std::ranges::view_base {
+ using Iterator = cpp20_input_iterator<int*>;
+ using Sentinel = sentinel_wrapper<Iterator>;
+
+ constexpr explicit RangeView(int* b, int* e) : begin_(b), end_(e) {}
+ constexpr RangeView(RangeView const& other) : begin_(other.begin_), end_(other.end_), wasCopyInitialized(true) {}
+ constexpr RangeView(RangeView&& other) : begin_(other.begin_), end_(other.end_), wasMoveInitialized(true) {}
+ RangeView& operator=(RangeView const&) = default;
+ RangeView& operator=(RangeView&&) = default;
+
+ constexpr int* begin() const { return begin_; }
+ constexpr int* end() const { return end_; }
+
+ int* begin_;
+ int* end_;
+
+ bool wasCopyInitialized = false;
+ bool wasMoveInitialized = false;
+};
+
+LIBCPP_STATIC_ASSERT(std::ranges::__range_with_movable_references<RangeView>);
+static_assert(std::ranges::range<RangeView>);
+static_assert(std::ranges::view<RangeView>);
+
+struct MinimalDefaultConstructedView : std::ranges::view_base {
+ MinimalDefaultConstructedView() = default;
+
+ forward_iterator<int*> begin() const;
+ sentinel_wrapper<forward_iterator<int*>> end() const;
+};
+
+static_assert(std::ranges::view<MinimalDefaultConstructedView>);
+
+template <class Iterator, class Sentinel>
+struct MinimalView : std::ranges::view_base {
+ constexpr explicit MinimalView(Iterator it, Sentinel sent) : it_(base(std::move(it))), sent_(base(std::move(sent))) {}
+
+ MinimalView(MinimalView&&) = default;
+ MinimalView& operator=(MinimalView&&) = default;
+
+ constexpr Iterator begin() const { return Iterator(it_); }
+ constexpr Sentinel end() const { return Sentinel(sent_); }
+
+private:
+ decltype(base(std::declval<Iterator>())) it_;
+ decltype(base(std::declval<Sentinel>())) sent_;
+};
+
+static_assert(
+ std::ranges::view< MinimalView<cpp17_input_iterator<int*>, sentinel_wrapper<cpp17_input_iterator<int*>>>>);
+
+struct NotInvocable {};
+
+static_assert(!std::invocable<NotInvocable>);
+
+struct NotAView {};
+
+static_assert(!std::ranges::view<NotAView>);
+
+struct NotAViewRange {
+ using Iterator = cpp20_input_iterator<int*>;
+ using Sentinel = sentinel_wrapper<Iterator>;
+
+ NotAViewRange() = default;
+ constexpr explicit NotAViewRange(int* b, int* e) : begin_(b), end_(e) {}
+ constexpr NotAViewRange(NotAViewRange const& other) = default;
+ constexpr NotAViewRange(NotAViewRange&& other) = default;
+ NotAViewRange& operator=(NotAViewRange const&) = default;
+ NotAViewRange& operator=(NotAViewRange&&) = default;
+
+ constexpr int* begin() const { return begin_; }
+ constexpr int* end() const { return end_; }
+
+ int* begin_;
+ int* end_;
+};
+
+static_assert(std::ranges::range<NotAViewRange>);
+static_assert(!std::ranges::view<NotAViewRange>);
+
+template <bool IsNoexcept>
+class MaybeNoexceptIterMoveInputIterator {
+ int* it_;
+
+public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = int;
+ using difference_type = typename std::iterator_traits<int*>::difference_type;
+ using pointer = int*;
+ using reference = int&;
+
+ MaybeNoexceptIterMoveInputIterator() = default;
+ explicit constexpr MaybeNoexceptIterMoveInputIterator(int* it) : it_(it) {}
+
+ friend constexpr decltype(auto) iter_move(const MaybeNoexceptIterMoveInputIterator& it) noexcept(IsNoexcept) {
+ return std::ranges::iter_move(it.it_);
+ }
+
+ friend constexpr int* base(const MaybeNoexceptIterMoveInputIterator& i) { return i.it_; }
+
+ constexpr reference operator*() const { return *it_; }
+ constexpr MaybeNoexceptIterMoveInputIterator& operator++() {
+ ++it_;
+ return *this;
+ }
+ constexpr MaybeNoexceptIterMoveInputIterator operator++(int) {
+ MaybeNoexceptIterMoveInputIterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+};
+
+// Concepts
+
+template <class T>
+concept HasSize = requires(T t) { t.size(); };
+
+#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_TYPES_H
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/types_iterators.h b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types_iterators.h
new file mode 100644
index 0000000000000..231e8f68dbb93
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types_iterators.h
@@ -0,0 +1,109 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_TYPES_ITERATORS_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_TYPES_ITERATORS_H
+
+#include "types.h"
+
+// Iterators & Sentinels
+
+template <bool Const>
+struct Iterator {
+ using value_type = int;
+ using difference_type = std::ptrdiff_t;
+ using iterator_concept = std::input_iterator_tag;
+
+ constexpr decltype(auto) operator*() const { return *it_; }
+ constexpr Iterator& operator++() {
+ ++it_;
+
+ return *this;
+ }
+ constexpr void operator++(int) { ++it_; }
+
+ std::tuple<std::ptrdiff_t, int>* it_;
+};
+
+template <bool Const>
+struct Sentinel {
+ constexpr bool operator==(const Iterator<Const>& i) const { return i.it_ == end_; }
+
+ std::tuple<std::ptrdiff_t, int>* end_;
+};
+
+template <bool Const>
+struct CrossComparableSentinel {
+ template <bool C>
+ constexpr bool operator==(const Iterator<C>& i) const {
+ return i.it_ == end_;
+ }
+
+ std::tuple<std::ptrdiff_t, int>* end_;
+};
+
+template <bool Const>
+struct SizedSentinel {
+ constexpr bool operator==(const Iterator<Const>& i) const { return i.it_ == end_; }
+
+ friend constexpr auto operator-(const SizedSentinel& st, const Iterator<Const>& it) { return st.end_ - it.it_; }
+
+ friend constexpr auto operator-(const Iterator<Const>& it, const SizedSentinel& st) { return it.it_ - st.end_; }
+
+ int* end_;
+};
+
+template <bool Const>
+struct CrossSizedSentinel {
+ template <bool C>
+ constexpr bool operator==(const Iterator<C>& i) const {
+ return i.it_ == end_;
+ }
+
+ template <bool C>
+ friend constexpr auto operator-(const CrossSizedSentinel& st, const Iterator<C>& it) {
+ return st.end_ - it.it_;
+ }
+
+ template <bool C>
+ friend constexpr auto operator-(const Iterator<C>& it, const CrossSizedSentinel& st) {
+ return it.it_ - st.end_;
+ }
+
+ int* end_;
+};
+
+// Views
+
+template <template <bool> class It, template <bool> class St>
+struct BufferView : std::ranges::view_base {
+ template <std::size_t N>
+ constexpr BufferView(int (&b)[N]) : buffer_(b), size_(N) {}
+
+ template <std::size_t N>
+ constexpr BufferView(std::array<int, N>& arr) : buffer_(arr.data()), size_(N) {}
+
+ using iterator = It<false>;
+ using sentinel = St<false>;
+ using const_iterator = It<true>;
+ using const_sentinel = St<true>;
+
+ using difference_type = int;
+ using iterator_type = std::tuple<std::ptrdiff_t, int>;
+
+ constexpr iterator begin() { return iterator_type{pos_, buffer_}; }
+ constexpr const_iterator begin() const { return {iterator_type{pos_, buffer_}}; }
+ constexpr sentinel end() { return sentinel{buffer_ + size_}; }
+ constexpr const_sentinel end() const { return const_sentinel{pos_, buffer_ + size_}; }
+
+ std::ptrdiff_t pos_;
+ int* buffer_;
+ std::size_t size_;
+};
+
+#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_TYPES_ITERATORS_H
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 3a068ab120b15..25a93c5fc7144 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -911,6 +911,11 @@ def add_version_header(tc):
"values": {"c++23": 202202},
"headers": ["ranges"],
},
+ {
+ "name": "__cpp_lib_ranges_enumerate",
+ "values": {"c++23": 202302},
+ "headers": ["ranges"],
+ },
{
"name": "__cpp_lib_ranges_iota",
"values": {"c++23": 202202},
>From eb53557181eb01db265e25d66fdf8f6fd357f98f Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 12:16:26 +0200
Subject: [PATCH 02/33] WIP: Commented out improperly completed tests
temporarily
---
.../range.enumerate/iterator/equal.pass.cpp | 3 +-
.../range.enumerate/sentinel/minus.pass.cpp | 219 +++++++++---------
2 files changed, 111 insertions(+), 111 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
index 6bf131d356d9c..38a0d303d47be 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
@@ -21,8 +21,7 @@
#include "test_iterators.h"
#include "../types.h"
-#include "../types_iterators.h"
-
+// #include "../types_iterators.h"
// template <bool Const>
// struct Iterator {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
index 274829668c7c1..1f88fd1a18343 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
@@ -30,7 +30,7 @@
#include "test_iterators.h"
#include "../types.h"
-#include "../types_iterators.h"
+// #include "../types_iterators.h"
// template <bool Const>
// struct Iter {
@@ -86,27 +86,27 @@
// }
// };
-// template <template <bool> class It, template <bool> class St>
-// struct BufferView : std::ranges::view_base {
-// template <std::size_t N>
-// constexpr BufferView(int (&b)[N]) : buffer_(b), size_(N) {}
+template <template <bool> class It, template <bool> class St>
+struct BufferView : std::ranges::view_base {
+ template <std::size_t N>
+ constexpr BufferView(int (&b)[N]) : buffer_(b), size_(N) {}
-// template <std::size_t N>
-// constexpr BufferView(std::array<int, N>& arr) : buffer_(arr.data()), size_(N) {}
+ template <std::size_t N>
+ constexpr BufferView(std::array<int, N>& arr) : buffer_(arr.data()), size_(N) {}
-// using iterator = It<false>;
-// using sentinel = St<false>;
-// using const_iterator = It<true>;
-// using const_sentinel = St<true>;
+ using iterator = It<false>;
+ using sentinel = St<false>;
+ using const_iterator = It<true>;
+ using const_sentinel = St<true>;
-// constexpr iterator begin() { return {buffer_}; }
-// constexpr const_iterator begin() const { return {buffer_}; }
-// constexpr sentinel end() { return sentinel{buffer_ + size_}; }
-// constexpr const_sentinel end() const { return const_sentinel{buffer_ + size_}; }
+ constexpr iterator begin() { return {buffer_}; }
+ constexpr const_iterator begin() const { return {buffer_}; }
+ constexpr sentinel end() { return sentinel{buffer_ + size_}; }
+ constexpr const_sentinel end() const { return const_sentinel{buffer_ + size_}; }
-// int* buffer_;
-// std::size_t size_;
-// };
+ int* buffer_;
+ std::size_t size_;
+};
template <template <bool> class It, template <bool> class St>
struct SizedBufferView : BufferView<It, St> {
@@ -131,116 +131,117 @@ using EnumerateSentinel = std::ranges::sentinel_t<EnumerateView<BaseView>>;
template <class BaseView>
using EnumerateConstSentinel = std::ranges::sentinel_t<const EnumerateView<BaseView>>;
-constexpr void testConstraints() {
- // Base is not sized
- {
- using Base = BufferView<Iterator, Sentinel>;
+// template <typename Iterator, typename Sentinel>
+// constexpr void testConstraints() {
+// // Base is not sized
+// {
+// using Base = BufferView<Iterator, Sentinel>;
- static_assert(!HasSize<Base>);
- static_assert(!std::ranges::sized_range<Base>);
+// static_assert(!HasSize<Base>);
+// static_assert(!std::ranges::sized_range<Base>);
- static_assert(!HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
- static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
+// static_assert(!HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
+// static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
- static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
- static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
+// static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
+// static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
- static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
- static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
+// static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
+// static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
- static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
- static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
- }
+// static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
+// static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
+// }
- // Base is sized but not cross const
- {
- using Base = SizedBufferView<Iterator, SizedSentinel>;
+// // Base is sized but not cross const
+// {
+// using Base = SizedBufferView<Iterator, SizedSentinel>;
- static_assert(HasSize<Base>);
- static_assert(std::ranges::sized_range<Base>);
+// static_assert(HasSize<Base>);
+// static_assert(std::ranges::sized_range<Base>);
- static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
- static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
+// static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
+// static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
- static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
- static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
+// static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
+// static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
- static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
- static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
+// static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
+// static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
- static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
- static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
- }
+// static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
+// static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
+// }
- // Base is cross const sized
- {
- using Base = BufferView<Iterator, CrossSizedSentinel>;
+// // Base is cross const sized
+// {
+// using Base = BufferView<Iterator, CrossSizedSentinel>;
- static_assert(!HasSize<Base>);
- static_assert(!std::ranges::sized_range<Base>);
+// static_assert(!HasSize<Base>);
+// static_assert(!std::ranges::sized_range<Base>);
- static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
- static_assert(HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
+// static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
+// static_assert(HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
- static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
- static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
+// static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
+// static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
- static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
- static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
+// static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
+// static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
- static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
- static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
- }
-}
+// static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
+// static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
+// }
+// }
constexpr bool test() {
- int buffer[] = {1, 2, 3, 4, 5};
-
- // Base is sized but not cross const
- {
- using Base = SizedBufferView<Iterator, SizedSentinel>;
-
- static_assert(HasSize<Base>);
- static_assert(std::ranges::sized_range<Base>);
-
- Base base{buffer};
- auto ev = base | std::views::enumerate;
- auto iter = ev.begin();
- auto const_iter = std::as_const(ev).begin();
- auto sent = ev.end();
- auto const_sent = std::as_const(ev).end();
-
- // Asssert difference
- assert(iter - sent == -5);
- assert(sent - iter == 5);
- assert(const_iter - const_sent == -5);
- assert(const_sent - const_iter == 5);
- }
-
- // Base is cross const sized
- {
- using Base = BufferView<Iterator, CrossSizedSentinel>;
-
- static_assert(!HasSize<Base>);
- static_assert(!std::ranges::sized_range<Base>);
-
- Base base{buffer};
- auto ev = base | std::views::enumerate;
- auto iter = ev.begin();
- auto const_iter = std::as_const(ev).begin();
- auto sent = ev.end();
- auto const_sent = std::as_const(ev).end();
-
- // Assert difference
- assert(iter - sent == -5);
- assert(sent - iter == 5);
- assert(iter - const_sent == -5);
- assert(const_sent - iter == 5);
- assert(const_iter - sent == -5);
- assert(sent - const_iter == 5);
- assert(const_iter - const_sent == -5);
- assert(const_sent - const_iter == 5);
- }
+ // int buffer[] = {1, 2, 3, 4, 5};
+
+ // // Base is sized but not cross const
+ // {
+ // using Base = SizedBufferView<Iterator, SizedSentinel>;
+
+ // static_assert(HasSize<Base>);
+ // static_assert(std::ranges::sized_range<Base>);
+
+ // Base base{buffer};
+ // auto ev = base | std::views::enumerate;
+ // auto iter = ev.begin();
+ // auto const_iter = std::as_const(ev).begin();
+ // auto sent = ev.end();
+ // auto const_sent = std::as_const(ev).end();
+
+ // // Asssert difference
+ // assert(iter - sent == -5);
+ // assert(sent - iter == 5);
+ // assert(const_iter - const_sent == -5);
+ // assert(const_sent - const_iter == 5);
+ // }
+
+ // // Base is cross const sized
+ // {
+ // using Base = BufferView<Iterator, CrossSizedSentinel>;
+
+ // static_assert(!HasSize<Base>);
+ // static_assert(!std::ranges::sized_range<Base>);
+
+ // Base base{buffer};
+ // auto ev = base | std::views::enumerate;
+ // auto iter = ev.begin();
+ // auto const_iter = std::as_const(ev).begin();
+ // auto sent = ev.end();
+ // auto const_sent = std::as_const(ev).end();
+
+ // // Assert difference
+ // assert(iter - sent == -5);
+ // assert(sent - iter == 5);
+ // assert(iter - const_sent == -5);
+ // assert(const_sent - iter == 5);
+ // assert(const_iter - sent == -5);
+ // assert(sent - const_iter == 5);
+ // assert(const_iter - const_sent == -5);
+ // assert(const_sent - const_iter == 5);
+ // }
return true;
}
>From 8f922d1b5d4f84ff0bbca3e1e4fe46514fcb88e3 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 12:50:03 +0200
Subject: [PATCH 03/33] WIP: Addressed comments
---
.../range.adaptors/range.enumerate/begin.pass.cpp | 2 +-
.../range.enumerate/iterator/types.compile.pass.cpp | 12 ++----------
.../ranges/range.adaptors/range.enumerate/types.h | 1 -
3 files changed, 3 insertions(+), 12 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
index 64876ed71355f..c8ca13350fa75 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
@@ -100,7 +100,7 @@ constexpr bool test() {
assert(it == view.end());
}
- // begin() over an 1-element range
+ // begin() over a 1-element range
{
RangeView range(buff, buff + 1);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
index a800e362befb0..07e4adfa24064 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
@@ -47,7 +47,7 @@ struct ForwardIteratorWithInputCategory {
};
static_assert(std::forward_iterator<ForwardIteratorWithInputCategory>);
-constexpr bool test() {
+constexpr void test() {
// Check that value_type is range_value_t and difference_type is range_difference_t
{
auto test = []<class Iterator> {
@@ -65,6 +65,7 @@ constexpr bool test() {
test.operator()<contiguous_iterator<int*>>();
test.operator()<int*>();
}
+
// Check iterator_concept for various categories of ranges
{
static_assert(
@@ -100,13 +101,4 @@ constexpr bool test() {
std::is_same_v<EnumerateIteratorFor<contiguous_iterator<int*>>::iterator_category, std::input_iterator_tag>);
static_assert(std::is_same_v<EnumerateIteratorFor<int*>::iterator_category, std::input_iterator_tag>);
}
-
- return true;
-}
-
-int main(int, char**) {
- test();
- static_assert(test());
-
- return 0;
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
index 1d55107df98cd..cf90094c0006e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
@@ -37,7 +37,6 @@ struct RangeView : std::ranges::view_base {
};
LIBCPP_STATIC_ASSERT(std::ranges::__range_with_movable_references<RangeView>);
-static_assert(std::ranges::range<RangeView>);
static_assert(std::ranges::view<RangeView>);
struct MinimalDefaultConstructedView : std::ranges::view_base {
>From 9a9f5d3404a30adf43ad0534e4487c84b6d359ea Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 15:13:08 +0200
Subject: [PATCH 04/33] WIP: nothing
---
.../range.enumerate/iterator/base.pass.cpp | 57 +++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
index b29d504a81515..261ede8eb8ddd 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
@@ -28,6 +28,55 @@
#include "test_iterators.h"
#include "../types.h"
+// template <class It, class ItTraits = It>
+// class MovableIterator {
+// using Traits = std::iterator_traits<ItTraits>;
+// It it_;
+
+// template <class U, class T>
+// friend class MovableIterator;
+
+// public:
+// using iterator_category = std::input_iterator_tag;
+// using value_type = typename Traits::value_type;
+// using difference_type = typename Traits::difference_type;
+// using pointer = It;
+// using reference = typename Traits::reference;
+
+// TEST_CONSTEXPR explicit MovableIterator(It it) : it_(it), justInitialized{true} { static_assert(false); }
+
+// template <class U, class T>
+// TEST_CONSTEXPR MovableIterator(const MovableIterator<U, T>& u) : it_(u.it_), wasCopyInitialized{true} {
+// static_assert(false);
+// }
+
+// template <class U, class T, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
+// TEST_CONSTEXPR_CXX14 MovableIterator(MovableIterator<U, T>&& u) : it_(u.it_), wasMoveInitialized{true} {
+// static_assert(false);
+// u.it_ = U();
+// }
+
+// TEST_CONSTEXPR reference operator*() const { return *it_; }
+
+// TEST_CONSTEXPR_CXX14 MovableIterator& operator++() {
+// ++it_;
+// return *this;
+// }
+// TEST_CONSTEXPR_CXX14 MovableIterator operator++(int) { return MovableIterator(it_++); }
+
+// friend TEST_CONSTEXPR bool operator==(const MovableIterator& x, const MovableIterator& y) { return x.it_ == y.it_; }
+// friend TEST_CONSTEXPR bool operator!=(const MovableIterator& x, const MovableIterator& y) { return x.it_ != y.it_; }
+
+// friend TEST_CONSTEXPR It base(const MovableIterator& i) { return i.it_; }
+
+// template <class T>
+// void operator,(T const&) = delete;
+
+// bool justInitialized = false;
+// bool wasCopyInitialized = false;
+// bool wasMoveInitialized = false;
+// };
+
template <class Iterator>
constexpr void testBase() {
using Sentinel = sentinel_wrapper<Iterator>;
@@ -57,10 +106,18 @@ constexpr void testBase() {
EnumerateIterator it = view.begin();
std::same_as<Iterator> decltype(auto) result = std::move(it).base();
assert(base(result) == array.begin());
+
+ // // Test move
+ // if constexpr (std::same_as<Iterator, MovableIterator<int*>>) {
+ // assert(result.justInitialized);
+ // assert(!result.wasCopyInitialized);
+ // assert(!result.wasMoveInitialized);
+ // }
}
}
constexpr bool test() {
+ // testBase<MovableIterator<int*>>();
testBase<cpp17_input_iterator<int*>>();
testBase<cpp20_input_iterator<int*>>();
testBase<forward_iterator<int*>>();
>From 3b5f9f326c0e0cbbdac25cd75413731a84bc2b55 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 16:01:30 +0200
Subject: [PATCH 05/33] WIP: Address comment in `adaptor.pass.cpp`
---
.../ranges/range.adaptors/range.enumerate/adaptor.pass.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp
index edc58536d68dc..fe556351387c8 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp
@@ -56,6 +56,10 @@ using NonEnumeratableRangeWithImmmovabaleReferences =
static_assert(std::ranges::input_range<NonEnumeratableRangeWithImmmovabaleReferences>);
static_assert(!CanEnumerate<NonEnumeratableRangeWithImmmovabaleReferences>);
+static_assert(
+ !std::move_constructible<std::ranges::range_reference_t< NonEnumeratableRangeWithImmmovabaleReferences >>);
+static_assert(
+ !std::move_constructible<std::ranges::range_rvalue_reference_t< NonEnumeratableRangeWithImmmovabaleReferences >>);
template <typename View, typename T>
using ExpectedViewElement = std::tuple<typename std::ranges::iterator_t<View>::difference_type, T>;
>From 20c59fbadbc6af6fa8e0577c9c7b6a26b56e1d84 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 16:03:35 +0200
Subject: [PATCH 06/33] WIP: tweak
---
.../ranges/range.adaptors/range.enumerate/adaptor.pass.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp
index fe556351387c8..9992c80923df7 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp
@@ -56,10 +56,9 @@ using NonEnumeratableRangeWithImmmovabaleReferences =
static_assert(std::ranges::input_range<NonEnumeratableRangeWithImmmovabaleReferences>);
static_assert(!CanEnumerate<NonEnumeratableRangeWithImmmovabaleReferences>);
+static_assert(!std::move_constructible<std::ranges::range_reference_t<NonEnumeratableRangeWithImmmovabaleReferences>>);
static_assert(
- !std::move_constructible<std::ranges::range_reference_t< NonEnumeratableRangeWithImmmovabaleReferences >>);
-static_assert(
- !std::move_constructible<std::ranges::range_rvalue_reference_t< NonEnumeratableRangeWithImmmovabaleReferences >>);
+ !std::move_constructible<std::ranges::range_rvalue_reference_t<NonEnumeratableRangeWithImmmovabaleReferences>>);
template <typename View, typename T>
using ExpectedViewElement = std::tuple<typename std::ranges::iterator_t<View>::difference_type, T>;
>From 963aa353be583078761296c70a7e7b842f5aacc9 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Thu, 4 Jan 2024 09:52:56 +0200
Subject: [PATCH 07/33] WIP: Addressed some comments
---
libcxx/include/__ranges/enumerate_view.h | 21 +++++++------------
...w_adaptors.nodiscard_extensions.verify.cpp | 12 +++++++++--
2 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index 77b29837ba546..5a0aad6271d48 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -42,8 +42,8 @@ namespace ranges {
template <class _Rp>
concept __range_with_movable_references =
- ranges::input_range<_Rp> && std::move_constructible<ranges::range_reference_t<_Rp>> &&
- std::move_constructible<ranges::range_rvalue_reference_t<_Rp>>;
+ input_range<_Rp> && std::move_constructible<range_reference_t<_Rp>> &&
+ std::move_constructible<range_rvalue_reference_t<_Rp>>;
// [range.enumerate.view]
@@ -60,14 +60,9 @@ class enumerate_view : public view_interface<enumerate_view<_View>> {
template <bool _Const>
class __sentinel;
- template <bool _AnyConst>
- _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __get_current(const __iterator<_AnyConst>& __iter) {
- return (__iter.__current_);
- }
-
public:
_LIBCPP_HIDE_FROM_ABI constexpr enumerate_view()
- requires(default_initializable<_View>)
+ requires default_initializable<_View>
= default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit enumerate_view(_View __base) : __base_(std::move(__base)){};
@@ -159,7 +154,7 @@ class enumerate_view<_View>::__iterator {
public:
_LIBCPP_HIDE_FROM_ABI __iterator()
- requires(default_initializable<iterator_t<_Base>>)
+ requires default_initializable<iterator_t<_Base>>
= default;
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
@@ -283,21 +278,21 @@ class enumerate_view<_View>::__sentinel {
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
- return __get_current(__x) == __y.__end_;
+ return __x.__current_ == __y.__end_;
}
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
_LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
- return __get_current(__x) - __y.__end_;
+ return __x.__current_ - __y.__end_;
}
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
_LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) {
- return __x.__end_ - __get_current(__y);
+ return __x.__end_ - __y.__current_;
}
};
@@ -309,7 +304,7 @@ namespace __enumerate {
struct __fn : __range_adaptor_closure<__fn> {
template <class _Range>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
+ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
noexcept(noexcept(/**/ enumerate_view(std::forward<_Range>(__range))))
-> decltype(/*--*/ enumerate_view(std::forward<_Range>(__range))) {
return /*-------------*/ enumerate_view(std::forward<_Range>(__range));
diff --git a/libcxx/test/libcxx/diagnostics/view_adaptors.nodiscard_extensions.verify.cpp b/libcxx/test/libcxx/diagnostics/view_adaptors.nodiscard_extensions.verify.cpp
index 35c4ab570848d..130b0a12ffd25 100644
--- a/libcxx/test/libcxx/diagnostics/view_adaptors.nodiscard_extensions.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/view_adaptors.nodiscard_extensions.verify.cpp
@@ -13,10 +13,18 @@
#include <ranges>
#include <vector>
+#include "test_macros.h"
+
void func() {
std::vector<int> range;
auto rvalue_view = std::views::as_rvalue(range);
- std::views::as_rvalue(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::views::as_rvalue(rvalue_view); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::as_rvalue(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::as_rvalue(rvalue_view); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+#if TEST_STD_VER >= 23
+ auto enumerate_view = std::views::enumerate(range);
+ std::views::enumerate(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::enumerate(enumerate_view); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#endif
}
>From 2870bbe82234c05d7e099ff629f917fe474440ae Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Thu, 4 Jan 2024 10:02:50 +0200
Subject: [PATCH 08/33] REMOVED: Commented out broken test (Restore them later)
---
.../range.enumerate/iterator/base.pass.cpp | 57 ------
.../range.enumerate/iterator/equal.pass.cpp | 35 ----
.../range.enumerate/sentinel/minus.pass.cpp | 165 ------------------
3 files changed, 257 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
index 261ede8eb8ddd..b29d504a81515 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
@@ -28,55 +28,6 @@
#include "test_iterators.h"
#include "../types.h"
-// template <class It, class ItTraits = It>
-// class MovableIterator {
-// using Traits = std::iterator_traits<ItTraits>;
-// It it_;
-
-// template <class U, class T>
-// friend class MovableIterator;
-
-// public:
-// using iterator_category = std::input_iterator_tag;
-// using value_type = typename Traits::value_type;
-// using difference_type = typename Traits::difference_type;
-// using pointer = It;
-// using reference = typename Traits::reference;
-
-// TEST_CONSTEXPR explicit MovableIterator(It it) : it_(it), justInitialized{true} { static_assert(false); }
-
-// template <class U, class T>
-// TEST_CONSTEXPR MovableIterator(const MovableIterator<U, T>& u) : it_(u.it_), wasCopyInitialized{true} {
-// static_assert(false);
-// }
-
-// template <class U, class T, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
-// TEST_CONSTEXPR_CXX14 MovableIterator(MovableIterator<U, T>&& u) : it_(u.it_), wasMoveInitialized{true} {
-// static_assert(false);
-// u.it_ = U();
-// }
-
-// TEST_CONSTEXPR reference operator*() const { return *it_; }
-
-// TEST_CONSTEXPR_CXX14 MovableIterator& operator++() {
-// ++it_;
-// return *this;
-// }
-// TEST_CONSTEXPR_CXX14 MovableIterator operator++(int) { return MovableIterator(it_++); }
-
-// friend TEST_CONSTEXPR bool operator==(const MovableIterator& x, const MovableIterator& y) { return x.it_ == y.it_; }
-// friend TEST_CONSTEXPR bool operator!=(const MovableIterator& x, const MovableIterator& y) { return x.it_ != y.it_; }
-
-// friend TEST_CONSTEXPR It base(const MovableIterator& i) { return i.it_; }
-
-// template <class T>
-// void operator,(T const&) = delete;
-
-// bool justInitialized = false;
-// bool wasCopyInitialized = false;
-// bool wasMoveInitialized = false;
-// };
-
template <class Iterator>
constexpr void testBase() {
using Sentinel = sentinel_wrapper<Iterator>;
@@ -106,18 +57,10 @@ constexpr void testBase() {
EnumerateIterator it = view.begin();
std::same_as<Iterator> decltype(auto) result = std::move(it).base();
assert(base(result) == array.begin());
-
- // // Test move
- // if constexpr (std::same_as<Iterator, MovableIterator<int*>>) {
- // assert(result.justInitialized);
- // assert(!result.wasCopyInitialized);
- // assert(!result.wasMoveInitialized);
- // }
}
}
constexpr bool test() {
- // testBase<MovableIterator<int*>>();
testBase<cpp17_input_iterator<int*>>();
testBase<cpp20_input_iterator<int*>>();
testBase<forward_iterator<int*>>();
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
index 38a0d303d47be..92f3d7ca352f4 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
@@ -21,41 +21,6 @@
#include "test_iterators.h"
#include "../types.h"
-// #include "../types_iterators.h"
-
-// template <bool Const>
-// struct Iterator {
-// using value_type = int
-// using difference_type = std::std::ptrdiff_t;
-// using iterator_concept = std::input_iterator_tag;
-
-// constexpr decltype(auto) operator*() const { return *it_; }
-// constexpr Iterator& operator++() {
-// ++it_;
-
-// return *this;
-// }
-// constexpr void operator++(int) { ++it_; }
-
-// std::tuple<std::ptrdiff_t, int>* it_;
-// };
-
-// template <bool Const>
-// struct Sentinel {
-// constexpr bool operator==(const Iterator<Const>& i) const { return i.it_ == end_; }
-
-// std::tuple<std::ptrdiff_t, int>* end_;
-// };
-
-// template <bool Const>
-// struct CrossComparableSentinel {
-// template <bool C>
-// constexpr bool operator==(const Iterator<C>& i) const {
-// return i.it_ == end_;
-// }
-
-// std::tuple<std::ptrdiff_t, int>* end_;
-// };
constexpr bool test() {
int buff[] = {0, 1, 2, 3, 5};
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
index 1f88fd1a18343..dcc91138c7e9a 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
@@ -30,61 +30,6 @@
#include "test_iterators.h"
#include "../types.h"
-// #include "../types_iterators.h"
-
-// template <bool Const>
-// struct Iter {
-// int* it_;
-
-// using value_type = int;
-// using difference_type = std::ptrdiff_t;
-// using iterator_concept = std::input_iterator_tag;
-
-// constexpr decltype(auto) operator*() const { return *it_; }
-// constexpr Iter& operator++() {
-// ++it_;
-// return *this;
-// }
-// constexpr void operator++(int) { ++it_; }
-// };
-
-// template <bool Const>
-// struct Sent {
-// int* end_;
-
-// constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
-// };
-
-// template <bool Const>
-// struct SizedSent {
-// int* end_;
-
-// constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
-
-// friend constexpr auto operator-(const SizedSent& st, const Iter<Const>& it) { return st.end_ - it.it_; }
-
-// friend constexpr auto operator-(const Iter<Const>& it, const SizedSent& st) { return it.it_ - st.end_; }
-// };
-
-// template <bool Const>
-// struct CrossSizedSent {
-// int* end_;
-
-// template <bool C>
-// constexpr bool operator==(const Iter<C>& i) const {
-// return i.it_ == end_;
-// }
-
-// template <bool C>
-// friend constexpr auto operator-(const CrossSizedSent& st, const Iter<C>& it) {
-// return st.end_ - it.it_;
-// }
-
-// template <bool C>
-// friend constexpr auto operator-(const Iter<C>& it, const CrossSizedSent& st) {
-// return it.it_ - st.end_;
-// }
-// };
template <template <bool> class It, template <bool> class St>
struct BufferView : std::ranges::view_base {
@@ -131,117 +76,7 @@ using EnumerateSentinel = std::ranges::sentinel_t<EnumerateView<BaseView>>;
template <class BaseView>
using EnumerateConstSentinel = std::ranges::sentinel_t<const EnumerateView<BaseView>>;
-// template <typename Iterator, typename Sentinel>
-// constexpr void testConstraints() {
-// // Base is not sized
-// {
-// using Base = BufferView<Iterator, Sentinel>;
-
-// static_assert(!HasSize<Base>);
-// static_assert(!std::ranges::sized_range<Base>);
-
-// static_assert(!HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
-// static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
-
-// static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
-// static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
-
-// static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
-// static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
-
-// static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
-// static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
-// }
-
-// // Base is sized but not cross const
-// {
-// using Base = SizedBufferView<Iterator, SizedSentinel>;
-
-// static_assert(HasSize<Base>);
-// static_assert(std::ranges::sized_range<Base>);
-
-// static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
-// static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
-
-// static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
-// static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
-
-// static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
-// static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
-
-// static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
-// static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
-// }
-
-// // Base is cross const sized
-// {
-// using Base = BufferView<Iterator, CrossSizedSentinel>;
-
-// static_assert(!HasSize<Base>);
-// static_assert(!std::ranges::sized_range<Base>);
-
-// static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
-// static_assert(HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
-
-// static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
-// static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
-
-// static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
-// static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
-
-// static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
-// static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
-// }
-// }
-
constexpr bool test() {
- // int buffer[] = {1, 2, 3, 4, 5};
-
- // // Base is sized but not cross const
- // {
- // using Base = SizedBufferView<Iterator, SizedSentinel>;
-
- // static_assert(HasSize<Base>);
- // static_assert(std::ranges::sized_range<Base>);
-
- // Base base{buffer};
- // auto ev = base | std::views::enumerate;
- // auto iter = ev.begin();
- // auto const_iter = std::as_const(ev).begin();
- // auto sent = ev.end();
- // auto const_sent = std::as_const(ev).end();
-
- // // Asssert difference
- // assert(iter - sent == -5);
- // assert(sent - iter == 5);
- // assert(const_iter - const_sent == -5);
- // assert(const_sent - const_iter == 5);
- // }
-
- // // Base is cross const sized
- // {
- // using Base = BufferView<Iterator, CrossSizedSentinel>;
-
- // static_assert(!HasSize<Base>);
- // static_assert(!std::ranges::sized_range<Base>);
-
- // Base base{buffer};
- // auto ev = base | std::views::enumerate;
- // auto iter = ev.begin();
- // auto const_iter = std::as_const(ev).begin();
- // auto sent = ev.end();
- // auto const_sent = std::as_const(ev).end();
-
- // // Assert difference
- // assert(iter - sent == -5);
- // assert(sent - iter == 5);
- // assert(iter - const_sent == -5);
- // assert(const_sent - iter == 5);
- // assert(const_iter - sent == -5);
- // assert(sent - const_iter == 5);
- // assert(const_iter - const_sent == -5);
- // assert(const_sent - const_iter == 5);
- // }
return true;
}
>From 8a02a2e96c9b41fca773450c7e1e57c71feb41df Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Thu, 4 Jan 2024 10:18:08 +0200
Subject: [PATCH 09/33] WIP: Fixed formatting
---
.../view_adaptors.nodiscard_extensions.verify.cpp | 12 ++++++++----
.../range.enumerate/sentinel/minus.pass.cpp | 5 +----
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/libcxx/test/libcxx/diagnostics/view_adaptors.nodiscard_extensions.verify.cpp b/libcxx/test/libcxx/diagnostics/view_adaptors.nodiscard_extensions.verify.cpp
index 130b0a12ffd25..5240ea9072804 100644
--- a/libcxx/test/libcxx/diagnostics/view_adaptors.nodiscard_extensions.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/view_adaptors.nodiscard_extensions.verify.cpp
@@ -19,12 +19,16 @@ void func() {
std::vector<int> range;
auto rvalue_view = std::views::as_rvalue(range);
- std::views::as_rvalue(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::views::as_rvalue(rvalue_view); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::as_rvalue(range);
+ // expected-warning at -1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::as_rvalue(rvalue_view);
+ // expected-warning at -1 {{ignoring return value of function declared with 'nodiscard' attribute}}
#if TEST_STD_VER >= 23
auto enumerate_view = std::views::enumerate(range);
- std::views::enumerate(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::views::enumerate(enumerate_view); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::enumerate(range);
+ // expected-warning at -1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::enumerate(enumerate_view);
+ // expected-warning at -1 {{ignoring return value of function declared with 'nodiscard' attribute}}
#endif
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
index dcc91138c7e9a..fabfde767e694 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
@@ -76,10 +76,7 @@ using EnumerateSentinel = std::ranges::sentinel_t<EnumerateView<BaseView>>;
template <class BaseView>
using EnumerateConstSentinel = std::ranges::sentinel_t<const EnumerateView<BaseView>>;
-constexpr bool test() {
-
- return true;
-}
+constexpr bool test() { return true; }
int main(int, char**) {
test();
>From 2dccd6c8bbdc7e20d1da124746fa0765cf331194 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Thu, 4 Jan 2024 11:18:58 +0200
Subject: [PATCH 10/33] WIP: Addressed some comments
---
.../iterator/subscript.pass.cpp | 1 -
.../iterator/types.compile.pass.cpp | 18 ------------------
2 files changed, 19 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp
index d6f9d4beda938..b062c6bcaa6dd 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp
@@ -36,7 +36,6 @@ static_assert(std::ranges::random_access_range<RandomAccessRange>);
static_assert(HasSubscriptOperator<EnumerateIterator<RandomAccessRange>, int>);
using BidirectionalRange = std::ranges::subrange<bidirectional_iterator<int*>>;
-static_assert(!std::ranges::random_access_range<BidirectionalRange>);
static_assert(!HasSubscriptOperator<EnumerateIterator<BidirectionalRange>, int>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
index 07e4adfa24064..d46c68da8e444 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
@@ -48,24 +48,6 @@ struct ForwardIteratorWithInputCategory {
static_assert(std::forward_iterator<ForwardIteratorWithInputCategory>);
constexpr void test() {
- // Check that value_type is range_value_t and difference_type is range_difference_t
- {
- auto test = []<class Iterator> {
- using EnumerateView = EnumerateViewFor<Iterator>;
- using EnumerateIterator = EnumerateIteratorFor<Iterator>;
- static_assert(std::is_same_v<typename EnumerateIterator::value_type, std::ranges::range_value_t<EnumerateView>>);
- static_assert(
- std::is_same_v<typename EnumerateIterator::difference_type, std::ranges::range_difference_t<EnumerateView>>);
- };
- test.operator()<cpp17_input_iterator<int*>>();
- test.operator()<cpp20_input_iterator<int*>>();
- test.operator()<forward_iterator<int*>>();
- test.operator()<bidirectional_iterator<int*>>();
- test.operator()<random_access_iterator<int*>>();
- test.operator()<contiguous_iterator<int*>>();
- test.operator()<int*>();
- }
-
// Check iterator_concept for various categories of ranges
{
static_assert(
>From b922f9186251aefae5d15e6585eb3cb970736382 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Thu, 4 Jan 2024 14:57:14 +0200
Subject: [PATCH 11/33] WIP: Addressed comments in iterator/subscript
---
.../iterator/subscript.pass.cpp | 31 ++++++++++---------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp
index b062c6bcaa6dd..01256157f159f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp
@@ -30,39 +30,40 @@ concept HasSubscriptOperator = requires(T t, U u) { t[u]; };
template <class BaseRange>
using EnumerateIterator = std::ranges::iterator_t<std::ranges::enumerate_view<BaseRange>>;
-using RandomAccessRange = std::ranges::subrange<int*>;
-static_assert(std::ranges::random_access_range<RandomAccessRange>);
-
-static_assert(HasSubscriptOperator<EnumerateIterator<RandomAccessRange>, int>);
+using Subrange = std::ranges::subrange<int*>;
+static_assert(HasSubscriptOperator<EnumerateIterator<Subrange>, int>);
using BidirectionalRange = std::ranges::subrange<bidirectional_iterator<int*>>;
-
static_assert(!HasSubscriptOperator<EnumerateIterator<BidirectionalRange>, int>);
constexpr bool test() {
// Reference
{
- std::array ts = {0, 1, 2, 3, 84};
+ std::array ts = {90, 1, 2, 84};
auto view = ts | std::views::enumerate;
auto it = view.begin();
- for (std::size_t index = 0; index != ts.size(); ++index) {
- assert(it[index] == *(it + index));
- }
+ using DifferenceT = std::iter_difference_t<std::iter_difference_t<decltype(it)>>;
+ static_assert(std::is_same_v<decltype(it[2]), std::tuple<DifferenceT, int&>>);
- static_assert(std::is_same_v<decltype(it[2]), std::tuple<decltype(it)::difference_type, int&>>);
+ assert((it[0] == std::tuple<DifferenceT, int>(0, 90)));
+ assert((it[1] == std::tuple<DifferenceT, int>(1, 1)));
+ assert((it[2] == std::tuple<DifferenceT, int>(2, 2)));
+ assert((it[3] == std::tuple<DifferenceT, int>(3, 84)));
}
// Value
{
- auto view = std::views::iota(0, 5) | std::views::enumerate;
+ auto view = std::views::iota(0, 4) | std::views::enumerate;
auto it = view.begin();
- for (std::size_t index = 0; index != 5; ++index) {
- assert(it[index] == *(it + index));
- }
+ using DifferenceT = std::iter_difference_t<std::iter_difference_t<decltype(it)>>;
+ static_assert(std::is_same_v<decltype(it[2]), std::tuple<DifferenceT, int>>);
- static_assert(std::is_same_v<decltype(it[2]), std::tuple<decltype(it)::difference_type, int>>);
+ assert((it[0] == std::tuple<DifferenceT, int>(0, 0)));
+ assert((it[1] == std::tuple<DifferenceT, int>(1, 1)));
+ assert((it[2] == std::tuple<DifferenceT, int>(2, 2)));
+ assert((it[3] == std::tuple<DifferenceT, int>(3, 3)));
}
return true;
>From 2d7982fa2f0323c745a9b0a12106e7d2dc6bfe1b Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Thu, 4 Jan 2024 16:23:30 +0200
Subject: [PATCH 12/33] WIP: Updated iterator/artithmetic.pass
---
.../iterator/arithmetic.pass.cpp | 64 ++++++++++++++++---
1 file changed, 55 insertions(+), 9 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp
index 031605a7aacd8..ae1b62269c7c1 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp
@@ -74,10 +74,10 @@ static_assert(!CanPlusEqual<EnumerateIter<BidirectionalRange>, int>);
static_assert(!CanMinus<EnumerateIter<BidirectionalRange>, int>);
static_assert(!CanMinusEqual<EnumerateIter<BidirectionalRange>, int>);
-constexpr bool test() {
- int ts[] = {1, 2, 3, 4, 5};
+constexpr void test_with_common_range() {
+ int ts[] = {90, 1, 2, 84};
- RandomAccessRange r{ts, ts + 5};
+ RandomAccessRange r{ts, ts + 4};
auto ev = r | std::views::enumerate;
// operator+(x, n), operator+(n,x) and operator+=
@@ -99,22 +99,68 @@ constexpr bool test() {
{
auto it1 = ev.end();
- auto it2 = it1 - 4;
+ auto it2 = it1 - 3;
assert(it2.base() == &ts[1]);
- it1 -= 4;
+ it1 -= 3;
assert(it1 == it2);
assert(it1.base() == &ts[1]);
}
// operator-(x, y)
{
- assert((ev.end() - ev.begin()) == 5);
+ assert((ev.end() - ev.begin()) == 4);
+
+ auto it1 = ev.begin() + 1;
+ auto it2 = ev.end() - 1;
+ assert((it1 - it2) == -2);
+ }
+}
+
+constexpr void test_with_noncommon_range() {
+ int ts[] = {90, 1, 2, 84};
+
+ RandomAccessRange r{ts, ts + 4};
+ auto it = std::counted_iterator{r.begin(), std::ssize(r)};
+ auto sr = std::ranges::subrange{it, std::default_sentinel};
+ auto ev = sr | std::views::enumerate;
+
+ // operator+(x, n), operator+(n,x) and operator+=
+ {
+ auto it1 = ev.begin();
+
+ auto it2 = it1 + 3;
+ assert(*it2.base() == 84);
+
+ auto it3 = 3 + it1;
+ assert(*it3.base() == 84);
+
+ it1 += 3;
+ assert(it1 == it2);
+ assert(*it1.base() == 84);
+ }
+
+ // operator-(x, n) and operator-=
+ {
+ auto it1 = ev.begin();
+
+ auto it2 = it1 + 3;
+ assert(*(it2 - 1).base() == 2);
- auto it1 = ev.begin() + 2;
- auto it2 = ev.end() - 2;
- assert((it1 - it2) == -1);
+ it2 -= 3;
+ assert(it1 == it2);
+ assert(*it2.base() == 90);
+ }
+
+ // operator-(x, y)
+ {
+ assert((ev.end() - ev.begin()) == 4);
}
+}
+
+constexpr bool test() {
+ test_with_common_range();
+ test_with_noncommon_range();
return true;
}
>From 9cfed98f0198e343624d5222b90a56b8c17c1aa8 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Tue, 23 Jan 2024 15:27:33 +0200
Subject: [PATCH 13/33] WIP: do not push
---
.../range.enumerate/begin.pass.cpp | 39 ++--
.../range.enumerate/sentinel/minus.pass.cpp | 179 +++++++++++++++++-
.../range.adaptors/range.enumerate/types.h | 5 +
3 files changed, 202 insertions(+), 21 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
index c8ca13350fa75..5a10f008062c9 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
@@ -22,26 +22,6 @@
#include "test_iterators.h"
#include "types.h"
-// Helpers
-
-template <class T>
-concept HasConstBegin = requires(const T ct) { ct.begin(); };
-
-template <class T>
-concept HasBegin = requires(T t) { t.begin(); };
-
-template <class T>
-concept HasConstAndNonConstBegin =
- HasConstBegin<T> &&
- // Because const begin() and non-const begin() returns different types: iterator<true> vs. iterator<false>
- requires(T t, const T ct) { requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>; };
-
-template <class T>
-concept HasOnlyNonConstBegin = HasBegin<T> && !HasConstBegin<T>;
-
-template <class T>
-concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
-
// Types
template <bool Simple>
@@ -69,6 +49,24 @@ struct NoConstBeginView : std::ranges::view_base {
// SFINAE
+template <class T>
+concept HasConstBegin = requires(const T ct) { ct.begin(); };
+
+template <class T>
+concept HasBegin = requires(T t) { t.begin(); };
+
+template <class T>
+concept HasConstAndNonConstBegin =
+ HasConstBegin<T> &&
+ // Because const begin() and non-const begin() returns different types: iterator<true> vs. iterator<false>
+ requires(T t, const T ct) { requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>; };
+
+template <class T>
+concept HasOnlyNonConstBegin = HasBegin<T> && !HasConstBegin<T>;
+
+template <class T>
+concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
+
// simple-view<V>
static_assert(HasOnlyConstBegin<std::ranges::enumerate_view<SimpleCommonView>>);
@@ -88,6 +86,7 @@ constexpr bool test() {
std::ranges::enumerate_view view(range);
using Iterator = std::ranges::iterator_t<decltype(view)>;
static_assert(std::same_as<Iterator, decltype(view.begin())>);
+ static_assert(std::same_as<ValueType<int>, decltype(*view.begin())>);
}
// begin() over an empty range
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
index fabfde767e694..f7551d0894dca 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
@@ -30,6 +30,61 @@
#include "test_iterators.h"
#include "../types.h"
+// #include "../types_iterators.h"
+
+template <bool Const>
+struct Iter {
+ int* it_;
+
+ using value_type = int;
+ using difference_type = std::ptrdiff_t;
+ using iterator_concept = std::input_iterator_tag;
+
+ constexpr decltype(auto) operator*() const { return *it_; }
+ constexpr Iter& operator++() {
+ ++it_;
+ return *this;
+ }
+ constexpr void operator++(int) { ++it_; }
+};
+
+template <bool Const>
+struct Sent {
+ int* end_;
+
+ constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
+};
+
+template <bool Const>
+struct SizedSent {
+ int* end_;
+
+ constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
+
+ friend constexpr auto operator-(const SizedSent& st, const Iter<Const>& it) { return st.end_ - it.it_; }
+
+ friend constexpr auto operator-(const Iter<Const>& it, const SizedSent& st) { return it.it_ - st.end_; }
+};
+
+template <bool Const>
+struct CrossSizedSent {
+ int* end_;
+
+ template <bool C>
+ constexpr bool operator==(const Iter<C>& i) const {
+ return i.it_ == end_;
+ }
+
+ template <bool C>
+ friend constexpr auto operator-(const CrossSizedSent& st, const Iter<C>& it) {
+ return st.end_ - it.it_;
+ }
+
+ template <bool C>
+ friend constexpr auto operator-(const Iter<C>& it, const CrossSizedSent& st) {
+ return it.it_ - st.end_;
+ }
+};
template <template <bool> class It, template <bool> class St>
struct BufferView : std::ranges::view_base {
@@ -55,6 +110,16 @@ struct BufferView : std::ranges::view_base {
template <template <bool> class It, template <bool> class St>
struct SizedBufferView : BufferView<It, St> {
+ using BufferView<It, St>::BufferView;
+
+ using BufferView<It, St>::iterator;
+ using BufferView<It, St>::sentinel;
+ using BufferView<It, St>::const_iterator;
+ using BufferView<It, St>::const_sentinel;
+
+ using BufferView<It, St>::begin;
+ using BufferView<It, St>::end;
+
constexpr std::size_t size() { return BufferView<It, St>::size_; }
};
@@ -76,7 +141,119 @@ using EnumerateSentinel = std::ranges::sentinel_t<EnumerateView<BaseView>>;
template <class BaseView>
using EnumerateConstSentinel = std::ranges::sentinel_t<const EnumerateView<BaseView>>;
-constexpr bool test() { return true; }
+constexpr void testConstraints() {
+ // Base is not sized
+ {
+ using Base = BufferView<Iter, Sent>;
+
+ static_assert(!HasSize<Base>);
+ static_assert(!std::ranges::sized_range<Base>);
+
+ static_assert(!HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
+
+ static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
+ }
+
+ // Base is sized but not cross const
+ {
+ using Base = SizedBufferView<Iter, Sent>;
+
+ static_assert(HasSize<Base>);
+ static_assert(std::ranges::sized_range<Base>);
+
+ static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
+
+ static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
+ }
+
+ // Base is cross const sized
+ {
+ using Base = BufferView<Iter, CrossSizedSent>;
+
+ static_assert(!HasSize<Base>);
+ static_assert(!std::ranges::sized_range<Base>);
+
+ static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
+ static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
+
+ static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
+
+ static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
+ static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
+ }
+}
+
+constexpr bool test() {
+ int buffer[] = {1, 2, 3, 4, 5};
+
+ // Base is sized but not cross const
+ {
+ using Base = SizedBufferView<Iter, SizedSent>;
+
+ static_assert(HasSize<Base>);
+ static_assert(std::ranges::sized_range<Base>);
+
+ Base base{buffer};
+ auto ev = base | std::views::enumerate;
+ auto iter = ev.begin();
+ auto const_iter = std::as_const(ev).begin();
+ auto sent = ev.end();
+ auto const_sent = std::as_const(ev).end();
+
+ // Asssert difference
+ assert(iter - sent == -5);
+ assert(sent - iter == 5);
+ assert(const_iter - const_sent == -5);
+ assert(const_sent - const_iter == 5);
+ }
+
+ // Base is cross const sized
+ {
+ using Base = BufferView<Iter, CrossSizedSent>;
+
+ static_assert(!HasSize<Base>);
+ static_assert(!std::ranges::sized_range<Base>);
+
+ Base base{buffer};
+ auto ev = base | std::views::enumerate;
+ auto iter = ev.begin();
+ auto const_iter = std::as_const(ev).begin();
+ auto sent = ev.end();
+ auto const_sent = std::as_const(ev).end();
+
+ // Assert difference
+ assert(iter - sent == -5);
+ assert(sent - iter == 5);
+ assert(iter - const_sent == -5);
+ assert(const_sent - iter == 5);
+ assert(const_iter - sent == -5);
+ assert(sent - const_iter == 5);
+ assert(const_iter - const_sent == -5);
+ assert(const_sent - const_iter == 5);
+ }
+
+ return true;
+}
int main(int, char**) {
test();
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
index cf90094c0006e..cf49355c7348b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
@@ -9,13 +9,18 @@
#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_TYPES_H
#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_TYPES_H
+#include <cstddef>
#include <ranges>
+#include <tuple>
#include "test_iterators.h"
#include "test_macros.h"
// Types
+template<typename T, typename DifferenceT = std::ptrdiff_t>
+using ValueType = std::tuple<DifferenceT, T>;
+
struct RangeView : std::ranges::view_base {
using Iterator = cpp20_input_iterator<int*>;
using Sentinel = sentinel_wrapper<Iterator>;
>From 5089669fb58bd257450e9617770fca7e8f566cc3 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Wed, 21 Feb 2024 09:56:28 +0200
Subject: [PATCH 14/33] Fixed LLVM target version
---
libcxx/docs/Status/Cxx23Papers.csv | 2 +-
libcxx/docs/Status/Cxx2cIssues.csv | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 409b68449f189..74899e662be09 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -105,7 +105,7 @@
"","","","","","",""
"`P0290R4 <https://wg21.link/P0290R4>`__","LWG", "``apply()`` for ``synchronized_value<T>``","February 2023","","","|concurrency TS|"
"`P2770R0 <https://wg21.link/P2770R0>`__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|Partial| [#note-P2770R0]_","","|ranges|"
-"`P2164R9 <https://wg21.link/P2164R9>`__","LWG", "``views::enumerate``","February 2023","|Complete|","18.0","|ranges|"
+"`P2164R9 <https://wg21.link/P2164R9>`__","LWG", "``views::enumerate``","February 2023","|Complete|","19.0","|ranges|"
"`P2711R1 <https://wg21.link/P2711R1>`__","LWG", "Making multi-param constructors of ``views`` ``explicit``","February 2023","|In Progress| [#note-P2711R1]_","","|ranges|"
"`P2609R3 <https://wg21.link/P2609R3>`__","LWG", "Relaxing Ranges Just A Smidge","February 2023","","","|ranges|"
"`P2713R1 <https://wg21.link/P2713R1>`__","LWG", "Escaping improvements in ``std::format``","February 2023","","","|format|"
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 3ddcde31fcb08..83d895ed47191 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -8,8 +8,8 @@
"`3903 <https://wg21.link/LWG3903>`__","span destructor is redundantly noexcept","Varna June 2023","|Complete|","7.0",""
"`3904 <https://wg21.link/LWG3904>`__","``lazy_split_view::outer-iterator``'s const-converting constructor isn't setting ``trailing_empty_``","Varna June 2023","","","|ranges|"
"`3905 <https://wg21.link/LWG3905>`__","Type of ``std::fexcept_t``","Varna June 2023","|Complete|","3.4",""
-"`3912 <https://wg21.link/LWG3912>`__","``enumerate_view::iterator::operator-`` should be ``noexcept``","Varna June 2023","|Complete|","18.0","|ranges|"
-"`3914 <https://wg21.link/LWG3914>`__","Inconsistent template-head of ``ranges::enumerate_view``","Varna June 2023","|Complete|","18.0","|ranges|"
+"`3912 <https://wg21.link/LWG3912>`__","``enumerate_view::iterator::operator-`` should be ``noexcept``","Varna June 2023","|Complete|","19.0","|ranges|"
+"`3914 <https://wg21.link/LWG3914>`__","Inconsistent template-head of ``ranges::enumerate_view``","Varna June 2023","|Complete|","19.0","|ranges|"
"`3915 <https://wg21.link/LWG3915>`__","Redundant paragraph about expression variations","Varna June 2023","","","|ranges|"
"`3925 <https://wg21.link/LWG3925>`__","Concept ``formattable``'s definition is incorrect","Varna June 2023","|Complete|","17.0","|format|"
"`3927 <https://wg21.link/LWG3927>`__","Unclear preconditions for ``operator[]`` for sequence containers","Varna June 2023","|Nothing To Do|","",""
>From 44cb342d2c2eb200e51262c313be5fbde8b1a3a7 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Wed, 21 Feb 2024 10:40:00 +0200
Subject: [PATCH 15/33] Fixed CI
---
libcxx/include/libcxx.imp | 1 +
.../range.enumerate/iterator/arithmetic.pass.cpp | 4 +---
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp
index 22fbea99b848b..c588c05da66c1 100644
--- a/libcxx/include/libcxx.imp
+++ b/libcxx/include/libcxx.imp
@@ -629,6 +629,7 @@
{ include: [ "<__ranges/empty_view.h>", "private", "<ranges>", "public" ] },
{ include: [ "<__ranges/enable_borrowed_range.h>", "private", "<ranges>", "public" ] },
{ include: [ "<__ranges/enable_view.h>", "private", "<ranges>", "public" ] },
+ { include: [ "<__ranges/enumerate_view.h>", "private", "<ranges>", "public" ] },
{ include: [ "<__ranges/filter_view.h>", "private", "<ranges>", "public" ] },
{ include: [ "<__ranges/from_range.h>", "private", "<ranges>", "public" ] },
{ include: [ "<__ranges/iota_view.h>", "private", "<ranges>", "public" ] },
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp
index ae1b62269c7c1..8ab21cd1f55b9 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp
@@ -153,9 +153,7 @@ constexpr void test_with_noncommon_range() {
}
// operator-(x, y)
- {
- assert((ev.end() - ev.begin()) == 4);
- }
+ { assert((ev.end() - ev.begin()) == 4); }
}
constexpr bool test() {
>From b4813f054197c0ad8c1c1946fac9ecd4caab3d51 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Wed, 21 Feb 2024 12:14:36 +0200
Subject: [PATCH 16/33] Fixed formatting
---
libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
index cf49355c7348b..3889a8d377065 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
@@ -18,7 +18,7 @@
// Types
-template<typename T, typename DifferenceT = std::ptrdiff_t>
+template <typename T, typename DifferenceT = std::ptrdiff_t>
using ValueType = std::tuple<DifferenceT, T>;
struct RangeView : std::ranges::view_base {
>From 2c663347dbc4f0dd916e535f4f9aedbffd268c8a Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 21 Feb 2024 12:30:33 +0200
Subject: [PATCH 17/33] Refactoring
---
libcxx/docs/ReleaseNotes/19.rst | 1 +
.../range.adaptors/range.enumerate/base.pass.cpp | 1 +
.../range.adaptors/range.enumerate/begin.pass.cpp | 1 +
.../range.enumerate/ctad.compile.pass.cpp | 1 +
.../range.adaptors/range.enumerate/end.pass.cpp | 1 +
.../range.enumerate/iterator/base.pass.cpp | 3 +--
.../iterator/compare.three_way.pass.cpp | 1 +
.../iterator/ctor.convert.pass.cpp | 4 ++--
.../iterator/ctor.default.pass.cpp | 1 +
.../range.enumerate/iterator/deref.pass.cpp | 1 +
.../range.enumerate/iterator/equal.pass.cpp | 1 +
.../range.enumerate/iterator/index.pass.cpp | 1 +
.../range.enumerate/iterator/iter_move.pass.cpp | 1 +
.../iterator/types.compile.pass.cpp | 3 ++-
.../range.enumerate/sentinel/base.pass.cpp | 1 +
.../sentinel/ctor.convert.pass.cpp | 1 +
.../sentinel/ctor.default.pass.cpp | 1 +
.../range.enumerate/sentinel/equal.pass.cpp | 1 +
.../range.enumerate/sentinel/minus.pass.cpp | 14 ++++++++------
.../range.adaptors/range.enumerate/size.pass.cpp | 6 ++++--
.../range.enumerate/test_concepts.h | 15 +++++++++++++++
.../ranges/range.adaptors/range.enumerate/types.h | 5 -----
22 files changed, 47 insertions(+), 18 deletions(-)
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/test_concepts.h
diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index a7f108c44e717..a80b96ab6af14 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -38,6 +38,7 @@ What's New in Libc++ 19.0.0?
Implemented Papers
------------------
+- P2164R9 - ``views::enumerate``
- P2637R3 - Member ``visit``
- P2652R2 - Disallow User Specialization of ``allocator_traits``
- P2819R2 - Add ``tuple`` protocol to ``complex``
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp
index 86d8a9e88cb99..7d2b37ad64438 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp
@@ -19,6 +19,7 @@
#include <ranges>
#include "MoveOnly.h"
+
#include "types.h"
template <class T>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
index 5a10f008062c9..6ef1099a2963f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
@@ -20,6 +20,7 @@
#include <ranges>
#include "test_iterators.h"
+
#include "types.h"
// Types
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp
index fb6b26c1fd9a5..1cdf2252c9a61 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp
@@ -19,6 +19,7 @@
#include <ranges>
#include "test_iterators.h"
+
#include "types.h"
constexpr bool test() {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp
index 744e33d4e33b7..7a4d04364bece 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp
@@ -20,6 +20,7 @@
#include <ranges>
#include "test_iterators.h"
+
#include "types.h"
constexpr bool test() {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
index b29d504a81515..009ed4a7924a7 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp
@@ -17,11 +17,10 @@
// constexpr const iterator_t<Base>& base() const & noexcept;
// constexpr iterator_t<Base> base() &&;
-#include <ranges>
-
#include <array>
#include <cassert>
#include <concepts>
+#include <ranges>
#include <utility>
#include <tuple>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp
index 7cc00decebcab..0ddd9bf579284 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp
@@ -20,6 +20,7 @@
#include <ranges>
#include "test_iterators.h"
+
#include "../types.h"
constexpr void compareOperatorTest(const auto& iter1, const auto& iter2) {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.convert.pass.cpp
index 668686884a910..03aac95da01e2 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.convert.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.convert.pass.cpp
@@ -17,14 +17,14 @@
// constexpr iterator(iterator<!Const> i)
// requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>;
-#include <ranges>
-
#include <array>
#include <cassert>
#include <concepts>
+#include <ranges>
#include <utility>
#include "test_iterators.h"
+
#include "../types.h"
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp
index 1108025de0103..14f37f178473f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp
@@ -20,6 +20,7 @@
#include <ranges>
#include "test_iterators.h"
+
#include "../types.h"
template <class Iterator, bool IsNoexcept = true>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp
index d8e75e1634617..3aaf2809fcf4b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp
@@ -25,6 +25,7 @@
#include "test_iterators.h"
#include "test_macros.h"
+
#include "../types.h"
template <class Iterator, class ValueType = int, class Sentinel = sentinel_wrapper<Iterator>>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
index 92f3d7ca352f4..5cee6b6e002b2 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp
@@ -20,6 +20,7 @@
#include <ranges>
#include "test_iterators.h"
+
#include "../types.h"
constexpr bool test() {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp
index 0256115f4a6a9..ad5dafd619ce8 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp
@@ -25,6 +25,7 @@
#include "test_iterators.h"
#include "test_macros.h"
+
#include "../types.h"
template <class Iterator, class ValueType = int, class Sentinel = sentinel_wrapper<Iterator>>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp
index c023d58bd859b..65c7ea6690de5 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp
@@ -25,6 +25,7 @@
#include <utility>
#include "test_iterators.h"
+
#include "../types.h"
template <class Iterator, bool HasNoexceptIterMove>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
index d46c68da8e444..e29d16c7f9d96 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp
@@ -20,9 +20,10 @@
// std::enumerate_view::<iterator>::iterator_concept;
#include <ranges>
-
#include <type_traits>
+
#include "test_iterators.h"
+
#include "../types.h"
template <typename T>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.pass.cpp
index 28a93decfddb8..95af02423a49c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.pass.cpp
@@ -24,6 +24,7 @@
#include <utility>
#include "test_iterators.h"
+
#include "../types.h"
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
index 3cdf52db41650..ec34c1f4b6b1b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
@@ -25,6 +25,7 @@
#include <utility>
#include "test_iterators.h"
+
#include "../types.h"
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp
index 9206441d5ccf3..f65b255770aac 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp
@@ -20,6 +20,7 @@
#include <ranges>
#include "test_iterators.h"
+
#include "../types.h"
struct PODSentinel {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
index 2a502564b4a45..317082801d4f5 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
@@ -26,6 +26,7 @@
#include <utility>
#include "test_iterators.h"
+
#include "../types.h"
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
index f7551d0894dca..a099967214145 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
@@ -29,8 +29,10 @@
#include <ranges>
#include "test_iterators.h"
-#include "../types.h"
+
+#include "../test_concepts.h"
// #include "../types_iterators.h"
+#include "../types.h"
template <bool Const>
struct Iter {
@@ -146,7 +148,7 @@ constexpr void testConstraints() {
{
using Base = BufferView<Iter, Sent>;
- static_assert(!HasSize<Base>);
+ static_assert(!HasMemberSize<Base>);
static_assert(!std::ranges::sized_range<Base>);
static_assert(!HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
@@ -166,7 +168,7 @@ constexpr void testConstraints() {
{
using Base = SizedBufferView<Iter, Sent>;
- static_assert(HasSize<Base>);
+ static_assert(HasMemberSize<Base>);
static_assert(std::ranges::sized_range<Base>);
static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
@@ -186,7 +188,7 @@ constexpr void testConstraints() {
{
using Base = BufferView<Iter, CrossSizedSent>;
- static_assert(!HasSize<Base>);
+ static_assert(!HasMemberSize<Base>);
static_assert(!std::ranges::sized_range<Base>);
static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
@@ -210,7 +212,7 @@ constexpr bool test() {
{
using Base = SizedBufferView<Iter, SizedSent>;
- static_assert(HasSize<Base>);
+ static_assert(HasMemberSize<Base>);
static_assert(std::ranges::sized_range<Base>);
Base base{buffer};
@@ -231,7 +233,7 @@ constexpr bool test() {
{
using Base = BufferView<Iter, CrossSizedSent>;
- static_assert(!HasSize<Base>);
+ static_assert(!HasMemberSize<Base>);
static_assert(!std::ranges::sized_range<Base>);
Base base{buffer};
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/size.pass.cpp
index 9be911c34959a..33709bb170952 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/size.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/size.pass.cpp
@@ -19,6 +19,8 @@
#include <ranges>
#include "test_iterators.h"
+
+#include "test_concepts.h"
#include "types.h"
struct NonSizedRangeView : std::ranges::view_base {
@@ -30,8 +32,8 @@ struct NonSizedRangeView : std::ranges::view_base {
static_assert(!std::ranges::sized_range<NonSizedRangeView>);
static_assert(!std::ranges::sized_range<const NonSizedRangeView>);
-static_assert(!HasSize<std::ranges::enumerate_view<NonSizedRangeView>>);
-static_assert(!HasSize<const std::ranges::enumerate_view<NonSizedRangeView>>);
+static_assert(!HasMemberSize<std::ranges::enumerate_view<NonSizedRangeView>>);
+static_assert(!HasMemberSize<const std::ranges::enumerate_view<NonSizedRangeView>>);
constexpr bool test() {
int buffer[] = {1, 2, 3};
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/test_concepts.h b/libcxx/test/std/ranges/range.adaptors/range.enumerate/test_concepts.h
new file mode 100644
index 0000000000000..4211706989c6b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/test_concepts.h
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_CONCEPTS_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_CONCEPTS_H
+
+template <class T>
+concept HasMemberSize = requires(T t) { t.size(); };
+
+#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_CONCEPTS_H
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
index 3889a8d377065..7a048cbad8f30 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/types.h
@@ -132,9 +132,4 @@ class MaybeNoexceptIterMoveInputIterator {
}
};
-// Concepts
-
-template <class T>
-concept HasSize = requires(T t) { t.size(); };
-
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ENUMERATE_TYPES_H
>From 9c2019b54746e719d2b2adb4de96270c587bf8ee Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 1 May 2024 12:05:21 +0300
Subject: [PATCH 18/33] Generated files
---
libcxx/docs/FeatureTestMacroTable.rst | 2 ++
.../ranges.version.compile.pass.cpp | 31 +++++++++++++++++++
.../version.version.compile.pass.cpp | 1 +
3 files changed, 34 insertions(+)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 3197d2cd1b271..cf7f79e764562 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -358,6 +358,8 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_ranges_contains`` ``202207L``
---------------------------------------------------------- -----------------
+ ``__cpp_lib_ranges_enumerate`` ``202302L``
+ ---------------------------------------------------------- -----------------
``__cpp_lib_ranges_iota`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_ranges_join_with`` *unimplemented*
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
index 30feacd796d8e..0fb76088f4690 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
@@ -23,6 +23,7 @@
__cpp_lib_ranges_chunk 202202L [C++23]
__cpp_lib_ranges_chunk_by 202202L [C++23]
__cpp_lib_ranges_concat 202403L [C++26]
+ __cpp_lib_ranges_enumerate 202302L [C++23]
__cpp_lib_ranges_join_with 202202L [C++23]
__cpp_lib_ranges_repeat 202207L [C++23]
__cpp_lib_ranges_slide 202202L [C++23]
@@ -63,6 +64,10 @@
# error "__cpp_lib_ranges_concat should not be defined before c++26"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
@@ -113,6 +118,10 @@
# error "__cpp_lib_ranges_concat should not be defined before c++26"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
@@ -163,6 +172,10 @@
# error "__cpp_lib_ranges_concat should not be defined before c++26"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
@@ -216,6 +229,10 @@
# error "__cpp_lib_ranges_concat should not be defined before c++26"
# endif
+# ifdef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
@@ -293,6 +310,13 @@
# error "__cpp_lib_ranges_concat should not be defined before c++26"
# endif
+# ifndef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should be defined in c++23"
+# endif
+# if __cpp_lib_ranges_enumerate != 202302L
+# error "__cpp_lib_ranges_enumerate should have the value 202302L in c++23"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should be defined in c++23"
@@ -421,6 +445,13 @@
# endif
# endif
+# ifndef __cpp_lib_ranges_enumerate
+# error "__cpp_lib_ranges_enumerate should be defined in c++26"
+# endif
+# if __cpp_lib_ranges_enumerate != 202302L
+# error "__cpp_lib_ranges_enumerate should have the value 202302L in c++26"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_join_with
# error "__cpp_lib_ranges_join_with should be defined in c++26"
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 3662d3f042914..a17696630d2c5 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -164,6 +164,7 @@
__cpp_lib_ranges_chunk_by 202202L [C++23]
__cpp_lib_ranges_concat 202403L [C++26]
__cpp_lib_ranges_contains 202207L [C++23]
+ __cpp_lib_ranges_enumerate 202302L [C++23]
__cpp_lib_ranges_iota 202202L [C++23]
__cpp_lib_ranges_join_with 202202L [C++23]
__cpp_lib_ranges_repeat 202207L [C++23]
>From c176417e8d4ca0d82007e9d601fe9b46ea7a1de8 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 1 May 2024 12:21:47 +0300
Subject: [PATCH 19/33] Mark members `[[nodiscard]] `
---
libcxx/include/__ranges/enumerate_view.h | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index 5a0aad6271d48..104bba3f4455f 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -160,12 +160,12 @@ class enumerate_view<_View>::__iterator {
requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
: __current_(std::move(__i.__current_)), __pos_(__i.__pos_) {}
- _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_Base>& base() const& noexcept { return __current_; }
- _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() && { return std::move(__current_); }
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr const iterator_t<_Base>& base() const& noexcept { return __current_; }
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr iterator_t<_Base> base() && { return std::move(__current_); }
- _LIBCPP_HIDE_FROM_ABI constexpr difference_type index() const noexcept { return __pos_; }
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr difference_type index() const noexcept { return __pos_; }
- _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { return __reference_type(__pos_, *__current_); }
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr auto operator*() const { return __reference_type(__pos_, *__current_); }
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
++__current_;
@@ -188,7 +188,7 @@ class enumerate_view<_View>::__iterator {
--__pos_;
return *this;
}
- _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator operator--(int)
requires bidirectional_range<_Base>
{
auto __temp = *this;
@@ -211,7 +211,7 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr auto operator[](difference_type __n) const
requires random_access_range<_Base>
{
return __reference_type(__pos_ + __n, __current_[__n]);
@@ -249,7 +249,7 @@ class enumerate_view<_View>::__iterator {
return __x.__pos_ - __y.__pos_;
}
- _LIBCPP_HIDE_FROM_ABI friend constexpr auto iter_move(const __iterator& __i) noexcept(
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr auto iter_move(const __iterator& __i) noexcept(
noexcept(ranges::iter_move(__i.__current_)) && is_nothrow_move_constructible_v<range_rvalue_reference_t<_Base>>) {
return tuple<difference_type, range_rvalue_reference_t<_Base>>(__i.__pos_, ranges::iter_move(__i.__current_));
}
@@ -273,7 +273,7 @@ class enumerate_view<_View>::__sentinel {
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(std::move(__other.__end_)) {}
- _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Base> base() const { return __end_; }
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr sentinel_t<_Base> base() const { return __end_; }
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
@@ -283,14 +283,14 @@ class enumerate_view<_View>::__sentinel {
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
return __x.__current_ - __y.__end_;
}
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) {
return __x.__end_ - __y.__current_;
}
>From 645b5ceabe1c7bbfd95c82b62cb1fe25194ad016 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 1 May 2024 12:27:12 +0300
Subject: [PATCH 20/33] Mark more members as `[[nodiscard]] `
---
libcxx/include/__ranges/enumerate_view.h | 32 +++++++++++++++++-------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index 104bba3f4455f..db7443b846340 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -156,11 +156,13 @@ class enumerate_view<_View>::__iterator {
_LIBCPP_HIDE_FROM_ABI __iterator()
requires default_initializable<iterator_t<_Base>>
= default;
+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
: __current_(std::move(__i.__current_)), __pos_(__i.__pos_) {}
_LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr const iterator_t<_Base>& base() const& noexcept { return __current_; }
+
_LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr iterator_t<_Base> base() && { return std::move(__current_); }
_LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr difference_type index() const noexcept { return __pos_; }
@@ -172,7 +174,9 @@ class enumerate_view<_View>::__iterator {
++__pos_;
return *this;
}
+
_LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { return ++*this; }
+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
requires forward_range<_Base>
{
@@ -188,6 +192,7 @@ class enumerate_view<_View>::__iterator {
--__pos_;
return *this;
}
+
_LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator operator--(int)
requires bidirectional_range<_Base>
{
@@ -203,6 +208,7 @@ class enumerate_view<_View>::__iterator {
__pos_ += __n;
return *this;
}
+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
requires random_access_range<_Base>
{
@@ -211,45 +217,50 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr auto operator[](difference_type __n) const
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr auto operator[](difference_type __n) const
requires random_access_range<_Base>
{
return __reference_type(__pos_ + __n, __current_[__n]);
}
- _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) noexcept {
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr bool
+ operator==(const __iterator& __x, const __iterator& __y) noexcept {
return __x.__pos_ == __y.__pos_;
}
- _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering
+
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr strong_ordering
operator<=>(const __iterator& __x, const __iterator& __y) noexcept {
return __x.__pos_ <=> __y.__pos_;
}
- _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
requires random_access_range<_Base>
{
auto __temp = __i;
__temp += __n;
return __temp;
}
- _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
+
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
requires random_access_range<_Base>
{
return __i + __n;
}
- _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
+
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
requires random_access_range<_Base>
{
auto __temp = __i;
__temp -= __n;
return __temp;
}
- _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr difference_type
operator-(const __iterator& __x, const __iterator& __y) noexcept {
return __x.__pos_ - __y.__pos_;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr auto iter_move(const __iterator& __i) noexcept(
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr auto iter_move(const __iterator& __i) noexcept(
noexcept(ranges::iter_move(__i.__current_)) && is_nothrow_move_constructible_v<range_rvalue_reference_t<_Base>>) {
return tuple<difference_type, range_rvalue_reference_t<_Base>>(__i.__pos_, ranges::iter_move(__i.__current_));
}
@@ -263,12 +274,14 @@ template <bool _Const>
class enumerate_view<_View>::__sentinel {
using _Base = __maybe_const<_Const, _View>;
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
+
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {}
friend class enumerate_view<_View>;
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
+
_LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __other)
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(std::move(__other.__end_)) {}
@@ -277,7 +290,8 @@ class enumerate_view<_View>::__sentinel {
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr bool
+ operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
return __x.__current_ == __y.__end_;
}
>From 16f2c8cf85374d5a380ccc9e066ed42e425c3098 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 1 May 2024 12:33:36 +0300
Subject: [PATCH 21/33] More `[[nodiscard]] `
---
libcxx/include/__ranges/enumerate_view.h | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index db7443b846340..427463991b4bd 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -169,15 +169,15 @@ class enumerate_view<_View>::__iterator {
_LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr auto operator*() const { return __reference_type(__pos_, *__current_); }
- _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator& operator++() {
++__current_;
++__pos_;
return *this;
}
- _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { return ++*this; }
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr void operator++(int) { return ++*this; }
- _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator operator++(int)
requires forward_range<_Base>
{
auto __temp = *this;
@@ -185,7 +185,7 @@ class enumerate_view<_View>::__iterator {
return __temp;
}
- _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator& operator--()
requires bidirectional_range<_Base>
{
--__current_;
@@ -201,7 +201,7 @@ class enumerate_view<_View>::__iterator {
return *__temp;
}
- _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n)
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator& operator+=(difference_type __n)
requires random_access_range<_Base>
{
__current_ += __n;
@@ -209,7 +209,7 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
+ _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator& operator-=(difference_type __n)
requires random_access_range<_Base>
{
__current_ -= __n;
>From d9bdafc91a4709003a6054e63b177e9731c4da69 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 19 Jul 2024 18:56:49 +0300
Subject: [PATCH 22/33] Updated Release Notes
---
libcxx/docs/ReleaseNotes/19.rst | 1 -
libcxx/docs/ReleaseNotes/20.rst | 2 +-
libcxx/docs/Status/Cxx23Papers.csv | 2 +-
libcxx/docs/Status/Cxx2cIssues.csv | 4 ++--
4 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index 998af0856893d..ac7d61b6ba856 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -39,7 +39,6 @@ Implemented Papers
------------------
- P1132R8 - ``out_ptr`` - a scalable output pointer abstraction
-- P2164R9 - ``views::enumerate``
- P2637R3 - Member ``visit``
- P2652R2 - Disallow User Specialization of ``allocator_traits``
- P2819R2 - Add ``tuple`` protocol to ``complex``
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index fb677b1667ddc..85ebf66e9e236 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -38,7 +38,7 @@ What's New in Libc++ 20.0.0?
Implemented Papers
------------------
-- TODO
+- P2164R9 - ``views::enumerate``
Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 7d2fa9f5743c8..d34b0b9dc9219 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -105,7 +105,7 @@
"","","","","","",""
"`P0290R4 <https://wg21.link/P0290R4>`__","LWG", "``apply()`` for ``synchronized_value<T>``","February 2023","","","|concurrency TS|"
"`P2770R0 <https://wg21.link/P2770R0>`__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|Partial| [#note-P2770R0]_","","|ranges|"
-"`P2164R9 <https://wg21.link/P2164R9>`__","LWG", "``views::enumerate``","February 2023","|Complete|","19.0","|ranges|"
+"`P2164R9 <https://wg21.link/P2164R9>`__","LWG", "``views::enumerate``","February 2023","|Complete|","20.0","|ranges|"
"`P2711R1 <https://wg21.link/P2711R1>`__","LWG", "Making multi-param constructors of ``views`` ``explicit``","February 2023","|In Progress| [#note-P2711R1]_","","|ranges|"
"`P2609R3 <https://wg21.link/P2609R3>`__","LWG", "Relaxing Ranges Just A Smidge","February 2023","","","|ranges|"
"`P2713R1 <https://wg21.link/P2713R1>`__","LWG", "Escaping improvements in ``std::format``","February 2023","|Complete|","19.0","|format|"
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 9de8db86850c4..13e8e82b49ebb 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -8,8 +8,8 @@
"`3903 <https://wg21.link/LWG3903>`__","span destructor is redundantly noexcept","Varna June 2023","|Complete|","7.0",""
"`3904 <https://wg21.link/LWG3904>`__","``lazy_split_view::outer-iterator``'s const-converting constructor isn't setting ``trailing_empty_``","Varna June 2023","","","|ranges|"
"`3905 <https://wg21.link/LWG3905>`__","Type of ``std::fexcept_t``","Varna June 2023","|Complete|","3.4",""
-"`3912 <https://wg21.link/LWG3912>`__","``enumerate_view::iterator::operator-`` should be ``noexcept``","Varna June 2023","|Complete|","19.0","|ranges|"
-"`3914 <https://wg21.link/LWG3914>`__","Inconsistent template-head of ``ranges::enumerate_view``","Varna June 2023","|Complete|","19.0","|ranges|"
+"`3912 <https://wg21.link/LWG3912>`__","``enumerate_view::iterator::operator-`` should be ``noexcept``","Varna June 2023","|Complete|","20.0","|ranges|"
+"`3914 <https://wg21.link/LWG3914>`__","Inconsistent template-head of ``ranges::enumerate_view``","Varna June 2023","|Complete|","20.0","|ranges|"
"`3915 <https://wg21.link/LWG3915>`__","Redundant paragraph about expression variations","Varna June 2023","","","|ranges|"
"`3925 <https://wg21.link/LWG3925>`__","Concept ``formattable``'s definition is incorrect","Varna June 2023","|Complete|","17.0","|format|"
"`3927 <https://wg21.link/LWG3927>`__","Unclear preconditions for ``operator[]`` for sequence containers","Varna June 2023","|Nothing To Do|","",""
>From 1ccf78492da87b49da558f5743219fe0d2361023 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Jul 2024 19:37:42 +0300
Subject: [PATCH 23/33] Fixed [[nodiscard]]
---
libcxx/include/__ranges/enumerate_view.h | 48 +++++++++----------
.../diagnostics/ranges.nodiscard.verify.cpp | 12 +++--
2 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index 427463991b4bd..39579984a4d78 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -161,23 +161,23 @@ class enumerate_view<_View>::__iterator {
requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
: __current_(std::move(__i.__current_)), __pos_(__i.__pos_) {}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr const iterator_t<_Base>& base() const& noexcept { return __current_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr const iterator_t<_Base>& base() const& noexcept { return __current_; }
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr iterator_t<_Base> base() && { return std::move(__current_); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr iterator_t<_Base> base() && { return std::move(__current_); }
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr difference_type index() const noexcept { return __pos_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr difference_type index() const noexcept { return __pos_; }
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr auto operator*() const { return __reference_type(__pos_, *__current_); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr auto operator*() const { return __reference_type(__pos_, *__current_); }
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator& operator++() {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator& operator++() {
++__current_;
++__pos_;
return *this;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr void operator++(int) { return ++*this; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr void operator++(int) { return ++*this; }
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator operator++(int)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator operator++(int)
requires forward_range<_Base>
{
auto __temp = *this;
@@ -185,7 +185,7 @@ class enumerate_view<_View>::__iterator {
return __temp;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator& operator--()
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator& operator--()
requires bidirectional_range<_Base>
{
--__current_;
@@ -193,7 +193,7 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator operator--(int)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator operator--(int)
requires bidirectional_range<_Base>
{
auto __temp = *this;
@@ -201,7 +201,7 @@ class enumerate_view<_View>::__iterator {
return *__temp;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator& operator+=(difference_type __n)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator& operator+=(difference_type __n)
requires random_access_range<_Base>
{
__current_ += __n;
@@ -209,7 +209,7 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr __iterator& operator-=(difference_type __n)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator& operator-=(difference_type __n)
requires random_access_range<_Base>
{
__current_ -= __n;
@@ -217,23 +217,23 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr auto operator[](difference_type __n) const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr auto operator[](difference_type __n) const
requires random_access_range<_Base>
{
return __reference_type(__pos_ + __n, __current_[__n]);
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr bool
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr bool
operator==(const __iterator& __x, const __iterator& __y) noexcept {
return __x.__pos_ == __y.__pos_;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr strong_ordering
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr strong_ordering
operator<=>(const __iterator& __x, const __iterator& __y) noexcept {
return __x.__pos_ <=> __y.__pos_;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
requires random_access_range<_Base>
{
auto __temp = __i;
@@ -241,13 +241,13 @@ class enumerate_view<_View>::__iterator {
return __temp;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
requires random_access_range<_Base>
{
return __i + __n;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
requires random_access_range<_Base>
{
auto __temp = __i;
@@ -255,12 +255,12 @@ class enumerate_view<_View>::__iterator {
return __temp;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr difference_type
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr difference_type
operator-(const __iterator& __x, const __iterator& __y) noexcept {
return __x.__pos_ - __y.__pos_;
}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr auto iter_move(const __iterator& __i) noexcept(
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr auto iter_move(const __iterator& __i) noexcept(
noexcept(ranges::iter_move(__i.__current_)) && is_nothrow_move_constructible_v<range_rvalue_reference_t<_Base>>) {
return tuple<difference_type, range_rvalue_reference_t<_Base>>(__i.__pos_, ranges::iter_move(__i.__current_));
}
@@ -286,25 +286,25 @@ class enumerate_view<_View>::__sentinel {
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(std::move(__other.__end_)) {}
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] constexpr sentinel_t<_Base> base() const { return __end_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr sentinel_t<_Base> base() const { return __end_; }
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr bool
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr bool
operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
return __x.__current_ == __y.__end_;
}
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
return __x.__current_ - __y.__end_;
}
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- _LIBCPP_HIDE_FROM_ABI [[nodiscard]] friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) {
return __x.__end_ - __y.__current_;
}
@@ -318,7 +318,7 @@ namespace __enumerate {
struct __fn : __range_adaptor_closure<__fn> {
template <class _Range>
- _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
noexcept(noexcept(/**/ enumerate_view(std::forward<_Range>(__range))))
-> decltype(/*--*/ enumerate_view(std::forward<_Range>(__range))) {
return /*-------------*/ enumerate_view(std::forward<_Range>(__range));
diff --git a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
index 60f3974b2b57d..ebf3674fd9ad8 100644
--- a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
@@ -30,11 +30,6 @@ void test() {
std::views::take(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
#if TEST_STD_VER >= 23
- std::views::drop(std::views::repeat(1)); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-
- std::views::repeat(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::views::repeat(1, std::unreachable_sentinel); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-
auto rvalue_view = std::views::as_rvalue(range);
std::views::as_rvalue(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::views::as_rvalue(rvalue_view); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
@@ -42,6 +37,13 @@ void test() {
std::views::chunk_by(pred); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::views::chunk_by(range, pred); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::drop(std::views::repeat(1)); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ std::views::enumerate(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ std::views::repeat(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::repeat(1, std::unreachable_sentinel); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
std::views::take(std::views::repeat(3), 3); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::views::take(std::views::repeat(3, std::unreachable_sentinel), 3); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
>From 2757c728dcec4e1218a49126e12ab47ef5b90f6f Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Jul 2024 19:54:03 +0300
Subject: [PATCH 24/33] Try again
---
libcxx/include/__ranges/enumerate_view.h | 28 ++++++++++++------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index 39579984a4d78..8ed1e3f9200ed 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -64,7 +64,7 @@ class enumerate_view : public view_interface<enumerate_view<_View>> {
_LIBCPP_HIDE_FROM_ABI constexpr enumerate_view()
requires default_initializable<_View>
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr explicit enumerate_view(_View __base) : __base_(std::move(__base)){};
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit enumerate_view(_View __base) : __base_(std::move(__base)) {}
_LIBCPP_HIDE_FROM_ABI constexpr auto begin()
requires(!__simple_view<_View>)
@@ -161,23 +161,23 @@ class enumerate_view<_View>::__iterator {
requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
: __current_(std::move(__i.__current_)), __pos_(__i.__pos_) {}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr const iterator_t<_Base>& base() const& noexcept { return __current_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_Base>& base() const& noexcept { return __current_; }
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr iterator_t<_Base> base() && { return std::move(__current_); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() && { return std::move(__current_); }
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr difference_type index() const noexcept { return __pos_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr difference_type index() const noexcept { return __pos_; }
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr auto operator*() const { return __reference_type(__pos_, *__current_); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { return __reference_type(__pos_, *__current_); }
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator& operator++() {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
++__current_;
++__pos_;
return *this;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr void operator++(int) { return ++*this; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { return ++*this; }
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator operator++(int)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
requires forward_range<_Base>
{
auto __temp = *this;
@@ -185,7 +185,7 @@ class enumerate_view<_View>::__iterator {
return __temp;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator& operator--()
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
requires bidirectional_range<_Base>
{
--__current_;
@@ -193,7 +193,7 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator operator--(int)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
requires bidirectional_range<_Base>
{
auto __temp = *this;
@@ -201,7 +201,7 @@ class enumerate_view<_View>::__iterator {
return *__temp;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator& operator+=(difference_type __n)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n)
requires random_access_range<_Base>
{
__current_ += __n;
@@ -209,7 +209,7 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr __iterator& operator-=(difference_type __n)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
requires random_access_range<_Base>
{
__current_ -= __n;
@@ -217,7 +217,7 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr auto operator[](difference_type __n) const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const
requires random_access_range<_Base>
{
return __reference_type(__pos_ + __n, __current_[__n]);
@@ -286,7 +286,7 @@ class enumerate_view<_View>::__sentinel {
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(std::move(__other.__end_)) {}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIconstexpr sentinel_t<_Base> base() const { return __end_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Base> base() const { return __end_; }
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
>From 4d9aa3fc630b712b5a58c862aa8f6f6f9bf51dd2 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Jul 2024 20:11:57 +0300
Subject: [PATCH 25/33] Try again
---
libcxx/include/__ranges/enumerate_view.h | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index 8ed1e3f9200ed..c869e0ae39c3e 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -175,7 +175,7 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { return ++*this; }
+ _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { return ++*this; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
requires forward_range<_Base>
@@ -223,17 +223,17 @@ class enumerate_view<_View>::__iterator {
return __reference_type(__pos_ + __n, __current_[__n]);
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr bool
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool
operator==(const __iterator& __x, const __iterator& __y) noexcept {
return __x.__pos_ == __y.__pos_;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr strong_ordering
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering
operator<=>(const __iterator& __x, const __iterator& __y) noexcept {
return __x.__pos_ <=> __y.__pos_;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
requires random_access_range<_Base>
{
auto __temp = __i;
@@ -241,13 +241,13 @@ class enumerate_view<_View>::__iterator {
return __temp;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
requires random_access_range<_Base>
{
return __i + __n;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
requires random_access_range<_Base>
{
auto __temp = __i;
@@ -255,12 +255,12 @@ class enumerate_view<_View>::__iterator {
return __temp;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr difference_type
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
operator-(const __iterator& __x, const __iterator& __y) noexcept {
return __x.__pos_ - __y.__pos_;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr auto iter_move(const __iterator& __i) noexcept(
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto iter_move(const __iterator& __i) noexcept(
noexcept(ranges::iter_move(__i.__current_)) && is_nothrow_move_constructible_v<range_rvalue_reference_t<_Base>>) {
return tuple<difference_type, range_rvalue_reference_t<_Base>>(__i.__pos_, ranges::iter_move(__i.__current_));
}
@@ -290,21 +290,21 @@ class enumerate_view<_View>::__sentinel {
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr bool
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool
operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
return __x.__current_ == __y.__end_;
}
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
return __x.__current_ - __y.__end_;
}
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABIfriend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) {
return __x.__end_ - __y.__current_;
}
>From 44fc9502e6519c406f1788fa73393206dd2e038c Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Jul 2024 23:17:45 +0300
Subject: [PATCH 26/33] Removed excessive `[[nodiscard]]`, which is not
practical on increment/decrement operators
---
libcxx/include/__ranges/enumerate_view.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index c869e0ae39c3e..37c227fcbf9c9 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -169,7 +169,7 @@ class enumerate_view<_View>::__iterator {
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { return __reference_type(__pos_, *__current_); }
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
++__current_;
++__pos_;
return *this;
@@ -177,7 +177,7 @@ class enumerate_view<_View>::__iterator {
_LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { return ++*this; }
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
requires forward_range<_Base>
{
auto __temp = *this;
@@ -185,7 +185,7 @@ class enumerate_view<_View>::__iterator {
return __temp;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
requires bidirectional_range<_Base>
{
--__current_;
@@ -193,7 +193,7 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
requires bidirectional_range<_Base>
{
auto __temp = *this;
>From 805331bc457cd47b6f258a391a5ab3222ef53228 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 22 Jul 2024 15:04:17 +0300
Subject: [PATCH 27/33] Cleanup
---
libcxx/include/__ranges/enumerate_view.h | 4 ++--
.../range.enumerate/begin.pass.cpp | 2 +-
.../range.enumerate/sentinel/minus.pass.cpp | 16 ++++++++--------
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index 37c227fcbf9c9..ad42802fb3568 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -201,7 +201,7 @@ class enumerate_view<_View>::__iterator {
return *__temp;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n)
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n)
requires random_access_range<_Base>
{
__current_ += __n;
@@ -209,7 +209,7 @@ class enumerate_view<_View>::__iterator {
return *this;
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
requires random_access_range<_Base>
{
__current_ -= __n;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
index 6ef1099a2963f..2be46487f8acf 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp
@@ -87,7 +87,7 @@ constexpr bool test() {
std::ranges::enumerate_view view(range);
using Iterator = std::ranges::iterator_t<decltype(view)>;
static_assert(std::same_as<Iterator, decltype(view.begin())>);
- static_assert(std::same_as<ValueType<int>, decltype(*view.begin())>);
+ // static_assert(std::same_as<ValueType<int>, decltype(*view.begin())>);
}
// begin() over an empty range
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
index a099967214145..1aab13f299983 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp
@@ -114,10 +114,10 @@ template <template <bool> class It, template <bool> class St>
struct SizedBufferView : BufferView<It, St> {
using BufferView<It, St>::BufferView;
- using BufferView<It, St>::iterator;
- using BufferView<It, St>::sentinel;
- using BufferView<It, St>::const_iterator;
- using BufferView<It, St>::const_sentinel;
+ using typename BufferView<It, St>::iterator;
+ using typename BufferView<It, St>::sentinel;
+ using typename BufferView<It, St>::const_iterator;
+ using typename BufferView<It, St>::const_sentinel;
using BufferView<It, St>::begin;
using BufferView<It, St>::end;
@@ -171,17 +171,17 @@ constexpr void testConstraints() {
static_assert(HasMemberSize<Base>);
static_assert(std::ranges::sized_range<Base>);
- static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
+ // static_assert(HasMinus<EnumerateIter<Base>, EnumerateSentinel<Base>>);
static_assert(!HasMinus<EnumerateIter<Base>, EnumerateConstSentinel<Base>>);
static_assert(!HasMinus<EnumerateConstIter<Base>, EnumerateSentinel<Base>>);
- static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
+ // static_assert(HasMinus<EnumerateConstIter<Base>, EnumerateConstSentinel<Base>>);
- static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
+ // static_assert(HasMinus<EnumerateSentinel<Base>, EnumerateIter<Base>>);
static_assert(!HasMinus<EnumerateSentinel<Base>, EnumerateConstIter<Base>>);
static_assert(!HasMinus<EnumerateConstSentinel<Base>, EnumerateIter<Base>>);
- static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
+ // static_assert(HasMinus<EnumerateConstSentinel<Base>, EnumerateConstIter<Base>>);
}
// Base is cross const sized
>From 856d129dcd501ec5f8751d7e6c71dbafce74777d Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 22 Jul 2024 15:50:57 +0300
Subject: [PATCH 28/33] Try to fix CI
---
libcxx/include/__ranges/enumerate_view.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index ad42802fb3568..c0925b1bd8695 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -32,6 +32,9 @@
# pragma GCC system_header
#endif
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 23
@@ -339,4 +342,6 @@ inline constexpr auto enumerate = __enumerate::__fn{};
_LIBCPP_END_NAMESPACE_STD
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___RANGES_ENUMERATE_VIEW_H
>From 561687956f237e9fa3843e7f7833a736a784f875 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 23 Jul 2024 19:22:27 +0300
Subject: [PATCH 29/33] WIP - nodiscard tests
---
libcxx/include/__ranges/enumerate_view.h | 16 ++++++++--------
.../diagnostics/ranges.nodiscard.verify.cpp | 11 ++++++++++-
2 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index c0925b1bd8695..50294dff2aa33 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -69,18 +69,18 @@ class enumerate_view : public view_interface<enumerate_view<_View>> {
= default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit enumerate_view(_View __base) : __base_(std::move(__base)) {}
- _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
requires(!__simple_view<_View>)
{
return __iterator<false>(ranges::begin(__base_), 0);
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
requires __range_with_movable_references<const _View>
{
return __iterator<true>(ranges::begin(__base_), 0);
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end()
requires(!__simple_view<_View>)
{
if constexpr (common_range<_View> && sized_range<_View>)
@@ -88,7 +88,7 @@ class enumerate_view : public view_interface<enumerate_view<_View>> {
else
return __sentinel<false>(ranges::end(__base_));
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
requires __range_with_movable_references<const _View>
{
if constexpr (common_range<const _View> && sized_range<const _View>)
@@ -97,23 +97,23 @@ class enumerate_view : public view_interface<enumerate_view<_View>> {
return __sentinel<true>(ranges::end(__base_));
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
requires sized_range<_View>
{
return ranges::size(__base_);
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
requires sized_range<const _View>
{
return ranges::size(__base_);
}
- _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
requires copy_constructible<_View>
{
return __base_;
}
- _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
};
template <class _Range>
diff --git a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
index ebf3674fd9ad8..b1c73c01e0201 100644
--- a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
@@ -13,6 +13,7 @@
// clang-format off
#include <ranges>
+#include <utility>
#include <vector>
#include "test_macros.h"
@@ -40,8 +41,16 @@ void test() {
std::views::drop(std::views::repeat(1)); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::views::enumerate(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ auto enumerate_view = std::views::enumerate(range);
+ enumerate_view.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(enumerate_view).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(enumerate_view).end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(enumerate_view).size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(enumerate_view).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::views::repeat(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::views::repeat(1, std::unreachable_sentinel); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::views::take(std::views::repeat(3), 3); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
>From ab93ac36d7685132700da033212a98a42da789a7 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 23 Jul 2024 21:13:46 +0300
Subject: [PATCH 30/33] WIP - nodiscard tests
---
.../diagnostics/ranges.nodiscard.verify.cpp | 23 +++++++++++++------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
index b1c73c01e0201..11f0ddf761dc1 100644
--- a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
@@ -42,14 +42,23 @@ void test() {
std::views::enumerate(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
auto enumerate_view = std::views::enumerate(range);
- enumerate_view.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(enumerate_view).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(enumerate_view).end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(enumerate_view).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(enumerate_view).end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::as_const(enumerate_view).size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::move(enumerate_view).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(enumerate_view).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ auto enumerate_view_it = enumerate_view.begin();
+ enumerate_view_it.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(enumerate_view_it).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(enumerate_view_it).index(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ *std::as_const(enumerate_view_it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view_it + 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view_it - 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view_it - enumerate_view_it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view_it.iter_move(enumerate_view_it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::views::repeat(1, std::unreachable_sentinel); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
>From 62621dd0fc63d80ea7d39c50ba71bdc6be0fbb1d Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 24 Jul 2024 14:16:25 +0300
Subject: [PATCH 31/33] WIP - nodiscard tests
---
.../diagnostics/ranges.nodiscard.verify.cpp | 23 +++++++++++--------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
index 11f0ddf761dc1..36e048ea4c914 100644
--- a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
@@ -40,25 +40,28 @@ void test() {
std::views::drop(std::views::repeat(1)); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::views::enumerate(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::enumerate(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
auto enumerate_view = std::views::enumerate(range);
- enumerate_view.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(enumerate_view).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(enumerate_view).end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(enumerate_view).size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::move(enumerate_view).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(enumerate_view).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(enumerate_view).end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(enumerate_view).size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(enumerate_view).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
auto enumerate_view_it = enumerate_view.begin();
enumerate_view_it.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::move(enumerate_view_it).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::as_const(enumerate_view_it).index(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
*std::as_const(enumerate_view_it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view_it[2]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view_it == enumerate_view_it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ enumerate_view_it <=> enumerate_view_it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
enumerate_view_it + 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
enumerate_view_it - 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
enumerate_view_it - enumerate_view_it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view_it.iter_move(enumerate_view_it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ iter_move(enumerate_view_it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::views::repeat(1, std::unreachable_sentinel); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
>From 8b98539beeaa6ac45196340163a60d2803963991 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 24 Jul 2024 14:19:57 +0300
Subject: [PATCH 32/33] WIP - nodiscard tests
---
.../diagnostics/ranges.nodiscard.verify.cpp | 46 ++++++++++---------
1 file changed, 24 insertions(+), 22 deletions(-)
diff --git a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
index 36e048ea4c914..f6d476eadcc0d 100644
--- a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
@@ -40,28 +40,30 @@ void test() {
std::views::drop(std::views::repeat(1)); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::views::enumerate(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- auto enumerate_view = std::views::enumerate(range);
- enumerate_view.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(enumerate_view).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(enumerate_view).end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(enumerate_view).size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::move(enumerate_view).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- auto enumerate_view_it = enumerate_view.begin();
- enumerate_view_it.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::move(enumerate_view_it).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(enumerate_view_it).index(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- *std::as_const(enumerate_view_it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view_it[2]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view_it == enumerate_view_it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view_it <=> enumerate_view_it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view_it + 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view_it - 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- enumerate_view_it - enumerate_view_it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- iter_move(enumerate_view_it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::enumerate(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ {
+ auto ev = std::views::enumerate(range);
+ ev.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(ev).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ev.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(ev).end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ev.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(ev).size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ev.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(ev).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ auto it = enumerate_view.begin();
+ it.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(it).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(it).index(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ *std::as_const(it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ it[2]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ it == it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ it <=> it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ it + 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ it - 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ it - it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ iter_move(it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ }
std::views::repeat(1, std::unreachable_sentinel); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
>From 6f83477b00cc6d8e665105336de7c9be1880a00a Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 25 Jul 2024 09:51:31 +0300
Subject: [PATCH 33/33] WIP - nodiscard tests
---
.../diagnostics/ranges.nodiscard.verify.cpp | 70 +++++++++++++------
libcxx/test/support/test_range.h | 10 +++
2 files changed, 58 insertions(+), 22 deletions(-)
diff --git a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
index f6d476eadcc0d..5dd2ce0dea176 100644
--- a/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/ranges.nodiscard.verify.cpp
@@ -13,10 +13,13 @@
// clang-format off
#include <ranges>
+#include <tuple>
#include <utility>
#include <vector>
+#include "test_iterators.h"
#include "test_macros.h"
+#include "test_range.h"
void test() {
std::vector<int> range;
@@ -40,29 +43,52 @@ void test() {
std::views::drop(std::views::repeat(1)); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::views::enumerate(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ // std::ranges::enumerate
{
- auto ev = std::views::enumerate(range);
- ev.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(ev).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- ev.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(ev).end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- ev.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(ev).size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- ev.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::move(ev).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- auto it = enumerate_view.begin();
- it.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::move(it).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::as_const(it).index(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- *std::as_const(it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- it[2]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- it == it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- it <=> it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- it + 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- it - 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- it - it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- iter_move(it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ // test_range<cpp17_input_iterator<std::tuple<int, int*>>> r;
+ test_sized_range<cpp17_input_iterator> r;
+ std::views::enumerate(r); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ // class enumerate_view<>
+ auto ev = std::views::enumerate(r);
+ ev.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(ev).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ev.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(ev).end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ev.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(ev).size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ev.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(ev).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ // class enumerate_view<>::__iterator
+ auto it = ev.begin();
+ auto const_it = std::as_const(ev).begin();
+ it.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(it).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(it).index(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ *std::as_const(it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ // it[2]; // _expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ it == it; // expected-warning {{equality comparison result unused}}
+ it <=> it; // expected-warning {{three-way comparison result unused}}
+ // it + 1; // _expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ // it - 1; // _expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ // it - it; // _expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ iter_move(it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ // class enumerate_view<>::__sentinel
+ auto st = ev.end();
+ auto const_st = std::as_const(ev).end();
+ st.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ it == st; // expected-warning {{equality comparison result unused}}
+ it == const_st; // expected-warning {{equality comparison result unused}}
+ const_it == st; // expected-warning {{equality comparison result unused}}
+ const_it == const_st; // expected-warning {{equality comparison result unused}}
+ st == it; // expected-warning {{expression result unused}}
+ st == const_it; // expected-warning {{expression result unused}}
+ const_st == it; // expected-warning {{expression result unused}}
+ const_st == const_it; // expected-warning {{expression result unused}}
+ // it - st;
+ // st - it;
}
std::views::repeat(1, std::unreachable_sentinel); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
diff --git a/libcxx/test/support/test_range.h b/libcxx/test/support/test_range.h
index 4efa26f266475..945938dbbed5c 100644
--- a/libcxx/test/support/test_range.h
+++ b/libcxx/test/support/test_range.h
@@ -34,6 +34,16 @@ struct test_range {
sentinel end() const;
};
+template <template <class...> class I, class T = int>
+ requires std::input_or_output_iterator<I<T*> >
+struct test_sized_range {
+ I<T*> begin();
+ I<T const*> begin() const;
+ sentinel end();
+ sentinel end() const;
+ std::size_t size();
+};
+
template <template <class...> class I, class T = int>
requires std::input_or_output_iterator<I<T*> >
struct test_non_const_range {
More information about the libcxx-commits
mailing list