// Core concepts and definitions for <ranges> -*- C++ -*-

// Copyright (C) 2019-2026 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file bits/ranges_base.h
 *  This is an internal header file, included by other library headers.
 *  Do not attempt to use it directly. @headername{ranges}
 */

#ifndef _GLIBCXX_RANGES_BASE_H
#define _GLIBCXX_RANGES_BASE_H 1

#ifdef _GLIBCXX_SYSHDR
#pragma GCC system_header
#endif

#if __cplusplus > 201703L
#include <initializer_list>
#include <bits/stl_iterator.h>
#include <ext/numeric_traits.h>
#include <bits/max_size_type.h>
#include <bits/version.h>

#if __glibcxx_containers_ranges // C++ >= 23
# include <bits/utility.h> // for tuple_element_t
#endif

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" // __int128

#if __glibcxx_algorithm_default_value_type // C++ >= 26
# define _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_I, _P) = projected_value_t<_I, _P>
#else
# define _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_I, _P)
#endif

#ifdef __cpp_lib_concepts
namespace std _GLIBCXX_VISIBILITY(default)
{
_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>
      concept __maybe_borrowed_range
	= is_lvalue_reference_v<_Tp>
	  || enable_borrowed_range<remove_cvref_t<_Tp>>;

  } // namespace __detail

  // Namespace for helpers for the <ranges> customization points.
  namespace __access
  {
    using std::ranges::__detail::__maybe_borrowed_range;
    using std::__detail::__range_iter_t;

    struct _Begin
    {
    private:
      template<typename _Tp>
	static consteval bool
	_S_noexcept()
	{
	  if constexpr (is_array_v<remove_reference_t<_Tp>>)
	    return true;
	  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()(_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);
	}
    };

    template<typename _Tp>
      concept __member_end = requires(_Tp& __t)
	{
	  { _GLIBCXX_AUTO_CAST(__t.end()) } -> sentinel_for<__range_iter_t<_Tp>>;
	};

    // Poison pill so that unqualified lookup doesn't find std::end.
    void end() = delete;

    template<typename _Tp>
      concept __adl_end = __class_or_enum<remove_reference_t<_Tp>>
	&& requires(_Tp& __t)
	{
	  { _GLIBCXX_AUTO_CAST(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
	};

    struct _End
    {
    private:
      template<typename _Tp>
	static consteval bool
	_S_noexcept()
	{
	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
	    return true;
	  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()(_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);
	}
    };

    template<typename _Tp>
      concept __member_rbegin = requires(_Tp& __t)
	{
	  { _GLIBCXX_AUTO_CAST(__t.rbegin()) } -> input_or_output_iterator;
	};

    void rbegin() = delete;

    template<typename _Tp>
      concept __adl_rbegin = __class_or_enum<remove_reference_t<_Tp>>
	&& requires(_Tp& __t)
	{
	  { _GLIBCXX_AUTO_CAST(rbegin(__t)) } -> input_or_output_iterator;
	};

    template<typename _Tp>
      concept __reversable = requires(_Tp& __t)
	{
	  { _Begin{}(__t) } -> bidirectional_iterator;
	  { _End{}(__t) } -> same_as<decltype(_Begin{}(__t))>;
	};

    struct _RBegin
    {
    private:
      template<typename _Tp>
	static consteval bool
	_S_noexcept()
	{
	  if constexpr (__member_rbegin<_Tp>)
	    return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().rbegin()));
	  else if constexpr (__adl_rbegin<_Tp>)
	    return noexcept(_GLIBCXX_AUTO_CAST(rbegin(std::declval<_Tp&>())));
	  else
	    {
	      if constexpr (noexcept(_End{}(std::declval<_Tp&>())))
		{
		  using _It = decltype(_End{}(std::declval<_Tp&>()));
		  // std::reverse_iterator copy-initializes its member.
		  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()(_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));
	}
    };

    template<typename _Tp>
      concept __member_rend = requires(_Tp& __t)
	{
	  { _GLIBCXX_AUTO_CAST(__t.rend()) }
	    -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
	};

    void rend() = delete;

    template<typename _Tp>
      concept __adl_rend = __class_or_enum<remove_reference_t<_Tp>>
	&& requires(_Tp& __t)
	{
	  { _GLIBCXX_AUTO_CAST(rend(__t)) }
	    -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
	};

    struct _REnd
    {
    private:
      template<typename _Tp>
	static consteval bool
	_S_noexcept()
	{
	  if constexpr (__member_rend<_Tp>)
	    return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().rend()));
	  else if constexpr (__adl_rend<_Tp>)
	    return noexcept(_GLIBCXX_AUTO_CAST(rend(std::declval<_Tp&>())));
	  else
	    {
	      if constexpr (noexcept(_Begin{}(std::declval<_Tp&>())))
		{
		  using _It = decltype(_Begin{}(std::declval<_Tp&>()));
		  // std::reverse_iterator copy-initializes its member.
		  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()(_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));
	}
    };

    template<typename _Tp>
      concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>>
	&& requires(_Tp& __t)
	{
	  { _GLIBCXX_AUTO_CAST(__t.size()) } -> __detail::__is_integer_like;
	};

    void size() = delete;

    template<typename _Tp>
      concept __adl_size = __class_or_enum<remove_reference_t<_Tp>>
	&& !disable_sized_range<remove_cvref_t<_Tp>>
	&& requires(_Tp& __t)
	{
	  { _GLIBCXX_AUTO_CAST(size(__t)) } -> __detail::__is_integer_like;
	};

    template<typename _Tp>
      concept __sentinel_size = requires(_Tp& __t)
	{
	  requires (!is_unbounded_array_v<remove_reference_t<_Tp>>);

	  { _Begin{}(__t) } -> forward_iterator;

	  { _End{}(__t) } -> sized_sentinel_for<decltype(_Begin{}(__t))>;

	  __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
	};

    struct _Size
    {
    private:
      template<typename _Tp>
	static consteval bool
	_S_noexcept()
	{
	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
	    return true;
	  else if constexpr (__member_size<_Tp>)
	    return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().size()));
	  else if constexpr (__adl_size<_Tp>)
	    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()(_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()(_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);
	      else
		return static_cast<make_signed_t<__size_type>>(__size);
	    }
	  else // Must be one of __max_diff_type or __max_size_type.
	    return __detail::__max_diff_type(__size);
	}
    };

    template<typename _Tp>
      concept __member_empty = requires(_Tp& __t) { bool(__t.empty()); };

    template<typename _Tp>
      concept __size0_empty = requires(_Tp& __t) { _Size{}(__t) == 0; };

    template<typename _Tp>
      concept __eq_iter_empty = requires(_Tp& __t)
	{
	  requires (!is_unbounded_array_v<remove_reference_t<_Tp>>);

	  { _Begin{}(__t) } -> forward_iterator;

	  bool(_Begin{}(__t) == _End{}(__t));
	};

    struct _Empty
    {
    private:
      template<typename _Tp>
	static consteval bool
	_S_noexcept()
	{
	  if constexpr (__member_empty<_Tp>)
	    return noexcept(bool(std::declval<_Tp&>().empty()));
	  else if constexpr (__size0_empty<_Tp>)
	    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()(_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));
	}
    };

    template<typename _Tp>
      concept __pointer_to_object = is_pointer_v<_Tp>
				    && is_object_v<remove_pointer_t<_Tp>>;

    template<typename _Tp>
      concept __member_data = requires(_Tp& __t)
	{
	  { _GLIBCXX_AUTO_CAST(__t.data()) } -> __pointer_to_object;
	};

    template<typename _Tp>
      concept __begin_data = contiguous_iterator<__range_iter_t<_Tp>>;

    struct _Data
    {
    private:
      template<typename _Tp>
	static consteval bool
	_S_noexcept()
	{
	  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()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
	{
	  if constexpr (__member_data<_Tp>)
	    return __t.data();
	  else
	    return std::to_address(_Begin{}(__t));
	}
    };

  } // namespace __access

  inline namespace _Cpo
  {
    inline constexpr ranges::__access::_Begin begin{};
    inline constexpr ranges::__access::_End end{};
    inline constexpr ranges::__access::_RBegin rbegin{};
    inline constexpr ranges::__access::_REnd rend{};
    inline constexpr ranges::__access::_Size size{};
    inline constexpr ranges::__access::_SSize ssize{};
    inline constexpr ranges::__access::_Empty empty{};
    inline constexpr ranges::__access::_Data data{};
  }

  /// [range.range] The range concept.
  template<typename _Tp>
    concept range = requires(_Tp& __t)
      {
	ranges::begin(__t);
	ranges::end(__t);
      };

  /// [range.range] The borrowed_range concept.
  template<typename _Tp>
    concept borrowed_range
      = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;

  template<typename _Tp>
    using iterator_t = std::__detail::__range_iter_t<_Tp>;

  template<range _Range>
    using sentinel_t = decltype(ranges::end(std::declval<_Range&>()));

