diff options
author | Patrick Palka <ppalka@redhat.com> | 2023-04-14 10:32:12 -0400 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2023-04-14 10:32:12 -0400 |
commit | 0d94c6df183375caaa7f672e288a2094ca813749 (patch) | |
tree | 0d5f5f1c1a656b0632467f560cb721e65298b112 /libstdc++-v3/include | |
parent | 2ab0d83e8880fe747af3f137aef382d2d4c09e4c (diff) | |
download | gcc-0d94c6df183375caaa7f672e288a2094ca813749.zip gcc-0d94c6df183375caaa7f672e288a2094ca813749.tar.gz gcc-0d94c6df183375caaa7f672e288a2094ca813749.tar.bz2 |
libstdc++: Implement P2278R4 "cbegin should always return a constant iterator"
This also implements the approved follow-up LWG issues 3765, 3766, 3769,
3770, 3811, 3850, 3853, 3862 and 3872.
libstdc++-v3/ChangeLog:
* include/bits/ranges_base.h (const_iterator_t): Define for C++23.
(const_sentinel_t): Likewise.
(range_const_reference_t): Likewise.
(constant_range): Likewise.
(__cust_access::__possibly_const_range): Likewise, replacing ...
(__cust_access::__as_const): ... this.
(__cust_access::_CBegin::operator()): Redefine for C++23 as per P2278R4.
(__cust_access::_CEnd::operator()): Likewise.
(__cust_access::_CRBegin::operator()): Likewise.
(__cust_access::_CREnd::operator()): Likewise.
(__cust_access::_CData::operator()): Likewise.
* include/bits/ranges_util.h (ranges::__detail::__different_from):
Make it an alias of std::__detail::__different_from.
(view_interface::cbegin): Define for C++23.
(view_interface::cend): Likewise.
* include/bits/stl_iterator.h (__detail::__different_from): Define.
(iter_const_reference_t): Define for C++23.
(__detail::__constant_iterator): Likewise.
(__detail::__is_const_iterator): Likewise.
(__detail::__not_a_const_iterator): Likewise.
(__detail::__iter_const_rvalue_reference_t): Likewise.
(__detail::__basic_const_iter_cat):: Likewise.
(const_iterator): Likewise.
(__detail::__const_sentinel): Likewise.
(const_sentinel): Likewise.
(basic_const_iterator): Likewise.
(common_type<basic_const_iterator<_Tp>, _Up>): Likewise.
(common_type<_Up, basic_const_iterator<_Tp>>): Likewise.
(common_type<basic_const_iterator<_Tp>, basic_const_iterator<Up>>):
Likewise.
(make_const_iterator): Define for C++23.
(make_const_sentinel): Likewise.
* include/std/ranges (__cpp_lib_ranges_as_const): Likewise.
(as_const_view): Likewise.
(enable_borrowed_range<as_const_view>): Likewise.
(views::__detail::__is_ref_view): Likewise.
(views::__detail::__can_is_const_view): Likewise.
(views::_AsConst, views::as_const): Likewise.
* include/std/span (span::const_iterator): Likewise.
(span::const_reverse_iterator): Likewise.
(span::cbegin): Likewise.
(span::cend): Likewise.
(span::crbegin): Likewise.
(span::crend): Likewise.
* include/std/version (__cpp_lib_ranges_as_const): Likewise.
* testsuite/std/ranges/adaptors/join.cc (test06): Adjust to
behave independently of C++20 vs C++23.
* testsuite/std/ranges/version_c++23.cc: Verify value of
__cpp_lib_ranges_as_const macro.
* testsuite/24_iterators/const_iterator/1.cc: New test.
* testsuite/std/ranges/adaptors/as_const/1.cc: New test.
Diffstat (limited to 'libstdc++-v3/include')
-rw-r--r-- | libstdc++-v3/include/bits/ranges_base.h | 99 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/ranges_util.h | 22 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/stl_iterator.h | 367 | ||||
-rw-r--r-- | libstdc++-v3/include/std/ranges | 106 | ||||
-rw-r--r-- | libstdc++-v3/include/std/span | 22 | ||||
-rw-r--r-- | libstdc++-v3/include/std/version | 1 |
6 files changed, 614 insertions, 3 deletions
diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index c89cb3e..698dac7 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -515,6 +515,17 @@ namespace ranges template<range _Range> using sentinel_t = decltype(ranges::end(std::declval<_Range&>())); +#if __cplusplus > 202002L + template<range _Range> + using const_iterator_t = const_iterator<iterator_t<_Range>>; + + template<range _Range> + using const_sentinel_t = const_sentinel<sentinel_t<_Range>>; + + template<range _Range> + using range_const_reference_t = iter_const_reference_t<iterator_t<_Range>>; +#endif + template<range _Range> using range_difference_t = iter_difference_t<iterator_t<_Range>>; @@ -607,8 +618,25 @@ namespace ranges concept common_range = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>; +#if __cplusplus > 202002L + template<typename _Tp> + concept constant_range + = input_range<_Tp> && std::__detail::__constant_iterator<iterator_t<_Tp>>; +#endif + namespace __cust_access { +#if __cplusplus > 202020L + template<typename _Range> + constexpr auto& + __possibly_const_range(_Range& __r) noexcept + { + if constexpr (constant_range<const _Range> && !constant_range<_Range>) + return const_cast<const _Range&>(__r); + else + return __r; + } +#else // If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&. template<typename _To, typename _Tp> constexpr decltype(auto) @@ -621,9 +649,24 @@ namespace ranges else return static_cast<const _Tp&&>(__t); } +#endif struct _CBegin { +#if __cplusplus > 202002L + template<__maybe_borrowed_range _Tp> + [[nodiscard]] + constexpr auto + operator()(_Tp&& __t) const + noexcept(noexcept(std::make_const_iterator + (ranges::begin(__cust_access::__possibly_const_range(__t))))) + requires requires { std::make_const_iterator + (ranges::begin(__cust_access::__possibly_const_range(__t))); } + { + auto& __r = __cust_access::__possibly_const_range(__t); + return const_iterator_t<decltype(__r)>(ranges::begin(__r)); + } +#else template<typename _Tp> [[nodiscard]] constexpr auto @@ -633,10 +676,25 @@ namespace ranges { return _Begin{}(__cust_access::__as_const<_Tp>(__e)); } +#endif }; struct _CEnd final { +#if __cplusplus > 202002L + template<__maybe_borrowed_range _Tp> + [[nodiscard]] + constexpr auto + operator()(_Tp&& __t) const + noexcept(noexcept(std::make_const_sentinel + (ranges::end(__cust_access::__possibly_const_range(__t))))) + requires requires { std::make_const_sentinel + (ranges::end(__cust_access::__possibly_const_range(__t))); } + { + auto& __r = __cust_access::__possibly_const_range(__t); + return const_sentinel_t<decltype(__r)>(ranges::end(__r)); + } +#else template<typename _Tp> [[nodiscard]] constexpr auto @@ -646,10 +704,25 @@ namespace ranges { return _End{}(__cust_access::__as_const<_Tp>(__e)); } +#endif }; struct _CRBegin { +#if __cplusplus > 202002L + template<__maybe_borrowed_range _Tp> + [[nodiscard]] + constexpr auto + operator()(_Tp&& __t) const + noexcept(noexcept(std::make_const_iterator + (ranges::rbegin(__cust_access::__possibly_const_range(__t))))) + requires requires { std::make_const_iterator + (ranges::rbegin(__cust_access::__possibly_const_range(__t))); } + { + auto& __r = __cust_access::__possibly_const_range(__t); + return const_iterator<decltype(ranges::rbegin(__r))>(ranges::rbegin(__r)); + } +#else template<typename _Tp> [[nodiscard]] constexpr auto @@ -659,10 +732,25 @@ namespace ranges { return _RBegin{}(__cust_access::__as_const<_Tp>(__e)); } +#endif }; struct _CREnd { +#if __cplusplus > 202002L + template<__maybe_borrowed_range _Tp> + [[nodiscard]] + constexpr auto + operator()(_Tp&& __t) const + noexcept(noexcept(std::make_const_sentinel + (ranges::rend(__cust_access::__possibly_const_range(__t))))) + requires requires { std::make_const_sentinel + (ranges::rend(__cust_access::__possibly_const_range(__t))); } + { + auto& __r = __cust_access::__possibly_const_range(__t); + return const_sentinel<decltype(ranges::rend(__r))>(ranges::rend(__r)); + } +#else template<typename _Tp> [[nodiscard]] constexpr auto @@ -672,10 +760,20 @@ namespace ranges { return _REnd{}(__cust_access::__as_const<_Tp>(__e)); } +#endif }; struct _CData { +#if __cplusplus > 202002L + template<__maybe_borrowed_range _Tp> + [[nodiscard]] + constexpr const auto* + operator()(_Tp&& __t) const + noexcept(noexcept(ranges::data(__cust_access::__possibly_const_range(__t)))) + requires requires { ranges::data(__cust_access::__possibly_const_range(__t)); } + { return ranges::data(__cust_access::__possibly_const_range(__t)); } +#else template<typename _Tp> [[nodiscard]] constexpr auto @@ -685,6 +783,7 @@ namespace ranges { return _Data{}(__cust_access::__as_const<_Tp>(__e)); } +#endif }; } // namespace __cust_access diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index 880a0ce..f7e3538 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -53,9 +53,7 @@ namespace ranges concept __has_arrow = input_iterator<_It> && (is_pointer_v<_It> || requires(_It __it) { __it.operator->(); }); - template<typename _Tp, typename _Up> - concept __different_from - = !same_as<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>; + using std::__detail::__different_from; } // namespace __detail /// The ranges::view_interface class template @@ -192,6 +190,24 @@ namespace ranges constexpr decltype(auto) operator[](range_difference_t<_Range> __n) const { return ranges::begin(_M_derived())[__n]; } + +#if __cplusplus > 202002L + constexpr auto + cbegin() requires input_range<_Derived> + { return ranges::cbegin(_M_derived()); } + + constexpr auto + cbegin() const requires input_range<const _Derived> + { return ranges::cbegin(_M_derived()); } + + constexpr auto + cend() requires input_range<_Derived> + { return ranges::cend(_M_derived()); } + + constexpr auto + cend() const requires input_range<const _Derived> + { return ranges::cend(_M_derived()); } +#endif }; namespace __detail diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index a6a09db..b22d9a4 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -102,6 +102,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Cat, typename _Limit, typename _Otherwise = _Cat> using __clamp_iter_cat = __conditional_t<derived_from<_Cat, _Limit>, _Limit, _Otherwise>; + + template<typename _Tp, typename _Up> + concept __different_from + = !same_as<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>; } #endif @@ -2578,6 +2582,369 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION add_pointer_t<iter_reference_t<_It>>, void>; }; + +#if __cplusplus > 202020L + template<indirectly_readable _It> + using iter_const_reference_t + = common_reference_t<const iter_value_t<_It>&&, iter_reference_t<_It>>; + + template<input_iterator _It> class basic_const_iterator; + + namespace __detail + { + template<typename _It> + concept __constant_iterator = input_iterator<_It> + && same_as<iter_const_reference_t<_It>, iter_reference_t<_It>>; + + template<typename _Tp> + inline constexpr bool __is_const_iterator = false; + + template<typename _It> + inline constexpr bool __is_const_iterator<basic_const_iterator<_It>> = true; + + template<typename _Tp> + concept __not_a_const_iterator = !__is_const_iterator<_Tp>; + + template<indirectly_readable _It> + using __iter_const_rvalue_reference_t + = common_reference_t<const iter_value_t<_It>&&, iter_rvalue_reference_t<_It>>; + + template<typename _It> + struct __basic_const_iterator_iter_cat + { }; + + template<forward_iterator _It> + struct __basic_const_iterator_iter_cat<_It> + { using iterator_category = iterator_traits<_It>::iterator_category; }; + } // namespace detail + + template<input_iterator _It> + using const_iterator + = __conditional_t<__detail::__constant_iterator<_It>, _It, basic_const_iterator<_It>>; + + namespace __detail + { + template<typename _Sent> + struct __const_sentinel + { using type = _Sent; }; + + template<input_iterator _Sent> + struct __const_sentinel<_Sent> + { using type = const_iterator<_Sent>; }; + } // namespace __detail + + template<semiregular _Sent> + using const_sentinel = typename __detail::__const_sentinel<_Sent>::type; + + template<input_iterator _It> + class basic_const_iterator + : public __detail::__basic_const_iterator_iter_cat<_It> + { + _It _M_current = _It(); + using __reference = iter_const_reference_t<_It>; + using __rvalue_reference = __detail::__iter_const_rvalue_reference_t<_It>; + + static auto + _S_iter_concept() + { + if constexpr (contiguous_iterator<_It>) + return contiguous_iterator_tag{}; + else if constexpr (random_access_iterator<_It>) + return random_access_iterator_tag{}; + else if constexpr (bidirectional_iterator<_It>) + return bidirectional_iterator_tag{}; + else if constexpr (forward_iterator<_It>) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + + template<input_iterator _It2> friend class basic_const_iterator; + + public: + using iterator_concept = decltype(_S_iter_concept()); + using value_type = iter_value_t<_It>; + using difference_type = iter_difference_t<_It>; + + basic_const_iterator() requires default_initializable<_It> = default; + + constexpr + basic_const_iterator(_It __current) + noexcept(is_nothrow_move_constructible_v<_It>) + : _M_current(std::move(__current)) + { } + + template<convertible_to<_It> _It2> + constexpr + basic_const_iterator(basic_const_iterator<_It2> __current) + noexcept(is_nothrow_constructible_v<_It, _It2>) + : _M_current(std::move(__current._M_current)) + { } + + template<__detail::__different_from<basic_const_iterator> _Tp> + requires convertible_to<_Tp, _It> + constexpr + basic_const_iterator(_Tp&& __current) + noexcept(is_nothrow_constructible_v<_It, _Tp>) + : _M_current(std::forward<_Tp>(__current)) + { } + + constexpr const _It& + base() const & noexcept + { return _M_current; } + + constexpr _It + base() && + noexcept(is_nothrow_move_constructible_v<_It>) + { return std::move(_M_current); } + + constexpr __reference + operator*() const + noexcept(noexcept(static_cast<__reference>(*_M_current))) + { return static_cast<__reference>(*_M_current); } + + constexpr const auto* + operator->() const + noexcept(contiguous_iterator<_It> || noexcept(*_M_current)) + requires is_lvalue_reference_v<iter_reference_t<_It>> + && same_as<remove_cvref_t<iter_reference_t<_It>>, value_type> + { + if constexpr (contiguous_iterator<_It>) + return std::to_address(_M_current); + else + return std::__addressof(*_M_current); + } + + constexpr basic_const_iterator& + operator++() + noexcept(noexcept(++_M_current)) + { + ++_M_current; + return *this; + } + + constexpr void + operator++(int) + noexcept(noexcept(++_M_current)) + { ++_M_current; } + + constexpr basic_const_iterator + operator++(int) + noexcept(noexcept(++*this) && is_nothrow_copy_constructible_v<basic_const_iterator>) + requires forward_iterator<_It> + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + constexpr basic_const_iterator& + operator--() + noexcept(noexcept(--_M_current)) + requires bidirectional_iterator<_It> + { + --_M_current; + return *this; + } + + constexpr basic_const_iterator + operator--(int) + noexcept(noexcept(--*this) && is_nothrow_copy_constructible_v<basic_const_iterator>) + requires bidirectional_iterator<_It> + { + auto __tmp = *this; + --*this; + return __tmp; + } + + constexpr basic_const_iterator& + operator+=(difference_type __n) + noexcept(noexcept(_M_current += __n)) + requires random_access_iterator<_It> + { + _M_current += __n; + return *this; + } + + constexpr basic_const_iterator& + operator-=(difference_type __n) + noexcept(noexcept(_M_current -= __n)) + requires random_access_iterator<_It> + { + _M_current -= __n; + return *this; + } + + constexpr __reference + operator[](difference_type __n) const + noexcept(noexcept(static_cast<__reference>(_M_current[__n]))) + requires random_access_iterator<_It> + { return static_cast<__reference>(_M_current[__n]); } + + template<sentinel_for<_It> _Sent> + constexpr bool + operator==(const _Sent& __s) const + noexcept(noexcept(_M_current == __s)) + { return _M_current == __s; } + + constexpr bool + operator<(const basic_const_iterator& __y) const + noexcept(noexcept(_M_current < __y._M_current)) + requires random_access_iterator<_It> + { return _M_current < __y._M_current; } + + constexpr bool + operator>(const basic_const_iterator& __y) const + noexcept(noexcept(_M_current > __y._M_current)) + requires random_access_iterator<_It> + { return _M_current > __y._M_current; } + + constexpr bool + operator<=(const basic_const_iterator& __y) const + noexcept(noexcept(_M_current <= __y._M_current)) + requires random_access_iterator<_It> + { return _M_current <= __y._M_current; } + + constexpr bool + operator>=(const basic_const_iterator& __y) const + noexcept(noexcept(_M_current >= __y._M_current)) + requires random_access_iterator<_It> + { return _M_current >= __y._M_current; } + + constexpr auto + operator<=>(const basic_const_iterator& __y) const + noexcept(noexcept(_M_current <=> __y._M_current)) + requires random_access_iterator<_It> && three_way_comparable<_It> + { return _M_current <=> __y._M_current; } + + template<__detail::__different_from<basic_const_iterator> _It2> + constexpr bool + operator<(const _It2& __y) const + noexcept(noexcept(_M_current < __y)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return _M_current < __y; } + + template<__detail::__different_from<basic_const_iterator> _It2> + constexpr bool + operator>(const _It2& __y) const + noexcept(noexcept(_M_current > __y)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return _M_current > __y; } + + template<__detail::__different_from<basic_const_iterator> _It2> + constexpr bool + operator<=(const _It2& __y) const + noexcept(noexcept(_M_current <= __y)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return _M_current <= __y; } + + template<__detail::__different_from<basic_const_iterator> _It2> + constexpr bool + operator>=(const _It2& __y) const + noexcept(noexcept(_M_current >= __y)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return _M_current >= __y; } + + template<__detail::__different_from<basic_const_iterator> _It2> + constexpr auto + operator<=>(const _It2& __y) const + noexcept(noexcept(_M_current <=> __y)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + && three_way_comparable_with<_It, _It2> + { return _M_current <=> __y; } + + template<__detail::__not_a_const_iterator _It2> + friend constexpr bool + operator<(const _It2& __x, const basic_const_iterator& __y) + noexcept(noexcept(__x < __y._M_current)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return __x < __y._M_current; } + + template<__detail::__not_a_const_iterator _It2> + friend constexpr bool + operator>(const _It2& __x, const basic_const_iterator& __y) + noexcept(noexcept(__x > __y._M_current)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return __x > __y._M_current; } + + template<__detail::__not_a_const_iterator _It2> + friend constexpr bool + operator<=(const _It2& __x, const basic_const_iterator& __y) + noexcept(noexcept(__x <= __y._M_current)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return __x <= __y._M_current; } + + template<__detail::__not_a_const_iterator _It2> + friend constexpr bool + operator>=(const _It2& __x, const basic_const_iterator& __y) + noexcept(noexcept(__x >= __y._M_current)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return __x >= __y._M_current; } + + friend constexpr basic_const_iterator + operator+(const basic_const_iterator& __i, difference_type __n) + noexcept(noexcept(basic_const_iterator(__i._M_current + __n))) + requires random_access_iterator<_It> + { return basic_const_iterator(__i._M_current + __n); } + + friend constexpr basic_const_iterator + operator+(difference_type __n, const basic_const_iterator& __i) + noexcept(noexcept(basic_const_iterator(__i._M_current + __n))) + requires random_access_iterator<_It> + { return basic_const_iterator(__i._M_current + __n); } + + friend constexpr basic_const_iterator + operator-(const basic_const_iterator& __i, difference_type __n) + noexcept(noexcept(basic_const_iterator(__i._M_current - __n))) + requires random_access_iterator<_It> + { return basic_const_iterator(__i._M_current - __n); } + + template<sized_sentinel_for<_It> _Sent> + constexpr difference_type + operator-(const _Sent& __y) const + noexcept(noexcept(_M_current - __y)) + { return _M_current - __y; } + + template<__detail::__not_a_const_iterator _Sent> + requires sized_sentinel_for<_Sent, _It> + friend constexpr difference_type + operator-(const _Sent& __x, const basic_const_iterator& __y) + noexcept(noexcept(__x - __y._M_current)) + { return __x - __y._M_current; } + + friend constexpr __rvalue_reference + iter_move(const basic_const_iterator& __i) + noexcept(noexcept(static_cast<__rvalue_reference>(ranges::iter_move(__i._M_current)))) + { return static_cast<__rvalue_reference>(ranges::iter_move(__i._M_current)); } + }; + + template<typename _Tp, common_with<_Tp> _Up> + requires input_iterator<common_type_t<_Tp, _Up>> + struct common_type<basic_const_iterator<_Tp>, _Up> + { using type = basic_const_iterator<common_type_t<_Tp, _Up>>; }; + + template<typename _Tp, common_with<_Tp> _Up> + requires input_iterator<common_type_t<_Tp, _Up>> + struct common_type<_Up, basic_const_iterator<_Tp>> + { using type = basic_const_iterator<common_type_t<_Tp, _Up>>; }; + + template<typename _Tp, common_with<_Tp> _Up> + requires input_iterator<common_type_t<_Tp, _Up>> + struct common_type<basic_const_iterator<_Tp>, basic_const_iterator<_Up>> + { using type = basic_const_iterator<common_type_t<_Tp, _Up>>; }; + + template<input_iterator _It> + constexpr const_iterator<_It> + make_const_iterator(_It __it) + noexcept(is_nothrow_convertible_v<_It, const_iterator<_It>>) + { return __it; } + + template<semiregular _Sent> + constexpr const_sentinel<_Sent> + make_const_sentinel(_Sent __s) + noexcept(is_nothrow_convertible_v<_Sent, const_sentinel<_Sent>>) + { return __s; } +#endif // C++23 #endif // C++20 /// @} group iterators diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 3f6ff50..283d757 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -8929,6 +8929,112 @@ namespace views::__adaptor inline constexpr _Enumerate enumerate; } + +#define __cpp_lib_ranges_as_const 202207L + + template<view _Vp> + requires input_range<_Vp> + class as_const_view : public view_interface<as_const_view<_Vp>> + { + _Vp _M_base = _Vp(); + + public: + as_const_view() requires default_initializable<_Vp> = default; + + constexpr explicit + as_const_view(_Vp __base) + noexcept(is_nothrow_move_constructible_v<_Vp>) + : _M_base(std::move(__base)) + { } + + constexpr _Vp + base() const & + noexcept(is_nothrow_copy_constructible_v<_Vp>) + requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + noexcept(is_nothrow_move_constructible_v<_Vp>) + { return std::move(_M_base); } + + constexpr auto + begin() requires (!__detail::__simple_view<_Vp>) + { return ranges::cbegin(_M_base); } + + constexpr auto + begin() const requires range<const _Vp> + { return ranges::cbegin(_M_base); } + + constexpr auto + end() requires (!__detail::__simple_view<_Vp>) + { return ranges::cend(_M_base); } + + constexpr auto + end() const requires range<const _Vp> + { return ranges::cend(_M_base); } + + constexpr auto + size() requires sized_range<_Vp> + { return ranges::size(_M_base); } + + constexpr auto + size() const requires sized_range<const _Vp> + { return ranges::size(_M_base); } + }; + + template<typename _Range> + as_const_view(_Range&&) -> as_const_view<views::all_t<_Range>>; + + template<typename _Tp> + inline constexpr bool enable_borrowed_range<as_const_view<_Tp>> + = enable_borrowed_range<_Tp>; + + namespace views + { + namespace __detail + { + template<typename _Tp> + inline constexpr bool __is_ref_view = false; + + template<typename _Range> + inline constexpr bool __is_ref_view<ref_view<_Range>> = true; + + template<typename _Range> + concept __can_as_const_view = requires { as_const_view(std::declval<_Range>()); }; + } + + struct _AsConst : __adaptor::_RangeAdaptorClosure + { + template<viewable_range _Range> + constexpr auto + operator()(_Range&& __r) const + noexcept(noexcept(as_const_view(std::declval<_Range>()))) + requires __detail::__can_as_const_view<_Range> + { + using _Tp = remove_cvref_t<_Range>; + using element_type = remove_reference_t<range_reference_t<_Range>>; + if constexpr (constant_range<views::all_t<_Range>>) + return views::all(std::forward<_Range>(__r)); + else if constexpr (__detail::__is_empty_view<_Tp>) + return views::empty<const element_type>; + else if constexpr (std::__detail::__is_span<_Tp>) + return span<const element_type, _Tp::extent>(std::forward<_Range>(__r)); + else if constexpr (__detail::__is_ref_view<_Tp> + && constant_range<const element_type>) + return ref_view(static_cast<const element_type&> + (std::forward<_Range>(__r).base())); + else if constexpr (is_lvalue_reference_v<_Range> + && constant_range<_Tp> + && !view<_Tp>) + return ref_view(static_cast<const _Tp&>(__r)); + else + return as_const_view(std::forward<_Range>(__r)); + } + }; + + inline constexpr _AsConst as_const; + } #endif // C++23 } // namespace ranges diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 06d5c18..6763389 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -137,6 +137,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using const_reference = const element_type&; using iterator = __gnu_cxx::__normal_iterator<pointer, span>; using reverse_iterator = std::reverse_iterator<iterator>; +#if __cplusplus > 202002L + using const_iterator = std::const_iterator<iterator>; + using const_reverse_iterator = std::const_iterator<reverse_iterator>; +#endif // member constants static constexpr size_t extent = _Extent; @@ -301,6 +305,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION rend() const noexcept { return reverse_iterator(this->begin()); } +#if __cplusplus > 202002L + constexpr const_iterator + cbegin() const noexcept + { return begin(); } + + constexpr const_iterator + cend() const noexcept + { return end(); } + + constexpr const_reverse_iterator + crbegin() const noexcept + { return rbegin(); } + + constexpr const_reverse_iterator + crend() const noexcept + { return rend(); } +#endif + // subviews template<size_t _Count> diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index d233b03..9f31f25 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -339,6 +339,7 @@ #define __cpp_lib_ranges_stride 202207L #define __cpp_lib_ranges_cartesian_product 202207L #define __cpp_lib_ranges_as_rvalue 202207L +#define __cpp_lib_ranges_as_const 202207L #define __cpp_lib_ranges_enumerate 202302L #define __cpp_lib_fold 202207L #if __cpp_constexpr_dynamic_alloc |