diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index a1506e115fe70..19e4e97e9a34f 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -350,7 +350,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_print`` ``202207L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_ranges_as_const`` *unimplemented* + ``__cpp_lib_ranges_as_const`` ``202311L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_ranges_as_rvalue`` ``202207L`` ---------------------------------------------------------- ----------------- diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv index c4c6a855cc517..78b5722915c98 100644 --- a/libcxx/docs/Status/Cxx23Issues.csv +++ b/libcxx/docs/Status/Cxx23Issues.csv @@ -220,7 +220,7 @@ "`LWG3762 `__","``generator::iterator::operator==`` should pass by reference","November 2022","","","" "`LWG3764 `__","``reference_wrapper::operator()`` should propagate noexcept","November 2022","|Complete|","17.0","" "`LWG3765 `__","``const_sentinel`` should be constrained","November 2022","","","|ranges|" -"`LWG3766 `__","``view_interface::cbegin`` is underconstrained","November 2022","","","|ranges|" +"`LWG3766 `__","``view_interface::cbegin`` is underconstrained","November 2022","|Complete|","20.0","|ranges|" "`LWG3770 `__","``const_sentinel_t`` is missing","November 2022","","","|ranges|" "`LWG3773 `__","``views::zip_transform`` still requires ``F`` to be ``copy_constructible`` when empty pack","November 2022","","","|ranges|" "`LWG3774 `__","```` should include ````","November 2022","","","|flat_containers|" @@ -252,7 +252,7 @@ "`LWG3664 `__","`LWG 3392 `__ ``broke std::ranges::distance(a, a+3)``","February 2023","","","|ranges|" "`LWG3720 `__","Restrict the valid types of ``arg-id`` for width and precision in ``std-format-spec``","February 2023","|Complete|","17.0","|format|" "`LWG3756 `__","Is the ``std::atomic_flag`` class signal-safe?","February 2023","","","" -"`LWG3769 `__","``basic_const_iterator::operator==`` causes infinite constraint recursion","February 2023","","","|spaceship|" +"`LWG3769 `__","``basic_const_iterator::operator==`` causes infinite constraint recursion","February 2023","|Complete|","20.0","|spaceship|" "`LWG3807 `__","The feature test macro for ``ranges::find_last`` should be renamed","February 2023","","","|ranges|" "`LWG3811 `__","``views::as_const`` on ``ref_view`` should return ``ref_view``","February 2023","","","|ranges|" "`LWG3820 `__","``cartesian_product_view::iterator::prev`` is not quite right","February 2023","","","|ranges|" @@ -271,7 +271,7 @@ "`LWG3849 `__","``cartesian_product_view::iterator``'s default constructor is overconstrained","February 2023","","","|ranges|" "`LWG3850 `__","``views::as_const`` on ``empty_view`` should return ``empty_view``","February 2023","","","|ranges|" "`LWG3851 `__","``chunk_view::inner-iterator`` missing custom ``iter_move`` and ``iter_swap``","February 2023","","","|ranges|" -"`LWG3853 `__","``basic_const_iterator::operator->`` is ill-formed","February 2023","","","" +"`LWG3853 `__","``basic_const_iterator::operator->`` is ill-formed","February 2023","|Complete|","20.0","" "`LWG3857 `__","``basic_string_view`` should allow explicit conversion when only traits vary","February 2023","|Complete|","17.0","" "`LWG3860 `__","``range_common_reference_t`` is missing","February 2023","|Complete|","17.0","|ranges|" "`LWG3866 `__","Bad Mandates for ``expected::transform_error`` overloads","February 2023","|Complete|","17.0","" @@ -293,12 +293,12 @@ "`LWG3836 `__","``std::expected`` conversion constructor ``expected(const expected&)`` should take precedence over ``expected(U&&)`` with operator ``bool``","February 2023","|Complete|","18.0","" "`LWG3843 `__","``std::expected::value() &`` assumes ``E`` is copy constructible","February 2023","|Complete|","17.0","" "`LWG3847 `__","``ranges::to`` can still return views","February 2023","|Complete|","17.0","|ranges|" -"`LWG3862 `__","``basic_const_iterator``'s ``common_type`` specialization is underconstrained","February 2023","","","" +"`LWG3862 `__","``basic_const_iterator``'s ``common_type`` specialization is underconstrained","February 2023","|Complete|","20.0","" "`LWG3865 `__","Sorting a range of ``pairs``","February 2023","|Complete|","17.0","|ranges|" "`LWG3869 `__","Deprecate ``std::errc`` constants related to UNIX STREAMS","February 2023","|Complete|","19.0","" "`LWG3870 `__","Remove ``voidify``","February 2023","","","" "`LWG3871 `__","Adjust note about ``terminate``","February 2023","","","" -"`LWG3872 `__","``basic_const_iterator`` should have custom ``iter_move``","February 2023","","","" +"`LWG3872 `__","``basic_const_iterator`` should have custom ``iter_move``","February 2023","|Complete|","20.0","" "`LWG3875 `__","``std::ranges::repeat_view::iterator`` may be ill-formed","February 2023","|Complete|","17.0","|ranges|" "`LWG3876 `__","Default constructor of ``std::layout_XX::mapping`` misses precondition","February 2023","","","" "`LWG3877 `__","Incorrect constraints on ``const``-qualified monadic overloads for ``std::expected``","February 2023","|Complete|","17.0","" diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index da498629ca5dd..e058f2bb51ec3 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -61,7 +61,7 @@ "`P1899R3 `__","``stride_view``","July 2022","","","|ranges|" "`P2093R14 `__","Formatted output","July 2022","|Complete|","18.0","|format|" "`P2165R4 `__","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","July 2022","","","" -"`P2278R4 `__","``cbegin`` should always return a constant iterator","July 2022","","","|ranges|" +"`P2278R4 `__","``cbegin`` should always return a constant iterator","July 2022","|Complete|","20.0","|ranges|" "`P2286R8 `__","Formatting Ranges","July 2022","|Complete|","16.0","|format| |ranges|" "`P2291R3 `__","Add Constexpr Modifiers to Functions ``to_chars`` and ``from_chars`` for Integral Types in ```` Header","July 2022","|Complete|","16.0","" "`P2302R4 `__","``std::ranges::contains``","July 2022","|Complete|","19.0","|ranges|" diff --git a/libcxx/docs/Status/Cxx2c.rst b/libcxx/docs/Status/Cxx2c.rst index 1b8d96588c3cb..2b786e5c8de4a 100644 --- a/libcxx/docs/Status/Cxx2c.rst +++ b/libcxx/docs/Status/Cxx2c.rst @@ -44,6 +44,7 @@ Paper Status .. [#note-P2944R3] Implemented comparisons for ``reference_wrapper`` only. .. [#note-P2422R1] Libc++ keeps the ``nodiscard`` attributes as a conforming extension. .. [#note-P2997R1] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.) + .. [#note-P2836R1] This paper is applies as DR against C++23 (MSVC STL and libstdc++ have done the same); .. _issues-status-cxx2c: diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv index a92a1fef77980..ab0f2e3a644d9 100644 --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -25,7 +25,7 @@ "`LWG3809 `__","Is ``std::subtract_with_carry_engine`` supposed to work","Kona November 2023","","","" "`LWG3892 `__","Incorrect formatting of nested ranges and tuples","Kona November 2023","|Complete|","17.0","|format|" "`LWG3897 `__","``inout_ptr`` will not update raw pointer to 0","Kona November 2023","|Complete|","19.0","" -"`LWG3946 `__","The definition of ``const_iterator_t`` should be reworked","Kona November 2023","","","" +"`LWG3946 `__","The definition of ``const_iterator_t`` should be reworked","Kona November 2023","|Complete|","20.0","" "`LWG3947 `__","Unexpected constraints on ``adjacent_transform_view::base()``","Kona November 2023","","","|ranges|" "`LWG3948 `__","``possibly-const-range and as-const-pointer`` should be ``noexcept``","Kona November 2023","","","|ranges|" "`LWG3949 `__","``std::atomic``'s trivial destructor dropped in C++17 spec wording","Kona November 2023","","","" diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index f12305d6ac452..87874f60b2d6d 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -42,7 +42,7 @@ "`P2819R2 `__","Add tuple protocol to complex","Kona November 2023","|Complete|","19.0","" "`P2937R0 `__","Freestanding: Remove ``strtok``","Kona November 2023","","","" "`P2833R2 `__","Freestanding Library: inout expected span","Kona November 2023","","","" -"`P2836R1 `__","``std::basic_const_iterator`` should follow its underlying type's convertibility","Kona November 2023","","","|DR|" +"`P2836R1 `__","``std::basic_const_iterator`` should follow its underlying type's convertibility","Kona November 2023","|Complete| [#note-P2836R1]","20.0","|DR|" "`P2264R7 `__","Make ``assert()`` macro user friendly for C and C++","Kona November 2023","","","" "`P1673R13 `__","A free function linear algebra interface based on the BLAS","Kona November 2023","","","" "","","","","","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 32579272858a8..99d8b22281a77 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -444,6 +444,7 @@ set(files __iterator/bounded_iter.h __iterator/common_iterator.h __iterator/concepts.h + __iterator/const_iterator.h __iterator/counted_iterator.h __iterator/cpp17_iterator_concepts.h __iterator/data.h @@ -635,14 +636,15 @@ set(files __random/weibull_distribution.h __ranges/access.h __ranges/all.h + __ranges/as_const_view.h __ranges/as_rvalue_view.h __ranges/chunk_by_view.h __ranges/common_view.h __ranges/concepts.h + __ranges/const_access.h __ranges/container_compatible_range.h __ranges/counted.h __ranges/dangling.h - __ranges/data.h __ranges/drop_view.h __ranges/drop_while_view.h __ranges/elements_view.h diff --git a/libcxx/include/__algorithm/ranges_reverse_copy.h b/libcxx/include/__algorithm/ranges_reverse_copy.h index e5ca5cf652dc4..7efb6df3a8b57 100644 --- a/libcxx/include/__algorithm/ranges_reverse_copy.h +++ b/libcxx/include/__algorithm/ranges_reverse_copy.h @@ -34,6 +34,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace ranges { +template +_LIBCPP_HIDE_FROM_ABI constexpr ranges::subrange>, + reverse_iterator>> +__reverse_range(_Range&& __range) { + auto __first = ranges::begin(__range); + return {std::make_reverse_iterator(ranges::next(__first, ranges::end(__range))), std::make_reverse_iterator(__first)}; +} + template using reverse_copy_result = in_out_result<_InIter, _OutIter>; @@ -49,7 +57,7 @@ struct __reverse_copy { requires indirectly_copyable, _OutIter> _LIBCPP_HIDE_FROM_ABI constexpr reverse_copy_result, _OutIter> operator()(_Range&& __range, _OutIter __result) const { - auto __ret = ranges::copy(std::__reverse_range(__range), std::move(__result)); + auto __ret = ranges::copy(std::ranges::__reverse_range(__range), std::move(__result)); return {ranges::next(ranges::begin(__range), ranges::end(__range)), std::move(__ret.out)}; } }; diff --git a/libcxx/include/__format/range_default_formatter.h b/libcxx/include/__format/range_default_formatter.h index b35223ae93329..4d6f5f02c08ca 100644 --- a/libcxx/include/__format/range_default_formatter.h +++ b/libcxx/include/__format/range_default_formatter.h @@ -22,8 +22,8 @@ #include <__format/formatter.h> #include <__format/range_formatter.h> #include <__iterator/back_insert_iterator.h> +#include <__ranges/access.h> #include <__ranges/concepts.h> -#include <__ranges/data.h> #include <__ranges/from_range.h> #include <__ranges/size.h> #include <__type_traits/conditional.h> diff --git a/libcxx/include/__format/range_formatter.h b/libcxx/include/__format/range_formatter.h index 6915630743493..f3cfc8e1872df 100644 --- a/libcxx/include/__format/range_formatter.h +++ b/libcxx/include/__format/range_formatter.h @@ -26,8 +26,8 @@ #include <__format/formatter_output.h> #include <__format/parser_std_format_spec.h> #include <__iterator/back_insert_iterator.h> +#include <__ranges/access.h> #include <__ranges/concepts.h> -#include <__ranges/data.h> #include <__ranges/from_range.h> #include <__ranges/size.h> #include <__type_traits/remove_cvref.h> diff --git a/libcxx/include/__iterator/const_iterator.h b/libcxx/include/__iterator/const_iterator.h new file mode 100644 index 0000000000000..495cba78f12b5 --- /dev/null +++ b/libcxx/include/__iterator/const_iterator.h @@ -0,0 +1,351 @@ +// -*- 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___ITERATOR_CONST_ITERATOR_H +#define _LIBCPP___ITERATOR_CONST_ITERATOR_H + +#include <__compare/three_way_comparable.h> +#include <__concepts/common_with.h> +#include <__concepts/convertible_to.h> +#include <__concepts/different_from.h> +#include <__concepts/same_as.h> +#include <__concepts/semiregular.h> +#include <__concepts/totally_ordered.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include <__memory/pointer_traits.h> +#include <__type_traits/common_reference.h> +#include <__type_traits/common_type.h> +#include <__type_traits/conditional.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_specialization.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +using iter_const_reference_t = common_reference_t&&, iter_reference_t<_Iter>>; + +template +concept __constant_iterator = input_iterator<_Iter> && same_as, iter_reference_t<_Iter>>; + +template +class basic_const_iterator; + +template +using const_iterator = conditional_t<__constant_iterator<_Iter>, _Iter, basic_const_iterator<_Iter>>; + +// This doesn't use `conditional_t` to avoid instantiating const_iterator<_Sent> when _Sent is not an input_iterator. +template +struct __const_sentinel_impl { + using type = _Sent; +}; +template + requires input_iterator<_Sent> +struct __const_sentinel_impl<_Sent> { + using type = const_iterator<_Sent>; +}; +template +using const_sentinel = __const_sentinel_impl<_Sent>::type; + +template +concept __not_a_const_iterator = !__is_specialization_v<_Iter, basic_const_iterator>; + +template +using __iter_const_rvalue_reference_t = common_reference_t&&, iter_rvalue_reference_t<_Iter>>; + +template +struct __basic_const_iterator_concept { + // clang-format off + using iterator_concept = + conditional_t, + contiguous_iterator_tag, + conditional_t, + random_access_iterator_tag, + conditional_t, + bidirectional_iterator_tag, + conditional_t, + forward_iterator_tag, + // else + input_iterator_tag>>>>; + // clang-format on +}; + +template +struct __basic_const_iterator_category : __basic_const_iterator_concept<_Iter> {}; +template +struct __basic_const_iterator_category<_Iter> : __basic_const_iterator_concept<_Iter> { + using iterator_category = std::iterator_traits<_Iter>::iterator_category; +}; + +template +class _LIBCPP_TEMPLATE_VIS basic_const_iterator : public __basic_const_iterator_category<_Iter> { + _Iter __current = _Iter(); + + using __reference = iter_const_reference_t<_Iter>; + using __rvalue_reference = __iter_const_rvalue_reference_t<_Iter>; + +public: + using value_type = iter_value_t<_Iter>; + using difference_type = iter_difference_t<_Iter>; + + _LIBCPP_HIDE_FROM_ABI basic_const_iterator() + requires default_initializable<_Iter> + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator(_Iter __cur) : __current(std::move(__cur)) {} + template _Type> + _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator(basic_const_iterator<_Type> __cur) + : __current(std::move(__cur.__current)) {} + template <__different_from _Type> + requires convertible_to<_Type, _Iter> + _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator(_Type&& __cur) : __current(std::forward<_Type>(__cur)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr const _Iter& base() const& noexcept { return __current; } + _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() && { return std::move(__current); } + + constexpr __reference operator*() const { return static_cast<__reference>(*__current); } + _LIBCPP_HIDE_FROM_ABI constexpr const auto* operator->() const + requires is_lvalue_reference_v> && + same_as>, value_type> + { + if constexpr (contiguous_iterator<_Iter>) { + return std::to_address(__current); + } else { + return std::addressof(*__current); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator& operator++() { + ++__current; + return *this; + } + constexpr void operator++(int) { ++__current; } + _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator operator++(int) + requires forward_iterator<_Iter> + { + auto __tmp = *this; + ++__current; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator& operator--() + requires bidirectional_iterator<_Iter> + { + --__current; + return *this; + } + _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator operator--(int) + requires bidirectional_iterator<_Iter> + { + auto __tmp = *this; + --__current; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator& operator+=(difference_type __n) + requires random_access_iterator<_Iter> + { + __current += __n; + return *this; + } + _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator& operator-=(difference_type __n) + requires random_access_iterator<_Iter> + { + __current -= __n; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __reference operator[](difference_type __n) const + requires random_access_iterator<_Iter> + { + return static_cast<__reference>(__current[__n]); + } + + template _Sent> + _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Sent& __sent) const { + return __current == __sent; + } + + template <__not_a_const_iterator _ConstIt> + requires __constant_iterator<_ConstIt> && convertible_to<_Iter const&, _ConstIt> + _LIBCPP_HIDE_FROM_ABI constexpr operator _ConstIt() const& { + return __current; + } + template <__not_a_const_iterator _ConstIt> + requires __constant_iterator<_ConstIt> && convertible_to<_Iter, _ConstIt> + _LIBCPP_HIDE_FROM_ABI constexpr operator _ConstIt() && { + return std::move(__current); + } + + _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const basic_const_iterator& __rhs) const + requires random_access_iterator<_Iter> + { + return __current < __rhs.__current; + } + _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const basic_const_iterator& __rhs) const + requires random_access_iterator<_Iter> + { + return __current > __rhs.__current; + } + _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const basic_const_iterator& __rhs) const + requires random_access_iterator<_Iter> + { + return __current <= __rhs.__current; + } + _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const basic_const_iterator& __rhs) const + requires random_access_iterator<_Iter> + { + return __current >= __rhs.__current; + } + _LIBCPP_HIDE_FROM_ABI constexpr auto operator<=>(const basic_const_iterator& __rhs) const + requires random_access_iterator<_Iter> && three_way_comparable<_Iter> + { + return __current <=> __rhs.__current; + } + + template <__different_from _Iter2> + _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Iter2& __rhs) const + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> + { + return __current < __rhs; + } + template <__different_from _Iter2> + _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Iter2& __rhs) const + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> + { + return __current > __rhs; + } + template <__different_from _Iter2> + _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Iter2& __rhs) const + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> + { + return __current <= __rhs; + } + template <__different_from _Iter2> + _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Iter2& __rhs) const + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> + { + return __current >= __rhs; + } + template <__different_from _Iter2> + _LIBCPP_HIDE_FROM_ABI constexpr auto operator<=>(const _Iter2& __rhs) const + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> && + three_way_comparable_with<_Iter, _Iter2> + { + return __current <=> __rhs; + } + + template <__not_a_const_iterator _Iter2> + friend _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Iter2& __lhs, const basic_const_iterator& __rhs) + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> + { + return __lhs < __rhs.__current; + } + template <__not_a_const_iterator _Iter2> + friend _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Iter2& __lhs, const basic_const_iterator& __rhs) + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> + { + return __lhs > __rhs.__current; + } + template <__not_a_const_iterator _Iter2> + friend _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Iter2& __lhs, const basic_const_iterator& __rhs) + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> + { + return __lhs <= __rhs.__current; + } + template <__not_a_const_iterator _Iter2> + friend _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Iter2& __lhs, const basic_const_iterator& __rhs) + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> + { + return __lhs >= __rhs.__current; + } + + friend _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator + operator+(const basic_const_iterator& __it, difference_type __n) + requires random_access_iterator<_Iter> + { + return basic_const_iterator(__it.__current + __n); + } + friend _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator + operator+(difference_type __n, const basic_const_iterator& __it) + requires random_access_iterator<_Iter> + { + return basic_const_iterator(__it.__current + __n); + } + + friend _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator + operator-(const basic_const_iterator& __it, difference_type __n) + requires random_access_iterator<_Iter> + { + return basic_const_iterator(__it.__current - __n); + } + template _Sent> + _LIBCPP_HIDE_FROM_ABI constexpr difference_type operator-(const _Sent& __rhs) const { + return __current - __rhs; + } + template <__not_a_const_iterator _Sent> + requires sized_sentinel_for<_Sent, _Iter> + friend _LIBCPP_HIDE_FROM_ABI constexpr difference_type + operator-(const _Sent& __lhs, const basic_const_iterator& __rhs) { + return __lhs - __rhs; + } + + friend _LIBCPP_HIDE_FROM_ABI constexpr __rvalue_reference iter_move(const basic_const_iterator& __it) noexcept( + noexcept(static_cast<__rvalue_reference>(ranges::iter_move(__it.__current)))) { + return static_cast<__rvalue_reference>(ranges::iter_move(__it.__current)); + } +}; + +template _Type2> + requires input_iterator> +struct common_type, _Type2> { + using type = basic_const_iterator>; +}; +template _Type2> + requires input_iterator> +struct common_type<_Type2, basic_const_iterator<_Type1>> { + using type = basic_const_iterator>; +}; +template _Type2> + requires input_iterator> +struct common_type, basic_const_iterator<_Type2>> { + using type = basic_const_iterator>; +}; + +template +_LIBCPP_HIDE_FROM_ABI constexpr const_iterator<_Iter> make_const_iterator(_Iter __it) { + return __it; +} +template +_LIBCPP_HIDE_FROM_ABI constexpr const_sentinel<_Sent> make_const_sentinel(_Sent __sent) { + return __sent; +} + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_CONST_ITERATOR_H diff --git a/libcxx/include/__iterator/reverse_iterator.h b/libcxx/include/__iterator/reverse_iterator.h index 50c0f21eaa286..823203cadf7e1 100644 --- a/libcxx/include/__iterator/reverse_iterator.h +++ b/libcxx/include/__iterator/reverse_iterator.h @@ -27,9 +27,6 @@ #include <__iterator/readable_traits.h> #include <__iterator/segmented_iterator.h> #include <__memory/addressof.h> -#include <__ranges/access.h> -#include <__ranges/concepts.h> -#include <__ranges/subrange.h> #include <__type_traits/conditional.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_assignable.h> @@ -315,16 +312,6 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator<_Ite } #endif -#if _LIBCPP_STD_VER >= 20 -template -_LIBCPP_HIDE_FROM_ABI constexpr ranges::subrange>, - reverse_iterator>> -__reverse_range(_Range&& __range) { - auto __first = ranges::begin(__range); - return {std::make_reverse_iterator(ranges::next(__first, ranges::end(__range))), std::make_reverse_iterator(__first)}; -} -#endif - template struct __unwrap_iter_impl >, __b> { using _UnwrappedIter = decltype(__unwrap_iter_impl<_Iter>::__unwrap(std::declval<_Iter>())); diff --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h index c0a40c5e10178..251898128f078 100644 --- a/libcxx/include/__ranges/access.h +++ b/libcxx/include/__ranges/access.h @@ -14,10 +14,13 @@ #include <__config> #include <__iterator/concepts.h> #include <__iterator/readable_traits.h> +#include <__memory/pointer_traits.h> #include <__ranges/enable_borrowed_range.h> #include <__type_traits/decay.h> +#include <__type_traits/is_pointer.h> #include <__type_traits/is_reference.h> #include <__type_traits/remove_cvref.h> +#include <__type_traits/remove_pointer.h> #include <__type_traits/remove_reference.h> #include <__utility/auto_cast.h> #include <__utility/declval.h> @@ -148,58 +151,39 @@ inline constexpr auto end = __end::__fn{}; } // namespace __cpo } // namespace ranges -// [range.access.cbegin] +// [range.prim.data] namespace ranges { -namespace __cbegin { -struct __fn { - template - requires is_lvalue_reference_v<_Tp&&> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::begin(static_cast&>(__t)))) - -> decltype(ranges::begin(static_cast&>(__t))) { - return ranges::begin(static_cast&>(__t)); - } +namespace __data { +template +concept __ptr_to_object = is_pointer_v<_Tp> && is_object_v>; - template - requires is_rvalue_reference_v<_Tp&&> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::begin(static_cast(__t)))) - -> decltype(ranges::begin(static_cast(__t))) { - return ranges::begin(static_cast(__t)); - } +template +concept __member_data = __can_borrow<_Tp> && requires(_Tp&& __t) { + { _LIBCPP_AUTO_CAST(__t.data()) } -> __ptr_to_object; }; -} // namespace __cbegin -inline namespace __cpo { -inline constexpr auto cbegin = __cbegin::__fn{}; -} // namespace __cpo -} // namespace ranges - -// [range.access.cend] +template +concept __ranges_begin_invocable = !__member_data<_Tp> && __can_borrow<_Tp> && requires(_Tp&& __t) { + { ranges::begin(__t) } -> contiguous_iterator; +}; -namespace ranges { -namespace __cend { struct __fn { - template - requires is_lvalue_reference_v<_Tp&&> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::end(static_cast&>(__t)))) - -> decltype(ranges::end(static_cast&>(__t))) { - return ranges::end(static_cast&>(__t)); + template <__member_data _Tp> + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept(noexcept(__t.data())) { + return __t.data(); } - template - requires is_rvalue_reference_v<_Tp&&> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept( - noexcept(ranges::end(static_cast(__t)))) -> decltype(ranges::end(static_cast(__t))) { - return ranges::end(static_cast(__t)); + template <__ranges_begin_invocable _Tp> + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(std::to_address(ranges::begin(__t)))) { + return std::to_address(ranges::begin(__t)); } }; -} // namespace __cend +} // namespace __data inline namespace __cpo { -inline constexpr auto cend = __cend::__fn{}; +inline constexpr auto data = __data::__fn{}; } // namespace __cpo } // namespace ranges diff --git a/libcxx/include/__ranges/as_const_view.h b/libcxx/include/__ranges/as_const_view.h new file mode 100644 index 0000000000000..d2613ad939fd0 --- /dev/null +++ b/libcxx/include/__ranges/as_const_view.h @@ -0,0 +1,205 @@ +// -*- 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_AS_CONST_VIEW_H +#define _LIBCPP___RANGES_AS_CONST_VIEW_H + +#include <__concepts/constructible.h> +#include <__iterator/concepts.h> +#include <__ranges/all.h> +#include <__ranges/concepts.h> +#include <__ranges/const_access.h> +#include <__ranges/empty_view.h> +#include <__ranges/range_adaptor.h> +#include <__ranges/ref_view.h> +#include <__ranges/size.h> +#include <__ranges/view_interface.h> +#include <__type_traits/is_specialization.h> +#include <__utility/auto_cast.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace ranges { +template + requires view<_View> +class as_const_view : public view_interface> { + _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); + +public: + _LIBCPP_HIDE_FROM_ABI as_const_view() + requires default_initializable<_View> + = default; + _LIBCPP_HIDE_FROM_ABI constexpr explicit as_const_view(_View __base) : __base_(std::move(__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_); } + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() + requires(!__simple_view<_View>) + { + return ranges::cbegin(__base_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + requires range + { + return ranges::cbegin(__base_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() + requires(!__simple_view<_View>) + { + return ranges::cend(__base_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + requires range + { + return ranges::cend(__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 + { + return ranges::size(__base_); + } +}; + +template +as_const_view(_Range&&) -> as_const_view>; + +template +inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Tp>; + +namespace views { +namespace __as_const { + +template +inline constexpr bool __is_span_v = false; // true if and only if _Tp is a specialization of span +template +inline constexpr bool __is_span_v> = true; + +template +struct __xtype { + using type = void; +}; +template +struct __xtype> { + using type = _XType; +}; +template +struct __xtype> { + using type = _XType; + constexpr static size_t __extent = _Extent; +}; +template +struct __xtype> { + using type = _XType; +}; + +struct __fn : __range_adaptor_closure<__fn> { + // implementation strategy taken from Microsoft's STL + enum class __strategy { + __already_const, + __empty_view, + __span, + __ref_view, + __const_is_constant_range, + __otherwise, + __none, + }; + + template + static consteval pair<__strategy, bool> __choose_strategy() { + using _UType = std::remove_cvref_t<_Type>; + using _XType = __xtype<_UType>::type; + + if constexpr (!requires { typename all_t<_Type>; }) { + return {__strategy::__none, false}; + } else if constexpr (constant_range>) { + return {__strategy::__already_const, noexcept(views::all(std::declval<_Type>()))}; + } else if constexpr (__is_specialization_v<_UType, empty_view>) { + return {__strategy::__empty_view, true}; + } else if constexpr (__is_span_v<_UType>) { + return {__strategy::__span, true}; + } else if constexpr (__is_specialization_v<_UType, ref_view> && constant_range) { + return {__strategy::__ref_view, noexcept(ref_view(static_cast(std::declval<_Type>().base())))}; + } else if constexpr (is_lvalue_reference_v<_Type> && constant_range && !view<_UType>) { + return {__strategy::__const_is_constant_range, + noexcept(ref_view(static_cast(std::declval<_Type>())))}; + } else { + return {__strategy::__otherwise, noexcept(as_const_view(std::declval<_Type>()))}; + } + } + + template + requires(__choose_strategy<_Type>().first != __strategy::__none) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto + operator()(_Type&& __range) noexcept(__choose_strategy<_Type>().second) { + using _UType = std::remove_cvref_t<_Type>; + using _XType = __xtype<_UType>::type; + + constexpr auto __st = __choose_strategy<_Type>().first; + + if constexpr (__st == __strategy::__already_const) { + return views::all(std::forward<_Type>(__range)); + } else if constexpr (__st == __strategy::__empty_view) { + return auto(views::empty); + } else if constexpr (__st == __strategy::__span) { + return span::__extent>(std::forward<_Type>(__range)); + } else if constexpr (__st == __strategy::__ref_view) { + return ref_view(static_cast(std::forward<_Type>(__range).base())); + } else if constexpr (__st == __strategy::__const_is_constant_range) { + return ref_view(static_cast(std::forward<_Type>(__range))); + } else if constexpr (__st == __strategy::__otherwise) { + return as_const_view(std::forward<_Type>(__range)); + } + } +}; + +} // namespace __as_const + +inline namespace __cpo { +inline constexpr auto as_const = __as_const::__fn{}; +} // namespace __cpo +} // namespace views + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_AS_CONST_VIEW_H diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h index 674a3f359ff99..22ff67a73bce1 100644 --- a/libcxx/include/__ranges/concepts.h +++ b/libcxx/include/__ranges/concepts.h @@ -15,12 +15,12 @@ #include <__concepts/same_as.h> #include <__config> #include <__iterator/concepts.h> +#include <__iterator/const_iterator.h> #include <__iterator/incrementable_traits.h> #include <__iterator/iter_move.h> #include <__iterator/iterator_traits.h> #include <__iterator/readable_traits.h> #include <__ranges/access.h> -#include <__ranges/data.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/enable_view.h> #include <__ranges/size.h> @@ -61,6 +61,8 @@ concept borrowed_range = template using sentinel_t = decltype(ranges::end(std::declval<_Rp&>())); +// `const_iterator_t` and `const_sentinel_t` defined in <__ranges/const_access.h> + template using range_difference_t = iter_difference_t>; @@ -70,6 +72,11 @@ using range_value_t = iter_value_t>; template using range_reference_t = iter_reference_t>; +# if _LIBCPP_STD_VER >= 23 +template +using range_const_reference_t = iter_const_reference_t>; +# endif + template using range_rvalue_reference_t = iter_rvalue_reference_t>; @@ -133,6 +140,11 @@ concept viewable_range = (is_lvalue_reference_v<_Tp> || (movable> && !__is_std_initializer_list>)))); +# if _LIBCPP_STD_VER >= 23 +template +concept constant_range = input_range<_Tp> && __constant_iterator>; +# endif // _LIBCPP_STD_VER >= 23 + } // namespace ranges #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__ranges/const_access.h b/libcxx/include/__ranges/const_access.h new file mode 100644 index 0000000000000..75600d8591772 --- /dev/null +++ b/libcxx/include/__ranges/const_access.h @@ -0,0 +1,262 @@ +// -*- 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_CONST_ACCESS_H +#define _LIBCPP___RANGES_CONST_ACCESS_H + +#include <__iterator/const_iterator.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/enable_borrowed_range.h> +#include <__ranges/rbegin.h> +#include <__ranges/rend.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_reference.h> +#include <__utility/declval.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [range.const] +# if _LIBCPP_STD_VER >= 23 +namespace ranges { +template +constexpr auto& __possibly_const_range(_Rp& __rng) noexcept { + if constexpr (constant_range && !constant_range<_Rp>) { + return const_cast(__rng); + } else { + return __rng; + } +} +} // namespace ranges +# endif // _LIBCPP_STD_VER >= 23 + +// [range.access.cbegin] +namespace ranges { + +template +concept __const_accessible_range = (!is_rvalue_reference_v<_Type&&> || enable_borrowed_range>); + +namespace __cbegin { +struct __fn { +# if _LIBCPP_STD_VER >= 23 + template + using _UType = decltype(ranges::begin(ranges::__possibly_const_range(std::declval<_Rng&>()))); + + template <__const_accessible_range _Rng> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto + operator()(_Rng&& __rng) noexcept(noexcept(const_iterator<_UType<_Rng>>( + ranges::begin(ranges::__possibly_const_range(__rng))))) -> const_iterator<_UType<_Rng>> { + return const_iterator<_UType<_Rng>>(ranges::begin(ranges::__possibly_const_range(__rng))); + } +# else // ^^^ _LIBCPP_STD_VER >= 23 / _LIBCPP_STD_VER < 23 vvv + template + requires is_lvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::begin(static_cast&>(__t)))) + -> decltype(ranges::begin(static_cast&>(__t))) { + return ranges::begin(static_cast&>(__t)); + } + + template + requires is_rvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::begin(static_cast(__t)))) + -> decltype(ranges::begin(static_cast(__t))) { + return ranges::begin(static_cast(__t)); + } +# endif // ^^^ _LIBCPP_STD_VER < 23 +}; +} // namespace __cbegin + +inline namespace __cpo { +inline constexpr auto cbegin = __cbegin::__fn{}; +} // namespace __cpo +} // namespace ranges + +// [range.range] +namespace ranges { +template +using const_iterator_t = decltype(ranges::cbegin(std::declval<_Rp&>())); +} + +// [range.access.cend] +namespace ranges { +namespace __cend { +struct __fn { +# if _LIBCPP_STD_VER >= 23 + template + using _UType = decltype(ranges::end(ranges::__possibly_const_range(std::declval<_Rng&>()))); + + template <__const_accessible_range _Rng> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto + operator()(_Rng&& __rng) noexcept(noexcept(const_sentinel<_UType<_Rng>>( + ranges::end(ranges::__possibly_const_range(__rng))))) -> const_sentinel<_UType<_Rng>> { + return const_sentinel<_UType<_Rng>>(ranges::end(ranges::__possibly_const_range(__rng))); + } +# else // ^^^ _LIBCPP_STD_VER >= 23 / _LIBCPP_STD_VER < 23 vvv + template + requires is_lvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::end(static_cast&>(__t)))) + -> decltype(ranges::end(static_cast&>(__t))) { + return ranges::end(static_cast&>(__t)); + } + + template + requires is_rvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept( + noexcept(ranges::end(static_cast(__t)))) -> decltype(ranges::end(static_cast(__t))) { + return ranges::end(static_cast(__t)); + } +# endif +}; +} // namespace __cend + +inline namespace __cpo { +inline constexpr auto cend = __cend::__fn{}; +} // namespace __cpo +} // namespace ranges + +// [range.range] +namespace ranges { +template +using const_sentinel_t = decltype(ranges::cend(std::declval<_Rp&>())); +} + +// [range.access.crbegin] +namespace ranges { +namespace __crbegin { +struct __fn { +# if _LIBCPP_STD_VER >= 23 + template + using _UType = decltype(ranges::rbegin(ranges::__possibly_const_range(std::declval<_Rng&>()))); + + template <__const_accessible_range _Rng> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto + operator()(_Rng&& __rng) noexcept(noexcept(const_iterator<_UType<_Rng>>( + ranges::rbegin(ranges::__possibly_const_range(__rng))))) -> const_iterator<_UType<_Rng>> { + return const_iterator<_UType<_Rng>>(ranges::rbegin(ranges::__possibly_const_range(__rng))); + } +# else // ^^^ _LIBCPP_STD_VER >= 23 / _LIBCPP_STD_VER < 23 + template + requires is_lvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::rbegin(static_cast&>(__t)))) + -> decltype(ranges::rbegin(static_cast&>(__t))) { + return ranges::rbegin(static_cast&>(__t)); + } + + template + requires is_rvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::rbegin(static_cast(__t)))) + -> decltype(ranges::rbegin(static_cast(__t))) { + return ranges::rbegin(static_cast(__t)); + } +# endif // ^^^ _LIBCPP_STD_VER < 23 +}; +} // namespace __crbegin + +inline namespace __cpo { +inline constexpr auto crbegin = __crbegin::__fn{}; +} // namespace __cpo +} // namespace ranges + +// [range.access.crend] +namespace ranges { +namespace __crend { +struct __fn { +# if _LIBCPP_STD_VER >= 23 + template + using _UType = decltype(ranges::rend(ranges::__possibly_const_range(std::declval<_Rng&>()))); + + template <__const_accessible_range _Rng> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto + operator()(_Rng&& __rng) noexcept(noexcept(const_sentinel<_UType<_Rng>>( + ranges::rend(ranges::__possibly_const_range(__rng))))) -> const_sentinel<_UType<_Rng>> { + return const_sentinel<_UType<_Rng>>(ranges::rend(ranges::__possibly_const_range(__rng))); + } +# else // ^^^ _LIBCPP_STD_VER >= 23 / _LIBCPP_STD_VER < 23 vvv + template + requires is_lvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::rend(static_cast&>(__t)))) + -> decltype(ranges::rend(static_cast&>(__t))) { + return ranges::rend(static_cast&>(__t)); + } + + template + requires is_rvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept( + noexcept(ranges::rend(static_cast(__t)))) -> decltype(ranges::rend(static_cast(__t))) { + return ranges::rend(static_cast(__t)); + } +# endif // ^^^ _LIBCPP_STD_VER < 23 +}; +} // namespace __crend + +inline namespace __cpo { +inline constexpr auto crend = __crend::__fn{}; +} // namespace __cpo +} // namespace ranges + +// [range.prim.cdata] + +namespace ranges { +namespace __cdata { +struct __fn { +# if _LIBCPP_STD_VER >= 23 + template + _LIBCPP_HIDE_FROM_ABI constexpr static auto __as_const_pointer(const _Tp* __ptr) noexcept { + return __ptr; + } + + template <__const_accessible_range _Rng> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto + operator()(_Rng&& __rng) noexcept(noexcept(__as_const_pointer(ranges::data(ranges::__possibly_const_range(__rng))))) + -> decltype(__as_const_pointer(ranges::data(ranges::__possibly_const_range(__rng)))) { + return __as_const_pointer(ranges::data(ranges::__possibly_const_range(__rng))); + } + +# else // ^^^ _LIBCPP_STD_VER >= 23 / _LIBCPP_STD_VER < 23 vvv + template + requires is_lvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::data(static_cast&>(__t)))) + -> decltype(ranges::data(static_cast&>(__t))) { + return ranges::data(static_cast&>(__t)); + } + + template + requires is_rvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept( + noexcept(ranges::data(static_cast(__t)))) -> decltype(ranges::data(static_cast(__t))) { + return ranges::data(static_cast(__t)); + } +# endif // ^^^ _LIBCPP_STD_VER < 23 +}; +} // namespace __cdata + +inline namespace __cpo { +inline constexpr auto cdata = __cdata::__fn{}; +} // namespace __cpo +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_CONST_ACCESS_H diff --git a/libcxx/include/__ranges/data.h b/libcxx/include/__ranges/data.h deleted file mode 100644 index 50db3cffeeed8..0000000000000 --- a/libcxx/include/__ranges/data.h +++ /dev/null @@ -1,102 +0,0 @@ -// -*- 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_DATA_H -#define _LIBCPP___RANGES_DATA_H - -#include <__concepts/class_or_enum.h> -#include <__config> -#include <__iterator/concepts.h> -#include <__iterator/iterator_traits.h> -#include <__memory/pointer_traits.h> -#include <__ranges/access.h> -#include <__type_traits/decay.h> -#include <__type_traits/is_object.h> -#include <__type_traits/is_pointer.h> -#include <__type_traits/is_reference.h> -#include <__type_traits/remove_pointer.h> -#include <__type_traits/remove_reference.h> -#include <__utility/auto_cast.h> - -#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -#endif - -_LIBCPP_BEGIN_NAMESPACE_STD - -#if _LIBCPP_STD_VER >= 20 - -// [range.prim.data] - -namespace ranges { -namespace __data { -template -concept __ptr_to_object = is_pointer_v<_Tp> && is_object_v>; - -template -concept __member_data = __can_borrow<_Tp> && requires(_Tp&& __t) { - { _LIBCPP_AUTO_CAST(__t.data()) } -> __ptr_to_object; -}; - -template -concept __ranges_begin_invocable = !__member_data<_Tp> && __can_borrow<_Tp> && requires(_Tp&& __t) { - { ranges::begin(__t) } -> contiguous_iterator; -}; - -struct __fn { - template <__member_data _Tp> - _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept(noexcept(__t.data())) { - return __t.data(); - } - - template <__ranges_begin_invocable _Tp> - _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(std::to_address(ranges::begin(__t)))) { - return std::to_address(ranges::begin(__t)); - } -}; -} // namespace __data - -inline namespace __cpo { -inline constexpr auto data = __data::__fn{}; -} // namespace __cpo -} // namespace ranges - -// [range.prim.cdata] - -namespace ranges { -namespace __cdata { -struct __fn { - template - requires is_lvalue_reference_v<_Tp&&> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::data(static_cast&>(__t)))) - -> decltype(ranges::data(static_cast&>(__t))) { - return ranges::data(static_cast&>(__t)); - } - - template - requires is_rvalue_reference_v<_Tp&&> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept( - noexcept(ranges::data(static_cast(__t)))) -> decltype(ranges::data(static_cast(__t))) { - return ranges::data(static_cast(__t)); - } -}; -} // namespace __cdata - -inline namespace __cpo { -inline constexpr auto cdata = __cdata::__fn{}; -} // namespace __cpo -} // namespace ranges - -#endif // _LIBCPP_STD_VER >= 20 - -_LIBCPP_END_NAMESPACE_STD - -#endif // _LIBCPP___RANGES_DATA_H diff --git a/libcxx/include/__ranges/owning_view.h b/libcxx/include/__ranges/owning_view.h index 254bdb4329119..7e1b8318a2a4d 100644 --- a/libcxx/include/__ranges/owning_view.h +++ b/libcxx/include/__ranges/owning_view.h @@ -15,7 +15,6 @@ #include <__config> #include <__ranges/access.h> #include <__ranges/concepts.h> -#include <__ranges/data.h> #include <__ranges/empty.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/size.h> diff --git a/libcxx/include/__ranges/rbegin.h b/libcxx/include/__ranges/rbegin.h index 12e739e1a2b85..a6f7e2d9f1aea 100644 --- a/libcxx/include/__ranges/rbegin.h +++ b/libcxx/include/__ranges/rbegin.h @@ -85,34 +85,6 @@ inline constexpr auto rbegin = __rbegin::__fn{}; } // namespace __cpo } // namespace ranges -// [range.access.crbegin] - -namespace ranges { -namespace __crbegin { -struct __fn { - template - requires is_lvalue_reference_v<_Tp&&> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::rbegin(static_cast&>(__t)))) - -> decltype(ranges::rbegin(static_cast&>(__t))) { - return ranges::rbegin(static_cast&>(__t)); - } - - template - requires is_rvalue_reference_v<_Tp&&> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::rbegin(static_cast(__t)))) - -> decltype(ranges::rbegin(static_cast(__t))) { - return ranges::rbegin(static_cast(__t)); - } -}; -} // namespace __crbegin - -inline namespace __cpo { -inline constexpr auto crbegin = __crbegin::__fn{}; -} // namespace __cpo -} // namespace ranges - #endif // _LIBCPP_STD_VER >= 20 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__ranges/ref_view.h b/libcxx/include/__ranges/ref_view.h index 5329d778dd30d..db858b8e79490 100644 --- a/libcxx/include/__ranges/ref_view.h +++ b/libcxx/include/__ranges/ref_view.h @@ -19,7 +19,6 @@ #include <__memory/addressof.h> #include <__ranges/access.h> #include <__ranges/concepts.h> -#include <__ranges/data.h> #include <__ranges/empty.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/size.h> diff --git a/libcxx/include/__ranges/rend.h b/libcxx/include/__ranges/rend.h index 02b4c5999a7eb..5171cc6cf3434 100644 --- a/libcxx/include/__ranges/rend.h +++ b/libcxx/include/__ranges/rend.h @@ -89,33 +89,6 @@ inline constexpr auto rend = __rend::__fn{}; } // namespace __cpo } // namespace ranges -// [range.access.crend] - -namespace ranges { -namespace __crend { -struct __fn { - template - requires is_lvalue_reference_v<_Tp&&> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::rend(static_cast&>(__t)))) - -> decltype(ranges::rend(static_cast&>(__t))) { - return ranges::rend(static_cast&>(__t)); - } - - template - requires is_rvalue_reference_v<_Tp&&> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept( - noexcept(ranges::rend(static_cast(__t)))) -> decltype(ranges::rend(static_cast(__t))) { - return ranges::rend(static_cast(__t)); - } -}; -} // namespace __crend - -inline namespace __cpo { -inline constexpr auto crend = __crend::__fn{}; -} // namespace __cpo -} // namespace ranges - #endif // _LIBCPP_STD_VER >= 20 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__ranges/view_interface.h b/libcxx/include/__ranges/view_interface.h index 3bcfbaf3a2f9e..2dd5029f4499f 100644 --- a/libcxx/include/__ranges/view_interface.h +++ b/libcxx/include/__ranges/view_interface.h @@ -20,6 +20,7 @@ #include <__memory/pointer_traits.h> #include <__ranges/access.h> #include <__ranges/concepts.h> +#include <__ranges/const_access.h> #include <__ranges/empty.h> #include <__ranges/size.h> #include <__type_traits/is_class.h> @@ -72,6 +73,27 @@ class view_interface { } } + constexpr auto cbegin() + requires input_range<_Derived> + { + return ranges::cbegin(__derived()); + } + constexpr auto cbegin() const + requires input_range + { + return ranges::cbegin(__derived()); + } + constexpr auto cend() + requires input_range<_Derived> + { + return ranges::cend(__derived()); + } + constexpr auto cend() const + requires input_range + { + return ranges::cend(__derived()); + } + template _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() requires requires(_D2& __t) { ranges::empty(__t); } diff --git a/libcxx/include/iterator b/libcxx/include/iterator index fca75f0a19ed1..9a0c618f860cf 100644 --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -383,6 +383,31 @@ insert_iterator inserter(Container& x, typename Container::iterator i template constexpr insert_iterator inserter(Container& x, ranges::iterator_t i); // since C++20 +template +using iter_const_reference_t = see below; // since C++23 +template +using const_iterator = see below; // since C++23 +template +using const_sentinel = see below; // since C++23 + +template +class basic_const_iterator; // since C++23 + +template U> + requires input_iterator> +struct common_type, U>; // since C++23 +template U> + requires input_iterator> +struct common_type>; // since C++23 +template U> + requires input_iterator> +struct common_type, basic_const_iterator>; // since C++23 + +template +constexpr const_iterator make_const_iterator(I it); // since C++23 +template +constexpr const_sentinel make_const_sentinel(S s); // since C++23 + template class move_iterator { public: @@ -726,6 +751,10 @@ template constexpr const E* data(initializer_list il) noexcept; # include <__iterator/unreachable_sentinel.h> #endif +#if _LIBCPP_STD_VER >= 23 +# include <__iterator/const_iterator.h> +#endif + #include // standard-mandated includes diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 13d0dce34d97e..5d82ae1d77db5 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1401,6 +1401,7 @@ module std_private_iterator_concepts [system] { export std_private_type_traits_is_reference export std_private_type_traits_remove_cvref } +module std_private_iterator_const_iterator [system] { header "__iterator/const_iterator.h" } module std_private_iterator_counted_iterator [system] { header "__iterator/counted_iterator.h" } module std_private_iterator_cpp17_iterator_concepts [system] { header "__iterator/cpp17_iterator_concepts.h" } module std_private_iterator_data [system] { header "__iterator/data.h" } @@ -1699,9 +1700,11 @@ module std_private_ranges_all [system] { export std_private_functional_perfect_forward export std_private_ranges_owning_view } +module std_private_ranges_as_const_view [system] { header "__ranges/as_const_view.h" } module std_private_ranges_as_rvalue_view [system] { header "__ranges/as_rvalue_view.h" } module std_private_ranges_chunk_by_view [system] { header "__ranges/chunk_by_view.h" } module std_private_ranges_common_view [system] { header "__ranges/common_view.h" } +module std_private_ranges_const_access [system] { header "__ranges/const_access.h" } module std_private_ranges_concepts [system] { header "__ranges/concepts.h" export std_private_iterator_concepts @@ -1712,7 +1715,6 @@ module std_private_ranges_counted [system] { export std_span } module std_private_ranges_dangling [system] { header "__ranges/dangling.h" } -module std_private_ranges_data [system] { header "__ranges/data.h" } module std_private_ranges_drop_view [system] { header "__ranges/drop_view.h" } module std_private_ranges_drop_while_view [system] { header "__ranges/drop_while_view.h" } module std_private_ranges_elements_view [system] { header "__ranges/elements_view.h" } diff --git a/libcxx/include/ranges b/libcxx/include/ranges index fa35874265de6..fa6f2e27969a7 100644 --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -39,6 +39,10 @@ namespace std::ranges { using iterator_t = decltype(ranges::begin(declval())); template using sentinel_t = decltype(ranges::end(declval())); + template + using const_iterator_t = decltype(ranges::cbegin(declval())); // since C++23 + template + using const_sentinel_t = decltype(ranges::cend(declval())); // since C++23 template using range_difference_t = iter_difference_t>; template @@ -47,6 +51,8 @@ namespace std::ranges { using range_value_t = iter_value_t>; template using range_reference_t = iter_reference_t>; + template + using range_const_reference_t = iter_const_reference_t>; // since C++23 template using range_rvalue_reference_t = iter_rvalue_reference_t>; template @@ -93,6 +99,9 @@ namespace std::ranges { template concept viewable_range = see below; + template + concept constant_range = see below; + // [range.adaptor.object], range adaptor objects template requires is_class_v && same_as> @@ -387,9 +396,9 @@ namespace std { # include <__ranges/all.h> # include <__ranges/common_view.h> # include <__ranges/concepts.h> +# include <__ranges/const_access.h> # include <__ranges/counted.h> # include <__ranges/dangling.h> -# include <__ranges/data.h> # include <__ranges/drop_view.h> # include <__ranges/drop_while_view.h> # include <__ranges/elements_view.h> @@ -421,6 +430,7 @@ namespace std { #endif #if _LIBCPP_STD_VER >= 23 +# include <__ranges/as_const_view.h> # include <__ranges/as_rvalue_view.h> # include <__ranges/chunk_by_view.h> # include <__ranges/from_range.h> diff --git a/libcxx/include/span b/libcxx/include/span index 60d76d830f0f3..94b0e4746aa33 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -65,7 +65,9 @@ public: using reference = element_type&; using const_reference = const element_type&; using iterator = implementation-defined; + using const_iterator = std::const_iterator; // since C++23 using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::const_iterator; // since C++23 static constexpr size_type extent = Extent; // [span.cons], span constructors, copy, assignment, and destructor @@ -115,8 +117,12 @@ public: // [span.iterators], span iterator support constexpr iterator begin() const noexcept; constexpr iterator end() const noexcept; + constexpr const_iterator cbegin() const noexcept; // since C++23 + constexpr const_iterator cend() const noexcept; // since C++23 constexpr reverse_iterator rbegin() const noexcept; constexpr reverse_iterator rend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; // since C++23 + constexpr const_reverse_iterator crend() const noexcept; // since C++23 private: pointer data_; // exposition only @@ -152,12 +158,13 @@ template #include <__fwd/span.h> #include <__iterator/bounded_iter.h> #include <__iterator/concepts.h> +#include <__iterator/const_iterator.h> #include <__iterator/iterator_traits.h> #include <__iterator/reverse_iterator.h> #include <__iterator/wrap_iter.h> #include <__memory/pointer_traits.h> +#include <__ranges/access.h> #include <__ranges/concepts.h> -#include <__ranges/data.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/enable_view.h> #include <__ranges/size.h> @@ -167,6 +174,7 @@ template #include <__type_traits/is_convertible.h> #include <__type_traits/is_integral.h> #include <__type_traits/is_same.h> +#include <__type_traits/is_volatile.h> #include <__type_traits/remove_const.h> #include <__type_traits/remove_cv.h> #include <__type_traits/remove_cvref.h> @@ -224,6 +232,20 @@ concept __span_compatible_iterator = template concept __span_compatible_sentinel_for = sized_sentinel_for<_Sentinel, _It> && !is_convertible_v<_Sentinel, size_t>; +# if _LIBCPP_STD_VER >= 23 +// As an extension, libc++'s `span` supports volatile types; however, `std::const_iterator` does not. +// Thus, we must remove the support for `cbegin` and friends if `span`'s element type is `volatile`-qualified. +template +struct __span_const_iterator { + using type = void; +}; +template + requires(!is_volatile_v<_Tp>) +struct __span_const_iterator<_Tp, _Iter> { + using type = std::const_iterator<_Iter>; +}; +# endif + template class _LIBCPP_TEMPLATE_VIS span { public: @@ -242,6 +264,10 @@ public: using iterator = __wrap_iter; # endif using reverse_iterator = std::reverse_iterator; +# if _LIBCPP_STD_VER >= 23 + using const_iterator = __span_const_iterator<_Tp, iterator>::type; + using const_reverse_iterator = __span_const_iterator<_Tp, reverse_iterator>::type; +# endif // _LIBCPP_STD_VER >= 23 static constexpr size_type extent = _Extent; @@ -390,8 +416,33 @@ public: return iterator(data() + size()); # endif } +# if _LIBCPP_STD_VER >= 23 + _LIBCPP_HIDE_FROM_ABI constexpr const_iterator cbegin() const noexcept + requires(!is_volatile_v<_Tp>) + { + return begin(); + } + _LIBCPP_HIDE_FROM_ABI constexpr const_iterator cend() const noexcept + requires(!is_volatile_v<_Tp>) + { + return end(); + } +# endif // _LIBCPP_STD_VER >= 23 + _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } +# if _LIBCPP_STD_VER >= 23 + _LIBCPP_HIDE_FROM_ABI constexpr const_reverse_iterator crbegin() const noexcept + requires(!is_volatile_v<_Tp>) + { + return rbegin(); + } + _LIBCPP_HIDE_FROM_ABI constexpr const_reverse_iterator crend() const noexcept + requires(!is_volatile_v<_Tp>) + { + return rend(); + } +# endif // _LIBCPP_STD_VER >= 23 _LIBCPP_HIDE_FROM_ABI span __as_bytes() const noexcept { return span{reinterpret_cast(data()), size_bytes()}; @@ -423,6 +474,10 @@ public: using iterator = __wrap_iter; # endif using reverse_iterator = std::reverse_iterator; +# if _LIBCPP_STD_VER >= 23 + using const_iterator = __span_const_iterator<_Tp, iterator>::type; + using const_reverse_iterator = __span_const_iterator<_Tp, reverse_iterator>::type; +# endif static constexpr size_type extent = dynamic_extent; @@ -552,8 +607,33 @@ public: return iterator(data() + size()); # endif } +# if _LIBCPP_STD_VER >= 23 + _LIBCPP_HIDE_FROM_ABI constexpr const_iterator cbegin() const noexcept + requires(!is_volatile_v<_Tp>) + { + return begin(); + } + _LIBCPP_HIDE_FROM_ABI constexpr const_iterator cend() const noexcept + requires(!is_volatile_v<_Tp>) + { + return end(); + } +# endif + _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } +# if _LIBCPP_STD_VER >= 23 + _LIBCPP_HIDE_FROM_ABI constexpr const_reverse_iterator crbegin() const noexcept + requires(!is_volatile_v<_Tp>) + { + return rbegin(); + } + _LIBCPP_HIDE_FROM_ABI constexpr const_reverse_iterator crend() const noexcept + requires(!is_volatile_v<_Tp>) + { + return rend(); + } +# endif _LIBCPP_HIDE_FROM_ABI span __as_bytes() const noexcept { return {reinterpret_cast(data()), size_bytes()}; diff --git a/libcxx/include/string_view b/libcxx/include/string_view index 2a03ee99e9ab5..d18e275028d47 100644 --- a/libcxx/include/string_view +++ b/libcxx/include/string_view @@ -218,8 +218,8 @@ namespace std { #include <__iterator/reverse_iterator.h> #include <__iterator/wrap_iter.h> #include <__memory/pointer_traits.h> +#include <__ranges/access.h> #include <__ranges/concepts.h> -#include <__ranges/data.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/enable_view.h> #include <__ranges/size.h> diff --git a/libcxx/include/version b/libcxx/include/version index fe64343eafbc9..0218897d358fe 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -184,7 +184,7 @@ __cpp_lib_print 202207L __cpp_lib_ranges 202207L -__cpp_lib_ranges_as_const 202207L +__cpp_lib_ranges_as_const 202311L __cpp_lib_ranges_as_rvalue 202207L __cpp_lib_ranges_chunk 202202L __cpp_lib_ranges_chunk_by 202202L @@ -480,7 +480,7 @@ __cpp_lib_void_t 201411L # define __cpp_lib_optional 202110L # define __cpp_lib_out_ptr 202106L # define __cpp_lib_print 202207L -// # define __cpp_lib_ranges_as_const 202207L +# define __cpp_lib_ranges_as_const 202311L # define __cpp_lib_ranges_as_rvalue 202207L // # define __cpp_lib_ranges_chunk 202202L # define __cpp_lib_ranges_chunk_by 202202L diff --git a/libcxx/modules/std/iterator.inc b/libcxx/modules/std/iterator.inc index 10c63d74e6e05..5278ceaf2785b 100644 --- a/libcxx/modules/std/iterator.inc +++ b/libcxx/modules/std/iterator.inc @@ -182,18 +182,21 @@ export namespace std { using std::insert_iterator; using std::inserter; +#if _LIBCPP_STD_VER >= 23 // [const.iterators], constant iterators and sentinels // [const.iterators.alias], alias templates - // using std::const_iterator; - // using std::const_sentinel; - // using std::iter_const_reference_t; + using std::const_iterator; + using std::const_sentinel; + using std::iter_const_reference_t; // [const.iterators.iterator], class template basic_const_iterator - // using std::basic_const_iterator; + using std::basic_const_iterator; - // using std::common_type; + using std::common_type; - // using std::make_const_iterator; + using std::make_const_iterator; + using std::make_const_sentinel; +#endif // [move.iterators], move iterators and sentinels using std::move_iterator; diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc index f71efe948ede1..e111d818a3ae0 100644 --- a/libcxx/modules/std/ranges.inc +++ b/libcxx/modules/std/ranges.inc @@ -34,10 +34,14 @@ export namespace std { using std::ranges::borrowed_range; - // using std::ranges::const_iterator_t; - // using std::ranges::const_sentinel_t; +#if _LIBCPP_STD_VER >= 23 + using std::ranges::const_iterator_t; + using std::ranges::const_sentinel_t; +#endif using std::ranges::iterator_t; - // using std::ranges::range_const_reference_t; +#if _LIBCPP_STD_VER >= 23 + using std::ranges::range_const_reference_t; +#endif using std::ranges::range_common_reference_t; using std::ranges::range_difference_t; using std::ranges::range_reference_t; @@ -58,7 +62,9 @@ export namespace std { // [range.refinements], other range refinements using std::ranges::bidirectional_range; using std::ranges::common_range; - // using std::ranges::constant_range; +#if _LIBCPP_STD_VER >= 23 + using std::ranges::constant_range; +#endif using std::ranges::contiguous_range; using std::ranges::forward_range; using std::ranges::input_range; diff --git a/libcxx/test/std/containers/views/views.span/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/views/views.span/range_concept_conformance.compile.pass.cpp index fe28aeea3802b..414d009ab93a0 100644 --- a/libcxx/test/std/containers/views/views.span/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/range_concept_conformance.compile.pass.cpp @@ -15,6 +15,8 @@ #include #include +#include "test_macros.h" + using range = std::span; @@ -35,3 +37,8 @@ static_assert(!std::ranges::view && !std::ranges::enable_view); static_assert(std::ranges::borrowed_range); static_assert(std::ranges::viewable_range); + +#if TEST_STD_VER >= 23 +static_assert(std::same_as, range::const_iterator>); +static_assert(std::same_as, range::const_iterator>); +#endif diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/begin.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/begin.pass.cpp index f6b24017ffc1f..70dda6e5c2a5e 100644 --- a/libcxx/test/std/containers/views/views.span/span.iterators/begin.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.iterators/begin.pass.cpp @@ -10,7 +10,7 @@ // // constexpr iterator begin() const noexcept; -// constexpr const_iterator cbegin() const noexcept; +// constexpr const_iterator cbegin() const noexcept; // since C++23 #include #include @@ -18,90 +18,68 @@ #include "test_macros.h" -template -constexpr bool testConstexprSpan(Span s) -{ - bool ret = true; - typename Span::iterator b = s.begin(); - - if (s.empty()) - { - ret = ret && (b == s.end()); - } - else - { - ret = ret && ( *b == s[0]); - ret = ret && (&*b == &s[0]); - } - return ret; +template +constexpr bool testSpanImpl(Span s, Iter first) { + bool ret = true; + if (s.empty()) { + ret = ret && (first == s.end()); + } else { + ret = ret && (*first == s[0]); + ret = ret && (&*first == &s[0]); + } + return ret; } +template +constexpr bool testSpan(Args&&... args) { + auto s1 = std::span(std::forward(args)...); + bool ret = true; -template -void testRuntimeSpan(Span s) -{ - typename Span::iterator b = s.begin(); - - if (s.empty()) - { - assert(b == s.end()); - } - else - { - assert( *b == s[0]); - assert(&*b == &s[0]); - } + ret = ret && testSpanImpl(s1, s1.begin()); +#if TEST_STD_VER >= 23 + ret = ret && testSpanImpl(s1, s1.cbegin()); +#endif + + auto s2 = std::span(std::forward(args)...); + ret = ret && testSpanImpl(s2, s2.begin()); +#if TEST_STD_VER >= 23 + ret = ret && testSpanImpl(s2, s2.cbegin()); +#endif + + return ret; } -struct A{}; -bool operator==(A, A) {return true;} - -constexpr int iArr1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; - - -int main(int, char**) -{ - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - - static_assert(testConstexprSpan(std::span(iArr1, 1)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 2)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 3)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 4)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 5)), ""); - - - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span()); - - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span()); - - testRuntimeSpan(std::span(iArr2, 1)); - testRuntimeSpan(std::span(iArr2, 2)); - testRuntimeSpan(std::span(iArr2, 3)); - testRuntimeSpan(std::span(iArr2, 4)); - testRuntimeSpan(std::span(iArr2, 5)); - - std::string s; - testRuntimeSpan(std::span(&s, (std::size_t) 0)); - testRuntimeSpan(std::span(&s, 1)); +struct A {}; +bool operator==(A, A) { return true; } + +constexpr int iArr1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + +int main(int, char**) { + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 1)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 2)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 3)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 4)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 5)); + + testSpan(iArr2, 1); + testSpan(iArr2, 2); + testSpan(iArr2, 3); + testSpan(iArr2, 4); + testSpan(iArr2, 5); + + std::string s1; + constexpr static std::string s2; + testSpan(&s1, static_cast(0)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(&s2, static_cast(0))); + testSpan(&s1, 1); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(&s2, 1)); return 0; } diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/end.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/end.pass.cpp index d6aaf74d1058c..5fc3cead94d6b 100644 --- a/libcxx/test/std/containers/views/views.span/span.iterators/end.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.iterators/end.pass.cpp @@ -10,7 +10,7 @@ // // constexpr iterator end() const noexcept; -// constexpr const_iterator cend() const noexcept; +// constexpr const_iterator cend() const noexcept; // since C++23 #include #include @@ -18,94 +18,69 @@ #include "test_macros.h" -template -constexpr bool testConstexprSpan(Span s) -{ - bool ret = true; - typename Span::iterator e = s.end(); - if (s.empty()) - { - ret = ret && (e == s.begin()); - } - else - { - typename Span::const_pointer last = &*(s.begin() + s.size() - 1); - ret = ret && (e != s.begin()); - ret = ret && (&*( e-1) == last); - } - - ret = ret && (static_cast(e - s.begin()) == s.size()); - return ret; +template +constexpr bool testSpanImpl(Span s, Iter last) { + bool ret = true; + if (s.empty()) { + ret = ret && (last == s.begin()); + } else { + ret = ret && (last != s.begin()); + ret = ret && (&*(last - 1) == s.data() + s.size() - 1); + } + ret = ret && (static_cast(last - s.begin()) == s.size()); + return ret; } -template -void testRuntimeSpan(Span s) -{ - typename Span::iterator e = s.end(); - if (s.empty()) - { - assert(e == s.begin()); - } - else - { - typename Span::const_pointer last = &*(s.begin() + s.size() - 1); - assert(e != s.begin()); - assert(&*( e-1) == last); - } - - assert(static_cast(e - s.begin()) == s.size()); -} - - -struct A{}; -bool operator==(A, A) {return true;} - -constexpr int iArr1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; - +template +constexpr bool testSpan(Args&&... args) { + auto s1 = std::span(std::forward(args)...); + bool ret = true; -int main(int, char**) -{ - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); + ret = ret && testSpanImpl(s1, s1.end()); +#if TEST_STD_VER >= 23 + ret = ret && testSpanImpl(s1, s1.cend()); +#endif - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); + auto s2 = std::span(std::forward(args)...); + ret = ret && testSpanImpl(s2, s2.end()); +#if TEST_STD_VER >= 23 + ret = ret && testSpanImpl(s2, s2.cend()); +#endif - static_assert(testConstexprSpan(std::span(iArr1, 1)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 2)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 3)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 4)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 5)), ""); - - - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span()); - - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span()); - - testRuntimeSpan(std::span(iArr2, 1)); - testRuntimeSpan(std::span(iArr2, 2)); - testRuntimeSpan(std::span(iArr2, 3)); - testRuntimeSpan(std::span(iArr2, 4)); - testRuntimeSpan(std::span(iArr2, 5)); + return ret; +} - std::string s; - testRuntimeSpan(std::span(&s, (std::size_t) 0)); - testRuntimeSpan(std::span(&s, 1)); +struct A {}; +bool operator==(A, A) { return true; } + +constexpr int iArr1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + +int main(int, char**) { + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 1)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 2)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 3)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 4)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 5)); + + testSpan(iArr2, 1); + testSpan(iArr2, 2); + testSpan(iArr2, 3); + testSpan(iArr2, 4); + testSpan(iArr2, 5); + + std::string s1; + constexpr static std::string s2; + testSpan(&s1, static_cast(0)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(&s2, static_cast(0))); + testSpan(&s1, 1); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(&s2, 1)); return 0; } diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp index 13a7628e6043d..7379ce61436d8 100644 --- a/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp @@ -26,20 +26,17 @@ constexpr void test_type() { using C = std::span; typename C::iterator ii1{}, ii2{}; typename C::iterator ii4 = ii1; - // TODO Test against C++23 after implementing - // P2278R4 cbegin should always return a constant iterator - // The means adjusting the #ifdef to guard against C++23. -#ifdef __cpp_lib_ranges_as_const +#if TEST_STD_VER >= 23 typename C::const_iterator cii{}; #endif assert(ii1 == ii2); assert(ii1 == ii4); -#ifdef __cpp_lib_ranges_as_const +#if TEST_STD_VER >= 23 assert(ii1 == cii); #endif assert(!(ii1 != ii2)); -#ifdef __cpp_lib_ranges_as_const +#if TEST_STD_VER >= 23 assert(!(ii1 != cii)); #endif @@ -47,21 +44,21 @@ constexpr void test_type() { C c{&v, 1}; assert(c.begin() == std::begin(c)); assert(c.rbegin() == std::rbegin(c)); -#ifdef __cpp_lib_ranges_as_const +#if TEST_STD_VER >= 23 assert(c.cbegin() == std::cbegin(c)); assert(c.crbegin() == std::crbegin(c)); #endif assert(c.end() == std::end(c)); assert(c.rend() == std::rend(c)); -#ifdef __cpp_lib_ranges_as_const +#if TEST_STD_VER >= 23 assert(c.cend() == std::cend(c)); assert(c.crend() == std::crend(c)); #endif assert(std::begin(c) != std::end(c)); assert(std::rbegin(c) != std::rend(c)); -#ifdef __cpp_lib_ranges_as_const +#if TEST_STD_VER >= 23 assert(std::cbegin(c) != std::cend(c)); assert(std::crbegin(c) != std::crend(c)); #endif @@ -70,7 +67,7 @@ constexpr void test_type() { std::same_as decltype(auto) r1 = ii1 <=> ii2; assert(r1 == std::strong_ordering::equal); -#ifdef __cpp_lib_ranges_as_const +#if TEST_STD_VER >= 23 std::same_as decltype(auto) r2 = cii <=> ii2; assert(r2 == std::strong_ordering::equal); #endif diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/iterator_concept_conformance.compile.pass.cpp index 1d9ea600bd2a0..3eedb24bee7b2 100644 --- a/libcxx/test/std/containers/views/views.span/span.iterators/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.iterators/iterator_concept_conformance.compile.pass.cpp @@ -19,6 +19,11 @@ using iterator = std::span::iterator; using reverse_iterator = std::span::reverse_iterator; using value_type = int; +#if TEST_STD_VER >= 23 +using const_iterator = std::span::const_iterator; +using const_reverse_iterator = std::span::const_reverse_iterator; +#endif + static_assert(std::contiguous_iterator); LIBCPP_STATIC_ASSERT(std::__has_random_access_iterator_category::value); static_assert(std::indirectly_writable); @@ -31,3 +36,18 @@ static_assert(std::indirectly_movable_storable); static_assert(std::indirectly_copyable); static_assert(std::indirectly_copyable_storable); static_assert(std::indirectly_swappable); + +#if TEST_STD_VER >= 23 +static_assert(std::contiguous_iterator); +LIBCPP_STATIC_ASSERT(std::__has_random_access_iterator_category::value); +static_assert(std::sentinel_for); +static_assert(std::sentinel_for); +static_assert(std::sentinel_for); +static_assert(!std::sentinel_for); +static_assert(!std::sentinel_for); +static_assert(std::sized_sentinel_for); +static_assert(std::sized_sentinel_for); +static_assert(std::sized_sentinel_for); +static_assert(!std::sized_sentinel_for); +static_assert(!std::sized_sentinel_for); +#endif diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/rbegin.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/rbegin.pass.cpp index 26e4389840857..5dca0e8956547 100644 --- a/libcxx/test/std/containers/views/views.span/span.iterators/rbegin.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.iterators/rbegin.pass.cpp @@ -9,8 +9,8 @@ // -// constexpr reverse_iterator rbegin() const noexcept; -// constexpr const_reverse_iterator crbegin() const noexcept; +// constexpr neverse_iterator rbegin() const noexcept; +// constexpr const_reverse_iterator crbegin() const noexcept; // since C++23 #include #include @@ -18,91 +18,70 @@ #include "test_macros.h" -template -constexpr bool testConstexprSpan(Span s) -{ - bool ret = true; - typename Span::reverse_iterator b = s.rbegin(); - if (s.empty()) - { - ret = ret && ( b == s.rend()); - } - else - { - const typename Span::size_type last = s.size() - 1; - ret = ret && ( *b == s[last]); - ret = ret && (&*b == &s[last]); - } - return ret; +template +constexpr bool testSpanImpl(Span s, Iter rfirst) { + bool ret = true; + if (s.empty()) { + ret = ret && (rfirst == s.rend()); + } else { + const typename Span::size_type last = s.size() - 1; + + ret = ret && (*rfirst == s[last]); + ret = ret && (&*rfirst == &s[last]); + } + return ret; } +template +constexpr bool testSpan(Args&&... args) { + auto s1 = std::span(std::forward(args)...); + bool ret = true; -template -void testRuntimeSpan(Span s) -{ - typename Span::reverse_iterator b = s.rbegin(); - if (s.empty()) - { - assert(b == s.rend()); - } - else - { - const typename Span::size_type last = s.size() - 1; - assert( *b == s[last]); - assert(&*b == &s[last]); - } -} - - -struct A{}; -bool operator==(A, A) {return true;} - -constexpr int iArr1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; - - -int main(int, char**) -{ - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); + ret = ret && testSpanImpl(s1, s1.rbegin()); +#if TEST_STD_VER >= 23 + ret = ret && testSpanImpl(s1, s1.crbegin()); +#endif - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); + auto s2 = std::span(std::forward(args)...); + ret = ret && testSpanImpl(s2, s2.rbegin()); +#if TEST_STD_VER >= 23 + ret = ret && testSpanImpl(s2, s2.crbegin()); +#endif - static_assert(testConstexprSpan(std::span(iArr1, 1)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 2)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 3)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 4)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 5)), ""); - - - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span()); - - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span()); - - testRuntimeSpan(std::span(iArr2, 1)); - testRuntimeSpan(std::span(iArr2, 2)); - testRuntimeSpan(std::span(iArr2, 3)); - testRuntimeSpan(std::span(iArr2, 4)); - testRuntimeSpan(std::span(iArr2, 5)); + return ret; +} - std::string s; - testRuntimeSpan(std::span(&s, static_cast(0))); - testRuntimeSpan(std::span(&s, 1)); +struct A {}; +bool operator==(A, A) { return true; } + +constexpr int iArr1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + +int main(int, char**) { + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 1)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 2)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 3)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 4)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 5)); + + testSpan(iArr2, 1); + testSpan(iArr2, 2); + testSpan(iArr2, 3); + testSpan(iArr2, 4); + testSpan(iArr2, 5); + + std::string s1; + constexpr static std::string s2; + testSpan(&s1, static_cast(0)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(&s2, static_cast(0))); + testSpan(&s1, 1); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(&s2, 1)); return 0; } diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/rend.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/rend.pass.cpp index ffec15c6b2492..85e43c0a0bb42 100644 --- a/libcxx/test/std/containers/views/views.span/span.iterators/rend.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.iterators/rend.pass.cpp @@ -10,7 +10,7 @@ // // constexpr reverse_iterator rend() const noexcept; -// constexpr const_reverse_iterator crend() const noexcept; +// constexpr const_reverse_iterator crend() const noexcept; // since C++23 #include #include @@ -18,90 +18,71 @@ #include "test_macros.h" -template -constexpr bool testConstexprSpan(Span s) -{ - bool ret = true; - typename Span::reverse_iterator e = s.rend(); - if (s.empty()) - { - ret = ret && (e == s.rbegin()); - } - else - { - ret = ret && (e != s.rbegin()); - } - - ret = ret && (static_cast(e - s.rbegin()) == s.size()); - return ret; -} - -template -void testRuntimeSpan(Span s) -{ - typename Span::reverse_iterator e = s.rend(); - if (s.empty()) - { - assert(e == s.rbegin()); - } - else - { - assert(e != s.rbegin()); - } - - assert(static_cast(e - s.rbegin()) == s.size()); -} - - -struct A{}; -bool operator==(A, A) {return true;} +template +constexpr bool testSpanImpl(Span s, Iter rlast) { + bool ret = true; + if (s.empty()) { + ret = ret && (rlast == s.rbegin()); + } else { + ret = ret && (rlast != s.rbegin()); + ret = ret && (rlast == std::make_reverse_iterator(s.begin())); + } -constexpr int iArr1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + ret = ret && (static_cast(rlast - s.rbegin()) == s.size()); + return ret; +} -int main(int, char**) -{ - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - static_assert(testConstexprSpan(std::span()), ""); - - static_assert(testConstexprSpan(std::span(iArr1, 1)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 2)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 3)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 4)), ""); - static_assert(testConstexprSpan(std::span(iArr1, 5)), ""); - +template +constexpr bool testSpan(Args&&... args) { + auto s1 = std::span(std::forward(args)...); + bool ret = true; - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span()); + ret = ret && testSpanImpl(s1, s1.rend()); +#if TEST_STD_VER >= 23 + ret = ret && testSpanImpl(s1, s1.crend()); +#endif - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span ()); - testRuntimeSpan(std::span()); + auto s2 = std::span(std::forward(args)...); + ret = ret && testSpanImpl(s2, s2.rend()); +#if TEST_STD_VER >= 23 + ret = ret && testSpanImpl(s2, s2.crend()); +#endif - testRuntimeSpan(std::span(iArr2, 1)); - testRuntimeSpan(std::span(iArr2, 2)); - testRuntimeSpan(std::span(iArr2, 3)); - testRuntimeSpan(std::span(iArr2, 4)); - testRuntimeSpan(std::span(iArr2, 5)); + return ret; +} - std::string s; - testRuntimeSpan(std::span(&s, (std::size_t) 0)); - testRuntimeSpan(std::span(&s, 1)); +struct A {}; +bool operator==(A, A) { return true; } + +constexpr int iArr1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + +int main(int, char**) { + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan()); + + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 1)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 2)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 3)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 4)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(iArr1, 5)); + + testSpan(iArr2, 1); + testSpan(iArr2, 2); + testSpan(iArr2, 3); + testSpan(iArr2, 4); + testSpan(iArr2, 5); + + std::string s1; + constexpr static std::string s2; + testSpan(&s1, static_cast(0)); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(&s2, static_cast(0))); + testSpan(&s1, 1); + ASSERT_RUNTIME_AND_CONSTEXPR(testSpan(&s2, 1)); return 0; } diff --git a/libcxx/test/std/iterators/const.iterators/alias.pass.cpp b/libcxx/test/std/iterators/const.iterators/alias.pass.cpp new file mode 100644 index 0000000000000..10c0665764cc8 --- /dev/null +++ b/libcxx/test/std/iterators/const.iterators/alias.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// std::const_iterator + +#include +#include +#include +#include "test_macros.h" + +ASSERT_SAME_TYPE(std::const_iterator, std::basic_const_iterator); +ASSERT_SAME_TYPE(std::const_iterator, const int*); +ASSERT_SAME_TYPE(std::const_sentinel, std::basic_const_iterator); +ASSERT_SAME_TYPE(std::const_sentinel, const int*); +ASSERT_SAME_TYPE(std::const_sentinel, std::default_sentinel_t); + +using list_iterator = std::list::iterator; +using list_const_iterator = std::list::const_iterator; + +ASSERT_SAME_TYPE(std::const_iterator, std::basic_const_iterator); +ASSERT_SAME_TYPE(std::const_iterator, list_const_iterator); +ASSERT_SAME_TYPE(std::const_sentinel, std::basic_const_iterator); +ASSERT_SAME_TYPE(std::const_sentinel, list_const_iterator); + +int main() { return 0; } diff --git a/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp b/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp new file mode 100644 index 0000000000000..9163976deb8f1 --- /dev/null +++ b/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp @@ -0,0 +1,139 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// std::basic_const_iterator + +#include +#include +#include +#include +#include "test_macros.h" +#include "test_iterators.h" +#include "type_algorithms.h" + +template +concept has_iterator_category = requires { typename T::iterator_category; }; + +template +constexpr bool check_category_and_concept() { + using ConstIt = std::basic_const_iterator; + + if constexpr (std::contiguous_iterator) { + ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::contiguous_iterator_tag); + static_assert(std::contiguous_iterator); + } else if constexpr (std::random_access_iterator) { + ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::random_access_iterator_tag); + static_assert(!std::contiguous_iterator); + static_assert(std::random_access_iterator); + } else if constexpr (std::bidirectional_iterator) { + ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::bidirectional_iterator_tag); + static_assert(!std::random_access_iterator); + static_assert(std::bidirectional_iterator); + } else if constexpr (std::forward_iterator) { + ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::forward_iterator_tag); + static_assert(!std::bidirectional_iterator); + static_assert(std::forward_iterator); + } else { + ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::input_iterator_tag); + static_assert(!std::forward_iterator); + static_assert(std::input_iterator); + } + + if constexpr (std::forward_iterator) { + ASSERT_SAME_TYPE(typename ConstIt::iterator_category, typename std::iterator_traits::iterator_category); + } else { + static_assert(!has_iterator_category); + } + + return true; +} + +constexpr bool test_p2836r1() { + auto f = [](std::vector::const_iterator) {}; + + auto v = std::vector(); + { + auto i1 = std::ranges::cbegin(v); + f(i1); + } + + auto t = v | std::views::take_while([](int const x) { return x < 100; }); + { + auto i2 = std::ranges::cbegin(t); + f(i2); + } + + return true; +} + +constexpr bool test_basic_operations() { + struct S { + int x; + }; + S arr[10] = {}; + std::basic_const_iterator first = arr; + std::basic_const_iterator last = arr + 10; + + for (auto it = first; it != last; ++it) { + (void)*it; + (void)it->x; + (void)iter_move(it); + } + static_assert(!std::is_invocable_v); + + assert(++first == arr + 1); + assert(--first == arr + 0); + assert(first++ == arr + 0); + assert(first-- == arr + 1); + + assert(first + 3 == arr + 3); + assert(last - 1 == arr + 9); + + first += 3; + assert(first == arr + 3); + first -= 2; + assert(first == arr + 1); + --first; + + assert(first < last); + assert(last > first); + assert(first <= last); + assert(last >= first); + + assert(first < arr + 1); + assert(arr + 1 > first); + assert(first <= arr + 1); + assert(arr + 1 >= first); + + assert((first <=> last) < 0); + assert((first <=> arr + 1) < 0); + assert((arr + 1 <=> first) > 0); + + return true; +} + +int main() { + types::for_each(types::cpp20_input_iterator_list{}, []() { + using ConstIt = std::basic_const_iterator; + ASSERT_SAME_TYPE(typename ConstIt::value_type, int); + static_assert(check_category_and_concept()); + + ASSERT_SAME_TYPE(std::iter_reference_t, const int&); + ASSERT_SAME_TYPE(std::iter_rvalue_reference_t, const int&&); + }); + + test_p2836r1(); + static_assert(test_p2836r1()); + + test_basic_operations(); + static_assert(test_basic_operations()); + + return 0; +} 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..74370e999acf7 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 @@ -18,7 +18,7 @@ /* Constant Value __cpp_lib_default_template_type_for_algorithm_values 202403L [C++26] __cpp_lib_ranges 202207L [C++20] - __cpp_lib_ranges_as_const 202207L [C++23] + __cpp_lib_ranges_as_const 202311L [C++23] __cpp_lib_ranges_as_rvalue 202207L [C++23] __cpp_lib_ranges_chunk 202202L [C++23] __cpp_lib_ranges_chunk_by 202202L [C++23] @@ -249,17 +249,11 @@ # error "__cpp_lib_ranges should have the value 202207L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_as_const -# error "__cpp_lib_ranges_as_const should be defined in c++23" -# endif -# if __cpp_lib_ranges_as_const != 202207L -# error "__cpp_lib_ranges_as_const should have the value 202207L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ranges_as_const -# error "__cpp_lib_ranges_as_const should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_as_const +# error "__cpp_lib_ranges_as_const should be defined in c++23" +# endif +# if __cpp_lib_ranges_as_const != 202311L +# error "__cpp_lib_ranges_as_const should have the value 202311L in c++23" # endif # ifndef __cpp_lib_ranges_as_rvalue @@ -368,17 +362,11 @@ # error "__cpp_lib_ranges should have the value 202207L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_as_const -# error "__cpp_lib_ranges_as_const should be defined in c++26" -# endif -# if __cpp_lib_ranges_as_const != 202207L -# error "__cpp_lib_ranges_as_const should have the value 202207L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ranges_as_const -# error "__cpp_lib_ranges_as_const should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_as_const +# error "__cpp_lib_ranges_as_const should be defined in c++26" +# endif +# if __cpp_lib_ranges_as_const != 202311L +# error "__cpp_lib_ranges_as_const should have the value 202311L in c++26" # endif # ifndef __cpp_lib_ranges_as_rvalue 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 b8bad696f1bae..21449752c9037 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 @@ -167,7 +167,7 @@ __cpp_lib_print 202207L [C++23] __cpp_lib_quoted_string_io 201304L [C++14] __cpp_lib_ranges 202207L [C++20] - __cpp_lib_ranges_as_const 202207L [C++23] + __cpp_lib_ranges_as_const 202311L [C++23] __cpp_lib_ranges_as_rvalue 202207L [C++23] __cpp_lib_ranges_chunk 202202L [C++23] __cpp_lib_ranges_chunk_by 202202L [C++23] @@ -5623,17 +5623,11 @@ # error "__cpp_lib_ranges should have the value 202207L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_as_const -# error "__cpp_lib_ranges_as_const should be defined in c++23" -# endif -# if __cpp_lib_ranges_as_const != 202207L -# error "__cpp_lib_ranges_as_const should have the value 202207L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ranges_as_const -# error "__cpp_lib_ranges_as_const should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_as_const +# error "__cpp_lib_ranges_as_const should be defined in c++23" +# endif +# if __cpp_lib_ranges_as_const != 202311L +# error "__cpp_lib_ranges_as_const should have the value 202311L in c++23" # endif # ifndef __cpp_lib_ranges_as_rvalue @@ -7474,17 +7468,11 @@ # error "__cpp_lib_ranges should have the value 202207L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_as_const -# error "__cpp_lib_ranges_as_const should be defined in c++26" -# endif -# if __cpp_lib_ranges_as_const != 202207L -# error "__cpp_lib_ranges_as_const should have the value 202207L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ranges_as_const -# error "__cpp_lib_ranges_as_const should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_as_const +# error "__cpp_lib_ranges_as_const should be defined in c++26" +# endif +# if __cpp_lib_ranges_as_const != 202311L +# error "__cpp_lib_ranges_as_const should have the value 202311L in c++26" # endif # ifndef __cpp_lib_ranges_as_rvalue diff --git a/libcxx/test/std/ranges/range.access/begin.pass.cpp b/libcxx/test/std/ranges/range.access/begin.pass.cpp index 5ca3d59abb140..7f2357b319a8a 100644 --- a/libcxx/test/std/ranges/range.access/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.access/begin.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // std::ranges::begin -// std::ranges::cbegin +// std::ranges::cbegin // until C++23 #include @@ -19,7 +19,9 @@ #include "test_iterators.h" using RangeBeginT = decltype(std::ranges::begin); +#if TEST_STD_VER < 23 using RangeCBeginT = decltype(std::ranges::cbegin); +#endif // TEST_STD_VER < 23 static int globalBuff[8]; @@ -27,33 +29,43 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct Incomplete; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 // This case is IFNDR; we handle it SFINAE-friendly. LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +#if TEST_STD_VER < 23 LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 // This case is IFNDR; we handle it SFINAE-friendly. LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +#if TEST_STD_VER < 23 LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct BeginMember { int x; @@ -65,45 +77,48 @@ static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 constexpr bool testReturnTypes() { - { - int *x[2]; - ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int**); - ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), int* const*); - } - { - int x[2][2]; - ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int(*)[2]); - ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), const int(*)[2]); - } - { - struct Different { - char*& begin(); - short*& begin() const; - } x; - ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), char*); - ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), short*); - } + int* a[2]; + int b[2][2]; + struct Different { + char*& begin(); + short*& begin() const; + } c; + + ASSERT_SAME_TYPE(decltype(std::ranges::begin(a)), int**); + ASSERT_SAME_TYPE(decltype(std::ranges::begin(b)), int(*)[2]); + ASSERT_SAME_TYPE(decltype(std::ranges::begin(c)), char*); + +#if TEST_STD_VER < 23 + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(a)), int* const*); + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(b)), const int(*)[2]); + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(c)), short*); +#endif // TEST_STD_VER < 23 + return true; } constexpr bool testArray() { int a[2]; - assert(std::ranges::begin(a) == a); - assert(std::ranges::cbegin(a) == a); - int b[2][2]; - assert(std::ranges::begin(b) == b); - assert(std::ranges::cbegin(b) == b); - BeginMember c[2]; + + assert(std::ranges::begin(a) == a); + assert(std::ranges::begin(b) == b); assert(std::ranges::begin(c) == c); + +#if TEST_STD_VER < 23 + assert(std::ranges::cbegin(a) == a); + assert(std::ranges::cbegin(b) == b); assert(std::ranges::cbegin(c) == c); +#endif // TEST_STD_VER < 23 return true; } @@ -136,8 +151,10 @@ struct NonConstBeginMember { }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct EnabledBorrowingBeginMember { constexpr int *begin() const { return &globalBuff[0]; } @@ -159,28 +176,28 @@ struct EmptyPtrBeginMember { constexpr bool testBeginMember() { BeginMember a; + NonConstBeginMember b; + EnabledBorrowingBeginMember c; + BeginMemberFunction d; + EmptyPtrBeginMember e; + assert(std::ranges::begin(a) == &a.x); - assert(std::ranges::cbegin(a) == &a.x); static_assert(!std::is_invocable_v); - static_assert(!std::is_invocable_v); - - NonConstBeginMember b; assert(std::ranges::begin(b) == &b.x); - static_assert(!std::is_invocable_v); - - EnabledBorrowingBeginMember c; assert(std::ranges::begin(c) == &globalBuff[0]); - assert(std::ranges::cbegin(c) == &globalBuff[0]); assert(std::ranges::begin(std::move(c)) == &globalBuff[0]); - assert(std::ranges::cbegin(std::move(c)) == &globalBuff[0]); - - BeginMemberFunction d; assert(std::ranges::begin(d) == &d.x); - assert(std::ranges::cbegin(d) == &d.x); - - EmptyPtrBeginMember e; assert(std::ranges::begin(e) == &e.x); + +#if TEST_STD_VER < 23 + assert(std::ranges::cbegin(a) == &a.x); + static_assert(!std::is_invocable_v); + static_assert(!std::is_invocable_v); + assert(std::ranges::cbegin(c) == &globalBuff[0]); + assert(std::ranges::cbegin(std::move(c)) == &globalBuff[0]); + assert(std::ranges::cbegin(d) == &d.x); assert(std::ranges::cbegin(e) == &e.x); +#endif // TEST_STD_VER < 23 return true; } @@ -193,8 +210,10 @@ struct BeginFunction { static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); // Ill-formed before P2602R2 Poison Pills are Too Toxic +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct BeginFunctionReturnsInt { friend int begin(BeginFunctionReturnsInt const&); @@ -215,7 +234,9 @@ static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct BeginFunctionEnabledBorrowing { friend constexpr int *begin(BeginFunctionEnabledBorrowing) { return &globalBuff[2]; } @@ -245,85 +266,96 @@ struct BeginFunctionWithPrivateBeginMember { constexpr bool testBeginFunction() { BeginFunction a{}; const BeginFunction aa{}; - assert(std::ranges::begin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::cbegin(a) == &a.x); - assert(std::ranges::begin(aa) == &aa.x); - assert(std::ranges::cbegin(aa) == &aa.x); - BeginFunctionByValue b{}; const BeginFunctionByValue bb{}; - assert(std::ranges::begin(b) == &globalBuff[1]); - assert(std::ranges::cbegin(b) == &globalBuff[1]); - assert(std::ranges::begin(bb) == &globalBuff[1]); - assert(std::ranges::cbegin(bb) == &globalBuff[1]); - BeginFunctionEnabledBorrowing c{}; const BeginFunctionEnabledBorrowing cc{}; - assert(std::ranges::begin(std::move(c)) == &globalBuff[2]); - assert(std::ranges::cbegin(std::move(c)) == &globalBuff[2]); - assert(std::ranges::begin(std::move(cc)) == &globalBuff[2]); - assert(std::ranges::cbegin(std::move(cc)) == &globalBuff[2]); - BeginFunctionReturnsEmptyPtr d{}; const BeginFunctionReturnsEmptyPtr dd{}; - assert(std::ranges::begin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::cbegin(d) == &d.x); - assert(std::ranges::begin(dd) == &dd.x); - assert(std::ranges::cbegin(dd) == &dd.x); - BeginFunctionWithDataMember e{}; const BeginFunctionWithDataMember ee{}; + BeginFunctionWithPrivateBeginMember f{}; + const BeginFunctionWithPrivateBeginMember ff{}; + + assert(std::ranges::begin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::begin(aa) == &aa.x); + assert(std::ranges::begin(b) == &globalBuff[1]); + assert(std::ranges::begin(bb) == &globalBuff[1]); + assert(std::ranges::begin(std::move(c)) == &globalBuff[2]); + assert(std::ranges::begin(std::move(cc)) == &globalBuff[2]); + assert(std::ranges::begin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::begin(dd) == &dd.x); assert(std::ranges::begin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::begin(ee) == &ee.x); + assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::begin(ff) == &ff.y); + +#if TEST_STD_VER < 23 + assert(std::ranges::cbegin(a) == &a.x); + assert(std::ranges::cbegin(aa) == &aa.x); + assert(std::ranges::cbegin(b) == &globalBuff[1]); + assert(std::ranges::cbegin(bb) == &globalBuff[1]); + assert(std::ranges::cbegin(std::move(c)) == &globalBuff[2]); + assert(std::ranges::cbegin(std::move(cc)) == &globalBuff[2]); + assert(std::ranges::cbegin(d) == &d.x); + assert(std::ranges::cbegin(dd) == &dd.x); assert(std::ranges::cbegin(e) == &e.x); assert(std::ranges::cbegin(ee) == &ee.x); - - BeginFunctionWithPrivateBeginMember f{}; - const BeginFunctionWithPrivateBeginMember ff{}; - assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cbegin(f) == &f.y); - assert(std::ranges::begin(ff) == &ff.y); assert(std::ranges::cbegin(ff) == &ff.y); +#endif // TEST_STD_VER < 23 return true; } ASSERT_NOEXCEPT(std::ranges::begin(std::declval())); +#if TEST_STD_VER < 23 ASSERT_NOEXCEPT(std::ranges::cbegin(std::declval())); +#endif // TEST_STD_VER < 23 struct NoThrowMemberBegin { ThrowingIterator begin() const noexcept; // auto(t.begin()) doesn't throw } ntmb; static_assert(noexcept(std::ranges::begin(ntmb))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::cbegin(ntmb))); +#endif // TEST_STD_VER < 23 struct NoThrowADLBegin { friend ThrowingIterator begin(NoThrowADLBegin&) noexcept; // auto(begin(t)) doesn't throw friend ThrowingIterator begin(const NoThrowADLBegin&) noexcept; } ntab; static_assert(noexcept(std::ranges::begin(ntab))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::cbegin(ntab))); +#endif // TEST_STD_VER < 23 struct NoThrowMemberBeginReturnsRef { ThrowingIterator& begin() const noexcept; // auto(t.begin()) may throw } ntmbrr; static_assert(!noexcept(std::ranges::begin(ntmbrr))); +#if TEST_STD_VER < 23 static_assert(!noexcept(std::ranges::cbegin(ntmbrr))); +#endif // TEST_STD_VER < 23 struct BeginReturnsArrayRef { auto begin() const noexcept -> int(&)[10]; } brar; static_assert(noexcept(std::ranges::begin(brar))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::cbegin(brar))); +#endif // TEST_STD_VER < 23 // Test ADL-proofing. struct Incomplete; template struct Holder { T t; }; static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); +#endif // TEST_STD_VER < 23 int main(int, char**) { static_assert(testReturnTypes()); diff --git a/libcxx/test/std/ranges/range.access/cbegin.pass.cpp b/libcxx/test/std/ranges/range.access/cbegin.pass.cpp new file mode 100644 index 0000000000000..a2da7cdf3b6d3 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/cbegin.pass.cpp @@ -0,0 +1,207 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// std::ranges::cbegin +// std::ranges::crbegin + +#include + +#include +#include +#include "almost_satisfies_types.h" +#include "test_macros.h" +#include "test_iterators.h" + +using RangeCBeginT = decltype(std::ranges::cbegin); +using RangeCRBeginT = decltype(std::ranges::crbegin); + +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +struct Incomplete; + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +// This case is IFNDR; we handle it SFINAE-friendly. +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); + +// This case is IFNDR; we handle it SFINAE-friendly. +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); + +struct NonborrowingRange { + int x; + constexpr const int* begin() const { return &x; } + constexpr const int* rbegin() const { return &x; } + constexpr const int* end() const { return &x; } + constexpr const int* rend() const { return &x; } +}; + +// Ensure that we can't call with rvalues with borrowing disabled. +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); + +constexpr bool testReturnTypes() { + int* a[2]; + int b[2][2]; + struct PossiblyConstRange { + char*& begin(); + char*& end(); + const short*& begin() const; + const short*& end() const; + int*& rbegin(); + int*& rend(); + const long*& rbegin() const; + const long*& rend() const; + } c; + struct AlwaysConstRange { + const char*& begin(); + const char*& end(); + const short*& begin() const; + const short*& end() const; + const int*& rbegin(); + const int*& rend(); + const long*& rbegin() const; + const long*& rend() const; + } d; + struct NeverConstRange { + char*& begin(); + char*& end(); + short*& begin() const; + short& end() const; + int*& rbegin(); + int*& rend(); + long*& rbegin() const; + long*& rend() const; + } e; + + static_assert(!std::ranges::constant_range); + static_assert(std::ranges::constant_range); + static_assert(std::ranges::constant_range); + static_assert(std::ranges::constant_range); + static_assert(!std::ranges::constant_range); + static_assert(!std::ranges::constant_range); + + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(a)), int* const*); + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(b)), const int(*)[2]); + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(c)), const short*); + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(d)), const char*); + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(e)), std::basic_const_iterator); + + ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(a)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(b)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(c)), const long*); + ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(d)), const int*); + ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(e)), std::basic_const_iterator); + + return true; +} + +constexpr bool testArray() { + int a[2]; + int b[2][2]; + NonborrowingRange c[2]; + + assert(std::ranges::cbegin(a) == a); + assert(std::ranges::cbegin(b) == b); + assert(std::ranges::cbegin(c) == c); + + assert(std::ranges::crbegin(a).base() == a + 2); + assert(std::ranges::crbegin(b).base() == b + 2); + assert(std::ranges::crbegin(c).base() == c + 2); + + return true; +} + +struct BorrowingRange { + int* begin() const; + int* end() const; +}; +template <> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); + +struct NoThrowBeginThrowingEnd { + const int* begin() const noexcept; + const int* end() const; +} ntbte; +static_assert(noexcept(std::ranges::cbegin(ntbte))); +static_assert(!noexcept(std::ranges::crbegin(ntbte))); + +struct ThrowingBeginNoThrowEnd { + const int* begin() const; + const int* end() const noexcept; +} tbnte; +static_assert(!noexcept(std::ranges::cbegin(tbnte))); +static_assert(noexcept(std::ranges::crbegin(tbnte))); + +// Test ADL-proofing. +struct Incomplete; +template +struct Holder { + T t; +}; +static_assert(!std::is_invocable_v*>); +static_assert(!std::is_invocable_v*&>); +static_assert(!std::is_invocable_v*>); +static_assert(!std::is_invocable_v*&>); + +int main(int, char**) { + static_assert(testReturnTypes()); + + testArray(); + static_assert(testArray()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.access/cbegin.verify.cpp b/libcxx/test/std/ranges/range.access/cbegin.verify.cpp new file mode 100644 index 0000000000000..18ac8ae65e338 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/cbegin.verify.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// std::ranges::cbegin + +#include + +struct NonBorrowedRange { + int* begin() const; + int* end() const; +}; +static_assert(!std::ranges::enable_borrowed_range); + +// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::cbegin` is ill-formed. +void test() { + std::ranges::cbegin(NonBorrowedRange()); + // expected-error-re@-1 {{{{no matching function for call to object of type 'const (std::ranges::)?__cbegin::__fn'}}}} +} diff --git a/libcxx/test/std/ranges/range.access/cend.pass.cpp b/libcxx/test/std/ranges/range.access/cend.pass.cpp new file mode 100644 index 0000000000000..86cb8ac160eb3 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/cend.pass.cpp @@ -0,0 +1,207 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// std::ranges::cend +// std::ranges::crend + +#include + +#include +#include +#include "almost_satisfies_types.h" +#include "test_macros.h" +#include "test_iterators.h" + +using RangeCEndT = decltype(std::ranges::cend); +using RangeCREndT = decltype(std::ranges::crend); + +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +struct Incomplete; + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +// This case is IFNDR; we handle it SFINAE-friendly. +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); + +// This case is IFNDR; we handle it SFINAE-friendly. +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +LIBCPP_STATIC_ASSERT(!std::is_invocable_v); + +struct NonborrowingRange { + int x; + constexpr const int* begin() const { return &x; } + constexpr const int* rbegin() const { return &x; } + constexpr const int* end() const { return &x; } + constexpr const int* rend() const { return &x; } +}; + +// Ensure that we can't call with rvalues with borrowing disabled. +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); + +constexpr bool testReturnTypes() { + int* a[2]; + int b[2][2]; + struct PossiblyConstRange { + char*& begin(); + char*& end(); + const short*& begin() const; + const short*& end() const; + int*& rbegin(); + int*& rend(); + const long*& rbegin() const; + const long*& rend() const; + } c; + struct AlwaysConstRange { + const char*& begin(); + const char*& end(); + const short*& begin() const; + const short*& end() const; + const int*& rbegin(); + const int*& rend(); + const long*& rbegin() const; + const long*& rend() const; + } d; + struct NeverConstRange { + char*& begin(); + char*& end(); + short*& begin() const; + short& end() const; + int*& rbegin(); + int*& rend(); + long*& rbegin() const; + long*& rend() const; + } e; + + static_assert(!std::ranges::constant_range); + static_assert(std::ranges::constant_range); + static_assert(std::ranges::constant_range); + static_assert(std::ranges::constant_range); + static_assert(!std::ranges::constant_range); + static_assert(!std::ranges::constant_range); + + ASSERT_SAME_TYPE(decltype(std::ranges::cend(a)), int* const*); + ASSERT_SAME_TYPE(decltype(std::ranges::cend(b)), const int(*)[2]); + ASSERT_SAME_TYPE(decltype(std::ranges::cend(c)), const short*); + ASSERT_SAME_TYPE(decltype(std::ranges::cend(d)), const char*); + ASSERT_SAME_TYPE(decltype(std::ranges::cend(e)), std::basic_const_iterator); + + ASSERT_SAME_TYPE(decltype(std::ranges::crend(a)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::crend(b)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::crend(c)), const long*); + ASSERT_SAME_TYPE(decltype(std::ranges::crend(d)), const int*); + ASSERT_SAME_TYPE(decltype(std::ranges::crend(e)), std::basic_const_iterator); + + return true; +} + +constexpr bool testArray() { + int a[2]; + int b[2][2]; + NonborrowingRange c[2]; + + assert(std::ranges::cend(a) == a + 2); + assert(std::ranges::cend(b) == b + 2); + assert(std::ranges::cend(c) == c + 2); + + assert(std::ranges::crend(a).base() == a); + assert(std::ranges::crend(b).base() == b); + assert(std::ranges::crend(c).base() == c); + + return true; +} + +struct BorrowingRange { + int* begin() const; + int* end() const; +}; +template <> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); + +struct NoThrowEndThrowingEnd { + const int* begin() const noexcept; + const int* end() const; +} ntbte; +static_assert(!noexcept(std::ranges::cend(ntbte))); +static_assert(noexcept(std::ranges::crend(ntbte))); + +struct ThrowingEndNoThrowEnd { + const int* begin() const; + const int* end() const noexcept; +} tbnte; +static_assert(noexcept(std::ranges::cend(tbnte))); +static_assert(!noexcept(std::ranges::crend(tbnte))); + +// Test ADL-proofing. +struct Incomplete; +template +struct Holder { + T t; +}; +static_assert(!std::is_invocable_v*>); +static_assert(!std::is_invocable_v*&>); +static_assert(!std::is_invocable_v*>); +static_assert(!std::is_invocable_v*&>); + +int main(int, char**) { + static_assert(testReturnTypes()); + + testArray(); + static_assert(testArray()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.access/cend.verify.cpp b/libcxx/test/std/ranges/range.access/cend.verify.cpp new file mode 100644 index 0000000000000..e50b90b4fbd49 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/cend.verify.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// std::ranges::cend + +#include + +struct NonBorrowedRange { + int* begin() const; + int* end() const; +}; +static_assert(!std::ranges::enable_borrowed_range); + +// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::cend` is ill-formed. +void test() { + std::ranges::cend(NonBorrowedRange()); + // expected-error-re@-1 {{{{no matching function for call to object of type 'const (std::ranges::)?__cend::__fn'}}}} +} diff --git a/libcxx/test/std/ranges/range.access/data.pass.cpp b/libcxx/test/std/ranges/range.access/data.pass.cpp index 357e52a146275..03bbaf0b1ca0f 100644 --- a/libcxx/test/std/ranges/range.access/data.pass.cpp +++ b/libcxx/test/std/ranges/range.access/data.pass.cpp @@ -9,6 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // std::ranges::data +// std::ranges::cdata #include @@ -20,6 +21,14 @@ using RangeDataT = decltype(std::ranges::data); using RangeCDataT = decltype(std::ranges::cdata); +#if TEST_STD_VER < 23 +# define STD_VER_20(...) __VA_ARGS__ +# define STD_VER_23(...) static_assert(true) +#else +# define STD_VER_20(...) static_assert(true) +# define STD_VER_23(...) __VA_ARGS__ +#endif + static int globalBuff[2]; struct Incomplete; @@ -38,9 +47,26 @@ static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +struct DataMemberNonRange { + int x; + constexpr const int* data() const { return &x; } +}; +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +#endif + struct DataMember { int x; constexpr const int *data() const { return &x; } + const int* begin() const; + const int* end() const; }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); @@ -66,16 +92,51 @@ constexpr bool testReturnTypes() { struct D { char*& data(); short*& data() const; + int* begin(); + int* end(); }; ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval())), char*); static_assert(!std::is_invocable_v); ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval())), short*); static_assert(!std::is_invocable_v); - ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), short*); + + static_assert(!std::is_invocable_v); + static_assert(!std::is_invocable_v); + STD_VER_20(ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), short*)); + STD_VER_23(ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), const char*)); + STD_VER_20(ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), short*)); + STD_VER_23(static_assert(!std::is_invocable_v)); + } +#if TEST_STD_VER >= 23 + { + struct D { + char*& data(); + short*& data() const; + int* begin(); + int* end(); + int* begin() const; + int* end() const; + }; + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), const char*); + static_assert(!std::is_invocable_v); + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), const short*); + static_assert(!std::is_invocable_v); + } + { + struct D { + char*& data(); + short*& data() const; + int* begin(); + int* end(); + const int* begin() const; + const int* end() const; + }; + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), const short*); static_assert(!std::is_invocable_v); - ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), short*); + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), const short*); static_assert(!std::is_invocable_v); } +#endif // TEST_STD_VER >= 23 { struct NC { char *begin() const; @@ -88,10 +149,16 @@ constexpr bool testReturnTypes() { static_assert(!std::is_invocable_v); ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval())), char*); static_assert(!std::is_invocable_v); - ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), char*); + static_assert(!std::is_invocable_v); - ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), char*); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), char*); + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), char*); +#else + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), const int*); + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), const char*); +#endif } return true; } @@ -121,10 +188,14 @@ static_assert(!std::is_invocable_v struct NonConstDataMember { int x; constexpr int *data() { return &x; } + int* begin(); + int* end(); }; struct EnabledBorrowingDataMember { constexpr int *data() { return &globalBuff[0]; } + int* begin(); + int* end(); }; template<> inline constexpr bool std::ranges::enable_borrowed_range = true; @@ -133,6 +204,7 @@ struct DataMemberAndBegin { int x; constexpr const int *data() const { return &x; } const int *begin() const; + const int* end() const; }; constexpr bool testDataMember() { @@ -142,15 +214,13 @@ constexpr bool testDataMember() { NonConstDataMember b; assert(std::ranges::data(b) == &b.x); - static_assert(!std::is_invocable_v); + STD_VER_20(static_assert(!std::is_invocable_v)); + STD_VER_23(assert(std::ranges::cdata(b) == &b.x)); EnabledBorrowingDataMember c; assert(std::ranges::data(std::move(c)) == &globalBuff[0]); - static_assert(!std::is_invocable_v); - - DataMemberAndBegin d; - assert(std::ranges::data(d) == &d.x); - assert(std::ranges::cdata(d) == &d.x); + STD_VER_20(static_assert(!std::is_invocable_v)); + STD_VER_23(assert(std::ranges::data(c) == &globalBuff[0])); return true; } @@ -161,6 +231,7 @@ struct BeginMemberContiguousIterator { int buff[8]; constexpr ContiguousIter begin() const { return ContiguousIter(buff); } + constexpr ContiguousIter end() const { return ContiguousIter(buff); } }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); @@ -175,6 +246,7 @@ struct BeginMemberRandomAccess { int buff[8]; random_access_iterator begin() const; + random_access_iterator end() const; }; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); @@ -191,6 +263,7 @@ struct BeginFriendContiguousIterator { friend constexpr ContiguousIter begin(const BeginFriendContiguousIterator &iter) { return ContiguousIter(iter.buff); } + friend constexpr ContiguousIter end(const BeginFriendContiguousIterator& iter) { return ContiguousIter(iter.buff); } }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); @@ -202,7 +275,8 @@ static_assert( std::is_invocable_v); struct BeginFriendRandomAccess { - friend random_access_iterator begin(const BeginFriendRandomAccess iter); + friend random_access_iterator begin(const BeginFriendRandomAccess& iter); + friend random_access_iterator end(const BeginFriendRandomAccess& iter); }; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); @@ -217,6 +291,7 @@ struct BeginMemberRvalue { int buff[8]; ContiguousIter begin() &&; + ContiguousIter end() &&; }; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); @@ -229,6 +304,7 @@ static_assert(!std::is_invocable_v); struct BeginMemberBorrowingEnabled { constexpr contiguous_iterator begin() { return contiguous_iterator{&globalBuff[1]}; } + constexpr contiguous_iterator end() { return contiguous_iterator{&globalBuff[2]}; } }; template<> inline constexpr bool std::ranges::enable_borrowed_range = true; @@ -236,11 +312,28 @@ static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); +STD_VER_20(static_assert(!std::is_invocable_v)); +STD_VER_23(static_assert(std::is_invocable_v)); +STD_VER_20(static_assert(!std::is_invocable_v)); +STD_VER_23(static_assert(std::is_invocable_v)); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +struct ConstBeginMemberBorrowingEnabled { + constexpr contiguous_iterator begin() const { return contiguous_iterator{&globalBuff[1]}; } + constexpr contiguous_iterator end() const { return contiguous_iterator{&globalBuff[2]}; } +}; +template <> +inline constexpr bool std::ranges::enable_borrowed_range = true; +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); + constexpr bool testViaRangesBegin() { int arr[2]; assert(std::ranges::data(arr) == arr + 0); @@ -256,7 +349,12 @@ constexpr bool testViaRangesBegin() { BeginMemberBorrowingEnabled c; assert(std::ranges::data(std::move(c)) == &globalBuff[1]); - static_assert(!std::is_invocable_v); + STD_VER_20(static_assert(!std::is_invocable_v)); + STD_VER_23(static_assert(std::is_invocable_v)); + + ConstBeginMemberBorrowingEnabled d; + assert(std::ranges::data(std::move(d)) == &globalBuff[1]); + assert(std::ranges::cdata(std::move(d)) == &globalBuff[1]); return true; } diff --git a/libcxx/test/std/ranges/range.access/end.pass.cpp b/libcxx/test/std/ranges/range.access/end.pass.cpp index 3e465b357e985..3197634c2d97f 100644 --- a/libcxx/test/std/ranges/range.access/end.pass.cpp +++ b/libcxx/test/std/ranges/range.access/end.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // std::ranges::end -// std::ranges::cend +// std::ranges::cend // until C++23 #include @@ -19,7 +19,9 @@ #include "test_iterators.h" using RangeEndT = decltype(std::ranges::end); +#if TEST_STD_VER < 23 using RangeCEndT = decltype(std::ranges::cend); +#endif // TEST_STD_VER < 23 static int globalBuff[8]; @@ -27,16 +29,20 @@ static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct Incomplete; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct EndMember { int x; @@ -49,47 +55,50 @@ static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 constexpr bool testReturnTypes() { - { - int *x[2]; - ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int**); - ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), int* const*); - } - { - int x[2][2]; - ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int(*)[2]); - ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), const int(*)[2]); - } - { - struct Different { - char *begin(); - sentinel_wrapper& end(); - short *begin() const; - sentinel_wrapper& end() const; - } x; - ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), sentinel_wrapper); - ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), sentinel_wrapper); - } + int* a[2]; + int b[2][2]; + struct Different { + char* begin(); + sentinel_wrapper& end(); + short* begin() const; + sentinel_wrapper& end() const; + } c; + + ASSERT_SAME_TYPE(decltype(std::ranges::end(a)), int**); + ASSERT_SAME_TYPE(decltype(std::ranges::end(b)), int(*)[2]); + ASSERT_SAME_TYPE(decltype(std::ranges::end(c)), sentinel_wrapper); + +#if TEST_STD_VER < 23 + ASSERT_SAME_TYPE(decltype(std::ranges::cend(a)), int* const*); + ASSERT_SAME_TYPE(decltype(std::ranges::cend(b)), const int(*)[2]); + ASSERT_SAME_TYPE(decltype(std::ranges::cend(c)), sentinel_wrapper); +#endif // TEST_STD_VER < 23 + return true; } constexpr bool testArray() { int a[2]; - assert(std::ranges::end(a) == a + 2); - assert(std::ranges::cend(a) == a + 2); - int b[2][2]; - assert(std::ranges::end(b) == b + 2); - assert(std::ranges::cend(b) == b + 2); - EndMember c[2]; + + assert(std::ranges::end(a) == a + 2); + assert(std::ranges::end(b) == b + 2); assert(std::ranges::end(c) == c + 2); + +#if TEST_STD_VER < 23 + assert(std::ranges::cend(a) == a + 2); + assert(std::ranges::cend(b) == b + 2); assert(std::ranges::cend(c) == c + 2); +#endif // TEST_STD_VER < 23 return true; } @@ -127,8 +136,10 @@ struct NonConstEndMember { }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct EnabledBorrowingEndMember { constexpr int *begin() const { return nullptr; } @@ -160,24 +171,24 @@ struct EmptyPtrEndMember { constexpr bool testEndMember() { EndMember a; - assert(std::ranges::end(a) == &a.x); - assert(std::ranges::cend(a) == &a.x); - NonConstEndMember b; - assert(std::ranges::end(b) == &b.x); - static_assert(!std::is_invocable_v); - EnabledBorrowingEndMember c; - assert(std::ranges::end(std::move(c)) == &globalBuff[0]); - assert(std::ranges::cend(std::move(c)) == &globalBuff[0]); - EndMemberFunction d; - assert(std::ranges::end(d) == &d.x); - assert(std::ranges::cend(d) == &d.x); - EmptyPtrEndMember e; + + assert(std::ranges::end(a) == &a.x); + assert(std::ranges::end(b) == &b.x); + assert(std::ranges::end(std::move(c)) == &globalBuff[0]); + assert(std::ranges::end(d) == &d.x); assert(std::ranges::end(e) == &e.x); + +#if TEST_STD_VER < 23 + assert(std::ranges::cend(a) == &a.x); + static_assert(!std::is_invocable_v); + assert(std::ranges::cend(std::move(c)) == &globalBuff[0]); + assert(std::ranges::cend(d) == &d.x); assert(std::ranges::cend(e) == &e.x); +#endif // TEST_STD_VER < 23 return true; } @@ -194,8 +205,10 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); // Ill-formed before P2602R2 Poison Pills are Too Toxic +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct EndFunctionReturnsInt { friend constexpr int begin(EndFunctionReturnsInt const&); @@ -230,7 +243,9 @@ struct EndFunctionByValue { friend constexpr int *begin(EndFunctionByValue) { return nullptr; } friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; } }; +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct EndFunctionEnabledBorrowing { friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; } @@ -268,61 +283,63 @@ struct BeginMemberEndFunction { constexpr bool testEndFunction() { const EndFunction a{}; - assert(std::ranges::end(a) == &a.x); - assert(std::ranges::cend(a) == &a.x); EndFunction aa{}; - assert(std::ranges::end(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::cend(aa) == &aa.x); - EndFunctionByValue b; - assert(std::ranges::end(b) == &globalBuff[1]); - assert(std::ranges::cend(b) == &globalBuff[1]); - EndFunctionEnabledBorrowing c; - assert(std::ranges::end(std::move(c)) == &globalBuff[2]); - assert(std::ranges::cend(std::move(c)) == &globalBuff[2]); - const EndFunctionReturnsEmptyPtr d{}; - assert(std::ranges::end(d) == &d.x); - assert(std::ranges::cend(d) == &d.x); EndFunctionReturnsEmptyPtr dd{}; - assert(std::ranges::end(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::cend(dd) == &dd.x); - const EndFunctionWithDataMember e{}; - assert(std::ranges::end(e) == &e.x); - assert(std::ranges::cend(e) == &e.x); EndFunctionWithDataMember ee{}; - assert(std::ranges::end(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::cend(ee) == &ee.x); - const EndFunctionWithPrivateEndMember f{}; - assert(std::ranges::end(f) == &f.y); - assert(std::ranges::cend(f) == &f.y); EndFunctionWithPrivateEndMember ff{}; - assert(std::ranges::end(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::cend(ff) == &ff.y); - const BeginMemberEndFunction g{}; - assert(std::ranges::end(g) == &g.x); - assert(std::ranges::cend(g) == &g.x); BeginMemberEndFunction gg{}; + + assert(std::ranges::end(a) == &a.x); + assert(std::ranges::end(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::end(b) == &globalBuff[1]); + assert(std::ranges::end(std::move(c)) == &globalBuff[2]); + assert(std::ranges::end(d) == &d.x); + assert(std::ranges::end(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::end(e) == &e.x); + assert(std::ranges::end(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::end(f) == &f.y); + assert(std::ranges::end(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::end(g) == &g.x); assert(std::ranges::end(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + +#if TEST_STD_VER < 23 + assert(std::ranges::cend(a) == &a.x); + assert(std::ranges::cend(aa) == &aa.x); + assert(std::ranges::cend(b) == &globalBuff[1]); + assert(std::ranges::cend(std::move(c)) == &globalBuff[2]); + assert(std::ranges::cend(d) == &d.x); + assert(std::ranges::cend(dd) == &dd.x); + assert(std::ranges::cend(e) == &e.x); + assert(std::ranges::cend(ee) == &ee.x); + assert(std::ranges::cend(f) == &f.y); + assert(std::ranges::cend(ff) == &ff.y); + assert(std::ranges::cend(g) == &g.x); assert(std::ranges::cend(gg) == &gg.x); +#endif // TEST_STD_VER < 23 return true; } ASSERT_NOEXCEPT(std::ranges::end(std::declval())); +#if TEST_STD_VER < 23 ASSERT_NOEXCEPT(std::ranges::cend(std::declval())); +#endif // TEST_STD_VER < 23 struct NoThrowMemberEnd { ThrowingIterator begin() const; ThrowingIterator end() const noexcept; // auto(t.end()) doesn't throw } ntme; static_assert(noexcept(std::ranges::end(ntme))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::cend(ntme))); +#endif // TEST_STD_VER < 23 struct NoThrowADLEnd { ThrowingIterator begin() const; @@ -330,29 +347,37 @@ struct NoThrowADLEnd { friend ThrowingIterator end(const NoThrowADLEnd&) noexcept; } ntae; static_assert(noexcept(std::ranges::end(ntae))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::cend(ntae))); +#endif // TEST_STD_VER < 23 struct NoThrowMemberEndReturnsRef { ThrowingIterator begin() const; ThrowingIterator& end() const noexcept; // auto(t.end()) may throw } ntmerr; static_assert(!noexcept(std::ranges::end(ntmerr))); +#if TEST_STD_VER < 23 static_assert(!noexcept(std::ranges::cend(ntmerr))); +#endif // TEST_STD_VER < 23 struct EndReturnsArrayRef { auto begin() const noexcept -> int(&)[10]; auto end() const noexcept -> int(&)[10]; } erar; static_assert(noexcept(std::ranges::end(erar))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::cend(erar))); +#endif // TEST_STD_VER < 23 // Test ADL-proofing. struct Incomplete; template struct Holder { T t; }; static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); +#endif // TEST_STD_VER < 23 int main(int, char**) { static_assert(testReturnTypes()); diff --git a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp index 3997f38efd029..7919b84d2b35a 100644 --- a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp +++ b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // std::ranges::rbegin -// std::ranges::crbegin +// std::ranges::crbegin // until C++23 #include @@ -19,7 +19,9 @@ #include "test_iterators.h" using RangeRBeginT = decltype(std::ranges::rbegin); +#if TEST_STD_VER < 23 using RangeCRBeginT = decltype(std::ranges::crbegin); +#endif // TEST_STD_VER < 23 static int globalBuff[8]; @@ -27,34 +29,42 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct Incomplete; static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); - +static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); + +#if TEST_STD_VER < 23 +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 // This case is IFNDR; we handle it SFINAE-friendly. LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +#if TEST_STD_VER < 23 LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 // This case is IFNDR; we handle it SFINAE-friendly. LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +#if TEST_STD_VER < 23 LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct RBeginMember { int x; @@ -66,45 +76,48 @@ static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 constexpr bool testReturnTypes() { - { - int *x[2]; - ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator); - ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator); - } - { - int x[2][2]; - ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator); - ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator); - } - { - struct Different { - char*& rbegin(); - short*& rbegin() const; - } x; - ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), char*); - ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), short*); - } + int* a[2]; + int b[2][2]; + struct Different { + char*& rbegin(); + short*& rbegin() const; + } c; + + ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(a)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(b)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(c)), char*); + +#if TEST_STD_VER < 23 + ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(a)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(b)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(c)), short*); +#endif // TEST_STD_VER < 23 + return true; } constexpr bool testArray() { int a[2]; - assert(std::ranges::rbegin(a).base() == a + 2); - assert(std::ranges::crbegin(a).base() == a + 2); - int b[2][2]; - assert(std::ranges::rbegin(b).base() == b + 2); - assert(std::ranges::crbegin(b).base() == b + 2); - RBeginMember c[2]; + + assert(std::ranges::rbegin(a).base() == a + 2); + assert(std::ranges::rbegin(b).base() == b + 2); assert(std::ranges::rbegin(c).base() == c + 2); + +#if TEST_STD_VER < 23 + assert(std::ranges::crbegin(a).base() == a + 2); + assert(std::ranges::crbegin(b).base() == b + 2); assert(std::ranges::crbegin(c).base() == c + 2); +#endif // TEST_STD_VER < 23 return true; } @@ -131,8 +144,10 @@ struct NonConstRBeginMember { }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct EnabledBorrowingRBeginMember { constexpr int *rbegin() const { return globalBuff; } @@ -154,28 +169,28 @@ struct EmptyPtrRBeginMember { constexpr bool testRBeginMember() { RBeginMember a; + NonConstRBeginMember b; + EnabledBorrowingRBeginMember c; + RBeginMemberFunction d; + EmptyPtrRBeginMember e; + assert(std::ranges::rbegin(a) == &a.x); - assert(std::ranges::crbegin(a) == &a.x); static_assert(!std::is_invocable_v); - static_assert(!std::is_invocable_v); - - NonConstRBeginMember b; assert(std::ranges::rbegin(b) == &b.x); - static_assert(!std::is_invocable_v); - - EnabledBorrowingRBeginMember c; assert(std::ranges::rbegin(c) == globalBuff); - assert(std::ranges::crbegin(c) == globalBuff); assert(std::ranges::rbegin(std::move(c)) == globalBuff); - assert(std::ranges::crbegin(std::move(c)) == globalBuff); - - RBeginMemberFunction d; assert(std::ranges::rbegin(d) == &d.x); - assert(std::ranges::crbegin(d) == &d.x); - - EmptyPtrRBeginMember e; assert(std::ranges::rbegin(e) == &e.x); + +#if TEST_STD_VER < 23 + assert(std::ranges::crbegin(a) == &a.x); + static_assert(!std::is_invocable_v); + static_assert(!std::is_invocable_v); + assert(std::ranges::crbegin(c) == globalBuff); + assert(std::ranges::crbegin(std::move(c)) == globalBuff); + assert(std::ranges::crbegin(d) == &d.x); assert(std::ranges::crbegin(e) == &e.x); +#endif // TEST_STD_VER < 23 return true; } @@ -189,8 +204,10 @@ static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); // Ill-formed before P2602R2 Poison Pills are Too Toxic +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct RBeginFunctionReturnsInt { friend int rbegin(RBeginFunctionReturnsInt const&); @@ -217,7 +234,9 @@ static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct RBeginFunctionEnabledBorrowing { friend constexpr int *rbegin(RBeginFunctionEnabledBorrowing) { return globalBuff + 2; } @@ -247,45 +266,44 @@ struct RBeginFunctionWithPrivateBeginMember { constexpr bool testRBeginFunction() { RBeginFunction a{}; const RBeginFunction aa{}; - assert(std::ranges::rbegin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::crbegin(a) == &a.x); - assert(std::ranges::rbegin(aa) == &aa.x); - assert(std::ranges::crbegin(aa) == &aa.x); - RBeginFunctionByValue b{}; const RBeginFunctionByValue bb{}; - assert(std::ranges::rbegin(b) == globalBuff + 1); - assert(std::ranges::crbegin(b) == globalBuff + 1); - assert(std::ranges::rbegin(bb) == globalBuff + 1); - assert(std::ranges::crbegin(bb) == globalBuff + 1); - RBeginFunctionEnabledBorrowing c{}; const RBeginFunctionEnabledBorrowing cc{}; - assert(std::ranges::rbegin(std::move(c)) == globalBuff + 2); - assert(std::ranges::crbegin(std::move(c)) == globalBuff + 2); - assert(std::ranges::rbegin(std::move(cc)) == globalBuff + 2); - assert(std::ranges::crbegin(std::move(cc)) == globalBuff + 2); - RBeginFunctionReturnsEmptyPtr d{}; const RBeginFunctionReturnsEmptyPtr dd{}; - assert(std::ranges::rbegin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::crbegin(d) == &d.x); - assert(std::ranges::rbegin(dd) == &dd.x); - assert(std::ranges::crbegin(dd) == &dd.x); - RBeginFunctionWithDataMember e{}; const RBeginFunctionWithDataMember ee{}; + RBeginFunctionWithPrivateBeginMember f{}; + const RBeginFunctionWithPrivateBeginMember ff{}; + + assert(std::ranges::rbegin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::rbegin(aa) == &aa.x); + assert(std::ranges::rbegin(b) == globalBuff + 1); + assert(std::ranges::rbegin(bb) == globalBuff + 1); + assert(std::ranges::rbegin(std::move(c)) == globalBuff + 2); + assert(std::ranges::rbegin(std::move(cc)) == globalBuff + 2); + assert(std::ranges::rbegin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::rbegin(dd) == &dd.x); assert(std::ranges::rbegin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::rbegin(ee) == &ee.x); + assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::rbegin(ff) == &ff.y); + +#if TEST_STD_VER < 23 + assert(std::ranges::crbegin(a) == &a.x); + assert(std::ranges::crbegin(aa) == &aa.x); + assert(std::ranges::crbegin(b) == globalBuff + 1); + assert(std::ranges::crbegin(bb) == globalBuff + 1); + assert(std::ranges::crbegin(std::move(c)) == globalBuff + 2); + assert(std::ranges::crbegin(std::move(cc)) == globalBuff + 2); + assert(std::ranges::crbegin(d) == &d.x); + assert(std::ranges::crbegin(dd) == &dd.x); assert(std::ranges::crbegin(e) == &e.x); assert(std::ranges::crbegin(ee) == &ee.x); - - RBeginFunctionWithPrivateBeginMember f{}; - const RBeginFunctionWithPrivateBeginMember ff{}; - assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::crbegin(f) == &f.y); - assert(std::ranges::rbegin(ff) == &ff.y); assert(std::ranges::crbegin(ff) == &ff.y); +#endif // TEST_STD_VER < 23 return true; } @@ -301,7 +319,9 @@ struct MemberBeginEnd { }; static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionBeginEnd { int b, e; @@ -319,7 +339,9 @@ struct FunctionBeginEnd { }; static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct MemberBeginFunctionEnd { int b, e; @@ -335,7 +357,9 @@ struct MemberBeginFunctionEnd { }; static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionBeginMemberEnd { int b, e; @@ -351,59 +375,77 @@ struct FunctionBeginMemberEnd { }; static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct MemberBeginEndDifferentTypes { bidirectional_iterator begin(); bidirectional_iterator end(); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionBeginEndDifferentTypes { friend bidirectional_iterator begin(FunctionBeginEndDifferentTypes&); friend bidirectional_iterator end(FunctionBeginEndDifferentTypes&); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct MemberBeginEndForwardIterators { forward_iterator begin(); forward_iterator end(); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionBeginEndForwardIterators { friend forward_iterator begin(FunctionBeginEndForwardIterators&); friend forward_iterator end(FunctionBeginEndForwardIterators&); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct MemberBeginOnly { bidirectional_iterator begin() const; }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionBeginOnly { friend bidirectional_iterator begin(FunctionBeginOnly&); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct MemberEndOnly { bidirectional_iterator end() const; }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionEndOnly { friend bidirectional_iterator end(FunctionEndOnly&); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 // Make sure there is no clash between the following cases: // - the case that handles classes defining member `rbegin` and `rend` functions; @@ -414,93 +456,112 @@ struct MemberBeginAndRBegin { int* rbegin() const; int* rend() const; }; -static_assert( std::is_invocable_v); -static_assert( std::is_invocable_v); +static_assert(std::is_invocable_v); static_assert( std::same_as, int*>); +#if TEST_STD_VER < 23 +static_assert(std::is_invocable_v); static_assert( std::same_as, int*>); +#endif // TEST_STD_VER < 23 constexpr bool testBeginEnd() { MemberBeginEnd a{}; const MemberBeginEnd aa{}; - assert(base(std::ranges::rbegin(a).base()) == &a.e); - assert(base(std::ranges::crbegin(a).base()) == &a.ce); - assert(base(std::ranges::rbegin(aa).base()) == &aa.ce); - assert(base(std::ranges::crbegin(aa).base()) == &aa.ce); - FunctionBeginEnd b{}; const FunctionBeginEnd bb{}; - assert(base(std::ranges::rbegin(b).base()) == &b.e); - assert(base(std::ranges::crbegin(b).base()) == &b.ce); - assert(base(std::ranges::rbegin(bb).base()) == &bb.ce); - assert(base(std::ranges::crbegin(bb).base()) == &bb.ce); - MemberBeginFunctionEnd c{}; const MemberBeginFunctionEnd cc{}; - assert(base(std::ranges::rbegin(c).base()) == &c.e); - assert(base(std::ranges::crbegin(c).base()) == &c.ce); - assert(base(std::ranges::rbegin(cc).base()) == &cc.ce); - assert(base(std::ranges::crbegin(cc).base()) == &cc.ce); - FunctionBeginMemberEnd d{}; const FunctionBeginMemberEnd dd{}; + + assert(base(std::ranges::rbegin(a).base()) == &a.e); + assert(base(std::ranges::rbegin(aa).base()) == &aa.ce); + assert(base(std::ranges::rbegin(b).base()) == &b.e); + assert(base(std::ranges::rbegin(bb).base()) == &bb.ce); + assert(base(std::ranges::rbegin(c).base()) == &c.e); + assert(base(std::ranges::rbegin(cc).base()) == &cc.ce); assert(base(std::ranges::rbegin(d).base()) == &d.e); - assert(base(std::ranges::crbegin(d).base()) == &d.ce); assert(base(std::ranges::rbegin(dd).base()) == &dd.ce); + +#if TEST_STD_VER < 23 + assert(base(std::ranges::crbegin(a).base()) == &a.ce); + assert(base(std::ranges::crbegin(aa).base()) == &aa.ce); + assert(base(std::ranges::crbegin(b).base()) == &b.ce); + assert(base(std::ranges::crbegin(bb).base()) == &bb.ce); + assert(base(std::ranges::crbegin(c).base()) == &c.ce); + assert(base(std::ranges::crbegin(cc).base()) == &cc.ce); + assert(base(std::ranges::crbegin(d).base()) == &d.ce); assert(base(std::ranges::crbegin(dd).base()) == &dd.ce); +#endif // TEST_STD_VER < 23 return true; } ASSERT_NOEXCEPT(std::ranges::rbegin(std::declval())); +#if TEST_STD_VER < 23 ASSERT_NOEXCEPT(std::ranges::crbegin(std::declval())); +#endif // TEST_STD_VER < 23 struct NoThrowMemberRBegin { ThrowingIterator rbegin() const noexcept; // auto(t.rbegin()) doesn't throw } ntmb; static_assert(noexcept(std::ranges::rbegin(ntmb))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::crbegin(ntmb))); +#endif // TEST_STD_VER < 23 struct NoThrowADLRBegin { friend ThrowingIterator rbegin(NoThrowADLRBegin&) noexcept; // auto(rbegin(t)) doesn't throw friend ThrowingIterator rbegin(const NoThrowADLRBegin&) noexcept; } ntab; static_assert(noexcept(std::ranges::rbegin(ntab))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::crbegin(ntab))); +#endif // TEST_STD_VER < 23 struct NoThrowMemberRBeginReturnsRef { ThrowingIterator& rbegin() const noexcept; // auto(t.rbegin()) may throw } ntmbrr; static_assert(!noexcept(std::ranges::rbegin(ntmbrr))); +#if TEST_STD_VER < 23 static_assert(!noexcept(std::ranges::crbegin(ntmbrr))); +#endif // TEST_STD_VER < 23 struct RBeginReturnsArrayRef { auto rbegin() const noexcept -> int(&)[10]; } brar; static_assert(noexcept(std::ranges::rbegin(brar))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::crbegin(brar))); +#endif // TEST_STD_VER < 23 struct NoThrowBeginThrowingEnd { int* begin() const noexcept; int* end() const; } ntbte; static_assert(!noexcept(std::ranges::rbegin(ntbte))); +#if TEST_STD_VER < 23 static_assert(!noexcept(std::ranges::crbegin(ntbte))); +#endif // TEST_STD_VER < 23 struct NoThrowEndThrowingBegin { int* begin() const; int* end() const noexcept; } ntetb; static_assert(noexcept(std::ranges::rbegin(ntetb))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::crbegin(ntetb))); +#endif // TEST_STD_VER < 23 // Test ADL-proofing. struct Incomplete; template struct Holder { T t; }; static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); +#endif // TEST_STD_VER < 23 int main(int, char**) { static_assert(testReturnTypes()); diff --git a/libcxx/test/std/ranges/range.access/rend.pass.cpp b/libcxx/test/std/ranges/range.access/rend.pass.cpp index f5f59edf19393..adb150461e044 100644 --- a/libcxx/test/std/ranges/range.access/rend.pass.cpp +++ b/libcxx/test/std/ranges/range.access/rend.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // std::ranges::rend -// std::ranges::crend +// std::ranges::crend // before C++23 #include @@ -19,7 +19,9 @@ #include "test_iterators.h" using RangeREndT = decltype(std::ranges::rend); +#if TEST_STD_VER < 23 using RangeCREndT = decltype(std::ranges::crend); +#endif // TEST_STD_VER < 23 static int globalBuff[8]; @@ -27,16 +29,20 @@ static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct Incomplete; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct REndMember { int x; @@ -49,50 +55,50 @@ static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 constexpr bool testReturnTypes() { - { - int *x[2]; - ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), std::reverse_iterator); - ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), std::reverse_iterator); - } - - { - int x[2][2]; - ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), std::reverse_iterator); - ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), std::reverse_iterator); - } - - { - struct Different { - char* rbegin(); - sentinel_wrapper& rend(); - short* rbegin() const; - sentinel_wrapper& rend() const; - } x; - ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), sentinel_wrapper); - ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), sentinel_wrapper); - } + int* a[2]; + int b[2][2]; + struct Different { + char* rbegin(); + sentinel_wrapper& rend(); + short* rbegin() const; + sentinel_wrapper& rend() const; + } c; + + ASSERT_SAME_TYPE(decltype(std::ranges::rend(a)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::rend(b)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::rend(c)), sentinel_wrapper); + +#if TEST_STD_VER < 23 + ASSERT_SAME_TYPE(decltype(std::ranges::crend(a)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::crend(b)), std::reverse_iterator); + ASSERT_SAME_TYPE(decltype(std::ranges::crend(c)), sentinel_wrapper); +#endif // TEST_STD_VER < 23 return true; } constexpr bool testArray() { int a[2]; - assert(std::ranges::rend(a).base() == a); - assert(std::ranges::crend(a).base() == a); - int b[2][2]; - assert(std::ranges::rend(b).base() == b); - assert(std::ranges::crend(b).base() == b); - REndMember c[2]; + + assert(std::ranges::rend(a).base() == a); + assert(std::ranges::rend(b).base() == b); assert(std::ranges::rend(c).base() == c); + +#if TEST_STD_VER < 23 + assert(std::ranges::crend(b).base() == b); + assert(std::ranges::crend(a).base() == a); assert(std::ranges::crend(c).base() == c); +#endif // TEST_STD_VER < 23 return true; } @@ -130,8 +136,10 @@ struct NonConstREndMember { }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct EnabledBorrowingREndMember { constexpr int* rbegin() const { return nullptr; } @@ -163,24 +171,24 @@ struct EmptyPtrREndMember { constexpr bool testREndMember() { REndMember a; - assert(std::ranges::rend(a) == &a.x); - assert(std::ranges::crend(a) == &a.x); - NonConstREndMember b; - assert(std::ranges::rend(b) == &b.x); - static_assert(!std::is_invocable_v); - EnabledBorrowingREndMember c; - assert(std::ranges::rend(std::move(c)) == &globalBuff[0]); - assert(std::ranges::crend(std::move(c)) == &globalBuff[0]); - REndMemberFunction d; - assert(std::ranges::rend(d) == &d.x); - assert(std::ranges::crend(d) == &d.x); - EmptyPtrREndMember e; + + assert(std::ranges::rend(a) == &a.x); + assert(std::ranges::rend(b) == &b.x); + assert(std::ranges::rend(std::move(c)) == &globalBuff[0]); + assert(std::ranges::rend(d) == &d.x); assert(std::ranges::rend(e) == &e.x); + +#if TEST_STD_VER < 23 + assert(std::ranges::crend(a) == &a.x); + static_assert(!std::is_invocable_v); + assert(std::ranges::crend(std::move(c)) == &globalBuff[0]); + assert(std::ranges::crend(d) == &d.x); assert(std::ranges::crend(e) == &e.x); +#endif // TEST_STD_VER < 23 return true; } @@ -197,8 +205,10 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); // Ill-formed before P2602R2 Poison Pills are Too Toxic +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct REndFunctionReturnsInt { friend constexpr int rbegin(REndFunctionReturnsInt const&); @@ -233,7 +243,9 @@ struct REndFunctionByValue { friend constexpr int* rbegin(REndFunctionByValue) { return nullptr; } friend constexpr int* rend(REndFunctionByValue) { return &globalBuff[1]; } }; +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct REndFunctionEnabledBorrowing { friend constexpr int* rbegin(REndFunctionEnabledBorrowing) { return nullptr; } @@ -269,47 +281,45 @@ struct RBeginMemberEndFunction { constexpr bool testREndFunction() { const REndFunction a{}; - assert(std::ranges::rend(a) == &a.x); - assert(std::ranges::crend(a) == &a.x); REndFunction aa{}; - assert(std::ranges::rend(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::crend(aa) == &aa.x); - REndFunctionByValue b; - assert(std::ranges::rend(b) == &globalBuff[1]); - assert(std::ranges::crend(b) == &globalBuff[1]); - REndFunctionEnabledBorrowing c; - assert(std::ranges::rend(std::move(c)) == &globalBuff[2]); - assert(std::ranges::crend(std::move(c)) == &globalBuff[2]); - const REndFunctionReturnsEmptyPtr d{}; - assert(std::ranges::rend(d) == &d.x); - assert(std::ranges::crend(d) == &d.x); REndFunctionReturnsEmptyPtr dd{}; - assert(std::ranges::rend(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::crend(dd) == &dd.x); - const REndFunctionWithDataMember e{}; - assert(std::ranges::rend(e) == &e.x); - assert(std::ranges::crend(e) == &e.x); REndFunctionWithDataMember ee{}; - assert(std::ranges::rend(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::crend(ee) == &ee.x); - const REndFunctionWithPrivateEndMember f{}; - assert(std::ranges::rend(f) == &f.y); - assert(std::ranges::crend(f) == &f.y); REndFunctionWithPrivateEndMember ff{}; - assert(std::ranges::rend(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic - assert(std::ranges::crend(ff) == &ff.y); - const RBeginMemberEndFunction g{}; - assert(std::ranges::rend(g) == &g.x); - assert(std::ranges::crend(g) == &g.x); RBeginMemberEndFunction gg{}; + + assert(std::ranges::rend(a) == &a.x); + assert(std::ranges::rend(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::rend(b) == &globalBuff[1]); + assert(std::ranges::rend(std::move(c)) == &globalBuff[2]); + assert(std::ranges::rend(d) == &d.x); + assert(std::ranges::rend(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::rend(e) == &e.x); + assert(std::ranges::rend(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::rend(f) == &f.y); + assert(std::ranges::rend(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic + assert(std::ranges::rend(g) == &g.x); assert(std::ranges::rend(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic + +#if TEST_STD_VER < 23 + assert(std::ranges::crend(a) == &a.x); + assert(std::ranges::crend(aa) == &aa.x); + assert(std::ranges::crend(b) == &globalBuff[1]); + assert(std::ranges::crend(std::move(c)) == &globalBuff[2]); + assert(std::ranges::crend(d) == &d.x); + assert(std::ranges::crend(dd) == &dd.x); + assert(std::ranges::crend(e) == &e.x); + assert(std::ranges::crend(ee) == &ee.x); + assert(std::ranges::crend(f) == &f.y); + assert(std::ranges::crend(ff) == &ff.y); + assert(std::ranges::crend(g) == &g.x); assert(std::ranges::crend(gg) == &gg.x); +#endif // TEST_STD_VER < 23 return true; } @@ -325,7 +335,9 @@ struct MemberBeginEnd { }; static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionBeginEnd { int b, e; @@ -343,7 +355,9 @@ struct FunctionBeginEnd { }; static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct MemberBeginFunctionEnd { int b, e; @@ -359,7 +373,9 @@ struct MemberBeginFunctionEnd { }; static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionBeginMemberEnd { int b, e; @@ -375,59 +391,77 @@ struct FunctionBeginMemberEnd { }; static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert( std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct MemberBeginEndDifferentTypes { bidirectional_iterator begin(); bidirectional_iterator end(); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionBeginEndDifferentTypes { friend bidirectional_iterator begin(FunctionBeginEndDifferentTypes&); friend bidirectional_iterator end(FunctionBeginEndDifferentTypes&); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct MemberBeginEndForwardIterators { forward_iterator begin(); forward_iterator end(); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionBeginEndForwardIterators { friend forward_iterator begin(FunctionBeginEndForwardIterators&); friend forward_iterator end(FunctionBeginEndForwardIterators&); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct MemberBeginOnly { bidirectional_iterator begin() const; }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionBeginOnly { friend bidirectional_iterator begin(FunctionBeginOnly&); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct MemberEndOnly { bidirectional_iterator end() const; }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 struct FunctionEndOnly { friend bidirectional_iterator end(FunctionEndOnly&); }; static_assert(!std::is_invocable_v); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v); +#endif // TEST_STD_VER < 23 // Make sure there is no clash between the following cases: // - the case that handles classes defining member `rbegin` and `rend` functions; @@ -438,53 +472,60 @@ struct MemberBeginAndRBegin { int* rbegin() const; int* rend() const; }; -static_assert( std::is_invocable_v); -static_assert( std::is_invocable_v); +static_assert(std::is_invocable_v); static_assert( std::same_as, int*>); +#if TEST_STD_VER < 23 +static_assert(std::is_invocable_v); static_assert( std::same_as, int*>); +#endif // TEST_STD_VER < 23 constexpr bool testBeginEnd() { MemberBeginEnd a{}; const MemberBeginEnd aa{}; - assert(base(std::ranges::rend(a).base()) == &a.b); - assert(base(std::ranges::crend(a).base()) == &a.cb); - assert(base(std::ranges::rend(aa).base()) == &aa.cb); - assert(base(std::ranges::crend(aa).base()) == &aa.cb); - FunctionBeginEnd b{}; const FunctionBeginEnd bb{}; - assert(base(std::ranges::rend(b).base()) == &b.b); - assert(base(std::ranges::crend(b).base()) == &b.cb); - assert(base(std::ranges::rend(bb).base()) == &bb.cb); - assert(base(std::ranges::crend(bb).base()) == &bb.cb); - MemberBeginFunctionEnd c{}; const MemberBeginFunctionEnd cc{}; - assert(base(std::ranges::rend(c).base()) == &c.b); - assert(base(std::ranges::crend(c).base()) == &c.cb); - assert(base(std::ranges::rend(cc).base()) == &cc.cb); - assert(base(std::ranges::crend(cc).base()) == &cc.cb); - FunctionBeginMemberEnd d{}; const FunctionBeginMemberEnd dd{}; + + assert(base(std::ranges::rend(a).base()) == &a.b); + assert(base(std::ranges::rend(aa).base()) == &aa.cb); + assert(base(std::ranges::rend(b).base()) == &b.b); + assert(base(std::ranges::rend(bb).base()) == &bb.cb); + assert(base(std::ranges::rend(c).base()) == &c.b); + assert(base(std::ranges::rend(cc).base()) == &cc.cb); assert(base(std::ranges::rend(d).base()) == &d.b); - assert(base(std::ranges::crend(d).base()) == &d.cb); assert(base(std::ranges::rend(dd).base()) == &dd.cb); + +#if TEST_STD_VER < 23 + assert(base(std::ranges::crend(a).base()) == &a.cb); + assert(base(std::ranges::crend(aa).base()) == &aa.cb); + assert(base(std::ranges::crend(b).base()) == &b.cb); + assert(base(std::ranges::crend(bb).base()) == &bb.cb); + assert(base(std::ranges::crend(c).base()) == &c.cb); + assert(base(std::ranges::crend(cc).base()) == &cc.cb); + assert(base(std::ranges::crend(d).base()) == &d.cb); assert(base(std::ranges::crend(dd).base()) == &dd.cb); +#endif // TEST_STD_VER < 23 return true; } ASSERT_NOEXCEPT(std::ranges::rend(std::declval())); +#if TEST_STD_VER < 23 ASSERT_NOEXCEPT(std::ranges::crend(std::declval())); +#endif // TEST_STD_VER < 23 struct NoThrowMemberREnd { ThrowingIterator rbegin() const; ThrowingIterator rend() const noexcept; // auto(t.rend()) doesn't throw } ntmre; static_assert(noexcept(std::ranges::rend(ntmre))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::crend(ntmre))); +#endif // TEST_STD_VER < 23 struct NoThrowADLREnd { ThrowingIterator rbegin() const; @@ -492,43 +533,55 @@ struct NoThrowADLREnd { friend ThrowingIterator rend(const NoThrowADLREnd&) noexcept; } ntare; static_assert(noexcept(std::ranges::rend(ntare))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::crend(ntare))); +#endif // TEST_STD_VER < 23 struct NoThrowMemberREndReturnsRef { ThrowingIterator rbegin() const; ThrowingIterator& rend() const noexcept; // auto(t.rend()) may throw } ntmrerr; static_assert(!noexcept(std::ranges::rend(ntmrerr))); +#if TEST_STD_VER < 23 static_assert(!noexcept(std::ranges::crend(ntmrerr))); +#endif // TEST_STD_VER < 23 struct REndReturnsArrayRef { auto rbegin() const noexcept -> int(&)[10]; auto rend() const noexcept -> int(&)[10]; } rerar; static_assert(noexcept(std::ranges::rend(rerar))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::crend(rerar))); +#endif // TEST_STD_VER < 23 struct NoThrowBeginThrowingEnd { int* begin() const noexcept; int* end() const; } ntbte; static_assert(noexcept(std::ranges::rend(ntbte))); +#if TEST_STD_VER < 23 static_assert(noexcept(std::ranges::crend(ntbte))); +#endif // TEST_STD_VER < 23 struct NoThrowEndThrowingBegin { int* begin() const; int* end() const noexcept; } ntetb; static_assert(!noexcept(std::ranges::rend(ntetb))); +#if TEST_STD_VER < 23 static_assert(!noexcept(std::ranges::crend(ntetb))); +#endif // TEST_STD_VER < 23 // Test ADL-proofing. struct Incomplete; template struct Holder { T t; }; static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); +#if TEST_STD_VER < 23 static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); +#endif // TEST_STD_VER < 23 int main(int, char**) { static_assert(testReturnTypes()); diff --git a/libcxx/test/std/ranges/range.adaptors/range.as.const/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.as.const/adaptor.pass.cpp new file mode 100644 index 0000000000000..a4bee12385733 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.as.const/adaptor.pass.cpp @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// std::views::as_const + +#include +#include +#include +#include +#include + +#include "test_iterators.h" + +template +concept HasPipe = requires { + { std::declval() | std::declval() }; +}; + +struct DefaultConstructibleView : std::ranges::view_base { + int i_; + int* begin(); + int* end(); +}; +struct NoView {}; + +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(HasPipe); +static_assert(HasPipe); +static_assert(!HasPipe); +static_assert(!HasPipe); +static_assert(std::is_same_v); + +struct const_iterator_range { + constexpr std::const_iterator begin() const { return {}; } + constexpr std::const_iterator end() const { return {}; } +}; +static_assert(!std::ranges::view); +static_assert(std::ranges::range); + +constexpr bool test() { + // Let E be an expression, let T be decltype((E)), and let U be remove_cvref_t. + // The expression views::as_const(E) is expression-equivalent to: + + // - If views::all_t models constant_range, then views::all(E). + { + [[maybe_unused]] std::same_as> decltype(auto) view = + std::views::as_const(const_iterator_range{}); + } + { + // ambiguous with empty_view case + [[maybe_unused]] std::same_as>> decltype(auto) view = + std::views::empty | std::views::as_const; + } + { + // ambiguous with span case + int a[3] = {}; + [[maybe_unused]] std::same_as>> decltype(auto) view1 = + std::span(a) | std::views::as_const; + [[maybe_unused]] std::same_as>> decltype(auto) view2 = + std::span(a) | std::views::as_const; + } + { + // ambiguous with ref_view case + std::array a = {}; + std::ranges::ref_view> r = a; + [[maybe_unused]] std::same_as>> decltype(auto) view = + r | std::views::as_const; + } + { + // ambiguous with constant_range case + std::array a = {}; + [[maybe_unused]] std::same_as>> decltype(auto) view = + a | std::views::as_const; + } + + // - Otherwise, if U denotes empty_view for some type X, then auto(views::empty). + { + [[maybe_unused]] std::same_as> decltype(auto) view = + std::views::empty | std::views::as_const; + } + + // - Otherwise, if U denotes span for some type X and some extent Extent, then span(E). + { + int a[3] = {}; + std::same_as> decltype(auto) view = std::span(a) | std::views::as_const; + assert(std::to_address(view.begin()) == a); + assert(std::to_address(view.end()) == a + 3); + } + { + int a[3] = {}; + std::same_as> decltype(auto) view = std::span(a) | std::views::as_const; + assert(std::to_address(view.begin()) == a); + assert(std::to_address(view.end()) == a + 3); + } + + // - Otherwise, if U denotes ref_view for some type X and const X models constant_range, then ref_view(static_cast(E.base())). + { + std::array a = {}; + std::ranges::ref_view> r = a; + [[maybe_unused]] std::same_as>> decltype(auto) view = + r | std::views::as_const; + } + + // - Otherwise, if E is an lvalue, const U models constant_range, and U does not model view, then ref_view(static_cast(E)). + { + std::array a = {}; + [[maybe_unused]] std::same_as>> decltype(auto) view = + a | std::views::as_const; + } + + // - Otherwise, as_const_view(E). + { // view | views::as_const + DefaultConstructibleView v{{}, 3}; + std::same_as> decltype(auto) view = v | std::views::as_const; + assert(view.base().i_ == 3); + } + + { // adaptor | views::as_const + DefaultConstructibleView v{{}, 3}; + const auto partial = std::views::transform(std::identity{}) | std::views::as_const; + std::same_as>> decltype(auto) view = partial(v); + assert(view.base().base().i_ == 3); + } + + { // views::as_const | adaptor + DefaultConstructibleView v{{}, 3}; + const auto partial = std::views::as_const | std::views::transform(std::identity{}); + std::same_as, + std::identity>> decltype(auto) view = partial(v); + assert(view.base().base().i_ == 3); + } + + { // range | views::as_const + [[maybe_unused]] std::same_as>>> decltype(auto) view = + std::vector{} | std::views::as_const; + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.as.const/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.as.const/base.pass.cpp new file mode 100644 index 0000000000000..c842c59f5ad66 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.as.const/base.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// constexpr V base() const& requires copy_constructible { return base_; } +// constexpr V base() && { return std::move(base_); } + +#include +#include +#include + +#include "MoveOnly.h" + +struct SimpleView : std::ranges::view_base { + int i; + int* begin() const; + int* end() const; +}; + +struct MoveOnlyView : SimpleView { + MoveOnly m; +}; + +template +concept HasBase = requires(T&& t) { std::forward(t).base(); }; + +static_assert(HasBase const&>); +static_assert(HasBase&&>); + +static_assert(!HasBase const&>); +static_assert(HasBase&&>); + +constexpr bool test() { + { // const & + const std::ranges::as_const_view view(SimpleView{{}, 5}); + std::same_as decltype(auto) v = view.base(); + assert(v.i == 5); + } + + { // & + std::ranges::as_const_view view(SimpleView{{}, 5}); + std::same_as decltype(auto) v = view.base(); + assert(v.i == 5); + } + + { // && + std::ranges::as_const_view view(SimpleView{{}, 5}); + std::same_as decltype(auto) v = std::move(view).base(); + assert(v.i == 5); + } + + { // const && + const std::ranges::as_const_view view(SimpleView{{}, 5}); + std::same_as decltype(auto) v = std::move(view).base(); + assert(v.i == 5); + } + + { // move only + std::ranges::as_const_view view(MoveOnlyView{{}, 5}); + std::same_as decltype(auto) v = std::move(view).base(); + assert(v.m.get() == 5); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.as.const/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.as.const/begin.pass.cpp new file mode 100644 index 0000000000000..809a08bce2fcc --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.as.const/begin.pass.cpp @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// constexpr auto begin() +// constexpr auto begin() const + +#include +#include +#include +#include + +#include "test_iterators.h" + +struct SimpleView : std::ranges::view_base { + int* begin() const; + int* end() const; +}; + +struct NonSimpleView : std::ranges::view_base { + char* begin(); + char* end(); + int* begin() const; + int* end() const; +}; + +struct NonConstView : std::ranges::view_base { + char* begin(); + char* end(); +}; + +template +concept HasBegin = requires(T t) { t.begin(); }; + +static_assert(HasBegin>); +static_assert(HasBegin>); +static_assert(HasBegin>); +static_assert(HasBegin>); +static_assert(HasBegin>); +static_assert(!HasBegin>); + +template +constexpr void test_range() { + int a[] = {1, 2}; + std::ranges::subrange range(Iter(std::begin(a)), Sent(Iter(std::end(a)))); + std::ranges::as_const_view view(std::move(range)); + std::same_as> decltype(auto) iter = view.begin(); + assert(base(iter.base()) == std::begin(a)); +} + +template +class WrapRange { + Iter iter_; + Sent sent_; + +public: + constexpr WrapRange(Iter iter, Sent sent) : iter_(std::move(iter)), sent_(std::move(sent)) {} + + constexpr Iter begin() const { return iter_; } + constexpr Sent end() const { return sent_; } +}; + +template +WrapRange(Iter, Sent) -> WrapRange; + +template +constexpr void test_const_range() { + int a[] = {1, 2}; + auto range = WrapRange{Iter(a), Sent(Iter(a + 2))}; + const std::ranges::as_const_view view(std::views::all(range)); + std::same_as decltype(auto) iter = view.begin(); + assert(base(iter) == std::begin(a)); +} + +struct const_pointer_view : std::ranges::view_base { + constexpr const int* begin() const { return {}; } + constexpr const int* end() const { return {}; } +}; +struct const_iterator_view : std::ranges::view_base { + constexpr std::const_iterator begin() const { return {}; } + constexpr std::const_iterator end() const { return {}; } +}; + +constexpr bool test() { + types::for_each(types::cpp20_input_iterator_list{}, [] { + if constexpr (std::sentinel_for) + test_range(); + test_range>(); + test_range>(); + }); + + types::for_each(types::forward_iterator_list{}, [] { + test_const_range(); + test_const_range>(); + test_const_range>(); + }); + + // check that with a const_iterator begin() doesn't return std::const_iterator + { + std::ranges::as_const_view view{const_pointer_view{}}; + std::same_as decltype(auto) it = view.begin(); + assert(it == nullptr); + } + { + std::ranges::as_const_view view{const_iterator_view{}}; + std::same_as> decltype(auto) it = view.begin(); + assert(it == std::const_iterator{}); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.as.const/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.as.const/ctad.compile.pass.cpp new file mode 100644 index 0000000000000..063b4bcd2c994 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.as.const/ctad.compile.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include +#include +#include + +static_assert(std::is_same_v{})), + std::ranges::as_const_view>>>); + +static_assert(std::is_same_v&>())), + std::ranges::as_const_view&>>>); + +static_assert(std::is_same_v{})), + std::ranges::as_const_view>>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.as.const/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.as.const/ctor.pass.cpp new file mode 100644 index 0000000000000..54384c9305d1c --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.as.const/ctor.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// std::ranges::as_const_view::as_const_view(...) + +#include +#include +#include +#include +#include + +struct DefaultConstructibleView : std::ranges::view_base { + int* begin() const; + int* end() const; + + int i_ = 23; +}; + +struct NonDefaultConstructibleView : std::ranges::view_base { + NonDefaultConstructibleView(int i) : i_(i) {} + + int* begin() const; + int* end() const; + + int i_ = 23; +}; + +static_assert(!std::is_constructible_v>); +static_assert(std::is_constructible_v, int>); +static_assert(std::is_nothrow_constructible_v>); + +template +concept IsImplicitlyConstructible = requires(T val, Args... args) { val = {std::forward(args)...}; }; + +static_assert(IsImplicitlyConstructible>); +static_assert(!IsImplicitlyConstructible, int>); + +constexpr bool test() { + std::ranges::as_const_view view = {}; + assert(view.base().i_ == 23); + + return true; +} + +int main(int, char**) { + static_assert(test()); + test(); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.as.const/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.as.const/enable_borrowed_range.compile.pass.cpp new file mode 100644 index 0000000000000..5086f6fdb50b2 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.as.const/enable_borrowed_range.compile.pass.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include +#include + +static_assert(std::ranges::enable_borrowed_range>>); +static_assert(std::ranges::enable_borrowed_range&>>>); +static_assert(!std::ranges::enable_borrowed_range>>>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.as.const/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.as.const/end.pass.cpp new file mode 100644 index 0000000000000..e7c7b16f74011 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.as.const/end.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 + +// constexpr auto end() +// constexpr auto end() const + +#include +#include +#include + +#include "test_iterators.h" + +struct DefaultConstructibleView : std::ranges::view_base { + int* begin() const; + int* end() const; +}; + +struct NonConstCommonRange : std::ranges::view_base { + int* begin(); + int* end(); + + int* begin() const; + sentinel_wrapper end() const; +}; + +struct NonConstView : std::ranges::view_base { + int* begin(); + int* end(); +}; + +template +concept HasEnd = requires(T t) { t.end(); }; + +static_assert(HasEnd>); +static_assert(HasEnd>); +static_assert(HasEnd>); +static_assert(!HasEnd>); + +static_assert(std::is_same_v>().end()), + std::const_iterator>); +static_assert(std::is_same_v>().end()), + std::const_sentinel>>); + +template +constexpr void test_range() { + int a[] = {1, 2}; + std::ranges::subrange range(Iter(std::begin(a)), Sent(Iter(std::end(a)))); + std::ranges::as_const_view view(std::move(range)); + std::same_as> decltype(auto) iter = view.end(); + assert(base(base(iter)) == std::end(a)); +} + +template +class WrapRange { + Iter iter_; + Sent sent_; + +public: + constexpr WrapRange(Iter iter, Sent sent) : iter_(std::move(iter)), sent_(std::move(sent)) {} + + constexpr Iter begin() const { return iter_; } + constexpr Sent end() const { return sent_; } +}; + +template +WrapRange(Iter, Sent) -> WrapRange; + +template +constexpr void test_const_range() { + int a[] = {1, 2}; + auto range = WrapRange{Iter(a), Sent(Iter(a + 2))}; + const std::ranges::as_const_view view(std::move(range)); + std::same_as> decltype(auto) iter = view.end(); + assert(base(base(iter)) == std::end(a)); +} + +struct const_pointer_view : std::ranges::view_base { + constexpr const int* begin() const { return {}; } + constexpr const int* end() const { return {}; } +}; +struct const_iterator_view : std::ranges::view_base { + constexpr std::const_iterator begin() const { return {}; } + constexpr std::const_iterator end() const { return {}; } +}; + +constexpr bool test() { + test_range, sentinel_wrapper>>(); + test_range, sized_sentinel>>(); + test_range, sentinel_wrapper>>(); + test_range, sized_sentinel>>(); + + types::for_each(types::forward_iterator_list{}, [] { + test_range(); + test_range>(); + test_range>(); + }); + + // check that with a const_iterator end() doesn't return std::const_iterator + { + std::ranges::as_const_view view{const_pointer_view{}}; + std::same_as decltype(auto) it = view.end(); + assert(it == nullptr); + } + { + std::ranges::as_const_view view{const_iterator_view{}}; + std::same_as> decltype(auto) it = view.end(); + assert(it == std::const_iterator{}); + } + + return true; +} + +int main(int, char**) { + test(); + +// gcc cannot have mutable member in constant expression +#if !defined(TEST_COMPILER_GCC) + static_assert(test()); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.as.const/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.as.const/size.pass.cpp new file mode 100644 index 0000000000000..62f8282ddc0b6 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.as.const/size.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// constexpr auto size() +// constexpr auto size() const + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +struct ConstSizedView : std::ranges::view_base { + bool* size_called; + int* begin() const; + int* end() const; + + constexpr std::size_t size() const { + *size_called = true; + return 3; + } +}; + +struct SizedView : std::ranges::view_base { + bool* size_called; + int* begin() const; + int* end() const; + + constexpr int size() { + *size_called = true; + return 5; + } +}; + +struct UnsizedView : std::ranges::view_base { + int* begin() const; + int* end() const; +}; + +template +concept HasSize = requires(T v) { v.size(); }; + +static_assert(HasSize); +static_assert(HasSize); +static_assert(HasSize); +static_assert(!HasSize); +static_assert(!HasSize); +static_assert(!HasSize); + +constexpr bool test() { + { + bool size_called = false; + std::ranges::as_const_view view(ConstSizedView{{}, &size_called}); + std::same_as auto size = view.size(); + assert(size == 3); + assert(size_called); + } + + { + bool size_called = false; + std::ranges::as_const_view view(SizedView{{}, &size_called}); + std::same_as auto size = view.size(); + assert(size == 5); + assert(size_called); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp index 3f7c174d3fe48..8c711cd770862 100644 --- a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp +++ b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp @@ -35,8 +35,15 @@ using InputIter = cpp20_input_iterator; struct InputRange : std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + constexpr InputIter begin() const { return InputIter(buff); } - constexpr InputIter end() const { return InputIter(buff + 8); } + constexpr sentinel_wrapper end() const { return sentinel_wrapper(InputIter(buff + 8)); } +}; + +struct NonConstInputRange : std::ranges::view_interface { + int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + constexpr InputIter begin() { return InputIter(buff); } + constexpr sentinel_wrapper end() { return sentinel_wrapper(InputIter(buff + 8)); } }; struct SizedInputRange : std::ranges::view_interface { @@ -222,6 +229,19 @@ constexpr bool testEmpty() { return true; } +#if TEST_STD_VER >= 23 +template +concept ConstAccessorsInvocable = requires(T& t) { + t.cbegin(); + t.cend(); +}; + +static_assert(ConstAccessorsInvocable); +static_assert(ConstAccessorsInvocable); +static_assert(ConstAccessorsInvocable); +static_assert(!ConstAccessorsInvocable); +#endif // TEST_STD_VER >= 23 + template concept DataInvocable = requires (T const& obj) { obj.data(); }; diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index 44bd4a597539d..b9d01c3e7a372 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -482,6 +482,13 @@ template three_way_contiguous_iterator(It) -> three_way_contiguous_iterator; #endif // TEST_STD_VER > 17 +#if TEST_STD_VER >= 23 +template +TEST_CONSTEXPR Iter base(std::basic_const_iterator i) { + return i.base(); +} +#endif + template // ADL base() for everything else (including pointers) TEST_CONSTEXPR Iter base(Iter i) { return i; } diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h index 15fc5b69b5207..596166bc60fbc 100644 --- a/libcxx/test/support/test_macros.h +++ b/libcxx/test/support/test_macros.h @@ -271,6 +271,12 @@ struct is_same { enum {value = 1}; }; static_assert((test_macros_detail::is_same<__VA_ARGS__>::value), \ "Types differ unexpectedly") +#define ASSERT_RUNTIME_AND_CONSTEXPR(...) \ + do { \ + assert((__VA_ARGS__)); \ + static_assert(__VA_ARGS__); \ + } while (0) + #ifndef TEST_HAS_NO_EXCEPTIONS #define TEST_THROW(...) throw __VA_ARGS__ #else diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index b041b08f02aac..28de28a5af113 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -1000,11 +1000,9 @@ def add_version_header(tc): { "name": "__cpp_lib_ranges_as_const", "values": { - "c++23": 202207 # P2278R4 cbegin should always return a constant iterator - # 202311 # DR P2836R1 std::basic_const_iterator should follow its underlying type’s convertibility + "c++23": 202311 # DR P2836R1 std::basic_const_iterator should follow its underlying type’s convertibility }, "headers": ["ranges"], - "unimplemented": True, }, { "name": "__cpp_lib_ranges_as_rvalue",