#if __glibcxx_ranges_as_const // >= C++23
  // const_iterator_t and const_sentinel_t defined below.

  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>>;

  template<range _Range>
    using range_value_t = iter_value_t<iterator_t<_Range>>;

  template<range _Range>
    using range_reference_t = iter_reference_t<iterator_t<_Range>>;

  template<range _Range>
    using range_rvalue_reference_t
      = iter_rvalue_reference_t<iterator_t<_Range>>;

  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 3860. range_common_reference_t is missing
  template<range _Range>
    using range_common_reference_t
      = iter_common_reference_t<iterator_t<_Range>>;

  /// [range.sized] The sized_range concept.
  template<typename _Tp>
    concept sized_range = range<_Tp>
      && requires(_Tp& __t) { ranges::size(__t); };

  template<sized_range _Range>
    using range_size_t = decltype(ranges::size(std::declval<_Range&>()));

  template<typename _Derived>
    requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
    class view_interface; // defined in <bits/ranges_util.h>

  namespace __detail
  {
    template<typename _Tp, typename _Up>
      requires (!same_as<_Tp, view_interface<_Up>>)
      void __is_derived_from_view_interface_fn(const _Tp&,
					       const view_interface<_Up>&); // not defined

    // Returns true iff _Tp has exactly one public base class that's a
    // specialization of view_interface.
    template<typename _Tp>
      concept __is_derived_from_view_interface
	= requires (_Tp __t) { __is_derived_from_view_interface_fn(__t, __t); };
  } // namespace __detail

  /// [range.view] The ranges::view_base type.
  struct view_base { };

  /// [range.view] The ranges::enable_view boolean.
  template<typename _Tp>
    inline constexpr bool enable_view = derived_from<_Tp, view_base>
      || __detail::__is_derived_from_view_interface<_Tp>;

  /// [range.view] The ranges::view concept.
  template<typename _Tp>
    concept view
      = range<_Tp> && movable<_Tp> && enable_view<_Tp>;

  // [range.refinements]

  /// A range for which ranges::begin returns an output iterator.
  template<typename _Range, typename _Tp>
    concept output_range
      = range<_Range> && output_iterator<iterator_t<_Range>, _Tp>;

  /// A range for which ranges::begin returns an input iterator.
  template<typename _Tp>
    concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>;

  /// A range for which ranges::begin returns a forward iterator.
  template<typename _Tp>
    concept forward_range
      = input_range<_Tp> && forward_iterator<iterator_t<_Tp>>;

  /// A range for which ranges::begin returns a bidirectional iterator.
  template<typename _Tp>
    concept bidirectional_range
      = forward_range<_Tp> && bidirectional_iterator<iterator_t<_Tp>>;

  /// A range for which ranges::begin returns a random access iterator.
  template<typename _Tp>
    concept random_access_range
      = bidirectional_range<_Tp> && random_access_iterator<iterator_t<_Tp>>;

  /// A range for which ranges::begin returns a contiguous iterator.
  template<typename _Tp>
    concept contiguous_range
      = random_access_range<_Tp> && contiguous_iterator<iterator_t<_Tp>>
      && requires(_Tp& __t)
      {
	{ ranges::data(__t) } -> same_as<add_pointer_t<range_reference_t<_Tp>>>;
      };

  /// A range for which ranges::begin and ranges::end return the same type.
  template<typename _Tp>
    concept common_range
      = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>;

