[1/2] libstdc++: Add always_inline to ranges iterator ops and access functions
Commit Message
Most of the basis operations for ranges such as ranges::begin and
ranges::next are trivial one-line function bodies, so can be made
always_inline to reduce the abstraction penalty for -O0 code.
Now that we no longer need to support the -fconcepts-ts grammar, we can
also move some [[nodiscard]] attributes to the more natural position
before the function declaration, instead of between the declarator-id
and the function parameters, e.g. we can use:
template<typename T> requires C<T> [[nodiscard]] auto operator()(T&&)
instead of:
template<typename T> requires C<T> auto operator() [[nodiscard]] (T&&)
The latter form was necessary because -fconcepts-ts used a different
grammar for the requires-clause, parsing 'C<T>[[x]]' as a subscripting
operator with an ill-formed argument '[x]'. In the C++20 grammar you
would need to use parentheses to use a subscript in a constraint, so
without parentheses it's parsed as an attribute.
libstdc++-v3/ChangeLog:
* include/bits/ranges_base.h (__detail::__to_unsigned_like)
(__access::__possible_const_range, __access::__as_const)
(__distance_fn::operator(), __next_fn::operator())
(__prev_fn::operator()): Add always_inline attribute.
(_Begin::operator(), _End::operator(), _RBegin::operator())
(_REnd::operator(), _Size::operator(), _SSize::operator())
(_Empty::operator(), _Data::operator(), _SSize::operator()):
Likewise. Move nodiscard attribute to start of declaration.
---
This change was inspired when I was adding more uses of ranges::next and
ranges::prev to fix the iterator arithmetic not using difference_type.
Tested powerpc64-linux.
libstdc++-v3/include/bits/ranges_base.h | 47 ++++++++++++++++---------
1 file changed, 30 insertions(+), 17 deletions(-)
Comments
On Thu, Sep 11, 2025 at 2:18 PM Jonathan Wakely <jwakely@redhat.com> wrote:
> Most of the basis operations for ranges such as ranges::begin and
> ranges::next are trivial one-line function bodies, so can be made
> always_inline to reduce the abstraction penalty for -O0 code.
>
> Now that we no longer need to support the -fconcepts-ts grammar, we can
> also move some [[nodiscard]] attributes to the more natural position
> before the function declaration, instead of between the declarator-id
> and the function parameters, e.g. we can use:
>
> template<typename T> requires C<T> [[nodiscard]] auto operator()(T&&)
>
> instead of:
>
> template<typename T> requires C<T> auto operator() [[nodiscard]] (T&&)
>
> The latter form was necessary because -fconcepts-ts used a different
> grammar for the requires-clause, parsing 'C<T>[[x]]' as a subscripting
> operator with an ill-formed argument '[x]'. In the C++20 grammar you
> would need to use parentheses to use a subscript in a constraint, so
> without parentheses it's parsed as an attribute.
>
> libstdc++-v3/ChangeLog:
>
> * include/bits/ranges_base.h (__detail::__to_unsigned_like)
> (__access::__possible_const_range, __access::__as_const)
> (__distance_fn::operator(), __next_fn::operator())
> (__prev_fn::operator()): Add always_inline attribute.
> (_Begin::operator(), _End::operator(), _RBegin::operator())
> (_REnd::operator(), _Size::operator(), _SSize::operator())
> (_Empty::operator(), _Data::operator(), _SSize::operator()):
> Likewise. Move nodiscard attribute to start of declaration.
> ---
>
> This change was inspired when I was adding more uses of ranges::next and
> ranges::prev to fix the iterator arithmetic not using difference_type.
>
LGTM.
>
> Tested powerpc64-linux.
>
> libstdc++-v3/include/bits/ranges_base.h | 47 ++++++++++++++++---------
> 1 file changed, 30 insertions(+), 17 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/ranges_base.h
> b/libstdc++-v3/include/bits/ranges_base.h
> index 02e13a2027d1..c1a9f6a90009 100644
> --- a/libstdc++-v3/include/bits/ranges_base.h
> +++ b/libstdc++-v3/include/bits/ranges_base.h
> @@ -61,29 +61,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> namespace ranges
> {
> template<typename>
> inline constexpr bool disable_sized_range = false;
>
> template<typename _Tp>
> inline constexpr bool enable_borrowed_range = false;
>
> namespace __detail
> {
> + [[__gnu__::__always_inline__]]
> constexpr __max_size_type
> __to_unsigned_like(__max_size_type __t) noexcept
> { return __t; }
>
> + [[__gnu__::__always_inline__]]
> constexpr __max_size_type
> __to_unsigned_like(__max_diff_type __t) noexcept
> { return __max_size_type(__t); }
>
> template<integral _Tp>
> + [[__gnu__::__always_inline__]]
> constexpr auto
> __to_unsigned_like(_Tp __t) noexcept
> { return static_cast<make_unsigned_t<_Tp>>(__t); }
>
> template<typename _Tp>
> using __make_unsigned_like_t
> = decltype(__detail::__to_unsigned_like(std::declval<_Tp>()));
>
> // Part of the constraints of ranges::borrowed_range
> template<typename _Tp>
> @@ -111,22 +114,23 @@ namespace ranges
> else if constexpr (__member_begin<_Tp>)
> return
> noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().begin()));
> else
> return
> noexcept(_GLIBCXX_AUTO_CAST(begin(std::declval<_Tp&>())));
> }
>
> public:
> template<__maybe_borrowed_range _Tp>
> requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
> || __adl_begin<_Tp>
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr auto
> - operator()[[nodiscard]](_Tp&& __t) const
> noexcept(_S_noexcept<_Tp&>())
> + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
> {
> if constexpr (is_array_v<remove_reference_t<_Tp>>)
> {
> static_assert(is_lvalue_reference_v<_Tp>);
> return __t + 0;
> }
> else if constexpr (__member_begin<_Tp>)
> return __t.begin();
> else
> return begin(__t);
> @@ -161,22 +165,23 @@ namespace ranges
> else if constexpr (__member_end<_Tp>)
> return
> noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().end()));
> else
> return noexcept(_GLIBCXX_AUTO_CAST(end(std::declval<_Tp&>())));
> }
>
> public:
> template<__maybe_borrowed_range _Tp>
> requires is_bounded_array_v<remove_reference_t<_Tp>>
> || __member_end<_Tp> || __adl_end<_Tp>
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr auto
> - operator()[[nodiscard]](_Tp&& __t) const
> noexcept(_S_noexcept<_Tp&>())
> + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
> {
> if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
> {
> static_assert(is_lvalue_reference_v<_Tp>);
> return __t + extent_v<remove_reference_t<_Tp>>;
> }
> else if constexpr (__member_end<_Tp>)
> return __t.end();
> else
> return end(__t);
> @@ -225,22 +230,23 @@ namespace ranges
> return is_nothrow_copy_constructible_v<_It>;
> }
> else
> return false;
> }
> }
>
> public:
> template<__maybe_borrowed_range _Tp>
> requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> ||
> __reversable<_Tp>
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr auto
> - operator()[[nodiscard]](_Tp&& __t) const
> + operator()(_Tp&& __t) const
> noexcept(_S_noexcept<_Tp&>())
> {
> if constexpr (__member_rbegin<_Tp>)
> return __t.rbegin();
> else if constexpr (__adl_rbegin<_Tp>)
> return rbegin(__t);
> else
> return std::make_reverse_iterator(_End{}(__t));
> }
> };
> @@ -282,22 +288,23 @@ namespace ranges
> return is_nothrow_copy_constructible_v<_It>;
> }
> else
> return false;
> }
> }
>
> public:
> template<__maybe_borrowed_range _Tp>
> requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr auto
> - operator()[[nodiscard]](_Tp&& __t) const
> + operator()(_Tp&& __t) const
> noexcept(_S_noexcept<_Tp&>())
> {
> if constexpr (__member_rend<_Tp>)
> return __t.rend();
> else if constexpr (__adl_rend<_Tp>)
> return rend(__t);
> else
> return std::make_reverse_iterator(_Begin{}(__t));
> }
> };
> @@ -346,42 +353,44 @@ namespace ranges
> return
> noexcept(_GLIBCXX_AUTO_CAST(size(std::declval<_Tp&>())));
> else if constexpr (__sentinel_size<_Tp>)
> return noexcept(_End{}(std::declval<_Tp&>())
> - _Begin{}(std::declval<_Tp&>()));
> }
>
> public:
> template<typename _Tp>
> requires is_bounded_array_v<remove_reference_t<_Tp>>
> || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp>
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr auto
> - operator()[[nodiscard]](_Tp&& __t) const
> noexcept(_S_noexcept<_Tp&>())
> + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
> {
> if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
> return extent_v<remove_reference_t<_Tp>>;
> else if constexpr (__member_size<_Tp>)
> return __t.size();
> else if constexpr (__adl_size<_Tp>)
> return size(__t);
> else if constexpr (__sentinel_size<_Tp>)
> return __detail::__to_unsigned_like(_End{}(__t) -
> _Begin{}(__t));
> }
> };
>
> struct _SSize
> {
> // _GLIBCXX_RESOLVE_LIB_DEFECTS
> // 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
> template<typename _Tp>
> requires requires (_Tp& __t) { _Size{}(__t); }
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr auto
> - operator()[[nodiscard]](_Tp&& __t) const
> noexcept(noexcept(_Size{}(__t)))
> + operator()(_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
> {
> auto __size = _Size{}(__t);
> using __size_type = decltype(__size);
> // Return the wider of ptrdiff_t and
> make-signed-like-t<__size_type>.
> if constexpr (integral<__size_type>)
> {
> using __gnu_cxx::__int_traits;
> if constexpr (__int_traits<__size_type>::__digits
> < __int_traits<ptrdiff_t>::__digits)
> return static_cast<ptrdiff_t>(__size);
> @@ -422,22 +431,23 @@ namespace ranges
> return noexcept(_Size{}(std::declval<_Tp&>()) == 0);
> else
> return noexcept(bool(_Begin{}(std::declval<_Tp&>())
> == _End{}(std::declval<_Tp&>())));
> }
>
> public:
> template<typename _Tp>
> requires __member_empty<_Tp> || __size0_empty<_Tp>
> || __eq_iter_empty<_Tp>
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr bool
> - operator()[[nodiscard]](_Tp&& __t) const
> noexcept(_S_noexcept<_Tp&>())
> + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
> {
> if constexpr (__member_empty<_Tp>)
> return bool(__t.empty());
> else if constexpr (__size0_empty<_Tp>)
> return _Size{}(__t) == 0;
> else
> return bool(_Begin{}(__t) == _End{}(__t));
> }
> };
>
> @@ -463,22 +473,23 @@ namespace ranges
> {
> if constexpr (__member_data<_Tp>)
> return
> noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().data()));
> else
> return noexcept(_Begin{}(std::declval<_Tp&>()));
> }
>
> public:
> template<__maybe_borrowed_range _Tp>
> requires __member_data<_Tp> || __begin_data<_Tp>
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr auto
> - operator()[[nodiscard]](_Tp&& __t) const
> noexcept(_S_noexcept<_Tp>())
> + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
> {
> if constexpr (__member_data<_Tp>)
> return __t.data();
> else
> return std::to_address(_Begin{}(__t));
> }
> };
>
> } // namespace __access
>
> @@ -625,33 +636,35 @@ namespace ranges
> #if __glibcxx_ranges_as_const // >= C++23
> template<typename _Tp>
> concept constant_range
> = input_range<_Tp> &&
> std::__detail::__constant_iterator<iterator_t<_Tp>>;
> #endif
>
> namespace __access
> {
> #if __glibcxx_ranges_as_const // >= C++23
> template<input_range _Range>
> + [[__gnu__::__always_inline__]]
> constexpr auto&
> __possibly_const_range(_Range& __r) noexcept
> {
> // _GLIBCXX_RESOLVE_LIB_DEFECTS
> // 4027. possibly-const-range should prefer returning const R&
> if constexpr (input_range<const _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>
> + [[__gnu__::__always_inline__]]
> constexpr decltype(auto)
> __as_const(_Tp& __t) noexcept
> {
> static_assert(std::is_same_v<_To&, _Tp&>);
>
> if constexpr (is_lvalue_reference_v<_To>)
> return const_cast<const _Tp&>(__t);
> else
> return static_cast<const _Tp&&>(__t);
> }
> @@ -960,106 +973,106 @@ namespace ranges
> iter_difference_t<_It> __n = 0;
> while (__first != __last)
> {
> ++__first;
> ++__n;
> }
> return __n;
> }
>
> template<typename _It, sized_sentinel_for<decay_t<_It>> _Sent>
> - [[nodiscard]]
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr iter_difference_t<decay_t<_It>>
> operator()(_It&& __first, _Sent __last) const
> { return __last - static_cast<const decay_t<_It>&>(__first); }
>
> template<range _Range>
> - [[nodiscard]]
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr range_difference_t<_Range>
> operator()(_Range&& __r) const
> {
> if constexpr (sized_range<_Range>)
> return
> static_cast<range_difference_t<_Range>>(ranges::size(__r));
> else
> return (*this)(ranges::begin(__r), ranges::end(__r));
> }
>
> void operator&() const = delete;
> };
>
> inline constexpr __distance_fn distance{};
>
> struct __next_fn final
> {
> template<input_or_output_iterator _It>
> - [[nodiscard]]
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr _It
> operator()(_It __x) const
> {
> ++__x;
> return __x;
> }
>
> template<input_or_output_iterator _It>
> - [[nodiscard]]
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr _It
> operator()(_It __x, iter_difference_t<_It> __n) const
> {
> ranges::advance(__x, __n);
> return __x;
> }
>
> template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
> - [[nodiscard]]
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr _It
> operator()(_It __x, _Sent __bound) const
> {
> ranges::advance(__x, __bound);
> return __x;
> }
>
> template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
> - [[nodiscard]]
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr _It
> operator()(_It __x, iter_difference_t<_It> __n, _Sent __bound) const
> {
> ranges::advance(__x, __n, __bound);
> return __x;
> }
>
> void operator&() const = delete;
> };
>
> inline constexpr __next_fn next{};
>
> struct __prev_fn final
> {
> template<bidirectional_iterator _It>
> - [[nodiscard]]
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr _It
> operator()(_It __x) const
> {
> --__x;
> return __x;
> }
>
> template<bidirectional_iterator _It>
> - [[nodiscard]]
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr _It
> operator()(_It __x, iter_difference_t<_It> __n) const
> {
> ranges::advance(__x, -__n);
> return __x;
> }
>
> template<bidirectional_iterator _It>
> - [[nodiscard]]
> + [[nodiscard, __gnu__::__always_inline__]]
> constexpr _It
> operator()(_It __x, iter_difference_t<_It> __n, _It __bound) const
> {
> ranges::advance(__x, -__n, __bound);
> return __x;
> }
>
> void operator&() const = delete;
> };
>
> --
> 2.51.0
>
>
@@ -61,29 +61,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace ranges
{
template<typename>
inline constexpr bool disable_sized_range = false;
template<typename _Tp>
inline constexpr bool enable_borrowed_range = false;
namespace __detail
{
+ [[__gnu__::__always_inline__]]
constexpr __max_size_type
__to_unsigned_like(__max_size_type __t) noexcept
{ return __t; }
+ [[__gnu__::__always_inline__]]
constexpr __max_size_type
__to_unsigned_like(__max_diff_type __t) noexcept
{ return __max_size_type(__t); }
template<integral _Tp>
+ [[__gnu__::__always_inline__]]
constexpr auto
__to_unsigned_like(_Tp __t) noexcept
{ return static_cast<make_unsigned_t<_Tp>>(__t); }
template<typename _Tp>
using __make_unsigned_like_t
= decltype(__detail::__to_unsigned_like(std::declval<_Tp>()));
// Part of the constraints of ranges::borrowed_range
template<typename _Tp>
@@ -111,22 +114,23 @@ namespace ranges
else if constexpr (__member_begin<_Tp>)
return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().begin()));
else
return noexcept(_GLIBCXX_AUTO_CAST(begin(std::declval<_Tp&>())));
}
public:
template<__maybe_borrowed_range _Tp>
requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
|| __adl_begin<_Tp>
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr auto
- operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
+ operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
{
if constexpr (is_array_v<remove_reference_t<_Tp>>)
{
static_assert(is_lvalue_reference_v<_Tp>);
return __t + 0;
}
else if constexpr (__member_begin<_Tp>)
return __t.begin();
else
return begin(__t);
@@ -161,22 +165,23 @@ namespace ranges
else if constexpr (__member_end<_Tp>)
return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().end()));
else
return noexcept(_GLIBCXX_AUTO_CAST(end(std::declval<_Tp&>())));
}
public:
template<__maybe_borrowed_range _Tp>
requires is_bounded_array_v<remove_reference_t<_Tp>>
|| __member_end<_Tp> || __adl_end<_Tp>
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr auto
- operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
+ operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
{
if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
{
static_assert(is_lvalue_reference_v<_Tp>);
return __t + extent_v<remove_reference_t<_Tp>>;
}
else if constexpr (__member_end<_Tp>)
return __t.end();
else
return end(__t);
@@ -225,22 +230,23 @@ namespace ranges
return is_nothrow_copy_constructible_v<_It>;
}
else
return false;
}
}
public:
template<__maybe_borrowed_range _Tp>
requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr auto
- operator()[[nodiscard]](_Tp&& __t) const
+ operator()(_Tp&& __t) const
noexcept(_S_noexcept<_Tp&>())
{
if constexpr (__member_rbegin<_Tp>)
return __t.rbegin();
else if constexpr (__adl_rbegin<_Tp>)
return rbegin(__t);
else
return std::make_reverse_iterator(_End{}(__t));
}
};
@@ -282,22 +288,23 @@ namespace ranges
return is_nothrow_copy_constructible_v<_It>;
}
else
return false;
}
}
public:
template<__maybe_borrowed_range _Tp>
requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr auto
- operator()[[nodiscard]](_Tp&& __t) const
+ operator()(_Tp&& __t) const
noexcept(_S_noexcept<_Tp&>())
{
if constexpr (__member_rend<_Tp>)
return __t.rend();
else if constexpr (__adl_rend<_Tp>)
return rend(__t);
else
return std::make_reverse_iterator(_Begin{}(__t));
}
};
@@ -346,42 +353,44 @@ namespace ranges
return noexcept(_GLIBCXX_AUTO_CAST(size(std::declval<_Tp&>())));
else if constexpr (__sentinel_size<_Tp>)
return noexcept(_End{}(std::declval<_Tp&>())
- _Begin{}(std::declval<_Tp&>()));
}
public:
template<typename _Tp>
requires is_bounded_array_v<remove_reference_t<_Tp>>
|| __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp>
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr auto
- operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
+ operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
{
if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
return extent_v<remove_reference_t<_Tp>>;
else if constexpr (__member_size<_Tp>)
return __t.size();
else if constexpr (__adl_size<_Tp>)
return size(__t);
else if constexpr (__sentinel_size<_Tp>)
return __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
}
};
struct _SSize
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
template<typename _Tp>
requires requires (_Tp& __t) { _Size{}(__t); }
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr auto
- operator()[[nodiscard]](_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
+ operator()(_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
{
auto __size = _Size{}(__t);
using __size_type = decltype(__size);
// Return the wider of ptrdiff_t and make-signed-like-t<__size_type>.
if constexpr (integral<__size_type>)
{
using __gnu_cxx::__int_traits;
if constexpr (__int_traits<__size_type>::__digits
< __int_traits<ptrdiff_t>::__digits)
return static_cast<ptrdiff_t>(__size);
@@ -422,22 +431,23 @@ namespace ranges
return noexcept(_Size{}(std::declval<_Tp&>()) == 0);
else
return noexcept(bool(_Begin{}(std::declval<_Tp&>())
== _End{}(std::declval<_Tp&>())));
}
public:
template<typename _Tp>
requires __member_empty<_Tp> || __size0_empty<_Tp>
|| __eq_iter_empty<_Tp>
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr bool
- operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
+ operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
{
if constexpr (__member_empty<_Tp>)
return bool(__t.empty());
else if constexpr (__size0_empty<_Tp>)
return _Size{}(__t) == 0;
else
return bool(_Begin{}(__t) == _End{}(__t));
}
};
@@ -463,22 +473,23 @@ namespace ranges
{
if constexpr (__member_data<_Tp>)
return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().data()));
else
return noexcept(_Begin{}(std::declval<_Tp&>()));
}
public:
template<__maybe_borrowed_range _Tp>
requires __member_data<_Tp> || __begin_data<_Tp>
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr auto
- operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
+ operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
{
if constexpr (__member_data<_Tp>)
return __t.data();
else
return std::to_address(_Begin{}(__t));
}
};
} // namespace __access
@@ -625,33 +636,35 @@ namespace ranges
#if __glibcxx_ranges_as_const // >= C++23
template<typename _Tp>
concept constant_range
= input_range<_Tp> && std::__detail::__constant_iterator<iterator_t<_Tp>>;
#endif
namespace __access
{
#if __glibcxx_ranges_as_const // >= C++23
template<input_range _Range>
+ [[__gnu__::__always_inline__]]
constexpr auto&
__possibly_const_range(_Range& __r) noexcept
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4027. possibly-const-range should prefer returning const R&
if constexpr (input_range<const _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>
+ [[__gnu__::__always_inline__]]
constexpr decltype(auto)
__as_const(_Tp& __t) noexcept
{
static_assert(std::is_same_v<_To&, _Tp&>);
if constexpr (is_lvalue_reference_v<_To>)
return const_cast<const _Tp&>(__t);
else
return static_cast<const _Tp&&>(__t);
}
@@ -960,106 +973,106 @@ namespace ranges
iter_difference_t<_It> __n = 0;
while (__first != __last)
{
++__first;
++__n;
}
return __n;
}
template<typename _It, sized_sentinel_for<decay_t<_It>> _Sent>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr iter_difference_t<decay_t<_It>>
operator()(_It&& __first, _Sent __last) const
{ return __last - static_cast<const decay_t<_It>&>(__first); }
template<range _Range>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr range_difference_t<_Range>
operator()(_Range&& __r) const
{
if constexpr (sized_range<_Range>)
return static_cast<range_difference_t<_Range>>(ranges::size(__r));
else
return (*this)(ranges::begin(__r), ranges::end(__r));
}
void operator&() const = delete;
};
inline constexpr __distance_fn distance{};
struct __next_fn final
{
template<input_or_output_iterator _It>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr _It
operator()(_It __x) const
{
++__x;
return __x;
}
template<input_or_output_iterator _It>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr _It
operator()(_It __x, iter_difference_t<_It> __n) const
{
ranges::advance(__x, __n);
return __x;
}
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr _It
operator()(_It __x, _Sent __bound) const
{
ranges::advance(__x, __bound);
return __x;
}
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr _It
operator()(_It __x, iter_difference_t<_It> __n, _Sent __bound) const
{
ranges::advance(__x, __n, __bound);
return __x;
}
void operator&() const = delete;
};
inline constexpr __next_fn next{};
struct __prev_fn final
{
template<bidirectional_iterator _It>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr _It
operator()(_It __x) const
{
--__x;
return __x;
}
template<bidirectional_iterator _It>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr _It
operator()(_It __x, iter_difference_t<_It> __n) const
{
ranges::advance(__x, -__n);
return __x;
}
template<bidirectional_iterator _It>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr _It
operator()(_It __x, iter_difference_t<_It> __n, _It __bound) const
{
ranges::advance(__x, -__n, __bound);
return __x;
}
void operator&() const = delete;
};