Skip to content

Commit

Permalink
libstdc++: Implement P2278R4 "cbegin should always return a constant …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
Patrick Palka committed Apr 14, 2023
1 parent 2ab0d83 commit 0d94c6d
Show file tree
Hide file tree
Showing 10 changed files with 827 additions and 7 deletions.
99 changes: 99 additions & 0 deletions libstdc++-v3/include/bits/ranges_base.h
Expand Up @@ -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>>;

Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -685,6 +783,7 @@ namespace ranges
{
return _Data{}(__cust_access::__as_const<_Tp>(__e));
}
#endif
};

} // namespace __cust_access
Expand Down
22 changes: 19 additions & 3 deletions libstdc++-v3/include/bits/ranges_util.h
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 0d94c6d

Please sign in to comment.