#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);
      }
#endif

    struct _CBegin
    {
#if __glibcxx_ranges_as_const // >= C++23
      template<__maybe_borrowed_range _Tp>
	[[nodiscard]]
	constexpr auto
	operator()(_Tp&& __t) const
	noexcept(noexcept(std::make_const_iterator
			  (ranges::begin(__access::__possibly_const_range(__t)))))
	requires requires { std::make_const_iterator
			    (ranges::begin(__access::__possibly_const_range(__t))); }
	{
	  auto& __r = __access::__possibly_const_range(__t);
	  return const_iterator<decltype(ranges::begin(__r))>(ranges::begin(__r));
	}
#else
      template<typename _Tp>
	[[nodiscard]]
	constexpr auto
	operator()(_Tp&& __e) const
	noexcept(noexcept(_Begin{}(__access::__as_const<_Tp>(__e))))
	requires requires { _Begin{}(__access::__as_const<_Tp>(__e)); }
	{
	  return _Begin{}(__access::__as_const<_Tp>(__e));
	}
#endif
    };

    struct _CEnd final
    {
#if __glibcxx_ranges_as_const // >= C++23
      template<__maybe_borrowed_range _Tp>
	[[nodiscard]]
	constexpr auto
	operator()(_Tp&& __t) const
	noexcept(noexcept(std::make_const_sentinel
			  (ranges::end(__access::__possibly_const_range(__t)))))
	requires requires { std::make_const_sentinel
			    (ranges::end(__access::__possibly_const_range(__t))); }
	{
	  auto& __r = __access::__possibly_const_range(__t);
	  return const_sentinel<decltype(ranges::end(__r))>(ranges::end(__r));
	}
#else
      template<typename _Tp>
	[[nodiscard]]
	constexpr auto
	operator()(_Tp&& __e) const
	noexcept(noexcept(_End{}(__access::__as_const<_Tp>(__e))))
	requires requires { _End{}(__access::__as_const<_Tp>(__e)); }
	{
	  return _End{}(__access::__as_const<_Tp>(__e));
	}
#endif
    };

    struct _CRBegin
    {
#if __glibcxx_ranges_as_const // >= C++23
      template<__maybe_borrowed_range _Tp>
	[[nodiscard]]
	constexpr auto
	operator()(_Tp&& __t) const
	noexcept(noexcept(std::make_const_iterator
			  (ranges::rbegin(__access::__possibly_const_range(__t)))))
	requires requires { std::make_const_iterator
			    (ranges::rbegin(__access::__possibly_const_range(__t))); }
	{
	  auto& __r = __access::__possibly_const_range(__t);
	  return const_iterator<decltype(ranges::rbegin(__r))>(ranges::rbegin(__r));
	}
#else
      template<typename _Tp>
	[[nodiscard]]
	constexpr auto
	operator()(_Tp&& __e) const
	noexcept(noexcept(_RBegin{}(__access::__as_const<_Tp>(__e))))
	requires requires { _RBegin{}(__access::__as_const<_Tp>(__e)); }
	{
	  return _RBegin{}(__access::__as_const<_Tp>(__e));
	}
#endif
    };

    struct _CREnd
    {
#if __glibcxx_ranges_as_const // >= C++23
      template<__maybe_borrowed_range _Tp>
	[[nodiscard]]
	constexpr auto
	operator()(_Tp&& __t) const
	noexcept(noexcept(std::make_const_sentinel
			  (ranges::rend(__access::__possibly_const_range(__t)))))
	requires requires { std::make_const_sentinel
			    (ranges::rend(__access::__possibly_const_range(__t))); }
	{
	  auto& __r = __access::__possibly_const_range(__t);
	  return const_sentinel<decltype(ranges::rend(__r))>(ranges::rend(__r));
	}
#else
      template<typename _Tp>
	[[nodiscard]]
	constexpr auto
	operator()(_Tp&& __e) const
	noexcept(noexcept(_REnd{}(__access::__as_const<_Tp>(__e))))
	requires requires { _REnd{}(__access::__as_const<_Tp>(__e)); }
	{
	  return _REnd{}(__access::__as_const<_Tp>(__e));
	}
#endif
    };

    struct _CData
    {
#if __glibcxx_ranges_as_const // >= C++23
      template<__maybe_borrowed_range _Tp>
	[[nodiscard]]
	constexpr const auto*
	operator()(_Tp&& __t) const
	noexcept(noexcept(ranges::data(__access::__possibly_const_range(__t))))
	requires requires { ranges::data(__access::__possibly_const_range(__t)); }
	{ return ranges::data(__access::__possibly_const_range(__t)); }
#else
      template<typename _Tp>
	[[nodiscard]]
	constexpr auto
	operator()(_Tp&& __e) const
	noexcept(noexcept(_Data{}(__access::__as_const<_Tp>(__e))))
	requires requires { _Data{}(__access::__as_const<_Tp>(__e)); }
	{
	  return _Data{}(__access::__as_const<_Tp>(__e));
	}
#endif
    };
  } // namespace __access

  inline namespace _Cpo
  {
    inline constexpr ranges::__access::_CBegin cbegin{};
    inline constexpr ranges::__access::_CEnd cend{};
    inline constexpr ranges::__access::_CRBegin crbegin{};
    inline constexpr ranges::__access::_CREnd crend{};
    inline constexpr ranges::__access::_CData cdata{};
  }

#if __glibcxx_ranges_as_const // >= C++23
  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 3946. The definition of const_iterator_t should be reworked
  template<range _Range>
    using const_iterator_t = decltype(ranges::cbegin(std::declval<_Range&>()));

  template<range _Range>
    using const_sentinel_t = decltype(ranges::cend(std::declval<_Range&>()));
#endif

  namespace __detail
  {
    template<typename _Tp>
      inline constexpr bool __is_initializer_list = false;

    template<typename _Tp>
      inline constexpr bool __is_initializer_list<initializer_list<_Tp>> = true;
  } // namespace __detail

  /// A range which can be safely converted to a view.
  template<typename _Tp>
    concept viewable_range = range<_Tp>
      && ((view<remove_cvref_t<_Tp>> && constructible_from<remove_cvref_t<_Tp>, _Tp>)
	  || (!view<remove_cvref_t<_Tp>>
	      && (is_lvalue_reference_v<_Tp>
		  || (movable<remove_reference_t<_Tp>>
		      && !__detail::__is_initializer_list<remove_cvref_t<_Tp>>))));

  // [range.iter.ops] range iterator operations

  struct __advance_fn final
  {
    template<input_or_output_iterator _It>
      constexpr void
      operator()(_It& __it, iter_difference_t<_It> __n) const
      {
	if constexpr (random_access_iterator<_It>)
	  __it += __n;
	else if constexpr (bidirectional_iterator<_It>)
	  {
	    if (__n > 0)
	      {
		do
		  {
		    ++__it;
		  }
		while (--__n);
	      }
	    else if (__n < 0)
	      {
		do
		  {
		    --__it;
		  }
		while (++__n);
	      }
	  }
	else
	  {
	    // cannot decrement a non-bidirectional iterator
	    __glibcxx_assert(__n >= 0);
	    while (__n-- > 0)
	      ++__it;
	  }
      }

    template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
      constexpr void
      operator()(_It& __it, _Sent __bound) const
      {
	if constexpr (assignable_from<_It&, _Sent>)
	  __it = std::move(__bound);
	else if constexpr (sized_sentinel_for<_Sent, _It>)
	  (*this)(__it, __bound - __it);
	else
	  {
	    while (__it != __bound)
	      ++__it;
	  }
      }

    template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
      constexpr iter_difference_t<_It>
      operator()(_It& __it, iter_difference_t<_It> __n, _Sent __bound) const
      {
	if constexpr (sized_sentinel_for<_Sent, _It>)
	  {
	    const iter_difference_t<_It> __diff = __bound - __it;

	    if (__diff == 0)
	      {
		// inline any possible side effects of advance(it, bound)
		if constexpr (assignable_from<_It&, _Sent>)
		  __it = std::move(__bound);
		else if constexpr (random_access_iterator<_It>)
		  __it += iter_difference_t<_It>(0);
		return __n;
	      }
	    else if (__diff > 0 ? __n >= __diff : __n <= __diff)
	      {
		(*this)(__it, __bound);
		return __n - __diff;
	      }
	    else if (__n != 0) [[likely]]
	      {
		// n and bound must not lead in opposite directions:
		__glibcxx_assert((__n < 0) == (__diff < 0));

		(*this)(__it, __n);
		return 0;
	      }
	    else
	      {
		// inline any possible side effects of advance(it, n)
		if constexpr (random_access_iterator<_It>)
		  __it += iter_difference_t<_It>(0);
		return 0;
	      }
	  }
	else if (__n == 0 || __it == __bound)
	  return __n;
	else if (__n > 0)
	  {
	    iter_difference_t<_It> __m = 0;
	    do
	      {
		++__it;
		++__m;
	      }
	    while (__m != __n && __it != __bound);
	    return __n - __m;
	  }
	else if constexpr (bidirectional_iterator<_It> && same_as<_It, _Sent>)
	  {
	    iter_difference_t<_It> __m = 0;
	    do
	      {
		--__it;
		--__m;
	      }
	    while (__m != __n && __it != __bound);
	    return __n - __m;
	  }
	else
	  {
	    // cannot decrement a non-bidirectional iterator
	    __glibcxx_assert(__n >= 0);
	    return __n;
	  }
      }

    void operator&() const = delete;
  };

  inline constexpr __advance_fn advance{};

  struct __distance_fn final
  {
    template<typename _It, sentinel_for<_It> _Sent>
      requires (!sized_sentinel_for<_Sent, _It>)
      constexpr iter_difference_t<_It>
      operator()[[nodiscard]](_It __first, _Sent __last) const
      {
	iter_difference_t<_It> __n = 0;
	while (__first != __last)
	  {
	    ++__first;
	    ++__n;
	  }
	return __n;
      }

    // _GLIBCXX_RESOLVE_LIB_DEFECTS
    // 3392. cannot be used on a move-only iterator with a sized sentinel
    // 3664. LWG 3392 broke std::ranges::distance(a, a+3)
    // 4242. ranges::distance does not work with volatile iterators
    template<typename _It, sized_sentinel_for<decay_t<_It>> _Sent>
      [[nodiscard, __gnu__::__always_inline__]]
      constexpr iter_difference_t<decay_t<_It>>
      operator()(_It&& __first, _Sent __last) const
      {
	if constexpr (!is_array_v<remove_reference_t<_It>>)
	  return __last - __first;
	else
	  return __last - static_cast<decay_t<_It>>(__first);
      }

    template<range _Range>
      [[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, __gnu__::__always_inline__]]
      constexpr _It
      operator()(_It __x) const
      {
	++__x;
	return __x;
      }

    template<input_or_output_iterator _It>
      [[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, __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, __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, __gnu__::__always_inline__]]
      constexpr _It
      operator()(_It __x) const
      {
	--__x;
	return __x;
      }

    template<bidirectional_iterator _It>
      [[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, __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;
  };

  inline constexpr __prev_fn prev{};

  /// Type returned by algorithms instead of a dangling iterator or subrange.
  struct dangling
  {
    constexpr dangling() noexcept = default;
    template<typename... _Args>
      constexpr dangling(_Args&&...) noexcept { }
  };

  template<range _Range>
    using borrowed_iterator_t = __conditional_t<borrowed_range<_Range>,
						iterator_t<_Range>,
						dangling>;
} // namespace ranges

#if __glibcxx_ranges_to_container // C++ >= 23
  struct from_range_t { explicit from_range_t() = default; };
  inline constexpr from_range_t from_range{};
#endif

#if __glibcxx_containers_ranges // C++ >= 23
/// @cond undocumented
  template<typename _T1, typename _T2>
    struct pair;

namespace __detail
{
  template<typename _Rg, typename _Tp>
    concept __container_compatible_range
      = ranges::input_range<_Rg>
	  && convertible_to<ranges::range_reference_t<_Rg>, _Tp>;

  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 4223. Deduction guides for maps are mishandling tuples and references
  template<ranges::input_range _Range>
    using __range_key_type
      = remove_cvref_t<tuple_element_t<0, ranges::range_value_t<_Range>>>;

  template<ranges::input_range _Range>
    using __range_mapped_type
      = remove_cvref_t<tuple_element_t<1, ranges::range_value_t<_Range>>>;

  // The allocator's value_type for map-like containers.
  template<ranges::input_range _Range>
    using __range_to_alloc_type
      = pair<const __range_key_type<_Range>, __range_mapped_type<_Range>>;
}
/// @endcond
#endif

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // library concepts
#pragma GCC diagnostic pop
#endif // C++20
#endif // _GLIBCXX_RANGES_BASE_H
