STL/stl/inc/ranges

9263 строки
406 KiB
C++

// ranges standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef _RANGES_
#define _RANGES_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#if !_HAS_CXX20
_EMIT_STL_WARNING(STL4038, "The contents of <ranges> are available only with C++20 or later.");
#else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv
#include <__msvc_int128.hpp>
#include <__msvc_ranges_to.hpp>
#include <iosfwd>
#include <iterator>
#include <limits>
#include <span>
#include <string_view>
#include <tuple>
#if _HAS_CXX23
#include <array>
#include <bit>
#endif // _HAS_CXX23
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
_STD_BEGIN
namespace ranges {
// MUCH machinery defined in <xutility>, some in <__msvc_ranges_to.hpp>
template <auto> // _Require_constant<E> is a valid template-id iff E is a constant expression of structural type
struct _Require_constant;
#if _HAS_CXX23
_EXPORT_STD template <range _Rng>
using const_iterator_t = decltype(_RANGES cbegin(_STD declval<_Rng&>()));
_EXPORT_STD template <range _Rng>
using const_sentinel_t = decltype(_RANGES cend(_STD declval<_Rng&>()));
_EXPORT_STD template <range _Rng>
using range_const_reference_t = iter_const_reference_t<iterator_t<_Rng>>;
template <range _Ty>
constexpr auto _Compile_time_max_size = (numeric_limits<_Make_unsigned_like_t<range_difference_t<_Ty>>>::max)();
template <sized_range _Ty>
constexpr auto _Compile_time_max_size<_Ty> = (numeric_limits<range_size_t<_Ty>>::max)();
#ifdef __EDG__ // TRANSITION, VSO-1898880
template <class _Ty>
concept _Constant_sized_range = sized_range<_Ty> && requires { typename _Require_constant<_Ty::size()>; };
template <_Constant_sized_range _Ty>
constexpr auto _Compile_time_max_size<_Ty> = _Ty::size();
#else // ^^^ workaround / no workaround vvv
template <sized_range _Ty>
requires requires { typename _Require_constant<_Ty::size()>; }
constexpr auto _Compile_time_max_size<_Ty> = _Ty::size();
#endif // ^^^ no workaround ^^^
template <class _Ty, size_t _Size>
constexpr auto _Compile_time_max_size<_Ty[_Size]> = _Size;
template <class _Ty, size_t _Size>
constexpr auto _Compile_time_max_size<array<_Ty, _Size>> = _Size;
template <class _Ty, size_t _Size>
constexpr auto _Compile_time_max_size<const array<_Ty, _Size>> = _Size;
template <class _Ty, size_t _Extent>
requires (_Extent != dynamic_extent)
constexpr auto _Compile_time_max_size<span<_Ty, _Extent>> = _Extent;
template <class _Ty, size_t _Extent>
requires (_Extent != dynamic_extent)
constexpr auto _Compile_time_max_size<const span<_Ty, _Extent>> = _Extent;
#endif // _HAS_CXX23
template <class _Rng>
concept _Simple_view = view<_Rng> && range<const _Rng> && same_as<iterator_t<_Rng>, iterator_t<const _Rng>>
&& same_as<sentinel_t<_Rng>, sentinel_t<const _Rng>>;
template <class _It>
concept _Has_arrow = input_iterator<_It> && (is_pointer_v<_It> || _Has_member_arrow<_It&>);
template <bool _IsWrapped, class _Ty>
using _Maybe_wrapped = conditional_t<_IsWrapped, _Ty, _Unwrapped_t<_Ty>>;
template <range _Rng, class _Derived>
class _Cached_position : public view_interface<_Derived> {
static_assert(_Always_false<_Rng>, "A range must be at least forward for position caching to be worthwhile.");
};
template <forward_range _Rng, class _Derived>
class _Cached_position<_Rng, _Derived> : public view_interface<_Derived> {
private:
using _It = iterator_t<_Rng>;
/* [[no_unique_address]] */ _It _Pos{};
bool _Cached = false;
protected:
_Cached_position() = default;
~_Cached_position() = default;
// a copied iterator doesn't point into a copied range, so cache values must not propagate via copy
constexpr _Cached_position(const _Cached_position&) noexcept(is_nothrow_default_constructible_v<_It>) {}
constexpr _Cached_position& operator=(const _Cached_position&) noexcept(noexcept(_Pos = _It{})) {
_Pos = _It{};
_Cached = false;
return *this;
}
// a moved iterator doesn't point into a moved range, so cache values must not propagate via move;
// similarly, a cache value might not be valid for a moved-from view so clear move sources
constexpr _Cached_position(_Cached_position&& _Other) noexcept(noexcept(_Pos = _It{})) {
_Other._Pos = _It{};
_Other._Cached = false;
}
constexpr _Cached_position& operator=(_Cached_position&& _Other) noexcept(noexcept(_Pos = _It{})) {
_Pos = _It{};
_Cached = false;
_Other._Pos = _It{};
_Other._Cached = false;
return *this;
}
_NODISCARD constexpr bool _Has_cache() const noexcept { // Is there a cached position?
return _Cached;
}
_NODISCARD constexpr _It _Get_cache(_Rng&) const noexcept(is_nothrow_copy_constructible_v<_It>) {
_STL_INTERNAL_CHECK(_Cached);
return _Pos;
}
constexpr void _Set_cache(_Rng&, _It _Iter) noexcept(is_nothrow_move_assignable_v<_It>) {
_Pos = _STD move(_Iter);
_Cached = true;
}
};
template <random_access_range _Rng, class _Derived>
class _Cached_position<_Rng, _Derived> : public view_interface<_Derived> {
private:
using _It = iterator_t<_Rng>;
range_difference_t<_Rng> _Off = -1;
protected:
_Cached_position() = default;
~_Cached_position() = default;
// Offsets are oblivious to copying, so cache values _do_ propagate via copying.
_Cached_position(const _Cached_position&) = default;
_Cached_position& operator=(const _Cached_position&) = default;
// Offsets are potentially invalidated by move, so source caches are invalidated after move
constexpr _Cached_position(_Cached_position&& _Other) noexcept
: _Off(_STD exchange(_Other._Off, range_difference_t<_Rng>{-1})) {}
constexpr _Cached_position& operator=(_Cached_position&& _Other) noexcept {
_Off = _STD exchange(_Other._Off, range_difference_t<_Rng>{-1});
return *this;
}
_NODISCARD constexpr bool _Has_cache() const noexcept { // Is there a cached position?
return _Off >= range_difference_t<_Rng>{0};
}
_NODISCARD constexpr _It _Get_cache(_Rng& _Range) const noexcept(noexcept(_RANGES begin(_Range) + _Off)) {
_STL_INTERNAL_CHECK(_Has_cache());
return _RANGES begin(_Range) + _Off;
}
constexpr void _Set_cache(_Rng& _Range, const _It& _Iter)
noexcept(noexcept(_Off = _Iter - _RANGES begin(_Range))) {
_Off = _Iter - _RANGES begin(_Range);
}
};
template <bool _Enable, class _Rng, class _Derived>
using _Cached_position_t = conditional_t<_Enable, _Cached_position<_Rng, _Derived>, view_interface<_Derived>>;
template <movable _Ty>
class _Defaultabox { // a simplified optional that augments movable types with default-constructibility
public:
constexpr _Defaultabox() noexcept {}
constexpr ~_Defaultabox() {
if (_Engaged) {
_Val.~_Ty();
}
}
~_Defaultabox()
requires is_trivially_destructible_v<_Ty>
= default;
_Defaultabox(const _Defaultabox&)
requires copy_constructible<_Ty> && is_trivially_copy_constructible_v<_Ty>
= default;
constexpr _Defaultabox(const _Defaultabox& _That) noexcept(is_nothrow_copy_constructible_v<_Ty>)
requires copy_constructible<_Ty>
: _Engaged{_That._Engaged} {
if (_That._Engaged) {
_STD _Construct_in_place(_Val, static_cast<const _Ty&>(_That._Val));
}
}
_Defaultabox(_Defaultabox&&)
requires is_trivially_move_constructible_v<_Ty>
= default;
constexpr _Defaultabox(_Defaultabox&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>)
: _Engaged{_That._Engaged} {
if (_That._Engaged) {
_STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val));
}
}
template <_Different_from<_Ty> _Uty>
requires convertible_to<const _Uty&, _Ty>
constexpr _Defaultabox(const _Defaultabox<_Uty>& _That) noexcept(is_nothrow_constructible_v<_Ty, const _Uty&>)
: _Engaged{_That} {
if (_That) {
_STD _Construct_in_place(_Val, *_That);
}
}
template <_Different_from<_Ty> _Uty>
requires convertible_to<_Uty, _Ty>
constexpr _Defaultabox(_Defaultabox<_Uty>&& _That) noexcept(is_nothrow_constructible_v<_Ty, _Uty>)
: _Engaged{_That} {
if (_That) {
_STD _Construct_in_place(_Val, _STD move(*_That));
}
}
_Defaultabox& operator=(const _Defaultabox&) noexcept
requires copyable<_Ty> && is_trivially_copy_assignable_v<_Ty>
= default;
constexpr _Defaultabox& operator=(const _Defaultabox& _That)
noexcept(is_nothrow_copy_constructible_v<_Ty> && is_nothrow_copy_assignable_v<_Ty>)
requires copyable<_Ty>
{
if (_Engaged) {
if (_That._Engaged) {
static_cast<_Ty&>(_Val) = static_cast<const _Ty&>(_That._Val);
} else {
_Val.~_Ty();
_Engaged = false;
}
} else {
if (_That._Engaged) {
_STD _Construct_in_place(_Val, static_cast<const _Ty&>(_That._Val));
_Engaged = true;
} else {
// nothing to do
}
}
return *this;
}
_Defaultabox& operator=(_Defaultabox&&) noexcept
requires is_trivially_move_assignable_v<_Ty>
= default;
constexpr _Defaultabox& operator=(_Defaultabox&& _That)
noexcept(is_nothrow_move_constructible_v<_Ty> && is_nothrow_move_assignable_v<_Ty>) {
if (_Engaged) {
if (_That._Engaged) {
static_cast<_Ty&>(_Val) = static_cast<_Ty&&>(_That._Val);
} else {
_Val.~_Ty();
_Engaged = false;
}
} else {
if (_That._Engaged) {
_STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val));
_Engaged = true;
} else {
// nothing to do
}
}
return *this;
}
constexpr _Defaultabox& operator=(_Ty&& _That)
noexcept(is_nothrow_move_constructible_v<_Ty> && is_nothrow_move_assignable_v<_Ty>) {
if (_Engaged) {
static_cast<_Ty&>(_Val) = _STD move(_That);
} else {
_STD _Construct_in_place(_Val, _STD move(_That));
_Engaged = true;
}
return *this;
}
constexpr _Defaultabox& operator=(const _Ty& _That)
noexcept(is_nothrow_copy_constructible_v<_Ty> && is_nothrow_copy_assignable_v<_Ty>)
requires copyable<_Ty>
{
if (_Engaged) {
static_cast<_Ty&>(_Val) = _That;
} else {
_STD _Construct_in_place(_Val, _That);
_Engaged = true;
}
return *this;
}
constexpr explicit operator bool() const noexcept {
return _Engaged;
}
_NODISCARD constexpr _Ty& operator*() noexcept {
_STL_INTERNAL_CHECK(_Engaged);
return _Val;
}
_NODISCARD constexpr const _Ty& operator*() const noexcept {
_STL_INTERNAL_CHECK(_Engaged);
return _Val;
}
constexpr void _Reset() noexcept {
if (_Engaged) {
_Val.~_Ty();
_Engaged = false;
}
}
_NODISCARD constexpr bool operator==(const _Defaultabox& _That) const
noexcept(noexcept(static_cast<const _Ty&>(_Val) == static_cast<const _Ty&>(_That._Val))) {
_STL_INTERNAL_STATIC_ASSERT(equality_comparable<_Ty>);
return _Engaged == _That._Engaged
&& (!_Engaged || static_cast<const _Ty&>(_Val) == static_cast<const _Ty&>(_That._Val));
}
private:
union {
remove_cv_t<_Ty> _Val;
};
bool _Engaged = false;
};
template <movable _Ty>
requires default_initializable<_Ty>
class _Defaultabox<_Ty> { // provide the same API more efficiently for default-constructible types
public:
_Defaultabox() = default;
template <_Different_from<_Ty> _Uty>
requires convertible_to<const _Uty&, _Ty>
constexpr _Defaultabox(const _Defaultabox<_Uty>& _That)
noexcept(is_nothrow_default_constructible_v<_Ty> && noexcept(_Value = static_cast<_Ty>(*_That))) {
if (_That) {
_Value = static_cast<_Ty>(*_That);
}
}
template <_Different_from<_Ty> _Uty>
requires convertible_to<_Uty, _Ty>
constexpr _Defaultabox(_Defaultabox<_Uty>&& _That) noexcept(
is_nothrow_default_constructible_v<_Ty> && noexcept(_Value = static_cast<_Ty>(_STD move(*_That)))) {
if (_That) {
_Value = static_cast<_Ty>(_STD move(*_That));
}
}
constexpr _Defaultabox& operator=(const _Ty& _Right) noexcept(is_nothrow_copy_assignable_v<_Ty>)
requires copyable<_Ty>
{
_Value = _Right;
return *this;
}
constexpr _Defaultabox& operator=(_Ty&& _Right) noexcept(is_nothrow_move_assignable_v<_Ty>) {
_Value = _STD move(_Right);
return *this;
}
constexpr explicit operator bool() const noexcept {
return true;
}
_NODISCARD constexpr _Ty& operator*() noexcept {
return _Value;
}
_NODISCARD constexpr const _Ty& operator*() const noexcept {
return _Value;
}
constexpr void _Reset() noexcept(noexcept(_Value = _Ty{})) {
_Value = _Ty{};
}
_NODISCARD bool operator==(const _Defaultabox&) const = default;
private:
/* [[no_unique_address]] */ _Ty _Value{};
};
template <_Destructible_object _Ty, bool _Needs_operator_bool = true>
class _Non_propagating_cache { // a simplified optional that resets on copy / move
public:
constexpr _Non_propagating_cache() noexcept {}
constexpr ~_Non_propagating_cache() {
if (_Engaged) {
_Val.~_Ty();
}
}
~_Non_propagating_cache()
requires is_trivially_destructible_v<_Ty>
= default;
constexpr _Non_propagating_cache(const _Non_propagating_cache&) noexcept {}
constexpr _Non_propagating_cache(_Non_propagating_cache&& _Other) noexcept {
if (_Other._Engaged) {
_Other._Val.~_Ty();
_Other._Engaged = false;
}
}
constexpr _Non_propagating_cache& operator=(const _Non_propagating_cache& _Other) noexcept {
if (_STD addressof(_Other) == this) {
return *this;
}
if (_Engaged) {
_Val.~_Ty();
_Engaged = false;
}
return *this;
}
constexpr _Non_propagating_cache& operator=(_Non_propagating_cache&& _Other) noexcept {
if (_Engaged) {
_Val.~_Ty();
_Engaged = false;
}
if (_Other._Engaged) {
_Other._Val.~_Ty();
_Other._Engaged = false;
}
return *this;
}
_NODISCARD constexpr explicit operator bool() const noexcept
requires _Needs_operator_bool
{
return _Engaged;
}
_NODISCARD constexpr _Ty& operator*() noexcept {
_STL_INTERNAL_CHECK(_Engaged);
return _Val;
}
_NODISCARD constexpr const _Ty& operator*() const noexcept {
_STL_INTERNAL_CHECK(_Engaged);
return _Val;
}
template <class... _Types>
constexpr _Ty& _Emplace(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) {
if (_Engaged) {
_Val.~_Ty();
_Engaged = false;
}
_STD _Construct_in_place(_Val, _STD forward<_Types>(_Args)...);
_Engaged = true;
return _Val;
}
private:
union {
remove_cv_t<_Ty> _Val;
};
bool _Engaged = false;
};
template <_Destructible_object _Ty>
requires is_trivially_destructible_v<_Ty>
class _Non_propagating_cache<_Ty, false> { // a specialization for trivially destructible types where checking if
// the cache contains a value is not needed
public:
constexpr _Non_propagating_cache() noexcept {}
~_Non_propagating_cache() = default;
constexpr _Non_propagating_cache(const _Non_propagating_cache&) noexcept {}
constexpr _Non_propagating_cache(_Non_propagating_cache&&) noexcept {}
constexpr _Non_propagating_cache& operator=(const _Non_propagating_cache&) noexcept {
return *this;
}
constexpr _Non_propagating_cache& operator=(_Non_propagating_cache&&) noexcept {
return *this;
}
_NODISCARD constexpr _Ty& operator*() noexcept {
return _Val;
}
_NODISCARD constexpr const _Ty& operator*() const noexcept {
return _Val;
}
template <class... _Types>
constexpr _Ty& _Emplace(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) {
_STD _Construct_in_place(_Val, _STD forward<_Types>(_Args)...);
return _Val;
}
private:
union {
remove_cv_t<_Ty> _Val;
};
};
#if _HAS_CXX23
_EXPORT_STD template <class _Derived>
requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
class range_adaptor_closure : public _Pipe::_Base<_Derived> {};
#endif // _HAS_CXX23
_EXPORT_STD template <class _Ty>
requires is_object_v<_Ty>
class empty_view : public view_interface<empty_view<_Ty>> {
public:
_NODISCARD static constexpr _Ty* begin() noexcept {
return nullptr;
}
_NODISCARD static constexpr _Ty* end() noexcept {
return nullptr;
}
_NODISCARD static constexpr _Ty* data() noexcept {
return nullptr;
}
_NODISCARD static constexpr size_t size() noexcept {
return 0;
}
_NODISCARD static constexpr bool empty() noexcept {
return true;
}
};
template <class _Ty>
constexpr bool enable_borrowed_range<empty_view<_Ty>> = true;
namespace views {
_EXPORT_STD template <class _Ty>
constexpr empty_view<_Ty> empty;
} // namespace views
_EXPORT_STD template <_Valid_movable_box_object _Ty>
class single_view : public view_interface<single_view<_Ty>> {
public:
single_view()
requires default_initializable<_Ty>
= default;
constexpr explicit single_view(const _Ty& _Val_) noexcept(is_nothrow_copy_constructible_v<_Ty>) // strengthened
requires copy_constructible<_Ty>
: _Val{in_place, _Val_} {}
constexpr explicit single_view(_Ty&& _Val_) noexcept(is_nothrow_move_constructible_v<_Ty>) // strengthened
: _Val{in_place, _STD move(_Val_)} {}
template <class... _Types>
requires constructible_from<_Ty, _Types...>
constexpr explicit single_view(in_place_t, _Types&&... _Args)
noexcept(is_nothrow_constructible_v<_Ty, _Types...>) // strengthened
: _Val{in_place, _STD forward<_Types>(_Args)...} {}
_NODISCARD constexpr _Ty* begin() noexcept {
return data();
}
_NODISCARD constexpr const _Ty* begin() const noexcept {
return data();
}
_NODISCARD constexpr _Ty* end() noexcept {
return data() + 1;
}
_NODISCARD constexpr const _Ty* end() const noexcept {
return data() + 1;
}
_NODISCARD static constexpr bool empty() noexcept {
return false;
}
_NODISCARD static constexpr size_t size() noexcept {
return 1;
}
_NODISCARD constexpr _Ty* data() noexcept {
return _STD addressof(*_Val);
}
_NODISCARD constexpr const _Ty* data() const noexcept {
return _STD addressof(*_Val);
}
private:
/* [[no_unique_address]] */ _Movable_box<_Ty> _Val{};
};
template <class _Ty>
single_view(_Ty) -> single_view<_Ty>;
namespace views {
struct _Single_fn {
template <class _Ty>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty&& _Val) _CONST_CALL_OPERATOR
noexcept(noexcept(single_view<decay_t<_Ty>>(_STD forward<_Ty>(_Val))))
requires requires {
typename single_view<decay_t<_Ty>>;
single_view<decay_t<_Ty>>(static_cast<_Ty&&>(_Val));
}
{
return single_view<decay_t<_Ty>>(_STD forward<_Ty>(_Val));
}
};
_EXPORT_STD inline constexpr _Single_fn single;
} // namespace views
template <class _Ty>
using _Iota_diff_t = conditional_t<is_integral_v<_Ty>,
conditional_t<sizeof(_Ty) < sizeof(int), int,
conditional_t<sizeof(_Ty) < sizeof(long long), long long, _Signed128>>,
iter_difference_t<_Ty>>;
template <class _Ty>
concept _Decrementable = incrementable<_Ty> && requires(_Ty __t) {
{ --__t } -> same_as<_Ty&>;
{ __t-- } -> same_as<_Ty>;
};
template <class _Ty>
concept _Advanceable =
_Decrementable<_Ty> && totally_ordered<_Ty> && requires(_Ty __i, const _Ty __j, const _Iota_diff_t<_Ty> __n) {
{ __i += __n } -> same_as<_Ty&>;
{ __i -= __n } -> same_as<_Ty&>;
_Ty(__j + __n);
_Ty(__n + __j);
_Ty(__j - __n);
{ __j - __j } -> convertible_to<_Iota_diff_t<_Ty>>;
};
template <class _Wi>
struct _Ioterator_category_base {};
template <incrementable _Wi>
requires integral<_Iota_diff_t<_Wi>>
struct _Ioterator_category_base<_Wi> {
using iterator_category = input_iterator_tag;
};
template <weakly_incrementable _Wi>
requires copyable<_Wi>
struct _Ioterator : _Ioterator_category_base<_Wi> {
/* [[no_unique_address]] */ _Wi _Current{};
using iterator_concept = conditional_t<_Advanceable<_Wi>, random_access_iterator_tag,
conditional_t<_Decrementable<_Wi>, bidirectional_iterator_tag,
conditional_t<incrementable<_Wi>, forward_iterator_tag, input_iterator_tag>>>;
using value_type = _Wi;
using difference_type = _Iota_diff_t<_Wi>;
_Ioterator()
requires default_initializable<_Wi>
= default;
constexpr explicit _Ioterator(_Wi _Val) noexcept(is_nothrow_move_constructible_v<_Wi>) /* strengthened */
: _Current(_STD move(_Val)) {}
_NODISCARD constexpr _Wi operator*() const noexcept(is_nothrow_copy_constructible_v<_Wi>) {
return _Current;
}
constexpr _Ioterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ {
++_Current;
return *this;
}
constexpr auto operator++(int) noexcept(
noexcept(++_Current) && (!incrementable<_Wi> || is_nothrow_copy_constructible_v<_Wi>) ) /* strengthened */ {
if constexpr (incrementable<_Wi>) {
auto _Tmp = *this;
++_Current;
return _Tmp;
} else {
++_Current;
}
}
constexpr _Ioterator& operator--() noexcept(noexcept(--_Current)) /* strengthened */
requires _Decrementable<_Wi>
{
--_Current;
return *this;
}
constexpr _Ioterator operator--(int) noexcept(is_nothrow_copy_constructible_v<_Wi> //
&& noexcept(--_Current)) /* strengthened */
requires _Decrementable<_Wi>
{
auto _Tmp = *this;
--_Current;
return _Tmp;
}
#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, DevCom-1347136
private:
template <class _Left, class _Right>
static constexpr bool _Nothrow_plus_equal = noexcept(_STD declval<_Left&>() += _STD declval<const _Right&>());
template <_Integer_like _Left, class _Right>
static constexpr bool _Nothrow_plus_equal<_Left, _Right> = true;
template <class _Left, class _Right>
static constexpr bool _Nothrow_minus_equal = noexcept(_STD declval<_Left&>() -= _STD declval<const _Right&>());
template <_Integer_like _Left, class _Right>
static constexpr bool _Nothrow_minus_equal<_Left, _Right> = true;
public:
#endif // ^^^ workaround ^^^
constexpr _Ioterator& operator+=(const difference_type _Off)
#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-1347136
noexcept(noexcept(_Current += _Off)) /* strengthened */
#else // ^^^ no workaround / workaround vvv
noexcept(_Nothrow_plus_equal<_Wi, difference_type>) /* strengthened */
#endif // ^^^ workaround ^^^
requires _Advanceable<_Wi>
{
if constexpr (_Integer_like<_Wi>) {
if constexpr (_Signed_integer_like<_Wi>) {
_Current = static_cast<_Wi>(_Current + _Off);
} else {
if (_Off >= difference_type{0}) {
_Current += static_cast<_Wi>(_Off);
} else {
_Current -= static_cast<_Wi>(-_Off);
}
}
} else {
_Current += _Off;
}
return *this;
}
constexpr _Ioterator& operator-=(const difference_type _Off)
#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-1347136
noexcept(noexcept(_Current -= _Off)) /* strengthened */
#else // ^^^ no workaround / workaround vvv
noexcept(_Nothrow_minus_equal<_Wi, difference_type>) /* strengthened */
#endif // ^^^ workaround ^^^
requires _Advanceable<_Wi>
{
if constexpr (_Integer_like<_Wi>) {
if constexpr (_Signed_integer_like<_Wi>) {
_Current = static_cast<_Wi>(_Current - _Off);
} else {
if (_Off >= difference_type{0}) {
_Current -= static_cast<_Wi>(_Off);
} else {
_Current += static_cast<_Wi>(-_Off);
}
}
} else {
_Current -= _Off;
}
return *this;
}
_NODISCARD constexpr _Wi operator[](const difference_type _Idx) const
noexcept(noexcept(static_cast<_Wi>(_Current + _Idx))) /* strengthened */
requires _Advanceable<_Wi>
{
if constexpr (_Integer_like<_Wi>) {
return static_cast<_Wi>(_Current + static_cast<_Wi>(_Idx));
} else {
return static_cast<_Wi>(_Current + _Idx);
}
}
_NODISCARD friend constexpr bool operator==(const _Ioterator& _Left, const _Ioterator& _Right)
noexcept(noexcept(_Left._Current == _Right._Current))
requires equality_comparable<_Wi>
{
return _Left._Current == _Right._Current;
}
_NODISCARD friend constexpr bool operator<(const _Ioterator& _Left, const _Ioterator& _Right)
noexcept(noexcept(_Left._Current < _Right._Current)) /* strengthened */
requires totally_ordered<_Wi>
{
return _Left._Current < _Right._Current;
}
_NODISCARD friend constexpr bool operator>(const _Ioterator& _Left, const _Ioterator& _Right)
noexcept(noexcept(_Right._Current < _Left._Current)) /* strengthened */
requires totally_ordered<_Wi>
{
return _Right._Current < _Left._Current;
}
_NODISCARD friend constexpr bool operator<=(const _Ioterator& _Left, const _Ioterator& _Right)
noexcept(noexcept(!(_Right._Current < _Left._Current))) /* strengthened */
requires totally_ordered<_Wi>
{
return !(_Right._Current < _Left._Current);
}
_NODISCARD friend constexpr bool operator>=(const _Ioterator& _Left, const _Ioterator& _Right)
noexcept(noexcept(!(_Left._Current < _Right._Current))) /* strengthened */
requires totally_ordered<_Wi>
{
return !(_Left._Current < _Right._Current);
}
_NODISCARD friend constexpr auto operator<=>(const _Ioterator& _Left, const _Ioterator& _Right)
noexcept(noexcept(_Left._Current <=> _Right._Current))
requires totally_ordered<_Wi> && three_way_comparable<_Wi>
{
return _Left._Current <=> _Right._Current;
}
_NODISCARD friend constexpr _Ioterator operator+(_Ioterator _It, const difference_type _Off)
noexcept(is_nothrow_move_constructible_v<_Ioterator> && noexcept(_It += _Off)) /* strengthened */
requires _Advanceable<_Wi>
{
_It += _Off;
return _It;
}
_NODISCARD friend constexpr _Ioterator operator+(const difference_type _Off, _Ioterator _It) noexcept(
is_nothrow_move_constructible_v<_Wi> && noexcept(static_cast<_Wi>(_It._Current + _Off))) /* strengthened */
requires _Advanceable<_Wi>
{
return _Ioterator{static_cast<_Wi>(_It._Current + _Off)};
}
_NODISCARD friend constexpr _Ioterator operator-(_Ioterator _It, const difference_type _Off)
noexcept(is_nothrow_move_constructible_v<_Ioterator> && noexcept(_It -= _Off)) /* strengthened */
requires _Advanceable<_Wi>
{
_It -= _Off;
return _It;
}
_NODISCARD friend constexpr difference_type operator-(const _Ioterator& _Left, const _Ioterator& _Right)
noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */
requires _Advanceable<_Wi>
{
if constexpr (_Integer_like<_Wi>) {
if constexpr (_Signed_integer_like<_Wi>) {
return static_cast<difference_type>(
static_cast<difference_type>(_Left._Current) - static_cast<difference_type>(_Right._Current));
} else if (_Right._Current > _Left._Current) {
return static_cast<difference_type>(
-static_cast<difference_type>(_Right._Current - _Left._Current));
} else {
return static_cast<difference_type>(_Left._Current - _Right._Current);
}
} else {
return static_cast<difference_type>(_Left._Current - _Right._Current);
}
}
};
template <weakly_incrementable _Wi, semiregular _Bo>
requires _Weakly_equality_comparable_with<_Wi, _Bo> && copyable<_Wi>
struct _Iotinel {
private:
using _It = _Ioterator<_Wi>;
_NODISCARD constexpr bool _Equal(const _It& _That) const noexcept(noexcept(_That._Current == _Last)) {
return _That._Current == _Last;
}
_NODISCARD constexpr iter_difference_t<_Wi> _Delta(const _It& _That) const
noexcept(noexcept(_Last - _That._Current)) {
_STL_INTERNAL_STATIC_ASSERT(sized_sentinel_for<_Bo, _Wi>);
return _Last - _That._Current;
}
public:
/* [[no_unique_address]] */ _Bo _Last{};
_NODISCARD friend constexpr bool operator==(const _It& _Left, const _Iotinel& _Right)
noexcept(noexcept(_Right._Equal(_Left))) /* strengthened */ {
return _Right._Equal(_Left);
}
_NODISCARD friend constexpr iter_difference_t<_Wi> operator-(const _It& _Left, const _Iotinel& _Right)
noexcept(noexcept(_Right._Delta(_Left))) /* strengthened */
requires sized_sentinel_for<_Bo, _Wi>
{
return -_Right._Delta(_Left);
}
_NODISCARD friend constexpr iter_difference_t<_Wi> operator-(const _Iotinel& _Left, const _It& _Right)
noexcept(noexcept(_Left._Delta(_Right))) /* strengthened */
requires sized_sentinel_for<_Bo, _Wi>
{
return _Left._Delta(_Right);
}
};
_EXPORT_STD template <weakly_incrementable _Wi, semiregular _Bo = unreachable_sentinel_t>
requires _Weakly_equality_comparable_with<_Wi, _Bo> && copyable<_Wi>
class iota_view : public view_interface<iota_view<_Wi, _Bo>> {
private:
/* [[no_unique_address]] */ _Wi _Value{};
/* [[no_unique_address]] */ _Bo _Bound{};
using _It = _Ioterator<_Wi>;
using _Se = conditional_t<same_as<_Wi, _Bo>, _It,
conditional_t<same_as<_Bo, unreachable_sentinel_t>, _Bo, _Iotinel<_Wi, _Bo>>>;
_NODISCARD static constexpr _Bo& _Bound_from(_Se& _Last) noexcept {
if constexpr (same_as<_Wi, _Bo>) {
return _Last._Current;
} else if constexpr (same_as<_Bo, unreachable_sentinel_t>) {
return _Last;
} else {
return _Last._Last;
}
}
public:
iota_view()
requires default_initializable<_Wi>
= default;
constexpr explicit iota_view(_Wi _Value_)
noexcept(is_nothrow_move_constructible_v<_Wi> && is_nothrow_default_constructible_v<_Bo>) // strengthened
: _Value(_STD move(_Value_)) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (totally_ordered_with<_Wi, _Bo>) {
_STL_VERIFY(_Value_ <= _Bound, "Per N4981 [range.iota.view]/6, the first argument must not exceed the "
"value-initialized bound when their types are totally ordered.");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
constexpr explicit iota_view(type_identity_t<_Wi> _Value_, type_identity_t<_Bo> _Bound_)
noexcept(is_nothrow_move_constructible_v<_Wi> && is_nothrow_move_constructible_v<_Bo>) // strengthened
: _Value(_STD move(_Value_)), _Bound(_STD move(_Bound_)) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (totally_ordered_with<_Wi, _Bo>) {
_STL_VERIFY(_Value_ <= _Bound_, "Per N4981 [range.iota.view]/8, the first argument must not exceed the "
"second when their types are totally ordered.");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
constexpr explicit iota_view(_It _First, _Se _Last)
noexcept(is_nothrow_move_constructible_v<_Wi> && is_nothrow_move_constructible_v<_Bo>) // strengthened
: _Value(_STD move(_First._Current)), _Bound(_STD move(_Bound_from(_Last))) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (totally_ordered_with<_Wi, _Bo>) {
_STL_VERIFY(_Value <= _Bound, "Per N4981 [range.iota.view]/8 and /10, the iterator must not exceed the "
"sentinel when their types are totally ordered.");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
_NODISCARD constexpr _It begin() const noexcept(is_nothrow_copy_constructible_v<_Wi>) /* strengthened */ {
return _It{_Value};
}
_NODISCARD constexpr _Se end() const noexcept(is_nothrow_copy_constructible_v<_Bo>) /* strengthened */ {
if constexpr (same_as<_Wi, _Bo>) {
return _It{_Bound};
} else if constexpr (same_as<_Bo, unreachable_sentinel_t>) {
return unreachable_sentinel;
} else {
return _Se{_Bound};
}
}
_NODISCARD constexpr bool empty() const noexcept(noexcept(_Value == _Bound)) /* strengthened */ {
return _Value == _Bound;
}
#pragma warning(push)
#pragma warning(disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
_NODISCARD constexpr auto size() const noexcept(noexcept(_Bound - _Value)) /* strengthened */
requires (same_as<_Wi, _Bo> && _Advanceable<_Wi>)
|| (_Integer_like<_Wi> && _Integer_like<_Bo>) || sized_sentinel_for<_Bo, _Wi>
{
if constexpr (_Integer_like<_Wi> && _Integer_like<_Bo>) {
return (_Value < 0) ? ((_Bound < 0) ? (_To_unsigned_like(-_Value) - _To_unsigned_like(-_Bound))
: (_To_unsigned_like(_Bound) + _To_unsigned_like(-_Value)))
: (_To_unsigned_like(_Bound) - _To_unsigned_like(_Value));
} else {
return _To_unsigned_like(_Bound - _Value);
}
}
#pragma warning(pop)
};
template <class _Wi, class _Bo>
requires (!_Integer_like<_Wi> || !_Integer_like<_Bo>
|| (_Signed_integer_like<_Wi> == _Signed_integer_like<_Bo>) )
iota_view(_Wi, _Bo) -> iota_view<_Wi, _Bo>;
template <class _Wi, class _Bo>
constexpr bool enable_borrowed_range<iota_view<_Wi, _Bo>> = true;
namespace views {
struct _Iota_fn {
template <class _Ty>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty&& _Val) _CONST_CALL_OPERATOR
noexcept(noexcept(iota_view<decay_t<_Ty>>(static_cast<_Ty&&>(_Val))))
requires requires { iota_view<decay_t<_Ty>>(static_cast<_Ty&&>(_Val)); }
{
return iota_view<decay_t<_Ty>>(static_cast<_Ty&&>(_Val));
}
template <class _Ty1, class _Ty2>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Ty1&& _Start, _Ty2&& _Bound) _CONST_CALL_OPERATOR
noexcept(noexcept(iota_view(static_cast<_Ty1&&>(_Start), static_cast<_Ty2&&>(_Bound))))
requires requires { iota_view(static_cast<_Ty1&&>(_Start), static_cast<_Ty2&&>(_Bound)); }
{
return iota_view(static_cast<_Ty1&&>(_Start), static_cast<_Ty2&&>(_Bound));
}
};
_EXPORT_STD inline constexpr _Iota_fn iota;
class _Take_fn;
class _Drop_fn;
} // namespace views
#if _HAS_CXX23
template <class _Ty>
concept _Integer_like_with_usable_difference_type =
_Signed_integer_like<_Ty> || (_Integer_like<_Ty> && weakly_incrementable<_Ty>);
template <class _Ty>
struct _Repeat_view_difference_type {
using type = _Iota_diff_t<_Ty>;
};
template <_Signed_integer_like _Ty>
struct _Repeat_view_difference_type<_Ty> {
using type = _Ty;
};
_EXPORT_STD template <move_constructible _Ty, semiregular _Bo = unreachable_sentinel_t>
requires (is_object_v<_Ty> && same_as<_Ty, remove_cv_t<_Ty>>
&& (_Integer_like_with_usable_difference_type<_Bo> || same_as<_Bo, unreachable_sentinel_t>) )
class repeat_view : public view_interface<repeat_view<_Ty, _Bo>> {
private:
friend views::_Take_fn;
friend views::_Drop_fn;
class _Iterator {
private:
friend repeat_view;
using _Index_type = conditional_t<same_as<_Bo, unreachable_sentinel_t>, ptrdiff_t, _Bo>;
const _Ty* _Value{};
/* [[no_unique_address]] */ _Index_type _Current{};
constexpr explicit _Iterator(const _Ty* _Val, _Index_type _Bo_ = _Index_type{}) noexcept // strengthened
: _Value(_Val), _Current(_Bo_) {
if constexpr (_Signed_integer_like<_Bo>) {
_STL_INTERNAL_CHECK(_Current >= 0);
}
}
public:
using iterator_concept = random_access_iterator_tag;
using iterator_category = random_access_iterator_tag;
using value_type = _Ty;
using difference_type = _Repeat_view_difference_type<_Index_type>::type;
_Iterator() = default;
_NODISCARD constexpr const _Ty& operator*() const noexcept {
return *_Value;
}
constexpr _Iterator& operator++() noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Current < (numeric_limits<_Index_type>::max)(),
"cannot increment repeat_view iterator past end (integer overflow)");
#endif // _CONTAINER_DEBUG_LEVEL > 0
++_Current;
return *this;
}
constexpr _Iterator operator++(int) noexcept /* strengthened */ {
auto _Tmp = *this;
++*this;
return _Tmp;
}
constexpr _Iterator& operator--() noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (is_same_v<_Bo, unreachable_sentinel_t>) {
_STL_VERIFY(_Current > (numeric_limits<_Index_type>::min)(),
"cannot decrement repeat_view iterator before begin (integer overflow)");
} else {
_STL_VERIFY(_Current > 0, "cannot decrement below 0");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
--_Current;
return *this;
}
constexpr _Iterator operator--(int) noexcept /* strengthened */ {
auto _Tmp = *this;
--*this;
return _Tmp;
}
constexpr _Iterator& operator+=(difference_type _Off) noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (sizeof(difference_type) > sizeof(_Index_type)) {
_STL_VERIFY(static_cast<_Index_type>(_Off) == _Off,
_Off > 0 ? "cannot advance repeat_view iterator past end (integer overflow)"
: "cannot advance repeat_view iterator before begin (integer overflow)");
}
if (_Off > 0) {
_STL_VERIFY(_Current <= (numeric_limits<_Index_type>::max)() - static_cast<_Index_type>(_Off),
"cannot advance repeat_view iterator past end (integer overflow)");
} else {
_STL_VERIFY(_Current >= (numeric_limits<_Index_type>::min)() - static_cast<_Index_type>(_Off),
"cannot advance repeat_view iterator before begin (integer overflow)");
}
if constexpr (!is_same_v<_Bo, unreachable_sentinel_t>) {
_STL_VERIFY(_Current + _Off >= 0, "cannot subtract below 0");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
_Current += static_cast<_Index_type>(_Off);
return *this;
}
constexpr _Iterator& operator-=(difference_type _Off) noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (sizeof(difference_type) > sizeof(_Index_type)) {
_STL_VERIFY(static_cast<_Index_type>(_Off) == _Off,
_Off < 0 ? "cannot advance repeat_view iterator past end (integer overflow)"
: "cannot advance repeat_view iterator before begin (integer overflow)");
}
if (_Off < 0) {
_STL_VERIFY(_Current <= (numeric_limits<_Index_type>::max)() + static_cast<_Index_type>(_Off),
"cannot advance repeat_view iterator past end (integer overflow)");
} else {
_STL_VERIFY(_Current >= (numeric_limits<_Index_type>::min)() + static_cast<_Index_type>(_Off),
"cannot advance repeat_view iterator before begin (integer overflow)");
}
if constexpr (!is_same_v<_Bo, unreachable_sentinel_t>) {
_STL_VERIFY(_Current - _Off >= 0, "cannot subtract below 0");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
_Current -= static_cast<_Index_type>(_Off);
return *this;
}
_NODISCARD constexpr const _Ty& operator[](difference_type _Idx) const noexcept {
return *(*this + _Idx);
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept
/* strengthened */ {
return _Left._Current == _Right._Current;
}
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept
/* strengthened */ {
return _Left._Current <=> _Right._Current;
}
_NODISCARD friend constexpr _Iterator operator+(_Iterator _Iter, difference_type _Off) noexcept
/* strengthened */ {
_Iter += _Off;
return _Iter;
}
_NODISCARD friend constexpr _Iterator operator+(difference_type _Off, _Iterator _Iter) noexcept
/* strengthened */ {
_Iter += _Off;
return _Iter;
}
_NODISCARD friend constexpr _Iterator operator-(_Iterator _Iter, difference_type _Off) noexcept
/* strengthened */ {
_Iter -= _Off;
return _Iter;
}
_NODISCARD friend constexpr difference_type operator-(
const _Iterator& _Left, const _Iterator& _Right) noexcept /* strengthened */ {
return static_cast<difference_type>(
static_cast<difference_type>(_Left._Current) - static_cast<difference_type>(_Right._Current));
}
};
/* [[no_unique_address]] */ _Movable_box<_Ty> _Value{};
/* [[no_unique_address]] */ _Bo _Bound{};
template <class _Tuple, size_t... _Indices>
_NODISCARD_CTOR constexpr repeat_view(_Tuple& _Val, index_sequence<_Indices...>, _Bo _Bound_)
noexcept(is_nothrow_constructible_v<_Ty, tuple_element_t<_Indices, _Tuple>...>)
: _Value(in_place, _Tuple_get<_Indices>(_STD move(_Val))...), _Bound(_STD move(_Bound_)) {}
public:
repeat_view()
requires default_initializable<_Ty>
= default;
_NODISCARD_CTOR constexpr explicit repeat_view(const _Ty& _Value_, _Bo _Bound_ = _Bo{})
noexcept(is_nothrow_copy_constructible_v<_Ty>) // strengthened
requires copy_constructible<_Ty>
: _Value(in_place, _Value_), _Bound(_STD move(_Bound_)) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (_Signed_integer_like<_Bo>) {
_STL_VERIFY(_Bound >= 0, "Bound must be >= 0");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
_NODISCARD_CTOR constexpr explicit repeat_view(_Ty&& _Value_, _Bo _Bound_ = _Bo{})
noexcept(is_nothrow_move_constructible_v<_Ty>) // strengthened
: _Value(in_place, _STD move(_Value_)), _Bound(_STD move(_Bound_)) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (_Signed_integer_like<_Bo>) {
_STL_VERIFY(_Bound >= 0, "Bound must be >= 0");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
template <class... _TArgs, class... _BArgs>
requires constructible_from<_Ty, _TArgs...> && constructible_from<_Bo, _BArgs...>
_NODISCARD_CTOR constexpr explicit repeat_view(
piecewise_construct_t, tuple<_TArgs...> _Val_args, tuple<_BArgs...> _Bound_args = tuple<>{})
noexcept(is_nothrow_constructible_v<_Ty, _TArgs...>
&& noexcept(_STD make_from_tuple<_Bo>(_Bound_args))) // strengthened
: repeat_view(_Val_args, index_sequence_for<_TArgs...>{}, _STD make_from_tuple<_Bo>(_Bound_args)) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (_Signed_integer_like<_Bo>) {
_STL_VERIFY(_Bound >= 0, "Bound must be >= 0");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
_NODISCARD constexpr _Iterator begin() const noexcept /* strengthened */ {
return _Iterator{_STD addressof(*_Value)};
}
_NODISCARD constexpr auto end() const noexcept /* strengthened */ {
if constexpr (same_as<_Bo, unreachable_sentinel_t>) {
return unreachable_sentinel;
} else {
return _Iterator{_STD addressof(*_Value), _Bound};
}
}
_NODISCARD constexpr auto size() const noexcept // strengthened
requires (!same_as<_Bo, unreachable_sentinel_t>)
{
return _STD _To_unsigned_like(_Bound);
}
};
template <class _Ty, class _Bo = unreachable_sentinel_t>
repeat_view(_Ty, _Bo = _Bo()) -> repeat_view<_Ty, _Bo>;
namespace views {
struct _Repeat_fn {
template <class _Ty>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty&& _Value) _CONST_CALL_OPERATOR
noexcept(noexcept(repeat_view<decay_t<_Ty>>(_STD forward<_Ty>(_Value))))
requires requires { repeat_view<decay_t<_Ty>>(_STD forward<_Ty>(_Value)); }
{
return repeat_view<decay_t<_Ty>>(_STD forward<_Ty>(_Value));
}
template <class _Ty1, class _Ty2>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Ty1&& _Value, _Ty2&& _Count) _CONST_CALL_OPERATOR
noexcept(noexcept(repeat_view(_STD forward<_Ty1>(_Value), _STD forward<_Ty2>(_Count))))
requires requires { repeat_view(_STD forward<_Ty1>(_Value), _STD forward<_Ty2>(_Count)); }
{
return repeat_view(_STD forward<_Ty1>(_Value), _STD forward<_Ty2>(_Count));
}
};
_EXPORT_STD inline constexpr _Repeat_fn repeat;
} // namespace views
#endif // _HAS_CXX23
template <class _Ty, class _Elem, class _Traits>
concept _Stream_extractable = requires(basic_istream<_Elem, _Traits>& __is, _Ty& __t) { __is >> __t; };
_EXPORT_STD template <movable _Ty, class _Elem, class _Traits = char_traits<_Elem>>
requires default_initializable<_Ty> && _Stream_extractable<_Ty, _Elem, _Traits>
class basic_istream_view : public view_interface<basic_istream_view<_Ty, _Elem, _Traits>> {
private:
class _Iterator {
private:
basic_istream_view* _Parent;
public:
using iterator_concept = input_iterator_tag;
using difference_type = ptrdiff_t;
using value_type = _Ty;
constexpr explicit _Iterator(basic_istream_view& _Parent_) noexcept : _Parent{_STD addressof(_Parent_)} {}
_Iterator(const _Iterator&) = delete;
_Iterator(_Iterator&&) = default;
_Iterator& operator=(const _Iterator&) = delete;
_Iterator& operator=(_Iterator&&) = default;
_Iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
// Per LWG-3489
_STL_VERIFY(
!_Parent->_Stream_at_end(), "cannot increment basic_istream_view iterator at end of stream");
#endif // _ITERATOR_DEBUG_LEVEL != 0
*_Parent->_Stream >> _Parent->_Val;
return *this;
}
void operator++(int) {
++*this;
}
_NODISCARD _Ty& operator*() const noexcept /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
// Per LWG-3489
_STL_VERIFY(
!_Parent->_Stream_at_end(), "cannot dereference basic_istream_view iterator at end of stream");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Parent->_Val;
}
_NODISCARD friend bool operator==(const _Iterator& _Left, default_sentinel_t) noexcept /* strengthened */ {
return _Left._Parent->_Stream_at_end();
}
};
basic_istream<_Elem, _Traits>* _Stream;
_Ty _Val = _Ty{};
public:
constexpr explicit basic_istream_view(basic_istream<_Elem, _Traits>& _Stream_)
noexcept(is_nothrow_default_constructible_v<_Ty>) // strengthened
: _Stream{_STD addressof(_Stream_)} {}
_NODISCARD constexpr auto begin() {
*_Stream >> _Val;
return _Iterator{*this};
}
_NODISCARD constexpr default_sentinel_t end() const noexcept {
return default_sentinel;
}
_NODISCARD constexpr bool _Stream_at_end() const noexcept {
return !*_Stream;
}
};
_EXPORT_STD template <class _Ty>
using istream_view = basic_istream_view<_Ty, char>;
_EXPORT_STD template <class _Ty>
using wistream_view = basic_istream_view<_Ty, wchar_t>;
namespace views {
template <class _Elem, class _Stream, class _CharT, class _Traits>
concept _Istreamable_impl = derived_from<_Stream, basic_istream<_CharT, _Traits>>
&& constructible_from<basic_istream_view<_Elem, _CharT, _Traits>, _Stream&>;
template <class _Elem, class _Stream>
concept _Istreamable = requires {
typename _Stream::char_type;
typename _Stream::traits_type;
requires _Istreamable_impl<_Elem, _Stream, typename _Stream::char_type, typename _Stream::traits_type>;
};
template <class _Ty>
struct _Istream_fn {
template <class _StreamTy>
requires _Istreamable<_Ty, _StreamTy>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_StreamTy& _Stream) _CONST_CALL_OPERATOR
noexcept(is_nothrow_default_constructible_v<_Ty>) /* strengthened */ {
return basic_istream_view<_Ty, typename _StreamTy::char_type, typename _StreamTy::traits_type>(_Stream);
}
};
_EXPORT_STD template <class _Ty>
constexpr _Istream_fn<_Ty> istream;
} // namespace views
#if _HAS_CXX23
template <class _Rng>
constexpr auto _Compile_time_max_size<ref_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const ref_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<owning_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const owning_view<_Rng>> = _Compile_time_max_size<const _Rng>;
_EXPORT_STD template <input_range _Vw>
requires view<_Vw>
class as_rvalue_view : public view_interface<as_rvalue_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
template <range _Rng>
static constexpr bool _Is_end_nothrow_v = noexcept(move_sentinel{_RANGES end(_STD declval<_Rng&>())});
template <common_range _Rng>
static constexpr bool _Is_end_nothrow_v<_Rng> = noexcept(move_iterator{_RANGES end(_STD declval<_Rng&>())});
public:
as_rvalue_view()
requires default_initializable<_Vw>
= default;
constexpr explicit as_rvalue_view(_Vw _Range_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Range(_STD move(_Range_)) {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) // strengthened
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin() noexcept(noexcept(move_iterator{_RANGES begin(_Range)})) // strengthened
requires (!_Simple_view<_Vw>)
{
return move_iterator{_RANGES begin(_Range)};
}
_NODISCARD constexpr auto begin() const noexcept(noexcept(move_iterator{_RANGES begin(_Range)})) // strengthened
requires range<const _Vw>
{
return move_iterator{_RANGES begin(_Range)};
}
_NODISCARD constexpr auto end() noexcept(_Is_end_nothrow_v<_Vw>) // strengthened
requires (!_Simple_view<_Vw>)
{
if constexpr (common_range<_Vw>) {
return move_iterator{_RANGES end(_Range)};
} else {
return move_sentinel{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto end() const noexcept(_Is_end_nothrow_v<const _Vw>) // strengthened
requires range<const _Vw>
{
if constexpr (common_range<const _Vw>) {
return move_iterator{_RANGES end(_Range)};
} else {
return move_sentinel{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Range))) // strengthened
requires sized_range<_Vw>
{
return _RANGES size(_Range);
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Range))) // strengthened
requires sized_range<const _Vw>
{
return _RANGES size(_Range);
}
};
template <class _Rng>
as_rvalue_view(_Rng&&) -> as_rvalue_view<views::all_t<_Rng>>;
template <class _Rng>
constexpr bool enable_borrowed_range<as_rvalue_view<_Rng>> = enable_borrowed_range<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<as_rvalue_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const as_rvalue_view<_Rng>> = _Compile_time_max_size<const _Rng>;
namespace views {
// direct-non-list-initialization is specified in the Standard (N4981 [range.as.rvalue.overview]/2.2)
// and needed for EDG, DevCom-10698021
template <class _Rng>
concept _Can_as_rvalue = requires(_Rng&& __r) { as_rvalue_view(static_cast<_Rng&&>(__r)); };
class _As_rvalue_fn : public _Pipe::_Base<_As_rvalue_fn> {
private:
enum class _St { _None, _All, _As_rvalue };
template <class _Rng>
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
if constexpr (input_range<_Rng> && same_as<range_rvalue_reference_t<_Rng>, range_reference_t<_Rng>>) {
return {_St::_All, noexcept(views::all(_STD declval<_Rng>()))};
} else if constexpr (_Can_as_rvalue<_Rng>) {
return {_St::_As_rvalue, noexcept(as_rvalue_view(_STD declval<_Rng>()))};
} else {
return {_St::_None};
}
}
template <class _Rng>
static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>();
public:
template <viewable_range _Rng>
requires (_Choice<_Rng>._Strategy != _St::_None)
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range) _CONST_CALL_OPERATOR
noexcept(_Choice<_Rng>._No_throw) {
constexpr _St _Strat = _Choice<_Rng>._Strategy;
if constexpr (_Strat == _St::_All) {
return views::all(_STD forward<_Rng>(_Range));
} else if constexpr (_Strat == _St::_As_rvalue) {
return as_rvalue_view(_STD forward<_Rng>(_Range));
} else {
_STL_INTERNAL_STATIC_ASSERT(false); // unexpected strategy
}
}
};
_EXPORT_STD inline constexpr _As_rvalue_fn as_rvalue;
} // namespace views
#endif // _HAS_CXX23
_EXPORT_STD template <input_range _Vw, indirect_unary_predicate<iterator_t<_Vw>> _Pr>
requires view<_Vw> && is_object_v<_Pr>
class filter_view : public _Cached_position_t<forward_range<_Vw>, _Vw, filter_view<_Vw, _Pr>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
/* [[no_unique_address]] */ _Movable_box<_Pr> _Pred{};
template <class _View>
struct _Category_base {};
template <forward_range _View>
struct _Category_base<_View> {
using iterator_category =
conditional_t<derived_from<_Iter_cat_t<iterator_t<_View>>, bidirectional_iterator_tag>,
bidirectional_iterator_tag,
conditional_t<derived_from<_Iter_cat_t<iterator_t<_View>>, forward_iterator_tag>,
forward_iterator_tag, _Iter_cat_t<iterator_t<_View>>>>;
};
class _Iterator : public _Category_base<_Vw> {
private:
/* [[no_unique_address]] */ iterator_t<_Vw> _Current{};
filter_view* _Parent{};
#if _ITERATOR_DEBUG_LEVEL != 0
constexpr void _Check_dereference() const noexcept {
_STL_VERIFY(_Parent != nullptr, "cannot dereference value-initialized filter_view iterator");
_STL_VERIFY(_Current != _RANGES end(_Parent->_Range), "cannot dereference end filter_view iterator");
}
#endif // _ITERATOR_DEBUG_LEVEL != 0
public:
using iterator_concept = conditional_t<bidirectional_range<_Vw>, bidirectional_iterator_tag,
conditional_t<forward_range<_Vw>, forward_iterator_tag, input_iterator_tag>>;
using value_type = range_value_t<_Vw>;
using difference_type = range_difference_t<_Vw>;
_Iterator()
requires default_initializable<iterator_t<_Vw>>
= default;
constexpr _Iterator(filter_view& _Parent_, iterator_t<_Vw> _Current_)
noexcept(is_nothrow_move_constructible_v<iterator_t<_Vw>>) // strengthened
: _Current(_STD move(_Current_)), _Parent{_STD addressof(_Parent_)} {
#if _ITERATOR_DEBUG_LEVEL != 0
_STD _Adl_verify_range(_Current, _RANGES end(_Parent_._Range));
if constexpr (forward_range<_Vw>) {
_STD _Adl_verify_range(_RANGES begin(_Parent_._Range), _Current);
}
#endif // _ITERATOR_DEBUG_LEVEL != 0
}
_NODISCARD constexpr const iterator_t<_Vw>& base() const& noexcept {
return _Current;
}
_NODISCARD constexpr iterator_t<_Vw> base() && noexcept(
is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */ {
return _STD move(_Current);
}
_NODISCARD constexpr range_reference_t<_Vw> operator*() const
noexcept(noexcept(*_Current)) /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_Check_dereference();
#endif // _ITERATOR_DEBUG_LEVEL != 0
return *_Current;
}
_NODISCARD constexpr iterator_t<_Vw> operator->() const
noexcept(is_nothrow_copy_constructible_v<iterator_t<_Vw>>) /* strengthened */
requires _Has_arrow<iterator_t<_Vw>> && copyable<iterator_t<_Vw>>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_Check_dereference();
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Current;
}
constexpr _Iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Parent != nullptr, "cannot increment value-initialized filter_view iterator");
_STL_VERIFY(_Current != _RANGES end(_Parent->_Range), "cannot increment filter_view iterator past end");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Current =
_RANGES find_if(_STD move(++_Current), _RANGES end(_Parent->_Range), _STD ref(*_Parent->_Pred));
return *this;
}
constexpr decltype(auto) operator++(int) {
if constexpr (forward_range<_Vw>) {
auto _Tmp = *this;
++*this;
return _Tmp;
} else {
++*this;
}
}
constexpr _Iterator& operator--()
requires bidirectional_range<_Vw>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Parent != nullptr, "cannot decrement value-initialized filter_view iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
do {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Current != _RANGES begin(_Parent->_Range),
"cannot decrement filter_view iterator before begin");
#endif // _ITERATOR_DEBUG_LEVEL != 0
--_Current;
} while (!_STD invoke(*_Parent->_Pred, *_Current));
return *this;
}
constexpr _Iterator operator--(int)
requires bidirectional_range<_Vw>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
requires equality_comparable<iterator_t<_Vw>>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(
_Left._Parent == _Right._Parent, "cannot compare incompatible filter_view iterators for equality");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Left._Current == _Right._Current;
}
_NODISCARD friend constexpr range_rvalue_reference_t<_Vw> iter_move(const _Iterator& _It)
noexcept(noexcept(_RANGES iter_move(_It._Current))) {
#if _ITERATOR_DEBUG_LEVEL != 0
_It._Check_dereference();
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _RANGES iter_move(_It._Current);
}
friend constexpr void iter_swap(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_RANGES iter_swap(_Left._Current, _Right._Current)))
requires indirectly_swappable<iterator_t<_Vw>>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_Left._Check_dereference();
_Right._Check_dereference();
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _RANGES iter_swap(_Left._Current, _Right._Current);
}
_NODISCARD constexpr bool _Equal(const sentinel_t<_Vw>& _Last) const
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Current == _Last))) {
return _Current == _Last;
}
};
class _Sentinel {
private:
/* [[no_unique_address]] */ sentinel_t<_Vw> _Last{};
public:
_Sentinel() = default;
constexpr explicit _Sentinel(filter_view& _Parent)
noexcept(noexcept(_RANGES end(_Parent._Range))
&& is_nothrow_move_constructible_v<sentinel_t<_Vw>>) // strengthened
: _Last(_RANGES end(_Parent._Range)) {}
_NODISCARD constexpr sentinel_t<_Vw> base() const
noexcept(is_nothrow_copy_constructible_v<sentinel_t<_Vw>>) /* strengthened */ {
return _Last;
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _It, const _Sentinel& _Se)
noexcept(noexcept(_It._Equal(_Se._Last))) /* strengthened */ {
return _It._Equal(_Se._Last);
}
};
public:
filter_view()
requires default_initializable<_Vw> && default_initializable<_Pr>
= default;
constexpr explicit filter_view(_Vw _Range_, _Pr _Pred_)
noexcept(is_nothrow_move_constructible_v<_Vw> && is_nothrow_move_constructible_v<_Pr>) // strengthened
: _Range(_STD move(_Range_)), _Pred{in_place, _STD move(_Pred_)} {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Pred, "filter_view has no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
return *_Pred;
}
_NODISCARD constexpr _Iterator begin() {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(
_Pred, "N4950 [range.filter.view]/3 forbids calling begin on a filter_view that holds no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
if constexpr (forward_range<_Vw>) {
if (this->_Has_cache()) {
return _Iterator{*this, this->_Get_cache(_Range)};
}
}
auto _First = _RANGES find_if(_Range, _STD ref(*_Pred));
if constexpr (forward_range<_Vw>) {
this->_Set_cache(_Range, _First);
}
return _Iterator{*this, _STD move(_First)};
}
_NODISCARD constexpr auto end() {
if constexpr (common_range<_Vw>) {
return _Iterator{*this, _RANGES end(_Range)};
} else {
return _Sentinel{*this};
}
}
};
template <class _Rng, class _Pr>
filter_view(_Rng&&, _Pr) -> filter_view<views::all_t<_Rng>, _Pr>;
#if _HAS_CXX23
template <class _Rng, class _Pr>
constexpr auto _Compile_time_max_size<filter_view<_Rng, _Pr>> = _Compile_time_max_size<_Rng>;
#endif // _HAS_CXX23
namespace views {
struct _Filter_fn {
template <viewable_range _Rng, class _Pr>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range, _Pr&& _Pred) _CONST_CALL_OPERATOR
noexcept(noexcept(filter_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred))))
requires requires { filter_view(static_cast<_Rng&&>(_Range), _STD forward<_Pr>(_Pred)); }
{
return filter_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred));
}
template <class _Pr>
requires constructible_from<decay_t<_Pr>, _Pr>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Pr&& _Pred) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Pr>, _Pr>) {
return _Range_closure<_Filter_fn, decay_t<_Pr>>{_STD forward<_Pr>(_Pred)};
}
};
_EXPORT_STD inline constexpr _Filter_fn filter;
} // namespace views
#if _HAS_CXX23
template <class _Rng, class _Fn>
constexpr auto _Compile_time_max_size<transform_view<_Rng, _Fn>> = _Compile_time_max_size<_Rng>;
template <class _Rng, class _Fn>
constexpr auto _Compile_time_max_size<const transform_view<_Rng, _Fn>> = _Compile_time_max_size<const _Rng>;
#endif // _HAS_CXX23
_EXPORT_STD template <view _Vw>
class take_view : public view_interface<take_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
range_difference_t<_Vw> _Count = 0;
template <bool _Const, bool _Wrapped = true>
class _Sentinel {
private:
friend take_view;
using _Base_t = _Maybe_const<_Const, _Vw>;
using _Base_sentinel = _Maybe_wrapped<_Wrapped, sentinel_t<_Base_t>>;
template <bool _OtherConst>
using _Base_iterator = _Maybe_wrapped<_Wrapped, iterator_t<_Maybe_const<_OtherConst, _Vw>>>;
template <bool _OtherConst>
using _Counted_iter = counted_iterator<_Base_iterator<_OtherConst>>;
_Base_sentinel _Last{};
public:
_Sentinel() = default;
constexpr explicit _Sentinel(_Base_sentinel _Last_)
noexcept(is_nothrow_move_constructible_v<_Base_sentinel>) // strengthened
: _Last(_STD move(_Last_)) {}
constexpr _Sentinel(_Sentinel<!_Const, _Wrapped> _That) noexcept(
is_nothrow_constructible_v<_Base_sentinel, _Maybe_wrapped<_Wrapped, sentinel_t<_Vw>>>) // strengthened
requires _Const && convertible_to<_Maybe_wrapped<_Wrapped, sentinel_t<_Vw>>, _Base_sentinel>
: _Last(_STD move(_That._Last)) {}
_NODISCARD constexpr _Base_sentinel base() const
noexcept(is_nothrow_copy_constructible_v<_Base_sentinel>) /* strengthened */ {
return _Last;
}
_NODISCARD friend constexpr bool operator==(const _Counted_iter<_Const>& _Left, const _Sentinel& _Right) {
return _Left.count() == 0 || _Left.base() == _Right._Last;
}
template <bool _OtherConst = !_Const>
requires sentinel_for<_Base_sentinel, _Base_iterator<_OtherConst>>
_NODISCARD friend constexpr bool operator==(
const _Counted_iter<_OtherConst>& _Left, const _Sentinel& _Right) {
return _Left.count() == 0 || _Left.base() == _Right._Last;
}
using _Prevent_inheriting_unwrap = _Sentinel;
_NODISCARD constexpr auto _Unwrapped() const& noexcept(
noexcept(_Sentinel<_Const, false>{_Last._Unwrapped()}))
requires _Wrapped && _Unwrappable_sentinel_for<sentinel_t<_Base_t>, const iterator_t<_Base_t>&>
{
return _Sentinel<_Const, false>{_Last._Unwrapped()};
}
_NODISCARD constexpr auto _Unwrapped() && noexcept(
noexcept(_Sentinel<_Const, false>{_STD move(_Last)._Unwrapped()}))
requires _Wrapped && _Unwrappable_sentinel_for<sentinel_t<_Base_t>, iterator_t<_Base_t>>
{
return _Sentinel<_Const, false>{_STD move(_Last)._Unwrapped()};
}
static constexpr bool _Unwrap_when_unverified = _Do_unwrap_when_unverified_v<iterator_t<_Base_t>>;
constexpr void _Seek_to(const _Sentinel<_Const, false>& _That)
requires _Wrapped
{
_Seek_wrapped(_Last, _That._Last);
}
constexpr void _Seek_to(_Sentinel<_Const, false>&& _That)
requires _Wrapped
{
_Seek_wrapped(_Last, _STD move(_That._Last));
}
};
public:
take_view()
requires default_initializable<_Vw>
= default;
constexpr explicit take_view(_Vw _Range_, const range_difference_t<_Vw> _Count_)
noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Range(_STD move(_Range_)), _Count{_Count_} {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Count_ >= 0, "Number of elements to take must be non-negative (N4971 [range.take.view]/1)");
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin()
requires (!_Simple_view<_Vw>)
{
if constexpr (sized_range<_Vw>) {
if constexpr (random_access_range<_Vw>) {
return _RANGES begin(_Range);
} else {
const auto _Size = static_cast<range_difference_t<_Vw>>(size());
return counted_iterator(_RANGES begin(_Range), _Size);
}
} else if constexpr (sized_sentinel_for<sentinel_t<_Vw>, iterator_t<_Vw>>) {
auto _Iter = _RANGES begin(_Range);
const auto _Size = (_STD min)(_Count, _RANGES end(_Range) - _Iter);
return counted_iterator(_STD move(_Iter), _Size);
} else {
return counted_iterator(_RANGES begin(_Range), _Count);
}
}
_NODISCARD constexpr auto begin() const
requires range<const _Vw>
{
if constexpr (sized_range<const _Vw>) {
if constexpr (random_access_range<const _Vw>) {
return _RANGES begin(_Range);
} else {
const auto _Size = static_cast<range_difference_t<_Vw>>(size());
return counted_iterator(_RANGES begin(_Range), _Size);
}
} else if constexpr (sized_sentinel_for<sentinel_t<const _Vw>, iterator_t<const _Vw>>) {
auto _Iter = _RANGES begin(_Range);
const auto _Size = (_STD min)(_Count, _RANGES end(_Range) - _Iter);
return counted_iterator(_STD move(_Iter), _Size);
} else {
return counted_iterator(_RANGES begin(_Range), _Count);
}
}
_NODISCARD constexpr auto end()
requires (!_Simple_view<_Vw>)
{
if constexpr (sized_range<_Vw>) {
if constexpr (random_access_range<_Vw>) {
return _RANGES begin(_Range) + static_cast<range_difference_t<_Vw>>(size());
} else {
return default_sentinel;
}
} else if constexpr (sized_sentinel_for<sentinel_t<_Vw>, iterator_t<_Vw>>) {
return default_sentinel;
} else {
return _Sentinel<false>{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto end() const
requires range<const _Vw>
{
if constexpr (sized_range<const _Vw>) {
if constexpr (random_access_range<const _Vw>) {
return _RANGES begin(_Range) + static_cast<range_difference_t<_Vw>>(size());
} else {
return default_sentinel;
}
} else if constexpr (sized_sentinel_for<sentinel_t<const _Vw>, iterator_t<const _Vw>>) {
return default_sentinel;
} else {
return _Sentinel<true>{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto size()
requires sized_range<_Vw>
{
const auto _Length = _RANGES size(_Range);
return (_STD min)(_Length, static_cast<decltype(_Length)>(_Count));
}
_NODISCARD constexpr auto size() const
requires sized_range<const _Vw>
{
const auto _Length = _RANGES size(_Range);
return (_STD min)(_Length, static_cast<decltype(_Length)>(_Count));
}
};
template <class _Rng>
take_view(_Rng&&, range_difference_t<_Rng>) -> take_view<views::all_t<_Rng>>;
template <class _Rng>
constexpr bool enable_borrowed_range<take_view<_Rng>> = enable_borrowed_range<_Rng>;
#if _HAS_CXX23
template <class _Rng>
constexpr auto _Compile_time_max_size<take_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const take_view<_Rng>> = _Compile_time_max_size<const _Rng>;
#endif // _HAS_CXX23
namespace views {
template <class _Rng>
concept _Random_sized_range = random_access_range<_Rng> && sized_range<_Rng>;
class _Take_fn {
private:
enum class _St {
_Empty,
_Reconstruct_span,
_Reconstruct_string_view,
_Reconstruct_iota_view,
_Reconstruct_repeat_view,
_Reconstruct_subrange,
_Take_view
};
template <class _Rng>
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
using _Ty = remove_cvref_t<_Rng>;
if constexpr (_Is_specialization_v<_Ty, empty_view>) {
return {_St::_Empty, true};
} else if constexpr (_Is_span_v<_Ty>) {
return {_St::_Reconstruct_span, true};
} else if constexpr (_Is_specialization_v<_Ty, basic_string_view>) {
return {_St::_Reconstruct_string_view, true};
} else if constexpr (_Random_sized_range<_Ty> && _Is_specialization_v<_Ty, iota_view>) {
return {_St::_Reconstruct_iota_view,
noexcept(_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>()))};
#if _HAS_CXX23
} else if constexpr (_Is_specialization_v<_Ty, repeat_view>) {
using _Range_val_t = range_value_t<_Ty>;
return {_St::_Reconstruct_repeat_view,
is_nothrow_constructible_v<_Range_val_t, _Forward_like_t<_Rng, _Range_val_t>>};
#endif // _HAS_CXX23
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange_v<_Ty>) {
return {_St::_Reconstruct_subrange,
noexcept(subrange(_RANGES begin(_STD declval<_Rng&>()),
_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>())))};
} else {
return {_St::_Take_view, noexcept(take_view(_STD declval<_Rng>(), range_difference_t<_Rng>{0}))};
}
}
template <class _Rng>
static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>();
public:
template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Rng&& _Range, range_difference_t<_Rng> _Count) _CONST_CALL_OPERATOR noexcept(_Choice<_Rng>._No_throw) {
constexpr _St _Strat = _Choice<_Rng>._Strategy;
if constexpr (_Strat == _St::_Empty) {
// it's an empty_view: return another empty view
return remove_cvref_t<_Rng>{};
} else if constexpr (_Strat == _St::_Take_view) {
return take_view(_STD forward<_Rng>(_Range), _Count);
#if _HAS_CXX23
} else if constexpr (!sized_range<_Rng> && _Strat == _St::_Reconstruct_repeat_view) {
return repeat_view(_STD forward_like<_Rng>(*_Range._Value), _Count);
#endif // _HAS_CXX23
} else {
// it's a "reconstructible range"; return the same kind of range with a restricted extent
_Count = (_STD min)(_RANGES distance(_Range), _Count);
const auto _First = _RANGES begin(_Range);
if constexpr (_Strat == _St::_Reconstruct_span) {
return span(_First, _First + _Count);
} else if constexpr (_Strat == _St::_Reconstruct_string_view) {
return remove_cvref_t<_Rng>(_First, _First + _Count);
} else if constexpr (_Strat == _St::_Reconstruct_iota_view) {
using _Vt = range_value_t<_Rng>;
return iota_view<_Vt, _Vt>(_First, _First + _Count);
#if _HAS_CXX23
} else if constexpr (_Strat == _St::_Reconstruct_repeat_view) {
return repeat_view(_STD forward_like<_Rng>(*_Range._Value), _Count);
#endif // _HAS_CXX23
} else if constexpr (_Strat == _St::_Reconstruct_subrange) {
return subrange(_First, _First + _Count);
} else {
_STL_INTERNAL_STATIC_ASSERT(false); // unexpected strategy
}
}
}
template <class _Ty>
requires constructible_from<decay_t<_Ty>, _Ty>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty&& _Length) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Ty>, _Ty>) {
return _Range_closure<_Take_fn, decay_t<_Ty>>{_STD forward<_Ty>(_Length)};
}
};
_EXPORT_STD inline constexpr _Take_fn take;
} // namespace views
_EXPORT_STD template <view _Vw, class _Pr>
requires input_range<_Vw> && is_object_v<_Pr> && indirect_unary_predicate<const _Pr, iterator_t<_Vw>>
class take_while_view : public view_interface<take_while_view<_Vw, _Pr>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
/* [[no_unique_address]] */ _Movable_box<_Pr> _Pred{};
template <bool _Const, bool _Wrapped = true>
class _Sentinel {
private:
friend take_while_view;
using _Base_t = _Maybe_const<_Const, _Vw>;
using _Base_iterator = _Maybe_wrapped<_Wrapped, iterator_t<_Base_t>>;
using _Base_sentinel = _Maybe_wrapped<_Wrapped, sentinel_t<_Base_t>>;
template <bool _OtherConst>
using _Maybe_const_iter = _Maybe_wrapped<_Wrapped, iterator_t<_Maybe_const<_OtherConst, _Vw>>>;
/* [[no_unique_address]] */ _Base_sentinel _Last{};
const _Pr* _Pred = nullptr;
public:
_Sentinel() = default;
constexpr explicit _Sentinel(_Base_sentinel _Last_, const _Pr* const _Pred_)
noexcept(is_nothrow_move_constructible_v<_Base_sentinel>) // strengthened
: _Last(_STD move(_Last_)), _Pred(_Pred_) {}
constexpr _Sentinel(_Sentinel<!_Const, _Wrapped> _That) noexcept(
is_nothrow_constructible_v<_Base_sentinel, _Maybe_wrapped<_Wrapped, sentinel_t<_Vw>>>) // strengthened
requires _Const && convertible_to<_Maybe_wrapped<_Wrapped, sentinel_t<_Vw>>, _Base_sentinel>
: _Last(_STD move(_That._Last)), _Pred(_That._Pred) {}
_NODISCARD constexpr _Base_sentinel base() const
noexcept(is_nothrow_copy_constructible_v<_Base_sentinel>) /* strengthened */ {
return _Last;
}
_NODISCARD friend constexpr bool operator==(const _Base_iterator& _Left, const _Sentinel& _Right) {
return _Right._Last == _Left || !_STD invoke(*_Right._Pred, *_Left);
}
template <bool _OtherConst = !_Const>
requires sentinel_for<_Base_sentinel, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr bool operator==(
const _Maybe_const_iter<_OtherConst>& _Left, const _Sentinel& _Right) {
return _Right._Last == _Left || !_STD invoke(*_Right._Pred, *_Left);
}
using _Prevent_inheriting_unwrap = _Sentinel;
_NODISCARD constexpr auto _Unwrapped() const& noexcept(
noexcept(_Sentinel<_Const, false>{_Last._Unwrapped(), _Pred}))
requires _Wrapped && _Unwrappable_sentinel_for<sentinel_t<_Base_t>, const iterator_t<_Base_t>&>
{
return _Sentinel<_Const, false>{_Last._Unwrapped(), _Pred};
}
_NODISCARD constexpr auto _Unwrapped() && noexcept(
noexcept(_Sentinel<_Const, false>{_STD move(_Last)._Unwrapped(), _Pred}))
requires _Wrapped && _Unwrappable_sentinel_for<sentinel_t<_Base_t>, iterator_t<_Base_t>>
{
return _Sentinel<_Const, false>{_STD move(_Last)._Unwrapped(), _Pred};
}
static constexpr bool _Unwrap_when_unverified = _Do_unwrap_when_unverified_v<iterator_t<_Base_t>>;
constexpr void _Seek_to(const _Sentinel<_Const, false>& _That)
requires _Wrapped
{
_Seek_wrapped(_Last, _That._Last);
}
constexpr void _Seek_to(_Sentinel<_Const, false>&& _That)
requires _Wrapped
{
_Seek_wrapped(_Last, _STD move(_That._Last));
}
};
public:
take_while_view()
requires default_initializable<_Vw> && default_initializable<_Pr>
= default;
constexpr explicit take_while_view(_Vw _Range_, _Pr _Pred_)
noexcept(is_nothrow_move_constructible_v<_Vw> && is_nothrow_move_constructible_v<_Pr>) // strengthened
: _Range(_STD move(_Range_)), _Pred{in_place, _STD move(_Pred_)} {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Pred, "take_while_view has no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
return *_Pred;
}
_NODISCARD constexpr auto begin() noexcept(noexcept(_RANGES begin(_Range))) /* strengthened */
requires (!_Simple_view<_Vw>)
{
return _RANGES begin(_Range);
}
_NODISCARD constexpr auto begin() const noexcept(noexcept(_RANGES begin(_Range))) /* strengthened */
requires range<const _Vw> && indirect_unary_predicate<const _Pr, iterator_t<const _Vw>>
{
return _RANGES begin(_Range);
}
_NODISCARD constexpr auto end() noexcept(
noexcept(_RANGES end(_Range)) && is_nothrow_move_constructible_v<_Sentinel<false>>) /* strengthened */
requires (!_Simple_view<_Vw>)
{
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Pred, "cannot call end on a take_while_view with no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
return _Sentinel<false>{_RANGES end(_Range), _STD addressof(*_Pred)};
}
_NODISCARD constexpr auto end() const noexcept(
noexcept(_RANGES end(_Range)) && is_nothrow_move_constructible_v<_Sentinel<true>>) /* strengthened */
requires range<const _Vw> && indirect_unary_predicate<const _Pr, iterator_t<const _Vw>>
{
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Pred, "cannot call end on a take_while_view with no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
return _Sentinel<true>{_RANGES end(_Range), _STD addressof(*_Pred)};
}
};
template <class _Rng, class _Pr>
take_while_view(_Rng&&, _Pr) -> take_while_view<views::all_t<_Rng>, _Pr>;
#if _HAS_CXX23
template <class _Rng, class _Pr>
constexpr auto _Compile_time_max_size<take_while_view<_Rng, _Pr>> = _Compile_time_max_size<_Rng>;
template <class _Rng, class _Pr>
constexpr auto _Compile_time_max_size<const take_while_view<_Rng, _Pr>> = _Compile_time_max_size<const _Rng>;
#endif // _HAS_CXX23
namespace views {
struct _Take_while_fn {
template <viewable_range _Rng, class _Pr>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range, _Pr _Pred) _CONST_CALL_OPERATOR
noexcept(noexcept(take_while_view(_STD forward<_Rng>(_Range), _STD move(_Pred))))
requires requires { take_while_view(static_cast<_Rng&&>(_Range), _STD move(_Pred)); }
{
return take_while_view(_STD forward<_Rng>(_Range), _STD move(_Pred));
}
template <class _Pr>
requires constructible_from<decay_t<_Pr>, _Pr>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Pr&& _Pred) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Pr>, _Pr>) {
return _Range_closure<_Take_while_fn, decay_t<_Pr>>{_STD forward<_Pr>(_Pred)};
}
};
_EXPORT_STD inline constexpr _Take_while_fn take_while;
} // namespace views
_EXPORT_STD template <view _Vw>
class drop_view : public _Cached_position_t<forward_range<_Vw> && !(random_access_range<_Vw> && sized_range<_Vw>),
_Vw, drop_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
range_difference_t<_Vw> _Count = 0;
_NODISCARD constexpr auto _Find_first() {
if constexpr (sized_range<_Vw>) {
_STL_INTERNAL_STATIC_ASSERT(!random_access_range<_Vw>);
auto _Offset = _RANGES distance(_Range);
if constexpr (bidirectional_range<_Vw> && common_range<_Vw>) {
if (_Count >= _Offset / 2) {
auto _Result = _RANGES end(_Range);
while (_Offset > _Count) {
--_Offset;
--_Result;
}
return _Result;
}
}
if (_Offset > _Count) {
_Offset = _Count;
}
return _RANGES next(_RANGES begin(_Range), _Offset);
} else {
return _RANGES next(_RANGES begin(_Range), _Count, _RANGES end(_Range));
}
}
public:
drop_view()
requires default_initializable<_Vw>
= default;
constexpr explicit drop_view(_Vw _Range_, const range_difference_t<_Vw> _Count_)
noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Range(_STD move(_Range_)), _Count{_Count_} {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Count_ >= 0, "Number of elements to drop must be non-negative (N4971 [range.drop.view]/1)");
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin()
requires (!(_Simple_view<_Vw> && random_access_range<const _Vw> && sized_range<const _Vw>) )
{
if constexpr (sized_range<_Vw> && random_access_range<_Vw>) {
const auto _Offset = (_STD min)(_RANGES distance(_Range), _Count);
return _RANGES begin(_Range) + _Offset;
} else {
if constexpr (forward_range<_Vw>) {
if (this->_Has_cache()) {
return this->_Get_cache(_Range);
}
}
same_as<iterator_t<_Vw>> auto _Result = _Find_first();
if constexpr (forward_range<_Vw>) {
this->_Set_cache(_Range, _Result);
}
return _Result;
}
}
_NODISCARD constexpr auto begin() const
requires random_access_range<const _Vw> && sized_range<const _Vw>
{
const auto _Offset = (_STD min)(_RANGES distance(_Range), _Count);
return _RANGES begin(_Range) + _Offset;
}
_NODISCARD constexpr auto end()
requires (!_Simple_view<_Vw>)
{
return _RANGES end(_Range);
}
_NODISCARD constexpr auto end() const
requires range<const _Vw>
{
return _RANGES end(_Range);
}
_NODISCARD constexpr auto size()
requires sized_range<_Vw>
{
const auto _Size = _RANGES size(_Range);
const auto _Count_as_size = static_cast<range_size_t<_Vw>>(_Count);
if (_Size < _Count_as_size) {
return range_size_t<_Vw>{0};
} else {
return static_cast<range_size_t<_Vw>>(_Size - _Count_as_size);
}
}
_NODISCARD constexpr auto size() const
requires sized_range<const _Vw>
{
const auto _Size = _RANGES size(_Range);
const auto _Count_as_size = static_cast<range_size_t<_Vw>>(_Count);
if (_Size < _Count_as_size) {
return range_size_t<_Vw>{0};
} else {
return static_cast<range_size_t<_Vw>>(_Size - _Count_as_size);
}
}
};
template <class _Rng>
drop_view(_Rng&&, range_difference_t<_Rng>) -> drop_view<views::all_t<_Rng>>;
template <class _Rng>
constexpr bool enable_borrowed_range<drop_view<_Rng>> = enable_borrowed_range<_Rng>;
#if _HAS_CXX23
template <class _Rng>
constexpr auto _Compile_time_max_size<drop_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const drop_view<_Rng>> = _Compile_time_max_size<const _Rng>;
#endif // _HAS_CXX23
namespace views {
class _Drop_fn {
private:
enum class _St {
_Empty,
_Reconstruct_span,
_Reconstruct_subrange,
_Reconstruct_repeat,
_Reconstruct_other,
_Drop_view
};
template <class _Rng>
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
using _Ty = remove_cvref_t<_Rng>;
if constexpr (_Is_specialization_v<_Ty, empty_view>) {
return {_St::_Empty, true};
} else if constexpr (_Is_span_v<_Ty>) {
return {_St::_Reconstruct_span, true};
} else if constexpr (_Is_specialization_v<_Ty, basic_string_view>) {
return {_St::_Reconstruct_other, true};
#if _HAS_CXX23
} else if constexpr (_Is_specialization_v<_Ty, repeat_view>) {
using _Range_val_t = range_value_t<_Ty>;
return {_St::_Reconstruct_repeat,
is_nothrow_constructible_v<_Range_val_t, _Forward_like_t<_Rng, _Range_val_t>>};
#endif // _HAS_CXX23
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange_v<_Ty>) {
if constexpr (sized_sentinel_for<sentinel_t<_Ty>, iterator_t<_Ty>>) {
return {_St::_Reconstruct_subrange,
noexcept(_Ty(_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>()),
_RANGES end(_STD declval<_Rng&>())))};
} else {
return {_St::_Reconstruct_subrange,
noexcept(_Ty(_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>()),
_RANGES end(_STD declval<_Rng&>()), range_difference_t<_Rng>{0}))};
}
} else if constexpr (_Random_sized_range<_Ty> && _Is_specialization_v<_Ty, iota_view>) {
return {_St::_Reconstruct_other,
noexcept(_Ty(_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>()),
_RANGES end(_STD declval<_Rng&>())))};
} else {
return {_St::_Drop_view, noexcept(drop_view(_STD declval<_Rng>(), range_difference_t<_Rng>{0}))};
}
}
template <class _Rng>
static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>();
public:
template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Rng&& _Range, range_difference_t<_Rng> _Count) _CONST_CALL_OPERATOR noexcept(_Choice<_Rng>._No_throw) {
constexpr _St _Strat = _Choice<_Rng>._Strategy;
if constexpr (_Strat == _St::_Empty) {
// it's an empty_view: return another empty view
return remove_cvref_t<_Rng>{};
} else if constexpr (_Strat == _St::_Drop_view) {
return drop_view(_STD forward<_Rng>(_Range), _Count);
#if _HAS_CXX23
} else if constexpr (_Strat == _St::_Reconstruct_repeat) {
if constexpr (sized_range<_Rng>) {
const auto _Size = _RANGES distance(_Range);
_Count = _Size - (_STD min)(_Size, _Count);
return repeat_view(_STD forward_like<_Rng>(*_Range._Value), _Count);
} else {
return _Range;
}
#endif // _HAS_CXX23
} else {
// it's a "reconstructible range"; return the same kind of range with a restricted extent
_Count = (_STD min)(_RANGES distance(_Range), _Count);
if constexpr (_Strat == _St::_Reconstruct_span) {
return span(_Ubegin(_Range) + _Count, _Uend(_Range));
} else if constexpr (_Strat == _St::_Reconstruct_subrange) {
if constexpr (sized_sentinel_for<sentinel_t<_Rng>, iterator_t<_Rng>>) {
return remove_cvref_t<_Rng>(_RANGES begin(_Range) + _Count, _RANGES end(_Range));
} else {
return remove_cvref_t<_Rng>(
_RANGES begin(_Range) + _Count, _RANGES end(_Range), _RANGES size(_Range) - _Count);
}
} else if constexpr (_Strat == _St::_Reconstruct_other) {
return remove_cvref_t<_Rng>(_RANGES begin(_Range) + _Count, _RANGES end(_Range));
} else {
_STL_INTERNAL_STATIC_ASSERT(false); // unexpected strategy
}
}
}
template <class _Ty>
requires constructible_from<decay_t<_Ty>, _Ty>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty&& _Length) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Ty>, _Ty>) {
return _Range_closure<_Drop_fn, decay_t<_Ty>>{_STD forward<_Ty>(_Length)};
}
};
_EXPORT_STD inline constexpr _Drop_fn drop;
} // namespace views
_EXPORT_STD template <view _Vw, class _Pr>
requires input_range<_Vw> && is_object_v<_Pr> && indirect_unary_predicate<const _Pr, iterator_t<_Vw>>
class drop_while_view : public _Cached_position_t<forward_range<_Vw>, _Vw, drop_while_view<_Vw, _Pr>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
/* [[no_unique_address]] */ _Movable_box<_Pr> _Pred{};
public:
drop_while_view()
requires default_initializable<_Vw> && default_initializable<_Pr>
= default;
constexpr explicit drop_while_view(_Vw _Range_, _Pr _Pred_)
noexcept(is_nothrow_move_constructible_v<_Vw> && is_nothrow_move_constructible_v<_Pr>) // strengthened
: _Range(_STD move(_Range_)), _Pred{in_place, _STD move(_Pred_)} {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Pred, "drop_while_view has no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
return *_Pred;
}
_NODISCARD constexpr auto begin() {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(
_Pred, "N4950 [range.drop.while.view]/3 forbids calling begin on a drop_while_view with no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
if constexpr (forward_range<_Vw>) {
if (this->_Has_cache()) {
return this->_Get_cache(_Range);
}
}
auto _First = _RANGES find_if_not(_Range, _STD cref(*_Pred));
if constexpr (forward_range<_Vw>) {
this->_Set_cache(_Range, _First);
}
return _First;
}
_NODISCARD constexpr auto end() noexcept(noexcept(_RANGES end(_Range))) /* strengthened */ {
return _RANGES end(_Range);
}
};
template <class _Rng, class _Pr>
drop_while_view(_Rng&&, _Pr) -> drop_while_view<views::all_t<_Rng>, _Pr>;
template <class _Rng, class _Pr>
constexpr bool enable_borrowed_range<drop_while_view<_Rng, _Pr>> = enable_borrowed_range<_Rng>;
#if _HAS_CXX23
template <class _Rng, class _Pr>
constexpr auto _Compile_time_max_size<drop_while_view<_Rng, _Pr>> = _Compile_time_max_size<_Rng>;
#endif // _HAS_CXX23
namespace views {
struct _Drop_while_fn {
template <viewable_range _Rng, class _Pr>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range, _Pr _Pred) _CONST_CALL_OPERATOR
noexcept(noexcept(drop_while_view(_STD forward<_Rng>(_Range), _STD move(_Pred))))
requires requires { drop_while_view(static_cast<_Rng&&>(_Range), _STD move(_Pred)); }
{
return drop_while_view(_STD forward<_Rng>(_Range), _STD move(_Pred));
}
template <class _Pr>
requires constructible_from<decay_t<_Pr>, _Pr>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Pr&& _Pred) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Pr>, _Pr>) {
return _Range_closure<_Drop_while_fn, decay_t<_Pr>>{_STD forward<_Pr>(_Pred)};
}
};
_EXPORT_STD inline constexpr _Drop_while_fn drop_while;
} // namespace views
template <class _Ty>
_NODISCARD constexpr _Ty& _As_lvalue(_Ty&& _Val) noexcept {
return static_cast<_Ty&>(_Val);
}
struct _Construct_tag {
explicit _Construct_tag() = default;
};
_EXPORT_STD template <input_range _Vw>
requires view<_Vw> && input_range<range_reference_t<_Vw>>
class join_view;
template <class _Vw>
class _Join_view_base : public view_interface<join_view<_Vw>> {
private:
struct _Cache_wrapper {
template <input_iterator _Iter>
constexpr _Cache_wrapper(_Construct_tag, const _Iter& _It)
noexcept(noexcept(static_cast<decltype(_Val)>(*_It)))
: _Val(*_It) {}
remove_cv_t<range_reference_t<_Vw>> _Val;
};
protected:
/* [[no_unique_address]] */ _Non_propagating_cache<_Cache_wrapper, false> _Inner{};
};
template <class _Vw>
requires is_reference_v<range_reference_t<_Vw>>
class _Join_view_base<_Vw> : public view_interface<join_view<_Vw>> {};
template <class _Vw>
class _Join_view_outer_iter_base : public _Join_view_base<_Vw> {
protected:
_Non_propagating_cache<iterator_t<_Vw>> _Outer;
};
template <forward_range _Vw>
class _Join_view_outer_iter_base<_Vw> : public _Join_view_base<_Vw> {};
_EXPORT_STD template <input_range _Vw>
requires view<_Vw> && input_range<range_reference_t<_Vw>>
class join_view : public _Join_view_outer_iter_base<_Vw> {
private:
template <bool _Const>
using _InnerRng = range_reference_t<_Maybe_const<_Const, _Vw>>;
/* [[no_unique_address]] */ _Vw _Range{};
template <class _Outer, class _Inner, bool _Deref_is_glvalue>
struct _Category_base {};
template <forward_range _Outer, forward_range _Inner>
struct _Category_base<_Outer, _Inner, true> {
using iterator_category =
conditional_t<common_range<_Inner>
&& derived_from<_Iter_cat_t<iterator_t<_Outer>>, bidirectional_iterator_tag>
&& derived_from<_Iter_cat_t<iterator_t<_Inner>>, bidirectional_iterator_tag>,
bidirectional_iterator_tag,
conditional_t<derived_from<_Iter_cat_t<iterator_t<_Outer>>, forward_iterator_tag>
&& derived_from<_Iter_cat_t<iterator_t<_Inner>>, forward_iterator_tag>,
forward_iterator_tag, input_iterator_tag>>;
};
template <bool _Const>
class _Iterator_base
: public _Category_base<_Maybe_const<_Const, _Vw>, _InnerRng<_Const>, is_reference_v<_InnerRng<_Const>>> {};
template <bool _Const>
requires forward_range<_Maybe_const<_Const, _Vw>>
class _Iterator_base<_Const>
: public _Category_base<_Maybe_const<_Const, _Vw>, _InnerRng<_Const>, is_reference_v<_InnerRng<_Const>>> {
protected:
using _OuterIter = iterator_t<_Maybe_const<_Const, _Vw>>;
_Iterator_base() = default;
constexpr explicit _Iterator_base(_OuterIter&& _Outer_) : _Outer(_STD move(_Outer_)) {}
/* [[no_unique_address]] */ _OuterIter _Outer{};
};
template <bool _Const>
class _Iterator : public _Iterator_base<_Const> {
private:
friend join_view;
using _Mybase = _Iterator_base<_Const>;
using _Parent_t = _Maybe_const<_Const, join_view>;
using _Base = _Maybe_const<_Const, _Vw>;
using _OuterIter = iterator_t<_Base>;
using _InnerIter = iterator_t<_InnerRng<_Const>>;
// True if and only if the expression *i, where i is an iterator from the outer range, is a glvalue:
static constexpr bool _Deref_is_glvalue = is_reference_v<_InnerRng<_Const>>;
/* [[no_unique_address]] */ _Defaultabox<_InnerIter> _Inner{}; // Non-standard extension: when _Inner_iter
// is default-constructible, we don't wrap in
// an optional-like.
_Parent_t* _Parent{};
constexpr _Iterator(_Parent_t& _Parent_, _OuterIter _Outer_)
requires forward_range<_Base>
: _Mybase{_STD move(_Outer_)}, _Parent{_STD addressof(_Parent_)} {
#if _ITERATOR_DEBUG_LEVEL != 0
_STD _Adl_verify_range(this->_Outer, _RANGES end(_Parent_._Range));
_STD _Adl_verify_range(_RANGES begin(_Parent_._Range), this->_Outer);
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Satisfy();
}
constexpr explicit _Iterator(_Parent_t& _Parent)
requires (!forward_range<_Base>)
: _Parent{_STD addressof(_Parent)} {
_Satisfy();
}
_NODISCARD constexpr _OuterIter& _Get_outer() noexcept {
if constexpr (forward_range<_Base>) {
return this->_Outer;
} else {
return *_Parent->_Outer;
}
}
_NODISCARD constexpr const _OuterIter& _Get_outer() const noexcept {
if constexpr (forward_range<_Base>) {
return this->_Outer;
} else {
return *_Parent->_Outer;
}
}
constexpr auto&& _Update_inner() {
if constexpr (_Deref_is_glvalue) {
return *_Get_outer();
} else {
return _Parent->_Inner._Emplace(_Construct_tag{}, _Get_outer())._Val;
}
}
constexpr void _Satisfy() {
auto& _Outer = _Get_outer();
const auto _Last = _RANGES end(_Parent->_Range);
for (; _Outer != _Last; ++_Outer) {
auto&& _Tmp = _Update_inner();
_Inner = _RANGES begin(_Tmp);
if (*_Inner != _RANGES end(_Tmp)) {
return;
}
}
if constexpr (_Deref_is_glvalue) {
_Inner._Reset();
}
}
#if _ITERATOR_DEBUG_LEVEL != 0
constexpr void _Check_dereference() const noexcept {
_STL_VERIFY(_Parent != nullptr, "cannot dereference value-initialized join_view iterator");
_STL_VERIFY(_Get_outer() != _RANGES end(_Parent->_Range), "cannot dereference join_view end iterator");
sentinel_t<_InnerRng<_Const>> _Last;
if constexpr (_Deref_is_glvalue) {
_Last = _RANGES end(_RANGES _As_lvalue(*_Get_outer()));
} else {
_Last = _RANGES end((*_Parent->_Inner)._Val);
}
_STL_VERIFY(_Inner && *_Inner != _Last, "cannot dereference join_view end iterator");
}
constexpr void _Same_range(const _Iterator& _Right) const noexcept {
_STL_VERIFY(_Parent == _Right._Parent, "cannot compare incompatible join_view iterators");
}
#endif // _ITERATOR_DEBUG_LEVEL != 0
public:
using iterator_concept =
conditional_t<_Deref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<_InnerRng<_Const>>
&& common_range<_InnerRng<_Const>>,
bidirectional_iterator_tag,
conditional_t<_Deref_is_glvalue && forward_range<_Base> && forward_range<_InnerRng<_Const>>,
forward_iterator_tag, input_iterator_tag>>;
using value_type = range_value_t<_InnerRng<_Const>>;
using difference_type = common_type_t<range_difference_t<_Base>, range_difference_t<_InnerRng<_Const>>>;
_Iterator() = default;
constexpr _Iterator(_Iterator<!_Const> _It)
requires _Const && convertible_to<iterator_t<_Vw>, _OuterIter>
&& convertible_to<iterator_t<_InnerRng<false>>, _InnerIter>
: _Mybase(_STD move(_It._Outer)), _Inner(_STD move(_It._Inner)), _Parent(_It._Parent) {}
_NODISCARD constexpr decltype(auto) operator*() const noexcept(noexcept(**_Inner)) /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_Check_dereference();
#endif // _ITERATOR_DEBUG_LEVEL != 0
return **_Inner;
}
_NODISCARD constexpr _InnerIter operator->() const
noexcept(is_nothrow_copy_constructible_v<_InnerIter>) // strengthened
requires _Has_arrow<_InnerIter> && copyable<_InnerIter>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_Check_dereference();
#endif // _ITERATOR_DEBUG_LEVEL != 0
return *_Inner;
}
constexpr _Iterator& operator++() {
auto& _Outer = _Get_outer();
if constexpr (_Deref_is_glvalue) {
if (++*_Inner == _RANGES end(_RANGES _As_lvalue(*_Outer))) {
++_Outer;
_Satisfy();
}
} else {
if (++*_Inner == _RANGES end((*_Parent->_Inner)._Val)) {
++_Outer;
_Satisfy();
}
}
return *this;
}
constexpr decltype(auto) operator++(int) {
if constexpr (_Deref_is_glvalue && forward_range<_Base> && forward_range<_InnerRng<_Const>>) {
auto _Tmp = *this;
++*this;
return _Tmp;
} else {
++*this;
}
}
constexpr _Iterator& operator--()
requires _Deref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<_InnerRng<_Const>>
&& common_range<_InnerRng<_Const>>
{
auto& _Outer = _Get_outer();
if (_Outer == _RANGES end(_Parent->_Range)) {
--_Outer;
_Inner = _RANGES end(_RANGES _As_lvalue(*_Outer));
}
while (*_Inner == _RANGES begin(_RANGES _As_lvalue(*_Outer))) {
--_Outer;
*_Inner = _RANGES end(_RANGES _As_lvalue(*_Outer));
}
--*_Inner;
return *this;
}
constexpr _Iterator operator--(int)
requires _Deref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<_InnerRng<_Const>>
&& common_range<_InnerRng<_Const>>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Outer == _Right._Outer && _Left._Inner == _Right._Inner)) /* strengthened */
requires _Deref_is_glvalue && forward_range<_Base> && equality_comparable<_InnerIter>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_Left._Same_range(_Right);
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Left._Outer == _Right._Outer && _Left._Inner == _Right._Inner;
}
_NODISCARD friend constexpr decltype(auto) iter_move(const _Iterator& _It)
noexcept(noexcept(_RANGES iter_move(*_It._Inner))) {
#if _ITERATOR_DEBUG_LEVEL != 0
_It._Check_dereference();
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _RANGES iter_move(*_It._Inner);
}
friend constexpr void iter_swap(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_RANGES iter_swap(*_Left._Inner, *_Right._Inner)))
requires indirectly_swappable<_InnerIter>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_Left._Check_dereference();
_Right._Check_dereference();
#endif // _ITERATOR_DEBUG_LEVEL != 0
_RANGES iter_swap(*_Left._Inner, *_Right._Inner);
}
};
template <bool _Const>
class _Sentinel {
private:
friend join_view;
using _Parent_t = _Maybe_const<_Const, join_view>;
using _Base = _Maybe_const<_Const, _Vw>;
template <bool _OtherConst>
using _Maybe_const_iter = iterator_t<_Maybe_const<_OtherConst, _Vw>>;
/* [[no_unique_address]] */ sentinel_t<_Base> _Last{};
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD constexpr bool _Equal(const _Iterator<_OtherConst>& _It) const
noexcept(noexcept(_STD _Fake_copy_init<bool>(_It._Get_outer() == _Last))) {
return _It._Get_outer() == _Last;
}
public:
_Sentinel() = default;
constexpr explicit _Sentinel(_Parent_t& _Parent)
noexcept(noexcept(_RANGES end(_Parent._Range))
&& is_nothrow_move_constructible_v<sentinel_t<_Base>>) // strengthened
: _Last(_RANGES end(_Parent._Range)) {}
constexpr _Sentinel(_Sentinel<!_Const> _Se)
noexcept(is_nothrow_constructible_v<sentinel_t<_Base>, sentinel_t<_Vw>>) // strengthened
requires _Const && convertible_to<sentinel_t<_Vw>, sentinel_t<_Base>>
: _Last(_STD move(_Se._Last)) {}
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right)
noexcept(noexcept(_Right._Equal(_Left))) /* strengthened */ {
return _Right._Equal(_Left);
}
};
public:
join_view()
requires default_initializable<_Vw>
= default;
constexpr explicit join_view(_Vw _Range_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Range(_STD move(_Range_)) {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin() {
if constexpr (forward_range<_Vw>) {
constexpr bool _Use_const = _Simple_view<_Vw> && is_reference_v<_InnerRng<false>>;
return _Iterator<_Use_const>{*this, _RANGES begin(_Range)};
} else {
this->_Outer._Emplace(_RANGES begin(_Range));
return _Iterator<false>{*this};
}
}
_NODISCARD constexpr _Iterator<true> begin() const
requires forward_range<const _Vw> && is_reference_v<_InnerRng<true>> && input_range<_InnerRng<true>>
{
return _Iterator<true>{*this, _RANGES begin(_Range)};
}
_NODISCARD constexpr auto end() {
if constexpr (forward_range<_Vw> && is_reference_v<_InnerRng<false>> && forward_range<_InnerRng<false>>
&& common_range<_Vw> && common_range<_InnerRng<false>>) {
return _Iterator<_Simple_view<_Vw>>{*this, _RANGES end(_Range)};
} else {
return _Sentinel<_Simple_view<_Vw>>{*this};
}
}
_NODISCARD constexpr auto end() const
requires forward_range<const _Vw> && is_reference_v<_InnerRng<true>> && input_range<_InnerRng<true>>
{
if constexpr (forward_range<_InnerRng<true>> && common_range<const _Vw> && common_range<_InnerRng<true>>) {
return _Iterator<true>{*this, _RANGES end(_Range)};
} else {
return _Sentinel<true>{*this};
}
}
};
template <class _Rng>
explicit join_view(_Rng&&) -> join_view<views::all_t<_Rng>>;
#if _HAS_CXX23
template <class _Rng>
_NODISCARD consteval auto _Join_view_compile_time_max_size() {
using _Inner = remove_reference_t<range_reference_t<_Rng>>;
using _Size_type =
common_type_t<decltype(_Compile_time_max_size<_Rng>), decltype(_Compile_time_max_size<_Inner>)>;
_Size_type _Result{};
const bool _Overflow = _Mul_overflow(static_cast<_Size_type>(_Compile_time_max_size<_Rng>),
static_cast<_Size_type>(_Compile_time_max_size<_Inner>), _Result);
if (_Overflow) {
return (numeric_limits<_Size_type>::max)();
} else {
return _Result;
}
}
template <class _Rng>
constexpr auto _Compile_time_max_size<join_view<_Rng>> = _Join_view_compile_time_max_size<_Rng>();
template <class _Rng>
constexpr auto _Compile_time_max_size<const join_view<_Rng>> = _Join_view_compile_time_max_size<const _Rng>();
#endif // _HAS_CXX23
namespace views {
class _Join_fn : public _Pipe::_Base<_Join_fn> {
public:
template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range) _CONST_CALL_OPERATOR
noexcept(noexcept(join_view<views::all_t<_Rng>>{_STD forward<_Rng>(_Range)}))
requires requires { join_view<views::all_t<_Rng>>{static_cast<_Rng&&>(_Range)}; }
{
return join_view<views::all_t<_Rng>>{_STD forward<_Rng>(_Range)};
}
};
_EXPORT_STD inline constexpr _Join_fn join;
} // namespace views
#if _HAS_CXX23
template <class... _Rngs>
using _Concat_reference_t = common_reference_t<range_reference_t<_Rngs>...>;
template <class... _Rngs>
using _Concat_value_t = common_type_t<range_value_t<_Rngs>...>;
template <class... _Rngs>
using _Concat_rvalue_reference_t = common_reference_t<range_rvalue_reference_t<_Rngs>...>;
template <class _Ref, class _RRef, class _It>
concept _Concat_indirectly_readable_impl = requires(const _It __i) {
{ *__i } -> convertible_to<_Ref>;
{ _RANGES iter_move(__i) } -> convertible_to<_RRef>;
};
template <class... _Rngs>
concept _Concat_indirectly_readable =
common_reference_with<_Concat_reference_t<_Rngs...>&&, _Concat_value_t<_Rngs...>&>
&& common_reference_with<_Concat_reference_t<_Rngs...>&&, _Concat_rvalue_reference_t<_Rngs...>&&>
&& common_reference_with<_Concat_rvalue_reference_t<_Rngs...>&&, const _Concat_value_t<_Rngs...>&>
&& (_Concat_indirectly_readable_impl<_Concat_reference_t<_Rngs...>, _Concat_rvalue_reference_t<_Rngs...>,
iterator_t<_Rngs>>
&& ...);
template <class... _Rngs>
concept _Concatable = requires {
typename _Concat_reference_t<_Rngs...>;
typename _Concat_value_t<_Rngs...>;
typename _Concat_rvalue_reference_t<_Rngs...>;
} && _Concat_indirectly_readable<_Rngs...>;
_EXPORT_STD template <input_range _Vw, forward_range _Pat>
requires view<_Vw> && input_range<range_reference_t<_Vw>> && view<_Pat>
&& _Concatable<range_reference_t<_Vw>, _Pat>
class join_with_view;
template <class _Vw, class _Pat>
class _Join_with_view_base : public view_interface<join_with_view<_Vw, _Pat>> {
private:
struct _Cache_wrapper {
template <input_iterator _Iter>
constexpr _Cache_wrapper(_Construct_tag, const _Iter& _It)
noexcept(noexcept(static_cast<decltype(_Val)>(*_It)))
: _Val(*_It) {}
remove_cv_t<range_reference_t<_Vw>> _Val;
};
protected:
/* [[no_unique_address]] */ _Non_propagating_cache<_Cache_wrapper, false> _Inner{};
};
template <class _Vw, class _Pat>
requires is_reference_v<range_reference_t<_Vw>>
class _Join_with_view_base<_Vw, _Pat> : public view_interface<join_with_view<_Vw, _Pat>> {};
template <class _Vw, class _Pat>
class _Join_with_view_outer_iter_base : public _Join_with_view_base<_Vw, _Pat> {
protected:
_Non_propagating_cache<iterator_t<_Vw>> _Outer_it;
};
template <forward_range _Vw, class _Pat>
class _Join_with_view_outer_iter_base<_Vw, _Pat> : public _Join_with_view_base<_Vw, _Pat> {};
_EXPORT_STD template <input_range _Vw, forward_range _Pat>
requires view<_Vw> && input_range<range_reference_t<_Vw>> && view<_Pat>
&& _Concatable<range_reference_t<_Vw>, _Pat>
class join_with_view : public _Join_with_view_outer_iter_base<_Vw, _Pat> {
private:
template <bool _Const>
using _InnerRng = range_reference_t<_Maybe_const<_Const, _Vw>>;
/* [[no_unique_address]] */ _Vw _Range{};
/* [[no_unique_address]] */ _Pat _Pattern{};
template <bool _Const>
struct _Category_base {};
template <bool _Const>
requires forward_range<_Maybe_const<_Const, _Vw>> && forward_range<_InnerRng<_Const>>
&& is_reference_v<_InnerRng<_Const>>
struct _Category_base<_Const> {
using _Outer = _Maybe_const<_Const, _Vw>;
using _Inner = _InnerRng<_Const>;
using _PatternBase = _Maybe_const<_Const, _Pat>;
using iterator_category = conditional_t<
!is_reference_v<common_reference_t<range_reference_t<_Inner>, range_reference_t<_PatternBase>>>,
input_iterator_tag,
conditional_t<common_range<_Inner> && common_range<_PatternBase>
&& derived_from<_Iter_cat_t<iterator_t<_Outer>>, bidirectional_iterator_tag>
&& derived_from<_Iter_cat_t<iterator_t<_Inner>>, bidirectional_iterator_tag>
&& derived_from<_Iter_cat_t<iterator_t<_PatternBase>>, bidirectional_iterator_tag>,
bidirectional_iterator_tag,
conditional_t<derived_from<_Iter_cat_t<iterator_t<_Outer>>, forward_iterator_tag>
&& derived_from<_Iter_cat_t<iterator_t<_Inner>>, forward_iterator_tag>
&& derived_from<_Iter_cat_t<iterator_t<_PatternBase>>, forward_iterator_tag>,
forward_iterator_tag, input_iterator_tag>>>;
};
template <bool _Const>
class _Iterator_base : public _Category_base<_Const> {};
template <bool _Const>
requires forward_range<_Maybe_const<_Const, _Vw>>
class _Iterator_base<_Const> : public _Category_base<_Const> {
protected:
using _OuterIter = iterator_t<_Maybe_const<_Const, _Vw>>;
_Iterator_base() = default;
constexpr explicit _Iterator_base(_OuterIter&& _Outer_it_) : _Outer_it(_STD move(_Outer_it_)) {}
/* [[no_unique_address]] */ _OuterIter _Outer_it{};
};
template <bool _Const>
class _Iterator : public _Iterator_base<_Const> {
private:
friend join_with_view;
using _Mybase = _Iterator_base<_Const>;
using _Parent_t = _Maybe_const<_Const, join_with_view>;
using _Base = _Maybe_const<_Const, _Vw>;
using _PatternBase = _Maybe_const<_Const, _Pat>;
using _OuterIter = iterator_t<_Base>;
using _InnerIter = iterator_t<_InnerRng<_Const>>;
using _PatternIter = iterator_t<_PatternBase>;
// True if and only if the expression *i, where i is an iterator from the outer range, is a glvalue:
static constexpr bool _Deref_is_glvalue = is_reference_v<_InnerRng<_Const>>;
_Parent_t* _Parent{};
_Variantish<_PatternIter, _InnerIter> _Inner_it{};
constexpr _Iterator(_Parent_t& _Parent_, _OuterIter _Outer_)
requires forward_range<_Base>
: _Mybase(_STD move(_Outer_)), _Parent(_STD addressof(_Parent_)) {
if (this->_Outer_it != _RANGES end(_Parent->_Range)) {
_Inner_it._Emplace_second(_RANGES begin(_Update_inner()));
_Satisfy();
}
}
constexpr explicit _Iterator(_Parent_t& _Parent_)
requires (!forward_range<_Base>)
: _Parent{_STD addressof(_Parent_)} {
if (*_Parent->_Outer_it != _RANGES end(_Parent->_Range)) {
_Inner_it._Emplace_second(_RANGES begin(_Update_inner()));
_Satisfy();
}
}
_NODISCARD constexpr _OuterIter& _Get_outer() noexcept {
if constexpr (forward_range<_Base>) {
return this->_Outer_it;
} else {
return *_Parent->_Outer_it;
}
}
_NODISCARD constexpr const _OuterIter& _Get_outer() const noexcept {
if constexpr (forward_range<_Base>) {
return this->_Outer_it;
} else {
return *_Parent->_Outer_it;
}
}
_NODISCARD constexpr auto& _Update_inner() {
if constexpr (_Deref_is_glvalue) {
return _RANGES _As_lvalue(*_Get_outer());
} else {
return _Parent->_Inner._Emplace(_Construct_tag{}, _Get_outer())._Val;
}
}
_NODISCARD constexpr auto& _Get_inner() noexcept {
if constexpr (_Deref_is_glvalue) {
return _RANGES _As_lvalue(*_Get_outer());
} else {
return (*_Parent->_Inner)._Val;
}
}
template <class _Ret = void>
constexpr _Ret _Visit_inner_it(auto&& _Func) const {
if (_Inner_it._Contains == _Variantish_state::_Holds_first) {
return _Func(_Inner_it._Get_first());
} else if (_Inner_it._Contains == _Variantish_state::_Holds_second) {
return _Func(_Inner_it._Get_second());
} else {
_STD _Throw_bad_variant_access();
}
}
constexpr void _Satisfy() {
for (;;) {
if (_Inner_it._Contains == _Variantish_state::_Holds_first) {
if (_Inner_it._Get_first() != _RANGES end(_Parent->_Pattern)) {
break;
}
_Inner_it._Emplace_second(_RANGES begin(_Update_inner()));
} else {
_STL_INTERNAL_CHECK(_Inner_it._Contains == _Variantish_state::_Holds_second);
if (_Inner_it._Get_second() != _RANGES end(_Get_inner())) {
break;
}
auto& _Outer_it = _Get_outer();
++_Outer_it;
if (_Outer_it == _RANGES end(_Parent->_Range)) {
if constexpr (_Deref_is_glvalue) {
_Inner_it._Emplace_first();
}
break;
}
_Inner_it._Emplace_first(_RANGES begin(_Parent->_Pattern));
}
}
}
public:
using iterator_concept =
conditional_t<_Deref_is_glvalue && bidirectional_range<_Base> && _Bidi_common_range<_InnerRng<_Const>>
&& _Bidi_common_range<_PatternBase>,
bidirectional_iterator_tag,
conditional_t<_Deref_is_glvalue && forward_range<_Base> && forward_range<_InnerRng<_Const>>,
forward_iterator_tag, input_iterator_tag>>;
using value_type = common_type_t<iter_value_t<_InnerIter>, iter_value_t<_PatternIter>>;
using difference_type = _Common_diff_t<_OuterIter, _InnerIter, _PatternIter>;
_Iterator() = default;
constexpr _Iterator(_Iterator<!_Const> _It)
requires _Const && convertible_to<iterator_t<_Vw>, _OuterIter>
&& convertible_to<iterator_t<_InnerRng<false>>, _InnerIter>
&& convertible_to<iterator_t<_Pat>, _PatternIter>
: _Mybase(_STD move(_It._Outer_it)), _Parent(_It._Parent) {
switch (_It._Inner_it._Contains) {
case _Variantish_state::_Holds_first:
_Inner_it._Emplace_first(_STD move(_It._Inner_it._Get_first()));
break;
case _Variantish_state::_Holds_second:
_Inner_it._Emplace_second(_STD move(_It._Inner_it._Get_second()));
break;
case _Variantish_state::_Nothing:
_STD _Throw_bad_variant_access();
}
}
_NODISCARD constexpr decltype(auto) operator*() const {
using _Ref = common_reference_t<iter_reference_t<_InnerIter>, iter_reference_t<_PatternIter>>;
return _Visit_inner_it<_Ref>([](auto&& _It) _STATIC_CALL_OPERATOR -> _Ref { return *_It; });
}
constexpr _Iterator& operator++() {
switch (_Inner_it._Contains) {
case _Variantish_state::_Holds_first:
++_Inner_it._Get_first();
break;
case _Variantish_state::_Holds_second:
++_Inner_it._Get_second();
break;
case _Variantish_state::_Nothing:
_STD _Throw_bad_variant_access();
}
_Satisfy();
return *this;
}
constexpr void operator++(int) {
++*this;
}
constexpr _Iterator operator++(int)
requires _Deref_is_glvalue && forward_iterator<_OuterIter> && forward_iterator<_InnerIter>
{
auto _Tmp = *this;
++*this;
return _Tmp;
}
constexpr _Iterator& operator--()
requires _Deref_is_glvalue && bidirectional_range<_Base> && _Bidi_common_range<_InnerRng<_Const>>
&& _Bidi_common_range<_PatternBase>
{
auto& _Outer_it = _Get_outer();
if (_Outer_it == _RANGES end(_Parent->_Range)) {
--_Outer_it;
_Inner_it._Emplace_second(_RANGES end(_Get_inner()));
}
for (;;) {
if (_Inner_it._Contains == _Variantish_state::_Holds_first) {
auto& _It = _Inner_it._Get_first();
if (_It == _RANGES begin(_Parent->_Pattern)) {
--_Outer_it;
_Inner_it._Emplace_second(_RANGES end(_Get_inner()));
} else {
break;
}
} else if (_Inner_it._Contains == _Variantish_state::_Holds_second) {
auto& _It = _Inner_it._Get_second();
if (_It == _RANGES begin(_Get_inner())) {
_Inner_it._Emplace_first(_RANGES end(_Parent->_Pattern));
} else {
break;
}
} else {
_STD _Throw_bad_variant_access();
}
}
switch (_Inner_it._Contains) {
case _Variantish_state::_Holds_first:
--_Inner_it._Get_first();
break;
case _Variantish_state::_Holds_second:
--_Inner_it._Get_second();
break;
case _Variantish_state::_Nothing:
_STD _Throw_bad_variant_access();
}
return *this;
}
constexpr _Iterator operator--(int)
requires _Deref_is_glvalue && bidirectional_range<_Base> && _Bidi_common_range<_InnerRng<_Const>>
&& _Bidi_common_range<_PatternBase>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
requires _Deref_is_glvalue && forward_range<_Base> && equality_comparable<_InnerIter>
{
if (_Left._Outer_it != _Right._Outer_it) {
return false;
}
if (_Left._Inner_it._Contains != _Right._Inner_it._Contains) {
return false;
}
switch (_Left._Inner_it._Contains) {
case _Variantish_state::_Holds_first:
return _Left._Inner_it._Get_first() == _Right._Inner_it._Get_first();
case _Variantish_state::_Holds_second:
return _Left._Inner_it._Get_second() == _Right._Inner_it._Get_second();
case _Variantish_state::_Nothing:
return true;
}
_STL_UNREACHABLE;
}
_NODISCARD friend constexpr decltype(auto) iter_move(const _Iterator& _It) {
using _Rvalue_ref =
common_reference_t<iter_rvalue_reference_t<_InnerIter>, iter_rvalue_reference_t<_PatternIter>>;
return _It._Visit_inner_it<_Rvalue_ref>(_RANGES iter_move);
}
friend constexpr void iter_swap(const _Iterator& _Left, const _Iterator& _Right)
requires indirectly_swappable<_InnerIter, _PatternIter>
{
switch (_Left._Inner_it._Contains) {
case _Variantish_state::_Holds_first:
switch (_Right._Inner_it._Contains) {
case _Variantish_state::_Holds_first:
return _RANGES iter_swap(_Left._Inner_it._Get_first(), _Right._Inner_it._Get_first());
case _Variantish_state::_Holds_second:
return _RANGES iter_swap(_Left._Inner_it._Get_first(), _Right._Inner_it._Get_second());
case _Variantish_state::_Nothing:
break;
}
break;
case _Variantish_state::_Holds_second:
switch (_Right._Inner_it._Contains) {
case _Variantish_state::_Holds_first:
return _RANGES iter_swap(_Left._Inner_it._Get_second(), _Right._Inner_it._Get_first());
case _Variantish_state::_Holds_second:
return _RANGES iter_swap(_Left._Inner_it._Get_second(), _Right._Inner_it._Get_second());
case _Variantish_state::_Nothing:
break;
}
break;
case _Variantish_state::_Nothing:
break;
}
_STD _Throw_bad_variant_access();
}
};
template <bool _Const>
class _Sentinel {
private:
friend join_with_view;
using _Parent_t = _Maybe_const<_Const, join_with_view>;
using _Base = _Maybe_const<_Const, _Vw>;
/* [[no_unique_address]] */ sentinel_t<_Base> _Last{};
constexpr explicit _Sentinel(_Parent_t& _Parent)
noexcept(noexcept(_RANGES end(_Parent._Range))
&& is_nothrow_move_constructible_v<sentinel_t<_Base>>) // strengthened
: _Last(_RANGES end(_Parent._Range)) {}
template <bool _OtherConst>
_NODISCARD constexpr bool _Equal(const _Iterator<_OtherConst>& _It) const
noexcept(noexcept(_STD _Fake_copy_init<bool>(_It._Get_outer() == _Last))) {
_STL_INTERNAL_STATIC_ASSERT(
sentinel_for<sentinel_t<_Base>, iterator_t<_Maybe_const<_OtherConst, _Vw>>>);
return _It._Get_outer() == _Last;
}
public:
_Sentinel() = default;
constexpr _Sentinel(_Sentinel<!_Const> _Se)
noexcept(is_nothrow_constructible_v<sentinel_t<_Base>, sentinel_t<_Vw>>) // strengthened
requires _Const && convertible_to<sentinel_t<_Vw>, sentinel_t<_Base>>
: _Last(_STD move(_Se._Last)) {}
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right)
noexcept(noexcept(_Right._Equal(_Left))) /* strengthened */ {
return _Right._Equal(_Left);
}
};
public:
join_with_view()
requires default_initializable<_Vw> && default_initializable<_Pat>
= default;
constexpr explicit join_with_view(_Vw _Range_, _Pat _Pattern_)
noexcept(is_nothrow_move_constructible_v<_Vw> && is_nothrow_move_constructible_v<_Pat>) // strengthened
: _Range{_STD move(_Range_)}, _Pattern{_STD move(_Pattern_)} {}
template <input_range _Rng>
requires constructible_from<_Vw, views::all_t<_Rng>>
&& constructible_from<_Pat, single_view<range_value_t<_InnerRng<false>>>>
constexpr explicit join_with_view(_Rng&& _Range_, range_value_t<_InnerRng<false>> _Elem)
noexcept(noexcept(_Vw(views::all(_STD forward<_Rng>(_Range_))))
&& noexcept(_Pat(views::single(_STD move(_Elem))))) // strengthened
: _Range(views::all(_STD forward<_Rng>(_Range_))), _Pattern(views::single(_STD move(_Elem))) {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin() {
if constexpr (forward_range<_Vw>) {
constexpr bool _Use_const = _Simple_view<_Vw> && is_reference_v<_InnerRng<false>> && _Simple_view<_Pat>;
return _Iterator<_Use_const>{*this, _RANGES begin(_Range)};
} else {
this->_Outer_it._Emplace(_RANGES begin(_Range));
return _Iterator<false>{*this};
}
}
_NODISCARD constexpr auto begin() const
requires forward_range<const _Vw> && forward_range<const _Pat> && is_reference_v<_InnerRng<true>>
&& input_range<_InnerRng<true>> && _Concatable<range_reference_t<const _Vw>, const _Pat>
{
return _Iterator<true>{*this, _RANGES begin(_Range)};
}
_NODISCARD constexpr auto end() {
constexpr bool _Both_simple = _Simple_view<_Vw> && _Simple_view<_Pat>;
if constexpr (forward_range<_Vw> && is_reference_v<_InnerRng<false>> && forward_range<_InnerRng<false>>
&& common_range<_Vw> && common_range<_InnerRng<false>>) {
return _Iterator<_Both_simple>{*this, _RANGES end(_Range)};
} else {
return _Sentinel<_Both_simple>{*this};
}
}
_NODISCARD constexpr auto end() const
requires forward_range<const _Vw> && forward_range<const _Pat> && is_reference_v<_InnerRng<true>>
&& input_range<_InnerRng<true>> && _Concatable<range_reference_t<const _Vw>, const _Pat>
{
if constexpr (forward_range<_InnerRng<true>> && common_range<_Vw> && common_range<_InnerRng<true>>) {
return _Iterator<true>{*this, _RANGES end(_Range)};
} else {
return _Sentinel<true>{*this};
}
}
};
template <class _Rng, class _Pat>
join_with_view(_Rng&&, _Pat&&) -> join_with_view<views::all_t<_Rng>, views::all_t<_Pat>>;
template <input_range _Rng>
join_with_view(_Rng&&, range_value_t<range_reference_t<_Rng>>)
-> join_with_view<views::all_t<_Rng>, single_view<range_value_t<range_reference_t<_Rng>>>>;
template <class _Rng, class _Pat>
_NODISCARD consteval auto _Join_with_view_compile_time_max_size() {
using _Inner = remove_reference_t<range_reference_t<_Rng>>;
using _Size_type = common_type_t<decltype(_Compile_time_max_size<_Rng>),
decltype(_Compile_time_max_size<_Inner>), decltype(_Compile_time_max_size<_Pat>)>;
_Size_type _Joined_max_size{};
_Size_type _Pattern_max_size{};
_Size_type _Result{};
const bool _Overflow =
_Mul_overflow(static_cast<_Size_type>(_Compile_time_max_size<_Rng>),
static_cast<_Size_type>(_Compile_time_max_size<_Inner>), _Joined_max_size)
|| _Mul_overflow((_STD max)(static_cast<_Size_type>(_Compile_time_max_size<_Rng>), _Size_type{1}) - 1,
static_cast<_Size_type>(_Compile_time_max_size<_Pat>), _Pattern_max_size)
|| _Add_overflow(_Joined_max_size, _Pattern_max_size, _Result);
if (_Overflow) {
return (numeric_limits<_Size_type>::max)();
} else {
return _Result;
}
}
template <class _Rng, class _Pat>
constexpr auto _Compile_time_max_size<join_with_view<_Rng, _Pat>> =
_Join_with_view_compile_time_max_size<_Rng, _Pat>();
template <class _Rng, class _Pat>
constexpr auto _Compile_time_max_size<const join_with_view<_Rng, _Pat>> =
_Join_with_view_compile_time_max_size<const _Rng, const _Pat>();
namespace views {
struct _Join_with_fn {
template <viewable_range _Rng, class _Pat>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Rng&& _Range, _Pat&& _Pattern) _CONST_CALL_OPERATOR
noexcept(noexcept(join_with_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern))))
requires requires { join_with_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern)); }
{
return join_with_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern));
}
template <class _Delim>
requires constructible_from<decay_t<_Delim>, _Delim>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Delim&& _Delimiter) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Delim>, _Delim>) {
return _Range_closure<_Join_with_fn, decay_t<_Delim>>{_STD forward<_Delim>(_Delimiter)};
}
};
_EXPORT_STD inline constexpr _Join_with_fn join_with;
} // namespace views
#endif // _HAS_CXX23
template <class _Ty>
concept _Tiny_range = sized_range<_Ty> && requires { typename _Require_constant<remove_reference_t<_Ty>::size()>; }
&& (remove_reference_t<_Ty>::size() <= 1);
_EXPORT_STD template <input_range _Vw, forward_range _Pat>
requires (view<_Vw> && view<_Pat> && indirectly_comparable<iterator_t<_Vw>, iterator_t<_Pat>, _RANGES equal_to>
&& (forward_range<_Vw> || _Tiny_range<_Pat>) )
class lazy_split_view;
template <class _Vw, class _Pat>
class _Lazy_split_view_base : public view_interface<lazy_split_view<_Vw, _Pat>> {
protected:
/* [[no_unique_address]] */ _Defaultabox<iterator_t<_Vw>> _Current{};
};
template <forward_range _Vw, class _Pat>
class _Lazy_split_view_base<_Vw, _Pat> : public view_interface<lazy_split_view<_Vw, _Pat>> {};
_EXPORT_STD template <input_range _Vw, forward_range _Pat>
requires (view<_Vw> && view<_Pat> && indirectly_comparable<iterator_t<_Vw>, iterator_t<_Pat>, _RANGES equal_to>
&& (forward_range<_Vw> || _Tiny_range<_Pat>) )
class lazy_split_view : public _Lazy_split_view_base<_Vw, _Pat> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
/* [[no_unique_address]] */ _Pat _Pattern{};
template <bool>
class _Inner_iter;
template <class>
class _Outer_iter_base {};
template <forward_iterator _Iter>
class _Outer_iter_base<_Iter> {
protected:
_Iter _Current{};
public:
using iterator_category = input_iterator_tag;
_Outer_iter_base() = default;
constexpr explicit _Outer_iter_base(_Iter _Current_) noexcept(is_nothrow_move_constructible_v<_Iter>)
: _Current{_STD move(_Current_)} {}
};
template <bool _Const>
class _Outer_iter : public _Outer_iter_base<iterator_t<_Maybe_const<_Const, _Vw>>> {
private:
friend lazy_split_view;
using _Mybase = _Outer_iter_base<iterator_t<_Maybe_const<_Const, _Vw>>>;
using _ParentTy = _Maybe_const<_Const, lazy_split_view>;
using _BaseTy = _Maybe_const<_Const, _Vw>;
_ParentTy* _Parent = nullptr;
bool _Trailing_empty = false;
_NODISCARD constexpr iterator_t<_BaseTy>& _Get_current() noexcept {
if constexpr (forward_range<_BaseTy>) {
return this->_Current;
} else {
return *_Parent->_Current;
}
}
_NODISCARD constexpr const iterator_t<_BaseTy>& _Get_current() const noexcept {
if constexpr (forward_range<_BaseTy>) {
return this->_Current;
} else {
return *_Parent->_Current;
}
}
_NODISCARD constexpr bool _At_end() const
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Get_current() == _RANGES end(_Parent->_Range)))) {
return _Get_current() == _RANGES end(_Parent->_Range);
}
public:
using iterator_concept = conditional_t<forward_range<_BaseTy>, forward_iterator_tag, input_iterator_tag>;
using difference_type = range_difference_t<_BaseTy>;
class value_type : public view_interface<value_type> {
private:
/* [[no_unique_address]] */ _Outer_iter _First{};
constexpr explicit value_type(_Outer_iter _First_)
noexcept(is_nothrow_move_constructible_v<_Outer_iter>)
: _First{_STD move(_First_)} {}
friend _Outer_iter;
public:
_NODISCARD constexpr auto begin() const {
return _Inner_iter<_Const>{_First};
}
_NODISCARD constexpr default_sentinel_t end() const noexcept {
return default_sentinel;
}
};
_Outer_iter() = default;
constexpr explicit _Outer_iter(_ParentTy& _Parent_) noexcept // strengthened
requires (!forward_range<_BaseTy>)
: _Parent{_STD addressof(_Parent_)} {}
constexpr _Outer_iter(_ParentTy& _Parent_, iterator_t<_BaseTy> _Current_)
noexcept(is_nothrow_move_constructible_v<iterator_t<_BaseTy>>) // strengthened
requires forward_range<_BaseTy>
: _Mybase{_STD move(_Current_)}, _Parent{_STD addressof(_Parent_)} {}
constexpr _Outer_iter(_Outer_iter<!_Const> _It)
requires _Const && convertible_to<iterator_t<_Vw>, iterator_t<_BaseTy>>
: _Mybase{_STD move(_It._Current)}, _Parent{_It._Parent}, _Trailing_empty{_It._Trailing_empty} {}
_NODISCARD constexpr auto operator*() const noexcept(noexcept(value_type{*this})) /* strengthened */ {
return value_type{*this};
}
constexpr _Outer_iter& operator++() {
const auto _End = _RANGES end(_Parent->_Range);
auto& _Cur = _Get_current();
if (_Cur == _End) {
_Trailing_empty = false;
return *this;
}
const auto _Pat_first = _RANGES begin(_Parent->_Pattern);
const auto _Pat_last = _RANGES end(_Parent->_Pattern);
if (_Pat_first == _Pat_last) {
++_Cur;
} else if constexpr (_Tiny_range<_Pat>) {
_Cur = _RANGES _Find_unchecked(_STD move(_Cur), _End, *_Pat_first);
if (_Cur != _End) {
++_Cur;
if (_Cur == _End) {
_Trailing_empty = true;
}
}
} else {
do {
auto _Result = _RANGES mismatch(_Cur, _End, _Pat_first, _Pat_last);
if (_Result.in2 == _Pat_last) { // pattern matches
_Cur = _STD move(_Result.in1);
if (_Cur == _End) {
_Trailing_empty = true;
}
break;
}
} while (++_Cur != _End);
}
return *this;
}
constexpr decltype(auto) operator++(int) {
if constexpr (forward_range<_BaseTy>) {
auto _Tmp = *this;
++*this;
return _Tmp;
} else {
++*this;
}
}
_NODISCARD friend constexpr bool operator==(const _Outer_iter& _Left, const _Outer_iter& _Right)
noexcept(noexcept(_Left._Current == _Right._Current)) /* strengthened */
requires forward_range<_BaseTy>
{
return _Left._Current == _Right._Current && _Left._Trailing_empty == _Right._Trailing_empty;
}
_NODISCARD friend constexpr bool operator==(const _Outer_iter& _Left, default_sentinel_t)
noexcept(noexcept(_Left._At_end())) /* strengthened */ {
return _Left._At_end() && !_Left._Trailing_empty;
}
};
template <class _BaseTy>
class _Inner_iter_base {};
template <forward_range _BaseTy>
class _Inner_iter_base<_BaseTy> {
private:
using _BaseCategory = iterator_traits<iterator_t<_BaseTy>>::iterator_category;
public:
using iterator_category =
conditional_t<derived_from<_BaseCategory, forward_iterator_tag>, forward_iterator_tag, _BaseCategory>;
};
template <bool _Const>
class _Inner_iter : public _Inner_iter_base<_Maybe_const<_Const, _Vw>> {
private:
using _BaseTy = _Maybe_const<_Const, _Vw>;
_Outer_iter<_Const> _It{};
bool _Incremented = false;
_NODISCARD constexpr bool _Equal(const _Inner_iter& _Right) const {
return _It._Get_current() == _Right._It._Get_current();
}
_NODISCARD constexpr iterator_t<_BaseTy>& _Get_current() noexcept {
return _It._Get_current();
}
_NODISCARD constexpr const iterator_t<_BaseTy>& _Get_current() const noexcept {
return _It._Get_current();
}
_NODISCARD constexpr bool _At_end() const {
auto _Pat_pos = _RANGES begin(_It._Parent->_Pattern);
const auto _Pat_end = _RANGES end(_It._Parent->_Pattern);
auto _Last = _RANGES end(_It._Parent->_Range);
if constexpr (_Tiny_range<_Pat>) {
const auto& _Cur = _It._Get_current(); // Intentionally a reference. Since _Pat is tiny, this could
// be a move-only iterator type.
if (_Cur == _Last) {
return true;
}
if (_Pat_pos == _Pat_end) {
return _Incremented;
}
return *_Cur == *_Pat_pos;
} else {
auto _Cur = _It._Get_current(); // Intentionally not a reference. _Pat is not tiny, so this is a
// forward (copyable) iterator.
if (_Cur == _Last) {
return true;
}
if (_Pat_pos == _Pat_end) {
return _Incremented;
}
do {
if (*_Cur != *_Pat_pos) {
return false;
}
if (++_Pat_pos == _Pat_end) {
return true;
}
} while (++_Cur != _Last);
return false;
}
}
public:
using iterator_concept = _Outer_iter<_Const>::iterator_concept;
using value_type = range_value_t<_BaseTy>;
using difference_type = range_difference_t<_BaseTy>;
_Inner_iter() = default;
constexpr explicit _Inner_iter(_Outer_iter<_Const> _It_)
noexcept(is_nothrow_move_constructible_v<_Outer_iter<_Const>>) // strengthened
: _It{_STD move(_It_)} {}
_NODISCARD constexpr const iterator_t<_BaseTy>& base() const& noexcept {
return _It._Get_current();
}
_NODISCARD constexpr iterator_t<_BaseTy> base() && noexcept(
is_nothrow_move_constructible_v<iterator_t<_BaseTy>>) /* strengthened */
requires forward_range<_Vw>
{
return _STD move(_It._Get_current());
}
_NODISCARD constexpr decltype(auto) operator*() const {
return *_It._Get_current();
}
constexpr _Inner_iter& operator++() {
_Incremented = true;
if constexpr (!forward_range<_BaseTy>) {
if constexpr (_Pat::size() == 0) {
return *this;
}
}
++_It._Get_current();
return *this;
}
constexpr decltype(auto) operator++(int) {
if constexpr (forward_range<_BaseTy>) {
auto _Tmp = *this;
++*this;
return _Tmp;
} else {
++*this;
}
}
_NODISCARD friend constexpr bool operator==(const _Inner_iter& _Left, const _Inner_iter& _Right)
requires forward_range<_BaseTy>
{
return _Left._Equal(_Right);
}
_NODISCARD friend constexpr bool operator==(const _Inner_iter& _Left, default_sentinel_t) {
return _Left._At_end();
}
_NODISCARD friend constexpr decltype(auto) iter_move(const _Inner_iter& _Iter)
noexcept(noexcept(_RANGES iter_move(_Iter._Get_current()))) {
return _RANGES iter_move(_Iter._Get_current());
}
friend constexpr void iter_swap(const _Inner_iter& _Left, const _Inner_iter& _Right)
noexcept(noexcept(_RANGES iter_swap(_Left._Get_current(), _Right._Get_current())))
requires indirectly_swappable<iterator_t<_BaseTy>>
{
_RANGES iter_swap(_Left._Get_current(), _Right._Get_current());
}
};
public:
lazy_split_view()
requires default_initializable<_Vw> && default_initializable<_Pat>
= default;
constexpr explicit lazy_split_view(_Vw _Range_, _Pat _Pattern_)
noexcept(is_nothrow_move_constructible_v<_Vw> && is_nothrow_move_constructible_v<_Pat>) // strengthened
: _Range(_STD move(_Range_)), _Pattern(_STD move(_Pattern_)) {}
template <input_range _Rng>
requires constructible_from<_Vw, views::all_t<_Rng>>
&& constructible_from<_Pat, single_view<range_value_t<_Rng>>>
constexpr explicit lazy_split_view(_Rng&& _Range_, range_value_t<_Rng> _Elem)
noexcept(noexcept(_Vw(views::all(_STD forward<_Rng>(_Range_))))
&& noexcept(_Pat(views::single(_STD move(_Elem))))) // strengthened
: _Range(views::all(_STD forward<_Rng>(_Range_))), _Pattern(views::single(_STD move(_Elem))) {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin() {
if constexpr (forward_range<_Vw>) {
constexpr bool _Both_simple = _Simple_view<_Vw> && _Simple_view<_Pat>;
return _Outer_iter<_Both_simple>{*this, _RANGES begin(_Range)};
} else {
this->_Current = _RANGES begin(_Range);
return _Outer_iter<false>{*this};
}
}
_NODISCARD constexpr auto begin() const
requires forward_range<_Vw> && forward_range<const _Vw>
{
return _Outer_iter<true>{*this, _RANGES begin(_Range)};
}
_NODISCARD constexpr auto end()
requires forward_range<_Vw> && common_range<_Vw>
{
constexpr bool _Both_simple = _Simple_view<_Vw> && _Simple_view<_Pat>;
return _Outer_iter<_Both_simple>{*this, _RANGES end(_Range)};
}
_NODISCARD constexpr auto end() const {
if constexpr (forward_range<_Vw> && forward_range<const _Vw> && common_range<const _Vw>) {
return _Outer_iter<true>{*this, _RANGES end(_Range)};
} else {
return default_sentinel;
}
}
};
template <class _Rng, class _Pat>
lazy_split_view(_Rng&&, _Pat&&) -> lazy_split_view<views::all_t<_Rng>, views::all_t<_Pat>>;
template <input_range _Rng>
lazy_split_view(
_Rng&&, range_value_t<_Rng>) -> lazy_split_view<views::all_t<_Rng>, single_view<range_value_t<_Rng>>>;
#if _HAS_CXX23
template <class _Rng, class _Pat>
constexpr auto _Compile_time_max_size<lazy_split_view<_Rng, _Pat>> = _Compile_time_max_size<_Rng>;
template <class _Rng, class _Pat>
constexpr auto _Compile_time_max_size<const lazy_split_view<_Rng, _Pat>> = _Compile_time_max_size<const _Rng>;
#endif // _HAS_CXX23
namespace views {
struct _Lazy_split_fn {
template <viewable_range _Rng, class _Pat>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Rng&& _Range, _Pat&& _Pattern) _CONST_CALL_OPERATOR
noexcept(noexcept(lazy_split_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern))))
requires requires { lazy_split_view(static_cast<_Rng&&>(_Range), static_cast<_Pat&&>(_Pattern)); }
{
return lazy_split_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern));
}
template <class _Delim>
requires constructible_from<decay_t<_Delim>, _Delim>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Delim&& _Delimiter) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Delim>, _Delim>) {
return _Range_closure<_Lazy_split_fn, decay_t<_Delim>>{_STD forward<_Delim>(_Delimiter)};
}
};
_EXPORT_STD inline constexpr _Lazy_split_fn lazy_split;
} // namespace views
_EXPORT_STD template <forward_range _Vw, forward_range _Pat>
requires view<_Vw> && view<_Pat> && indirectly_comparable<iterator_t<_Vw>, iterator_t<_Pat>, _RANGES equal_to>
class split_view : public view_interface<split_view<_Vw, _Pat>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
/* [[no_unique_address]] */ _Pat _Pattern{};
_Non_propagating_cache<subrange<iterator_t<_Vw>>> _Next{};
class _Iterator {
private:
friend split_view;
split_view* _Parent = nullptr;
iterator_t<_Vw> _Current = {};
subrange<iterator_t<_Vw>> _Next = {};
bool _Trailing_empty = false;
public:
using iterator_concept = forward_iterator_tag;
using iterator_category = input_iterator_tag;
using value_type = subrange<iterator_t<_Vw>>;
using difference_type = range_difference_t<_Vw>;
_Iterator() = default;
constexpr _Iterator(split_view& _Parent_, iterator_t<_Vw> _Current_, subrange<iterator_t<_Vw>> _Next_) //
noexcept(is_nothrow_move_constructible_v<iterator_t<_Vw>>) // strengthened
: _Parent{_STD addressof(_Parent_)}, _Current{_STD move(_Current_)}, _Next{_STD move(_Next_)} {}
_NODISCARD constexpr iterator_t<_Vw> base() const
noexcept(is_nothrow_copy_constructible_v<iterator_t<_Vw>>) /* strengthened */ {
return _Current;
}
_NODISCARD constexpr value_type operator*() const
noexcept(is_nothrow_copy_constructible_v<iterator_t<_Vw>>) /* strengthened */ {
return {_Current, _Next.begin()};
}
constexpr _Iterator& operator++() {
const auto _Last = _RANGES end(_Parent->_Range);
_Current = _Next.begin();
if (_Current == _Last) {
_Trailing_empty = false;
return *this;
}
_Current = _Next.end();
if (_Current == _Last) {
_Trailing_empty = true;
_Next = {_Current, _Current};
return *this;
}
auto [_Begin, _End] = _RANGES search(subrange{_Current, _Last}, _Parent->_Pattern);
if (_Begin != _Last && _RANGES empty(_Parent->_Pattern)) {
++_Begin;
++_End;
}
_Next = {_STD move(_Begin), _STD move(_End)};
return *this;
}
constexpr _Iterator operator++(int) {
auto _Tmp = *this;
++*this;
return _Tmp;
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current == _Right._Current)) /* strengthened */ {
return _Left._Current == _Right._Current && _Left._Trailing_empty == _Right._Trailing_empty;
}
};
class _Sentinel {
private:
/* [[no_unique_address]] */ sentinel_t<_Vw> _Last{};
_NODISCARD constexpr bool _Equal(const _Iterator& _It) const
noexcept(noexcept(_STD _Fake_copy_init<bool>(_It._Current == _Last))) {
return !_It._Trailing_empty && _It._Current == _Last;
}
public:
_Sentinel() = default;
constexpr explicit _Sentinel(split_view& _Parent)
noexcept(noexcept(_RANGES end(_Parent._Range))
&& is_nothrow_move_constructible_v<sentinel_t<_Vw>>) // strengthened
: _Last(_RANGES end(_Parent._Range)) {}
_NODISCARD friend constexpr bool operator==(const _Iterator& _It, const _Sentinel& _Se)
noexcept(noexcept(_Se._Equal(_It))) /* strengthened */ {
return _Se._Equal(_It);
}
};
constexpr subrange<iterator_t<_Vw>> _Find_next(iterator_t<_Vw> _It) {
const auto _Last = _RANGES end(_Range);
auto [_Begin, _End] = _RANGES search(subrange{_It, _Last}, _Pattern);
if (_Begin != _Last && _RANGES empty(_Pattern)) {
++_Begin;
++_End;
}
return {_STD move(_Begin), _STD move(_End)};
}
public:
split_view()
requires default_initializable<_Vw> && default_initializable<_Pat>
= default;
constexpr explicit split_view(_Vw _Range_, _Pat _Pattern_)
noexcept(is_nothrow_move_constructible_v<_Vw> && is_nothrow_move_constructible_v<_Pat>) // strengthened
: _Range(_STD move(_Range_)), _Pattern(_STD move(_Pattern_)) {}
template <forward_range _Rng>
requires constructible_from<_Vw, views::all_t<_Rng>>
&& constructible_from<_Pat, single_view<range_value_t<_Rng>>>
constexpr explicit split_view(_Rng&& _Range_, range_value_t<_Rng> _Elem)
noexcept(is_nothrow_constructible_v<_Vw, views::all_t<_Rng>>
&& is_nothrow_constructible_v<_Pat, single_view<range_value_t<_Rng>>>
&& is_nothrow_move_constructible_v<range_value_t<_Rng>>) // strengthened
: _Range(views::all(_STD forward<_Rng>(_Range_))), _Pattern(views::single(_STD move(_Elem))) {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin() {
auto _First = _RANGES begin(_Range);
if (!_Next) {
_Next._Emplace(_Find_next(_First));
}
return _Iterator{*this, _First, *_Next};
}
_NODISCARD constexpr auto end() {
if constexpr (common_range<_Vw>) {
return _Iterator{*this, _RANGES end(_Range), {}};
} else {
return _Sentinel{*this};
}
}
};
template <class _Rng, class _Pat>
split_view(_Rng&&, _Pat&&) -> split_view<views::all_t<_Rng>, views::all_t<_Pat>>;
template <forward_range _Rng>
split_view(_Rng&&, range_value_t<_Rng>) -> split_view<views::all_t<_Rng>, single_view<range_value_t<_Rng>>>;
#if _HAS_CXX23
template <class _Rng, class _Pat>
constexpr auto _Compile_time_max_size<split_view<_Rng, _Pat>> = _Compile_time_max_size<_Rng>;
#endif // _HAS_CXX23
namespace views {
struct _Split_fn {
template <viewable_range _Rng, class _Pat>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Rng&& _Range, _Pat&& _Pattern) _CONST_CALL_OPERATOR
noexcept(noexcept(split_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern))))
requires requires { split_view(static_cast<_Rng&&>(_Range), static_cast<_Pat&&>(_Pattern)); }
{
return split_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern));
}
template <class _Delim>
requires constructible_from<decay_t<_Delim>, _Delim>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Delim&& _Delimiter) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Delim>, _Delim>) {
return _Range_closure<_Split_fn, decay_t<_Delim>>{_STD forward<_Delim>(_Delimiter)};
}
};
_EXPORT_STD inline constexpr _Split_fn split;
class _Counted_fn {
private:
enum class _St { _None, _Span, _Subrange, _Subrange_counted };
template <class _It>
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
using _Decayed = decay_t<_It>;
_STL_INTERNAL_STATIC_ASSERT(input_or_output_iterator<_Decayed>);
if constexpr (contiguous_iterator<_Decayed>) {
return {_St::_Span,
noexcept(span(_STD to_address(_STD declval<_It>()), iter_difference_t<_Decayed>{}))};
} else if constexpr (random_access_iterator<_Decayed>) {
return {_St::_Subrange,
noexcept(subrange(_STD declval<_It>(), _STD declval<_It>() + iter_difference_t<_Decayed>{}))};
} else if constexpr (constructible_from<_Decayed, _It>) {
return {_St::_Subrange_counted,
noexcept(subrange(
counted_iterator(_STD declval<_It>(), iter_difference_t<_Decayed>{}), default_sentinel))};
} else {
return {_St::_None};
}
}
template <class _It>
static constexpr _Choice_t<_St> _Choice = _Choose<_It>();
public:
template <class _It>
requires (input_or_output_iterator<decay_t<_It>> && _Choice<_It>._Strategy != _St::_None)
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_It&& _First,
const iter_difference_t<decay_t<_It>> _Count) _CONST_CALL_OPERATOR noexcept(_Choice<_It>._No_throw) {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Count >= 0, "The size passed to views::counted must be non-negative");
#endif // _CONTAINER_DEBUG_LEVEL > 0
constexpr _St _Strat = _Choice<_It>._Strategy;
if constexpr (_Strat == _St::_Span) {
return span(_STD to_address(_STD forward<_It>(_First)), static_cast<size_t>(_Count));
} else if constexpr (_Strat == _St::_Subrange) {
return subrange(_First, _First + _Count);
} else if constexpr (_Strat == _St::_Subrange_counted) {
return subrange(counted_iterator(_STD forward<_It>(_First), _Count), default_sentinel);
}
}
};
_EXPORT_STD inline constexpr _Counted_fn counted;
} // namespace views
_EXPORT_STD template <view _Vw>
requires (!common_range<_Vw> && copyable<iterator_t<_Vw>>)
class common_view : public view_interface<common_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Base{};
public:
common_view()
requires default_initializable<_Vw>
= default;
constexpr explicit common_view(_Vw _Base_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Base(_STD move(_Base_)) {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Base;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Base);
}
_NODISCARD constexpr auto begin() noexcept(
noexcept(_RANGES begin(_Base)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */
requires (!_Simple_view<_Vw>)
{
if constexpr (random_access_range<_Vw> && sized_range<_Vw>) {
return _RANGES begin(_Base);
} else {
return common_iterator<iterator_t<_Vw>, sentinel_t<_Vw>>{_RANGES begin(_Base)};
}
}
_NODISCARD constexpr auto begin() const noexcept(
noexcept(_RANGES begin(_Base)) && is_nothrow_move_constructible_v<iterator_t<const _Vw>>) /* strengthened */
requires range<const _Vw>
{
if constexpr (random_access_range<const _Vw> && sized_range<const _Vw>) {
return _RANGES begin(_Base);
} else {
return common_iterator<iterator_t<const _Vw>, sentinel_t<const _Vw>>{_RANGES begin(_Base)};
}
}
_NODISCARD constexpr auto end()
requires (!_Simple_view<_Vw>)
{
if constexpr (random_access_range<_Vw> && sized_range<_Vw>) {
return _RANGES begin(_Base) + _RANGES distance(_Base);
} else {
return common_iterator<iterator_t<_Vw>, sentinel_t<_Vw>>{_RANGES end(_Base)};
}
}
_NODISCARD constexpr auto end() const
requires range<const _Vw>
{
if constexpr (random_access_range<const _Vw> && sized_range<const _Vw>) {
return _RANGES begin(_Base) + _RANGES distance(_Base);
} else {
return common_iterator<iterator_t<const _Vw>, sentinel_t<const _Vw>>{_RANGES end(_Base)};
}
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Base))) /* strengthened */
requires sized_range<_Vw>
{
return _RANGES size(_Base);
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Base))) /* strengthened */
requires sized_range<const _Vw>
{
return _RANGES size(_Base);
}
};
template <class _Rng>
common_view(_Rng&&) -> common_view<views::all_t<_Rng>>;
template <class _Rng>
constexpr bool enable_borrowed_range<common_view<_Rng>> = enable_borrowed_range<_Rng>;
#if _HAS_CXX23
template <class _Rng>
constexpr auto _Compile_time_max_size<common_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const common_view<_Rng>> = _Compile_time_max_size<const _Rng>;
#endif // _HAS_CXX23
namespace views {
class _Common_fn : public _Pipe::_Base<_Common_fn> {
private:
enum class _St { _None, _All, _Common };
template <class _Rng>
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
if constexpr (common_range<_Rng>) {
return {_St::_All, noexcept(views::all(_STD declval<_Rng>()))};
} else if constexpr (copyable<iterator_t<_Rng>>) {
return {_St::_Common, noexcept(common_view{_STD declval<_Rng>()})};
} else {
return {_St::_None};
}
}
template <class _Rng>
static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>();
public:
template <viewable_range _Rng>
requires (_Choice<_Rng>._Strategy != _St::_None)
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range) _CONST_CALL_OPERATOR
noexcept(_Choice<_Rng>._No_throw) {
constexpr _St _Strat = _Choice<_Rng>._Strategy;
if constexpr (_Strat == _St::_All) {
return views::all(_STD forward<_Rng>(_Range));
} else if constexpr (_Strat == _St::_Common) {
return common_view{_STD forward<_Rng>(_Range)};
} else {
_STL_INTERNAL_STATIC_ASSERT(false); // unexpected strategy
}
}
};
_EXPORT_STD inline constexpr _Common_fn common;
} // namespace views
_EXPORT_STD template <view _Vw>
requires bidirectional_range<_Vw>
class reverse_view : public _Cached_position_t<!common_range<_Vw>, _Vw, reverse_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
template <class _Rng>
using _Rev_iter = reverse_iterator<iterator_t<_Rng>>;
public:
reverse_view()
requires default_initializable<_Vw>
= default;
constexpr explicit reverse_view(_Vw _Range_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Range(_STD move(_Range_)) {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr _Rev_iter<_Vw> begin() {
if constexpr (common_range<_Vw>) {
return _Rev_iter<_Vw>{_RANGES end(_Range)};
} else {
if (this->_Has_cache()) {
return _Rev_iter<_Vw>{this->_Get_cache(_Range)};
}
iterator_t<_Vw> _First;
if constexpr (sized_range<_Vw>) {
_First = _RANGES next(_RANGES begin(_Range), _RANGES distance(_Range));
} else {
_First = _RANGES next(_RANGES begin(_Range), _RANGES end(_Range));
}
this->_Set_cache(_Range, _First);
return _Rev_iter<_Vw>{_STD move(_First)};
}
}
_NODISCARD constexpr auto begin() const
noexcept(noexcept(_Rev_iter<const _Vw>{_RANGES end(_Range)})) /* strengthened */
requires common_range<const _Vw>
{
return _Rev_iter<const _Vw>{_RANGES end(_Range)};
}
_NODISCARD constexpr _Rev_iter<_Vw> end()
noexcept(noexcept(_Rev_iter<_Vw>{_RANGES begin(_Range)})) /* strengthened */ {
return _Rev_iter<_Vw>{_RANGES begin(_Range)};
}
_NODISCARD constexpr auto end() const
noexcept(noexcept(_Rev_iter<const _Vw>{_RANGES begin(_Range)})) /* strengthened */
requires common_range<const _Vw>
{
return _Rev_iter<const _Vw>{_RANGES begin(_Range)};
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Range))) /* strengthened */
requires sized_range<_Vw>
{
return _RANGES size(_Range);
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Range))) /* strengthened */
requires sized_range<const _Vw>
{
return _RANGES size(_Range);
}
};
template <class _Rng>
reverse_view(_Rng&&) -> reverse_view<views::all_t<_Rng>>;
template <class _Rng>
constexpr bool enable_borrowed_range<reverse_view<_Rng>> = enable_borrowed_range<_Rng>;
#if _HAS_CXX23
template <class _Rng>
constexpr auto _Compile_time_max_size<reverse_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const reverse_view<_Rng>> = _Compile_time_max_size<const _Rng>;
#endif // _HAS_CXX23
namespace views {
template <class _Rng>
concept _Can_extract_base = requires(_Rng&& __r) { static_cast<_Rng&&>(__r).base(); };
template <class _Rng>
concept _Can_reverse = requires(_Rng&& __r) { reverse_view{static_cast<_Rng&&>(__r)}; };
class _Reverse_fn : public _Pipe::_Base<_Reverse_fn> {
private:
enum class _St { _None, _Base, _Subrange_unsized, _Subrange_sized, _Reverse };
template <class>
static constexpr auto _Reversed_subrange = -1;
template <class _It, subrange_kind _Ki>
static constexpr auto _Reversed_subrange<subrange<reverse_iterator<_It>, reverse_iterator<_It>, _Ki>> =
static_cast<int>(_Ki);
template <class _Rng>
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
using _Ty = remove_cvref_t<_Rng>;
if constexpr (_Is_specialization_v<_Ty, reverse_view>) {
if constexpr (_Can_extract_base<_Rng>) {
return {_St::_Base, noexcept(_STD declval<_Rng>().base())};
}
} else if constexpr (_Reversed_subrange<_Ty> == 0) {
using _It = decltype(_STD declval<_Rng&>().begin().base());
return {_St::_Subrange_unsized,
noexcept(subrange<_It, _It, subrange_kind::unsized>{
_STD declval<_Rng&>().end().base(), _STD declval<_Rng&>().begin().base()})};
} else if constexpr (_Reversed_subrange<_Ty> == 1) {
using _It = decltype(_STD declval<_Rng&>().begin().base());
return {_St::_Subrange_sized,
noexcept(subrange<_It, _It, subrange_kind::sized>{_STD declval<_Rng&>().end().base(),
_STD declval<_Rng&>().begin().base(), _STD declval<_Rng&>().size()})};
} else if constexpr (_Can_reverse<_Rng>) {
return {_St::_Reverse, noexcept(reverse_view{_STD declval<_Rng>()})};
}
return {_St::_None};
}
template <class _Rng>
static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>();
public:
template <viewable_range _Rng>
requires (_Choice<_Rng>._Strategy != _St::_None)
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range) _CONST_CALL_OPERATOR
noexcept(_Choice<_Rng>._No_throw) {
constexpr _St _Strat = _Choice<_Rng>._Strategy;
if constexpr (_Strat == _St::_Base) {
return _STD forward<_Rng>(_Range).base();
} else if constexpr (_Strat == _St::_Subrange_unsized) {
return subrange{_Range.end().base(), _Range.begin().base()};
} else if constexpr (_Strat == _St::_Subrange_sized) {
return subrange{_Range.end().base(), _Range.begin().base(), _Range.size()};
} else if constexpr (_Strat == _St::_Reverse) {
return reverse_view{_STD forward<_Rng>(_Range)};
} else {
_STL_INTERNAL_STATIC_ASSERT(false); // unexpected strategy
}
}
};
_EXPORT_STD inline constexpr _Reverse_fn reverse;
} // namespace views
#if _HAS_CXX23
_EXPORT_STD template <view _Vw>
requires input_range<_Vw>
class as_const_view : public view_interface<as_const_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
public:
as_const_view()
requires default_initializable<_Vw>
= default;
constexpr explicit as_const_view(_Vw _Range_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Range(_STD move(_Range_)) {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) // strengthened
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin() noexcept(noexcept(_RANGES cbegin(_Range))) // strengthened
requires (!_Simple_view<_Vw>)
{
return _RANGES cbegin(_Range);
}
_NODISCARD constexpr auto begin() const noexcept(noexcept(_RANGES cbegin(_Range))) // strengthened
requires range<const _Vw>
{
return _RANGES cbegin(_Range);
}
_NODISCARD constexpr auto end() noexcept(noexcept(_RANGES cend(_Range))) // strengthened
requires (!_Simple_view<_Vw>)
{
return _RANGES cend(_Range);
}
_NODISCARD constexpr auto end() const noexcept(noexcept(_RANGES cend(_Range))) // strengthened
requires range<const _Vw>
{
return _RANGES cend(_Range);
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Range))) // strengthened
requires sized_range<_Vw>
{
return _RANGES size(_Range);
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Range))) // strengthened
requires sized_range<const _Vw>
{
return _RANGES size(_Range);
}
};
template <class _Rng>
as_const_view(_Rng&&) -> as_const_view<views::all_t<_Rng>>;
template <class _Rng>
constexpr bool enable_borrowed_range<as_const_view<_Rng>> = enable_borrowed_range<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<as_const_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const as_const_view<_Rng>> = _Compile_time_max_size<const _Rng>;
namespace views {
template <class _Rng>
concept _Can_as_const = requires(_Rng&& __r) { as_const_view{static_cast<_Rng&&>(__r)}; };
class _As_const_fn : public _Pipe::_Base<_As_const_fn> {
private:
enum class _St { _None, _All, _Empty, _Reconstruct_span, _Reconstruct_ref, _Ref, _As_const };
template <class>
static constexpr bool _Can_reconstruct_ref_view_v = false;
template <class _Ty>
requires constant_range<const _Ty>
static constexpr bool _Can_reconstruct_ref_view_v<ref_view<_Ty>> = true;
template <class _Rng>
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
using _Ty = remove_cvref_t<_Rng>;
if constexpr (constant_range<views::all_t<_Rng>>) {
return {_St::_All, noexcept(views::all(_STD declval<_Rng>()))};
} else if constexpr (_Is_specialization_v<_Ty, empty_view>) {
return {_St::_Empty, true};
} else if constexpr (_Is_span_v<_Ty>) {
return {_St::_Reconstruct_span, true};
} else if constexpr (_Can_reconstruct_ref_view_v<_Ty>) {
return {_St::_Reconstruct_ref, noexcept(ref_view{_STD as_const(_STD declval<_Rng>().base())})};
} else if constexpr (is_lvalue_reference_v<_Rng> && constant_range<const _Ty> && !view<_Ty>) {
return {_St::_Ref, noexcept(ref_view{_STD as_const(_STD declval<_Rng>())})};
} else if constexpr (_Can_as_const<_Rng>) {
return {_St::_As_const, noexcept(as_const_view{_STD declval<_Rng>()})};
} else {
return {_St::_None};
}
}
template <class _Rng>
static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>();
public:
template <viewable_range _Rng>
requires (_Choice<_Rng>._Strategy != _St::_None)
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range) _CONST_CALL_OPERATOR
noexcept(_Choice<_Rng>._No_throw) {
using _Ty = remove_cvref_t<_Rng>;
constexpr _St _Strat = _Choice<_Rng>._Strategy;
if constexpr (_Strat == _St::_All) {
return views::all(_STD forward<_Rng>(_Range));
} else if constexpr (_Strat == _St::_Empty) {
return empty_view<const remove_reference_t<range_reference_t<_Rng>>>{};
} else if constexpr (_Strat == _St::_Reconstruct_span) {
return span<const typename _Ty::element_type, _Ty::extent>{_STD forward<_Rng>(_Range)};
} else if constexpr (_Strat == _St::_Reconstruct_ref) {
return ref_view{_STD as_const(_STD forward<_Rng>(_Range).base())};
} else if constexpr (_Strat == _St::_Ref) {
return ref_view{_STD as_const(_STD forward<_Rng>(_Range))};
} else if constexpr (_Strat == _St::_As_const) {
return as_const_view{_STD forward<_Rng>(_Range)};
} else {
_STL_INTERNAL_STATIC_ASSERT(false); // unexpected strategy
}
}
};
_EXPORT_STD inline constexpr _As_const_fn as_const;
} // namespace views
#endif // _HAS_CXX23
template <class _Tuple, size_t _Index>
concept _Has_tuple_element =
#if _HAS_CXX23
_Tuple_like<_Tuple> && _Index < tuple_size_v<_Tuple>;
#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv
requires(_Tuple __t) {
typename tuple_size<_Tuple>::type;
requires _Index < tuple_size_v<_Tuple>;
typename tuple_element_t<_Index, _Tuple>;
{ _STD get<_Index>(__t) } -> convertible_to<const tuple_element_t<_Index, _Tuple>&>;
};
#endif // ^^^ !_HAS_CXX23 ^^^
template <class _Tuple, size_t _Index>
concept _Returnable_element = is_reference_v<_Tuple> || move_constructible<tuple_element_t<_Index, _Tuple>>;
_EXPORT_STD template <input_range _Vw, size_t _Index>
requires view<_Vw> && _Has_tuple_element<range_value_t<_Vw>, _Index>
&& _Has_tuple_element<remove_reference_t<range_reference_t<_Vw>>, _Index>
&& _Returnable_element<range_reference_t<_Vw>, _Index>
class elements_view : public view_interface<elements_view<_Vw, _Index>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
template <class _Base>
struct _Category_base {};
template <forward_range _Base>
struct _Category_base<_Base> {
using iterator_category =
conditional_t<!is_lvalue_reference_v<decltype(_STD get<_Index>(*_STD declval<iterator_t<_Base>>()))>,
input_iterator_tag,
conditional_t<derived_from<_Iter_cat_t<iterator_t<_Base>>, random_access_iterator_tag>,
random_access_iterator_tag, _Iter_cat_t<iterator_t<_Base>>>>;
};
template <bool _Const>
class _Iterator : public _Category_base<_Maybe_const<_Const, _Vw>> {
private:
friend elements_view;
using _Base = _Maybe_const<_Const, _Vw>;
iterator_t<_Base> _Current{};
public:
using iterator_concept = conditional_t<random_access_range<_Base>, random_access_iterator_tag,
conditional_t<bidirectional_range<_Base>, bidirectional_iterator_tag,
conditional_t<forward_range<_Base>, forward_iterator_tag, input_iterator_tag>>>;
using value_type = remove_cvref_t<tuple_element_t<_Index, range_value_t<_Base>>>;
using difference_type = range_difference_t<_Base>;
_Iterator()
requires default_initializable<iterator_t<_Base>>
= default;
constexpr explicit _Iterator(iterator_t<_Base> _Current_)
noexcept(is_nothrow_move_constructible_v<iterator_t<_Base>>) // strengthened
: _Current{_STD move(_Current_)} {}
constexpr _Iterator(_Iterator<!_Const> _It)
noexcept(is_nothrow_constructible_v<iterator_t<_Base>, iterator_t<_Vw>>) // strengthened
requires _Const && convertible_to<iterator_t<_Vw>, iterator_t<_Base>>
: _Current(_STD move(_It._Current)) {}
_NODISCARD constexpr const iterator_t<_Base>& base() const& noexcept {
return _Current;
}
_NODISCARD constexpr iterator_t<_Base> base() && noexcept(
is_nothrow_move_constructible_v<iterator_t<_Base>>) /* strengthened */ {
return _STD move(_Current);
}
_NODISCARD constexpr decltype(auto) operator*() const
noexcept(noexcept(_STD get<_Index>(*_Current))) /* strengthened */
requires is_reference_v<range_reference_t<_Base>>
{
return _STD get<_Index>(*_Current);
}
_NODISCARD constexpr decltype(auto) operator*() const
noexcept(is_nothrow_move_constructible_v<tuple_element_t<_Index, range_reference_t<_Base>>> //
&& noexcept(_STD get<_Index>(*_Current))) /* strengthened */ {
using _ElemTy = remove_cv_t<tuple_element_t<_Index, range_reference_t<_Base>>>;
return static_cast<_ElemTy>(_STD get<_Index>(*_Current));
}
constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ {
++_Current;
return *this;
}
constexpr void operator++(int) noexcept(noexcept(++_Current)) /* strengthened */ {
++_Current;
}
constexpr _Iterator operator++(int)
noexcept(noexcept(++_Current) && is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
requires forward_range<_Base>
{
auto _Tmp = *this;
++_Current;
return _Tmp;
}
constexpr _Iterator& operator--() noexcept(noexcept(--_Current)) /* strengthened */
requires bidirectional_range<_Base>
{
--_Current;
return *this;
}
constexpr _Iterator operator--(int)
noexcept(noexcept(--_Current) && is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
requires bidirectional_range<_Base>
{
auto _Tmp = *this;
--_Current;
return _Tmp;
}
#if _ITERATOR_DEBUG_LEVEL != 0
constexpr void _Verify_offset(const difference_type _Off) const
requires random_access_range<_Base>
{
if constexpr (_Offset_verifiable_v<iterator_t<_Base>>) {
_Current._Verify_offset(_Off);
}
}
#endif // _ITERATOR_DEBUG_LEVEL != 0
constexpr _Iterator& operator+=(const difference_type _Off)
noexcept(noexcept(_Current += _Off)) /* strengthened */
requires random_access_range<_Base>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_Verify_offset(_Off);
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Current += _Off;
return *this;
}
constexpr _Iterator& operator-=(const difference_type _Off)
noexcept(noexcept(_Current -= _Off)) /* strengthened */
requires random_access_range<_Base>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Off != _Min_possible_v<difference_type>, "integer overflow");
_Verify_offset(-_Off);
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Current -= _Off;
return *this;
}
_NODISCARD constexpr decltype(auto) operator[](const difference_type _Idx) const
noexcept(noexcept(_STD get<_Index>(*(_Current + _Idx)))) /* strengthened */
requires random_access_range<_Base> && is_reference_v<range_reference_t<_Base>>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_Verify_offset(_Idx);
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _STD get<_Index>(*(_Current + _Idx));
}
_NODISCARD constexpr decltype(auto) operator[](const difference_type _Idx) const
noexcept(is_nothrow_move_constructible_v<tuple_element_t<_Index, range_reference_t<_Base>>> //
&& noexcept(_STD get<_Index>(*(_Current + _Idx)))) /* strengthened */
requires random_access_range<_Base>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_Verify_offset(_Idx);
#endif // _ITERATOR_DEBUG_LEVEL != 0
using _ElemTy = remove_cv_t<tuple_element_t<_Index, range_reference_t<_Base>>>;
return static_cast<_ElemTy>(_STD get<_Index>(*(_Current + _Idx)));
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current == _Right._Current)) /* strengthened */
requires equality_comparable<iterator_t<_Base>>
{
return _Left._Current == _Right._Current;
}
_NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current < _Right._Current)) /* strengthened */
requires random_access_range<_Base>
{
return _Left._Current < _Right._Current;
}
_NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current < _Right._Current)) /* strengthened */
requires random_access_range<_Base>
{
return _Right < _Left;
}
_NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current < _Right._Current)) /* strengthened */
requires random_access_range<_Base>
{
return !(_Right < _Left);
}
_NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current < _Right._Current)) /* strengthened */
requires random_access_range<_Base>
{
return !(_Left < _Right);
}
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current <=> _Right._Current)) /* strengthened */
requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>>
{
return _Left._Current <=> _Right._Current;
}
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off)
noexcept(noexcept(_STD declval<iterator_t<_Base>&>() += _Off)
&& is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
requires random_access_range<_Base>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_It._Verify_offset(_Off);
#endif // _ITERATOR_DEBUG_LEVEL != 0
auto _Copy = _It;
_Copy._Current += _Off;
return _Copy;
}
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It)
noexcept(noexcept(_STD declval<iterator_t<_Base>&>() += _Off)
&& is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
requires random_access_range<_Base>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_It._Verify_offset(_Off);
#endif // _ITERATOR_DEBUG_LEVEL != 0
auto _Copy = _It;
_Copy._Current += _Off;
return _Copy;
}
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off)
noexcept(noexcept(_STD declval<iterator_t<_Base>&>() -= _Off)
&& is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
requires random_access_range<_Base>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Off != _Min_possible_v<difference_type>, "integer overflow");
_It._Verify_offset(-_Off);
#endif // _ITERATOR_DEBUG_LEVEL != 0
auto _Copy = _It;
_Copy._Current -= _Off;
return _Copy;
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */
requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>>
{
return _Left._Current - _Right._Current;
}
};
template <bool _Const>
class _Sentinel {
private:
friend elements_view;
using _Base = _Maybe_const<_Const, _Vw>;
template <bool _OtherConst>
using _Maybe_const_iter = iterator_t<_Maybe_const<_OtherConst, _Vw>>;
sentinel_t<_Base> _Last{};
template <bool _OtherConst>
_NODISCARD static constexpr const _Maybe_const_iter<_OtherConst>& _Get_current(
const _Iterator<_OtherConst>& _It) noexcept {
return _It._Current;
}
public:
_Sentinel() = default;
constexpr explicit _Sentinel(sentinel_t<_Base> _Last_)
noexcept(is_nothrow_move_constructible_v<sentinel_t<_Base>>) // strengthened
: _Last(_STD move(_Last_)) {}
constexpr _Sentinel(_Sentinel<!_Const> _Se)
noexcept(is_nothrow_constructible_v<sentinel_t<_Base>, sentinel_t<_Vw>>) // strengthened
requires _Const && convertible_to<sentinel_t<_Vw>, sentinel_t<_Base>>
: _Last(_STD move(_Se._Last)) {}
_NODISCARD constexpr sentinel_t<_Base> base() const
noexcept(is_nothrow_copy_constructible_v<sentinel_t<_Base>>) /* strengthened */ {
return _Last;
}
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right)
noexcept(noexcept(_Get_current(_Left) == _Right._Last)) /* strengthened */ {
return _Get_current(_Left) == _Right._Last;
}
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(
const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right)
noexcept(noexcept(_Get_current(_Left) - _Right._Last)) /* strengthened */ {
return _Get_current(_Left) - _Right._Last;
}
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(
const _Sentinel& _Left, const _Iterator<_OtherConst>& _Right)
noexcept(noexcept(_Left._Last - _Get_current(_Right))) /* strengthened */ {
return _Left._Last - _Get_current(_Right);
}
};
public:
elements_view()
requires default_initializable<_Vw>
= default;
constexpr explicit elements_view(_Vw _Range_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Range(_STD move(_Range_)) {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr _Iterator<false> begin() noexcept(
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */
requires (!_Simple_view<_Vw>)
{
return _Iterator<false>{_RANGES begin(_Range)};
}
_NODISCARD constexpr _Iterator<true> begin() const
noexcept(noexcept(_RANGES begin(_Range))
&& is_nothrow_move_constructible_v<iterator_t<const _Vw>>) /* strengthened */
requires range<const _Vw>
{
return _Iterator<true>{_RANGES begin(_Range)};
}
_NODISCARD constexpr auto end() noexcept(
noexcept(_RANGES end(_Range)) && is_nothrow_move_constructible_v<sentinel_t<_Vw>>) /* strengthened */
requires (!_Simple_view<_Vw>)
{
if constexpr (common_range<_Vw>) {
return _Iterator<false>{_RANGES end(_Range)};
} else {
return _Sentinel<false>{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto end() const noexcept(
noexcept(_RANGES end(_Range)) && is_nothrow_move_constructible_v<sentinel_t<const _Vw>>) /* strengthened */
requires range<const _Vw>
{
if constexpr (common_range<const _Vw>) {
return _Iterator<true>{_RANGES end(_Range)};
} else {
return _Sentinel<true>{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Range))) /* strengthened */
requires sized_range<_Vw>
{
return _RANGES size(_Range);
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Range))) /* strengthened */
requires sized_range<const _Vw>
{
return _RANGES size(_Range);
}
};
template <class _Rng, size_t _Index>
constexpr bool enable_borrowed_range<elements_view<_Rng, _Index>> = enable_borrowed_range<_Rng>;
#if _HAS_CXX23
template <class _Rng, size_t _Index>
constexpr auto _Compile_time_max_size<elements_view<_Rng, _Index>> = _Compile_time_max_size<_Rng>;
template <class _Rng, size_t _Index>
constexpr auto _Compile_time_max_size<const elements_view<_Rng, _Index>> = _Compile_time_max_size<const _Rng>;
#endif // _HAS_CXX23
_EXPORT_STD template <class _Rng>
using keys_view = elements_view<_Rng, 0>;
_EXPORT_STD template <class _Rng>
using values_view = elements_view<_Rng, 1>;
namespace views {
template <size_t _Index>
class _Elements_fn : public _Pipe::_Base<_Elements_fn<_Index>> {
public:
template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range) _CONST_CALL_OPERATOR
noexcept(noexcept(elements_view<views::all_t<_Rng>, _Index>{_STD forward<_Rng>(_Range)}))
requires requires { elements_view<views::all_t<_Rng>, _Index>{static_cast<_Rng&&>(_Range)}; }
{
return elements_view<views::all_t<_Rng>, _Index>{_STD forward<_Rng>(_Range)};
}
};
_EXPORT_STD template <size_t _Index>
constexpr _Elements_fn<_Index> elements;
_EXPORT_STD inline constexpr auto keys = elements<0>;
_EXPORT_STD inline constexpr auto values = elements<1>;
} // namespace views
#if _HAS_CXX23
template <class _Rng>
concept _Range_with_movable_references = input_range<_Rng> && move_constructible<range_reference_t<_Rng>>
&& move_constructible<range_rvalue_reference_t<_Rng>>;
_EXPORT_STD template <view _Vw>
requires _Range_with_movable_references<_Vw>
class enumerate_view : public view_interface<enumerate_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
template <bool _Const>
class _Iterator {
private:
friend enumerate_view;
using _Base_t = _Maybe_const<_Const, _Vw>;
using _Base_iterator = iterator_t<_Base_t>;
using _Reference_type = tuple<range_difference_t<_Base_t>, range_reference_t<_Base_t>>;
/* [[no_unique_address]] */ _Base_iterator _Current{};
range_difference_t<_Base_t> _Pos = 0;
constexpr explicit _Iterator(_Base_iterator _Current_, range_difference_t<_Base_t> _Pos_)
noexcept(is_nothrow_move_constructible_v<_Base_iterator>) // strengthened
: _Current(_STD move(_Current_)), _Pos(_Pos_) {}
public:
using iterator_category = input_iterator_tag;
using iterator_concept = conditional_t<random_access_range<_Base_t>, random_access_iterator_tag,
conditional_t<bidirectional_range<_Base_t>, bidirectional_iterator_tag,
conditional_t<forward_range<_Base_t>, forward_iterator_tag, input_iterator_tag>>>;
using difference_type = range_difference_t<_Base_t>;
using value_type = tuple<difference_type, range_value_t<_Base_t>>;
_Iterator()
requires default_initializable<_Base_iterator>
= default;
constexpr _Iterator(_Iterator<!_Const> _Other)
noexcept(is_nothrow_constructible_v<_Base_iterator, iterator_t<_Vw>>) // strengthened
requires _Const && convertible_to<iterator_t<_Vw>, _Base_iterator>
: _Current(_STD move(_Other._Current)), _Pos(_Other._Pos) {}
_NODISCARD constexpr const _Base_iterator& base() const& noexcept {
return _Current;
}
_NODISCARD constexpr _Base_iterator base() && noexcept(
is_nothrow_move_constructible_v<_Base_iterator>) /* strengthened */ {
return _STD move(_Current);
}
_NODISCARD constexpr difference_type index() const noexcept {
return _Pos;
}
_NODISCARD constexpr auto operator*() const noexcept(
noexcept(*_Current) && is_nothrow_copy_constructible_v<range_reference_t<_Base_t>>) /* strengthened */ {
return _Reference_type{_Pos, *_Current};
}
constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ {
++_Current;
++_Pos;
return *this;
}
constexpr void operator++(int) noexcept(noexcept(++_Current)) /* strengthened */ {
++*this;
}
constexpr _Iterator operator++(int)
noexcept(noexcept(++*this) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires forward_range<_Base_t>
{
auto _Tmp = *this;
++*this;
return _Tmp;
}
constexpr _Iterator& operator--() noexcept(noexcept(--_Current)) // strengthened
requires bidirectional_range<_Base_t>
{
--_Current;
--_Pos;
return *this;
}
constexpr _Iterator operator--(int)
noexcept(noexcept(--*this) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires bidirectional_range<_Base_t>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
constexpr _Iterator& operator+=(const difference_type _Off)
noexcept(noexcept(_Current += _Off)) // strengthened
requires random_access_range<_Base_t>
{
_Current += _Off;
_Pos += _Off;
return *this;
}
constexpr _Iterator& operator-=(const difference_type _Off)
noexcept(noexcept(_Current -= _Off)) // strengthened
requires random_access_range<_Base_t>
{
_Current -= _Off;
_Pos -= _Off;
return *this;
}
_NODISCARD constexpr auto operator[](const difference_type _Off) const noexcept(
noexcept(_Current[_Off]) && is_nothrow_copy_constructible_v<range_reference_t<_Base_t>>) // strengthened
requires random_access_range<_Base_t>
{
return _Reference_type{static_cast<difference_type>(_Pos + _Off), _Current[_Off]};
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept {
return _Left._Pos == _Right._Pos;
}
_NODISCARD friend constexpr strong_ordering operator<=>(
const _Iterator& _Left, const _Iterator& _Right) noexcept {
return _Left._Pos <=> _Right._Pos;
}
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off)
noexcept(is_nothrow_copy_constructible_v<_Iterator>
&& noexcept(_STD declval<_Iterator&>() += _Off)) // strengthened
requires random_access_range<_Base_t>
{
auto _Tmp = _It;
_Tmp += _Off;
return _Tmp;
}
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It)
noexcept(noexcept(_It + _Off)) // strengthened
requires random_access_range<_Base_t>
{
return _It + _Off;
}
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off)
noexcept(is_nothrow_copy_constructible_v<_Iterator>
&& noexcept(_STD declval<_Iterator&>() -= _Off)) // strengthened
requires random_access_range<_Base_t>
{
auto _Tmp = _It;
_Tmp -= _Off;
return _Tmp;
}
_NODISCARD friend constexpr difference_type operator-(
const _Iterator& _Left, const _Iterator& _Right) noexcept {
return _Left._Pos - _Right._Pos;
}
_NODISCARD friend constexpr auto iter_move(const _Iterator& _It)
noexcept(noexcept(_RANGES iter_move(_It._Current))
&& is_nothrow_move_constructible_v<range_rvalue_reference_t<_Base_t>>) {
return tuple<difference_type, range_rvalue_reference_t<_Base_t>>{
_It._Pos, _RANGES iter_move(_It._Current)};
}
};
template <bool _Const>
class _Sentinel {
private:
friend enumerate_view;
using _Base_t = _Maybe_const<_Const, _Vw>;
using _Base_sentinel = sentinel_t<_Base_t>;
/* [[no_unique_address]] */ _Base_sentinel _End{};
constexpr explicit _Sentinel(_Base_sentinel _End_)
noexcept(is_nothrow_move_constructible_v<_Base_sentinel>) // strengthened
: _End(_STD move(_End_)) {}
template <bool _OtherConst>
requires sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD constexpr bool _Equal(const _Iterator<_OtherConst>& _It) const
noexcept(noexcept(_STD _Fake_copy_init<bool>(_It._Current == _End))) {
return _It._Current == _End;
}
template <bool _OtherConst>
requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> _Distance_from(
const _Iterator<_OtherConst>& _It) const noexcept(noexcept(_End - _It._Current)) {
return _End - _It._Current;
}
public:
_Sentinel() = default;
constexpr _Sentinel(_Sentinel<!_Const> _Other)
noexcept(is_nothrow_constructible_v<_Base_sentinel, sentinel_t<_Vw>>) // strengthened
requires _Const && convertible_to<sentinel_t<_Vw>, _Base_sentinel>
: _End(_STD move(_Other._End)) {}
_NODISCARD constexpr _Base_sentinel base() const
noexcept(is_nothrow_copy_constructible_v<_Base_sentinel>) /* strengthened */ {
return _End;
}
template <bool _OtherConst>
requires sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _It, const _Sentinel& _Se)
noexcept(noexcept(_Se._Equal(_It))) /* strengthened */ {
return _Se._Equal(_It);
}
template <bool _OtherConst>
requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(
const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) //
noexcept(noexcept(_Se._Distance_from(_It))) /* strengthened */ {
return -_Se._Distance_from(_It);
}
template <bool _OtherConst>
requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(
const _Sentinel& _Se, const _Iterator<_OtherConst>& _It) //
noexcept(noexcept(_Se._Distance_from(_It))) /* strengthened */ {
return _Se._Distance_from(_It);
}
};
template <class _Rng>
static constexpr bool _Is_end_nothrow_v = is_nothrow_move_constructible_v<sentinel_t<_Rng>> //
&& noexcept(_RANGES end(_STD declval<_Rng&>()));
template <class _Rng>
requires common_range<_Rng> && sized_range<_Rng>
static constexpr bool _Is_end_nothrow_v<_Rng> = is_nothrow_move_constructible_v<sentinel_t<_Rng>> //
&& noexcept(_RANGES end(_STD declval<_Rng&>())) //
&& noexcept(_RANGES distance(_STD declval<_Rng&>()));
public:
constexpr enumerate_view()
requires default_initializable<_Vw>
= default;
constexpr explicit enumerate_view(_Vw _Range_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Range(_STD move(_Range_)) {}
_NODISCARD constexpr auto begin() noexcept(
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) // strengthened
requires (!_Simple_view<_Vw>)
{
return _Iterator<false>{_RANGES begin(_Range), 0};
}
_NODISCARD constexpr auto begin() const noexcept(
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<const _Vw>>) // strengthened
requires _Range_with_movable_references<const _Vw>
{
return _Iterator<true>{_RANGES begin(_Range), 0};
}
_NODISCARD constexpr auto end() noexcept(_Is_end_nothrow_v<_Vw>) // strengthened
requires (!_Simple_view<_Vw>)
{
if constexpr (forward_range<_Vw> && common_range<_Vw> && sized_range<_Vw>) {
return _Iterator<false>{_RANGES end(_Range), _RANGES distance(_Range)};
} else {
return _Sentinel<false>{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto end() const noexcept(_Is_end_nothrow_v<const _Vw>) // strengthened
requires _Range_with_movable_references<const _Vw>
{
if constexpr (forward_range<const _Vw> && common_range<const _Vw> && sized_range<const _Vw>) {
return _Iterator<true>{_RANGES end(_Range), _RANGES distance(_Range)};
} else {
return _Sentinel<true>{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Range))) // strengthened
requires sized_range<_Vw>
{
return _RANGES size(_Range);
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Range))) // strengthened
requires sized_range<const _Vw>
{
return _RANGES size(_Range);
}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) // strengthened
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
};
template <class _Rng>
enumerate_view(_Rng&&) -> enumerate_view<views::all_t<_Rng>>;
template <class _Rng>
constexpr bool enable_borrowed_range<enumerate_view<_Rng>> = enable_borrowed_range<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<enumerate_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const enumerate_view<_Rng>> = _Compile_time_max_size<const _Rng>;
namespace views {
class _Enumerate_fn : public _Pipe::_Base<_Enumerate_fn> {
public:
template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range) _CONST_CALL_OPERATOR
noexcept(noexcept(enumerate_view<views::all_t<_Rng>>{_STD forward<_Rng>(_Range)}))
requires requires { enumerate_view<views::all_t<_Rng>>{_STD forward<_Rng>(_Range)}; }
{
return enumerate_view<views::all_t<_Rng>>{_STD forward<_Rng>(_Range)};
}
};
_EXPORT_STD inline constexpr _Enumerate_fn enumerate;
} // namespace views
template <class _Size>
_NODISCARD constexpr _Size _Div_ceil(const _Size _Num, const _Size _Denom) noexcept {
_Size _Result = _Num / _Denom;
if (_Num % _Denom != 0) {
++_Result;
}
return _Result;
}
_EXPORT_STD template <view _Vw>
requires input_range<_Vw>
class chunk_view : public view_interface<chunk_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Range;
range_difference_t<_Vw> _Count;
range_difference_t<_Vw> _Remainder = 0;
_Non_propagating_cache<iterator_t<_Vw>> _Current{};
class _Inner_iterator {
private:
friend chunk_view;
chunk_view* _Parent{};
constexpr explicit _Inner_iterator(chunk_view* _Parent_) noexcept : _Parent(_Parent_) {}
_NODISCARD constexpr range_difference_t<_Vw> _Get_remainder() const noexcept {
return _Parent->_Remainder;
}
_NODISCARD constexpr range_difference_t<_Vw> _Get_size() const
noexcept(noexcept(_RANGES end(_Parent->_Range) - *_Parent->_Current)) {
return (_STD min)(_Parent->_Remainder, _RANGES end(_Parent->_Range) - *_Parent->_Current);
}
_NODISCARD constexpr const iterator_t<_Vw>& _Get_current() const noexcept {
return *_Parent->_Current;
}
public:
using iterator_concept = input_iterator_tag;
using difference_type = range_difference_t<_Vw>;
using value_type = range_value_t<_Vw>;
_Inner_iterator(_Inner_iterator&&) = default;
_Inner_iterator& operator=(_Inner_iterator&&) = default;
_NODISCARD constexpr const iterator_t<_Vw>& base() const& noexcept /* strengthened */ {
return *_Parent->_Current;
}
_NODISCARD constexpr range_reference_t<_Vw> operator*() const
noexcept(noexcept(**_Parent->_Current)) /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(*this != default_sentinel, "cannot dereference chunk_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return **_Parent->_Current;
}
constexpr _Inner_iterator& operator++() noexcept(
noexcept(++*_Parent->_Current)
&& noexcept(static_cast<bool>(*_Parent->_Current == _RANGES end(_Parent->_Range)))) /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(*this != default_sentinel, "cannot increment chunk_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
++*_Parent->_Current;
if (*_Parent->_Current == _RANGES end(_Parent->_Range)) {
_Parent->_Remainder = 0;
} else {
--_Parent->_Remainder;
}
return *this;
}
constexpr void operator++(int) noexcept(
noexcept(++*_Parent->_Current)
&& noexcept(static_cast<bool>(*_Parent->_Current == _RANGES end(_Parent->_Range)))) /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(*this != default_sentinel, "cannot increment chunk_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
++*_Parent->_Current;
if (*_Parent->_Current == _RANGES end(_Parent->_Range)) {
_Parent->_Remainder = 0;
} else {
--_Parent->_Remainder;
}
}
_NODISCARD friend constexpr bool operator==(const _Inner_iterator& _Left, default_sentinel_t) noexcept
/* strengthened */ {
return _Left._Get_remainder() == 0;
}
_NODISCARD friend constexpr difference_type operator-(default_sentinel_t, const _Inner_iterator& _Right)
noexcept(noexcept(_Right._Get_size())) /* strengthened */
requires sized_sentinel_for<sentinel_t<_Vw>, iterator_t<_Vw>>
{
return _Right._Get_size();
}
_NODISCARD friend constexpr difference_type operator-(const _Inner_iterator& _Left, default_sentinel_t)
noexcept(noexcept(_Left._Get_size())) /* strengthened */
requires sized_sentinel_for<sentinel_t<_Vw>, iterator_t<_Vw>>
{
return -_Left._Get_size();
}
_NODISCARD friend constexpr range_rvalue_reference_t<_Vw> iter_move(const _Inner_iterator& _It)
noexcept(noexcept(_RANGES iter_move(_It._Get_current()))) {
return _RANGES iter_move(_It._Get_current());
}
friend constexpr void iter_swap(const _Inner_iterator& _Left, const _Inner_iterator& _Right)
noexcept(noexcept(_RANGES iter_swap(_Left._Get_current(), _Right._Get_current())))
requires indirectly_swappable<iterator_t<_Vw>>
{
_RANGES iter_swap(_Left._Get_current(), _Right._Get_current());
}
};
class _Outer_iterator {
private:
friend chunk_view;
chunk_view* _Parent{};
constexpr explicit _Outer_iterator(chunk_view* _Parent_) noexcept : _Parent(_Parent_) {}
_NODISCARD constexpr bool _Is_end() const
noexcept(noexcept(*_Parent->_Current == _RANGES end(_Parent->_Range) && true)) {
return *_Parent->_Current == _RANGES end(_Parent->_Range) && _Parent->_Remainder != 0;
}
_NODISCARD constexpr range_difference_t<_Vw> _Get_size() const
noexcept(noexcept(_RANGES end(_Parent->_Range) - *_Parent->_Current)) {
const auto _Size = _RANGES end(_Parent->_Range) - *_Parent->_Current;
if (_Size < _Parent->_Remainder) {
return _Size == 0 ? 0 : 1;
}
return _Div_ceil(_Size - _Parent->_Remainder, _Parent->_Count) + 1;
}
public:
using iterator_concept = input_iterator_tag;
using difference_type = range_difference_t<_Vw>;
struct value_type : view_interface<value_type> {
private:
friend _Outer_iterator;
chunk_view* _Parent{};
constexpr explicit value_type(chunk_view* _Parent_) noexcept : _Parent(_Parent_) {}
public:
_NODISCARD constexpr _Inner_iterator begin() const noexcept {
return _Inner_iterator{_Parent};
}
_NODISCARD constexpr default_sentinel_t end() const noexcept {
return default_sentinel;
}
_NODISCARD constexpr auto size() const
noexcept(noexcept(_RANGES end(_Parent->_Range) - *_Parent->_Current)) /* strengthened */
requires sized_sentinel_for<sentinel_t<_Vw>, iterator_t<_Vw>>
{
return _To_unsigned_like(
(_STD min)(_Parent->_Remainder, _RANGES end(_Parent->_Range) - *_Parent->_Current));
}
};
_Outer_iterator(_Outer_iterator&&) = default;
_Outer_iterator& operator=(_Outer_iterator&&) = default;
_NODISCARD constexpr value_type operator*() const noexcept /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(*this != default_sentinel, "cannot dereference chunk_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return value_type{_Parent};
}
constexpr _Outer_iterator& operator++() /* not strengthened, see _RANGES advance */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(*this != default_sentinel, "cannot increment chunk_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_RANGES advance(*_Parent->_Current, _Parent->_Remainder, _RANGES end(_Parent->_Range));
_Parent->_Remainder = _Parent->_Count;
return *this;
}
constexpr void operator++(int) /* not strengthened, see _RANGES advance */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(*this != default_sentinel, "cannot increment chunk_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_RANGES advance(*_Parent->_Current, _Parent->_Remainder, _RANGES end(_Parent->_Range));
_Parent->_Remainder = _Parent->_Count;
}
_NODISCARD friend constexpr bool operator==(const _Outer_iterator& _Left, default_sentinel_t)
noexcept(noexcept(_Left._Is_end())) /* strengthened */ {
return _Left._Is_end();
}
_NODISCARD friend constexpr difference_type operator-(default_sentinel_t, const _Outer_iterator& _Right)
noexcept(noexcept(_Right._Get_size())) /* strengthened */
requires sized_sentinel_for<sentinel_t<_Vw>, iterator_t<_Vw>>
{
return _Right._Get_size();
}
_NODISCARD friend constexpr difference_type operator-(const _Outer_iterator& _Left, default_sentinel_t)
noexcept(noexcept(_Left._Get_size())) /* strengthened */
requires sized_sentinel_for<sentinel_t<_Vw>, iterator_t<_Vw>>
{
return -_Left._Get_size();
}
};
public:
constexpr explicit chunk_view(_Vw _Range_, const range_difference_t<_Vw> _Count_)
noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */
: _Range(_STD move(_Range_)), _Count{_Count_} {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Count > 0, "chunk size must be greater than 0");
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr _Outer_iterator begin()
noexcept(noexcept(_Current._Emplace(_RANGES begin(_Range)))) /* strengthened */ {
_Current._Emplace(_RANGES begin(_Range));
_Remainder = _Count;
return _Outer_iterator{this};
}
_NODISCARD constexpr default_sentinel_t end() const noexcept {
return default_sentinel;
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES distance(_Range))) /* strengthened */
requires sized_range<_Vw>
{
return _To_unsigned_like(_Div_ceil(_RANGES distance(_Range), _Count));
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES distance(_Range))) /* strengthened */
requires sized_range<const _Vw>
{
return _To_unsigned_like(_Div_ceil(_RANGES distance(_Range), _Count));
}
};
template <view _Vw>
requires forward_range<_Vw>
class chunk_view<_Vw> : public view_interface<chunk_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Range;
range_difference_t<_Vw> _Count;
template <bool _Const>
class _Iterator {
private:
friend chunk_view;
using _ParentTy = _Maybe_const<_Const, chunk_view>;
using _Base = _Maybe_const<_Const, _Vw>;
using _Base_iterator = iterator_t<_Base>;
using _Base_sentinel = sentinel_t<_Base>;
/* [[no_unique_address]] */ _Base_iterator _Current{};
/* [[no_unique_address]] */ _Base_sentinel _End{};
range_difference_t<_Base> _Count = 0;
range_difference_t<_Base> _Missing = 0;
constexpr _Iterator(_ParentTy* _Parent, _Base_iterator _Current_,
range_difference_t<_Base> _Missing_ = 0) //
noexcept(noexcept(_RANGES end(_Parent->_Range)) && is_nothrow_move_constructible_v<_Base_iterator> //
&& is_nothrow_move_constructible_v<_Base_sentinel>) /* strengthened */
: _Current(_STD move(_Current_)), _End(_RANGES end(_Parent->_Range)), _Count(_Parent->_Count),
_Missing(_Missing_) {}
public:
using iterator_category = input_iterator_tag;
using iterator_concept = conditional_t<random_access_range<_Base>, random_access_iterator_tag,
conditional_t<bidirectional_range<_Base>, bidirectional_iterator_tag, forward_iterator_tag>>;
using value_type = decltype(views::take(subrange(_Current, _End), _Count));
using difference_type = range_difference_t<_Base>;
_Iterator() = default;
constexpr _Iterator(_Iterator<!_Const> _Other)
noexcept(is_nothrow_constructible_v<_Base_iterator, typename _Iterator<!_Const>::_Base_iterator>
&& is_nothrow_constructible_v<_Base_sentinel,
typename _Iterator<!_Const>::_Base_sentinel>) /* strengthened */
requires _Const && convertible_to<iterator_t<_Vw>, _Base_iterator>
&& convertible_to<sentinel_t<_Vw>, _Base_sentinel>
: _Current(_STD move(_Other._Current)), _End(_STD move(_Other._End)), _Count(_Other._Count),
_Missing(_Other._Missing) {}
_NODISCARD constexpr _Base_iterator base() const
noexcept(is_nothrow_copy_constructible_v<_Base_iterator>) /* strengthened */ {
return _Current;
}
_NODISCARD constexpr value_type operator*() const
noexcept(noexcept(views::take(subrange(_Current, _End), _Count))) /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Current != _End, "cannot dereference chunk_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return views::take(subrange(_Current, _End), _Count);
}
constexpr _Iterator& operator++() /* not strengthened, see _RANGES advance */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Current != _End, "cannot increment chunk_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Missing = _RANGES advance(_Current, _Count, _End);
return *this;
}
constexpr _Iterator operator++(int) /* not strengthened, see _RANGES advance */ {
auto _Tmp = *this;
++*this;
return _Tmp;
}
constexpr _Iterator& operator--() /* not strengthened, see _RANGES advance */
requires bidirectional_range<_Base>
{
_RANGES advance(_Current, _Missing - _Count);
_Missing = 0;
return *this;
}
constexpr _Iterator operator--(int) /* not strengthened, see _RANGES advance */
requires bidirectional_range<_Base>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
constexpr _Iterator& operator+=(const difference_type _Off) /* not strengthened, see _RANGES advance */
requires random_access_range<_Base>
{
if (_Off > 0) {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Count <= (numeric_limits<difference_type>::max)() / _Off,
"cannot advance chunk_view iterator past end (integer overflow)");
if constexpr (sized_sentinel_for<_Base_sentinel, _Base_iterator>) {
_STL_VERIFY(_End - _Current > _Count * (_Off - 1), //
"cannot advance chunk_view iterator past end");
}
#endif // _ITERATOR_DEBUG_LEVEL != 0
if constexpr (sized_sentinel_for<_Base_sentinel, _Base_iterator>) {
_Missing = _RANGES advance(_Current, _Count * _Off, _End);
} else {
_Current += static_cast<difference_type>(_Count * (_Off - 1));
_Missing = _RANGES advance(_Current, _Count, _End);
}
} else if (_Off < 0) {
_Current += static_cast<difference_type>(_Count * _Off + _Missing);
_Missing = 0;
}
return *this;
}
constexpr _Iterator& operator-=(const difference_type _Off) /* not strengthened, see _RANGES advance */
requires random_access_range<_Base>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Off != (numeric_limits<difference_type>::min)(),
"cannot advance chunk_view iterator past end (integer overflow)");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return *this += -_Off;
}
_NODISCARD constexpr value_type operator[](const difference_type _Off) const
noexcept(noexcept(*(*this + _Off))) /* strengthened */
requires random_access_range<_Base>
{
return *(*this + _Off);
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Current == _Right._Current))) /* strengthened */ {
return _Left._Current == _Right._Current;
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, default_sentinel_t)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Current == _Left._End))) /* strengthened */ {
return _Left._Current == _Left._End;
}
_NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Current < _Right._Current))) /* strengthened */
requires random_access_range<_Base>
{
return _Left._Current < _Right._Current;
}
_NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Right._Current < _Left._Current))) /* strengthened */
requires random_access_range<_Base>
{
return _Right._Current < _Left._Current;
}
_NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(!(_Right._Current < _Left._Current)))) /* strengthened */
requires random_access_range<_Base>
{
return !(_Right._Current < _Left._Current);
}
_NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(!(_Left._Current < _Right._Current)))) /* strengthened */
requires random_access_range<_Base>
{
return !(_Left._Current < _Right._Current);
}
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current <=> _Right._Current)) /* strengthened */
requires random_access_range<_Base> && three_way_comparable<_Base_iterator>
{
return _Left._Current <=> _Right._Current;
}
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off)
noexcept(is_nothrow_copy_constructible_v<_Iterator>
&& noexcept(_STD declval<_Iterator&>() += _Off)) /* strengthened */
requires random_access_range<_Base>
{
auto _Copy = _It;
_Copy += _Off;
return _Copy;
}
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It)
noexcept(is_nothrow_copy_constructible_v<_Iterator>
&& noexcept(_STD declval<_Iterator&>() += _Off)) /* strengthened */
requires random_access_range<_Base>
{
auto _Copy = _It;
_Copy += _Off;
return _Copy;
}
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off)
noexcept(is_nothrow_copy_constructible_v<_Iterator>
&& noexcept(_STD declval<_Iterator&>() -= _Off)) /* strengthened */
requires random_access_range<_Base>
{
auto _Copy = _It;
_Copy -= _Off;
return _Copy;
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */
requires sized_sentinel_for<_Base_iterator, _Base_iterator>
{
return (_Left._Current - _Right._Current + _Left._Missing - _Right._Missing) / _Left._Count;
}
_NODISCARD friend constexpr difference_type operator-(default_sentinel_t, const _Iterator& _Right)
noexcept(noexcept(_Right._End - _Right._Current)) /* strengthened */
requires sized_sentinel_for<_Base_sentinel, _Base_iterator>
{
return _Div_ceil(_Right._End - _Right._Current, _Right._Count);
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, default_sentinel_t)
noexcept(noexcept(_Left._End - _Left._Current)) /* strengthened */
requires sized_sentinel_for<_Base_sentinel, _Base_iterator>
{
return -_Div_ceil(_Left._End - _Left._Current, _Left._Count);
}
};
public:
constexpr explicit chunk_view(_Vw _Range_, const range_difference_t<_Vw> _Count_)
noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */
: _Range(_STD move(_Range_)), _Count{_Count_} {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Count > 0, "chunk size must be greater than 0");
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin() noexcept(
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */
requires (!_Simple_view<_Vw>)
{
return _Iterator<false>{this, _RANGES begin(_Range)};
}
_NODISCARD constexpr auto begin() const
noexcept(noexcept(_RANGES begin(_Range))
&& is_nothrow_move_constructible_v<iterator_t<const _Vw>>) /* strengthened */
requires forward_range<const _Vw>
{
return _Iterator<true>{this, _RANGES begin(_Range)};
}
_NODISCARD constexpr auto end() noexcept(noexcept(_RANGES distance(_Range)) && noexcept(_RANGES end(_Range))
&& is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */
requires (!_Simple_view<_Vw>)
{
if constexpr (common_range<_Vw> && sized_range<_Vw>) {
const auto _Missing = static_cast<range_difference_t<_Vw>>(_Count - _RANGES distance(_Range) % _Count);
if (_Missing == _Count) {
return _Iterator<false>{this, _RANGES end(_Range)};
}
return _Iterator<false>{this, _RANGES end(_Range), _Missing};
} else if constexpr (common_range<_Vw> && !bidirectional_range<_Vw>) {
return _Iterator<false>{this, _RANGES end(_Range)};
} else {
return default_sentinel;
}
}
_NODISCARD constexpr auto end() const
noexcept(noexcept(_RANGES distance(_Range)) && noexcept(_RANGES end(_Range))
&& is_nothrow_move_constructible_v<iterator_t<const _Vw>>) /* strengthened */
requires forward_range<const _Vw>
{
if constexpr (common_range<const _Vw> && sized_range<const _Vw>) {
const auto _Missing = static_cast<range_difference_t<_Vw>>(_Count - _RANGES distance(_Range) % _Count);
if (_Missing == _Count) {
return _Iterator<true>{this, _RANGES end(_Range)};
}
return _Iterator<true>{this, _RANGES end(_Range), _Missing};
} else if constexpr (common_range<const _Vw> && !bidirectional_range<const _Vw>) {
return _Iterator<true>{this, _RANGES end(_Range)};
} else {
return default_sentinel;
}
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES distance(_Range))) /* strengthened */
requires sized_range<_Vw>
{
return _To_unsigned_like(_Div_ceil(_RANGES distance(_Range), _Count));
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES distance(_Range))) /* strengthened */
requires sized_range<const _Vw>
{
return _To_unsigned_like(_Div_ceil(_RANGES distance(_Range), _Count));
}
};
template <class _Rng>
chunk_view(_Rng&&, range_difference_t<_Rng>) -> chunk_view<views::all_t<_Rng>>;
template <class _Vw>
constexpr bool enable_borrowed_range<chunk_view<_Vw>> = enable_borrowed_range<_Vw> && forward_range<_Vw>;
template <class _Rng>
constexpr auto _Compile_time_max_size<chunk_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
requires forward_range<_Rng>
constexpr auto _Compile_time_max_size<const chunk_view<_Rng>> = _Compile_time_max_size<const _Rng>;
namespace views {
struct _Chunk_fn {
template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Rng&& _Range, const range_difference_t<_Rng> _Count) _CONST_CALL_OPERATOR
noexcept(noexcept(chunk_view(_STD forward<_Rng>(_Range), _Count)))
requires requires { chunk_view(_STD forward<_Rng>(_Range), _Count); }
{
return chunk_view(_STD forward<_Rng>(_Range), _Count);
}
template <class _Ty>
requires constructible_from<decay_t<_Ty>, _Ty>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty&& _Count) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Ty>, _Ty>) {
return _Range_closure<_Chunk_fn, decay_t<_Ty>>{_STD forward<_Ty>(_Count)};
}
};
_EXPORT_STD inline constexpr _Chunk_fn chunk;
} // namespace views
template <class _Vw>
concept _Slide_caches_nothing = random_access_range<_Vw> && sized_range<_Vw>;
template <class _Vw>
concept _Slide_caches_last = !_Slide_caches_nothing<_Vw> && bidirectional_range<_Vw> && common_range<_Vw>;
template <class _Vw>
concept _Slide_caches_first = !_Slide_caches_nothing<_Vw> && !_Slide_caches_last<_Vw>;
_EXPORT_STD template <forward_range _Vw>
requires view<_Vw>
class slide_view : public _Cached_position_t<!_Slide_caches_nothing<_Vw>, _Vw, slide_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Range;
range_difference_t<_Vw> _Count;
template <class>
class _Iter_base {};
template <_Slide_caches_first _Base>
class _Iter_base<_Base> {
protected:
using _Base_iterator = iterator_t<_Base>;
_Base_iterator _Last_element{};
public:
_Iter_base() = default;
constexpr explicit _Iter_base(_Base_iterator _Last_element_)
noexcept(is_nothrow_move_constructible_v<_Base_iterator>)
: _Last_element{_STD move(_Last_element_)} {}
_NODISCARD constexpr const _Base_iterator& _Get_last_element() const noexcept {
return _Last_element;
}
};
template <bool _Const>
class _Iterator : public _Iter_base<_Maybe_const<_Const, _Vw>> {
private:
friend slide_view;
using _Base = _Maybe_const<_Const, _Vw>;
using _Base_iterator = iterator_t<_Base>;
/* [[no_unique_address]] */ _Base_iterator _Current{};
range_difference_t<_Base> _Count = 0;
constexpr _Iterator(_Base_iterator _Current_, range_difference_t<_Base> _Count_)
noexcept(is_nothrow_move_constructible_v<_Base_iterator>) /* strengthened */
requires (!_Slide_caches_first<_Base>)
: _Current(_STD move(_Current_)), _Count(_Count_) {}
constexpr _Iterator(_Base_iterator _Current_, _Base_iterator _Last_, range_difference_t<_Base> _Count_) //
noexcept(is_nothrow_move_constructible_v<_Base_iterator>) /* strengthened */
requires _Slide_caches_first<_Base>
: _Iter_base<_Base>(_STD move(_Last_)), _Current(_STD move(_Current_)), _Count(_Count_) {}
public:
using value_type = decltype(views::counted(_Current, _Count));
using difference_type = range_difference_t<_Base>;
using iterator_category = input_iterator_tag;
using iterator_concept = conditional_t<random_access_range<_Base>, random_access_iterator_tag,
conditional_t<bidirectional_range<_Base>, bidirectional_iterator_tag, forward_iterator_tag>>;
_Iterator() = default;
constexpr _Iterator(_Iterator<!_Const> _Other)
noexcept(is_nothrow_constructible_v<_Base_iterator, iterator_t<_Vw>>) // strengthened
requires _Const && convertible_to<iterator_t<_Vw>, _Base_iterator>
: _Current(_STD move(_Other._Current)), _Count(_Other._Count) {}
_NODISCARD constexpr value_type operator*() const
noexcept(noexcept(views::counted(_Current, _Count))) /* strengthened */ {
return views::counted(_Current, _Count);
}
constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ {
++_Current;
if constexpr (_Slide_caches_first<_Base>) {
++this->_Last_element;
}
return *this;
}
constexpr _Iterator operator++(int) noexcept(is_nothrow_copy_constructible_v<_Base_iterator> //
&& noexcept(++_Current)) /* strengthened */ {
auto _Tmp = *this;
++*this;
return _Tmp;
}
constexpr _Iterator& operator--() noexcept(noexcept(--_Current)) /* strengthened */
requires bidirectional_range<_Base>
{
--_Current;
if constexpr (_Slide_caches_first<_Base>) {
--this->_Last_element;
}
return *this;
}
constexpr _Iterator operator--(int) noexcept(is_nothrow_copy_constructible_v<_Base_iterator> //
&& noexcept(--_Current)) /* strengthened */
requires bidirectional_range<_Base>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
constexpr _Iterator& operator+=(const difference_type _Off)
noexcept(noexcept(_Current += _Off)) /* strengthened */
requires random_access_range<_Base>
{
_Current += _Off;
if constexpr (_Slide_caches_first<_Base>) {
this->_Last_element += _Off;
}
return *this;
}
constexpr _Iterator& operator-=(const difference_type _Off)
noexcept(noexcept(_Current -= _Off)) /* strengthened */
requires random_access_range<_Base>
{
_Current -= _Off;
if constexpr (_Slide_caches_first<_Base>) {
this->_Last_element -= _Off;
}
return *this;
}
_NODISCARD constexpr value_type operator[](const difference_type _Off) const
noexcept(noexcept(views::counted(_Current + _Off, _Count))) /* strengthened */
requires random_access_range<_Base>
{
return views::counted(_Current + _Off, _Count);
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Current == _Right._Current))) /* strengthened */ {
if constexpr (_Slide_caches_first<_Base>) {
return _Left._Last_element == _Right._Last_element;
} else {
return _Left._Current == _Right._Current;
}
}
_NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Current < _Right._Current))) /* strengthened */
requires random_access_range<_Base>
{
return _Left._Current < _Right._Current;
}
_NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Right._Current < _Left._Current))) /* strengthened */
requires random_access_range<_Base>
{
return _Right._Current < _Left._Current;
}
_NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(!(_Right._Current < _Left._Current)))) /* strengthened */
requires random_access_range<_Base>
{
return !(_Right._Current < _Left._Current);
}
_NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(!(_Left._Current < _Right._Current)))) /* strengthened */
requires random_access_range<_Base>
{
return !(_Left._Current < _Right._Current);
}
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current <=> _Right._Current)) /* strengthened */
requires random_access_range<_Base> && three_way_comparable<_Base_iterator>
{
return _Left._Current <=> _Right._Current;
}
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off)
noexcept(noexcept(_STD declval<_Iterator&>() += _Off)) /* strengthened */
requires random_access_range<_Base>
{
auto _Copy = _It;
_Copy += _Off;
return _Copy;
}
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It)
noexcept(noexcept(_STD declval<_Iterator&>() += _Off)) /* strengthened */
requires random_access_range<_Base>
{
auto _Copy = _It;
_Copy += _Off;
return _Copy;
}
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off)
noexcept(noexcept(_STD declval<_Iterator&>() -= _Off)) /* strengthened */
requires random_access_range<_Base>
{
auto _Copy = _It;
_Copy -= _Off;
return _Copy;
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */
requires sized_sentinel_for<_Base_iterator, _Base_iterator>
{
if constexpr (_Slide_caches_first<_Base>) {
return _Left._Last_element - _Right._Last_element;
} else {
return _Left._Current - _Right._Current;
}
}
};
class _Sentinel {
private:
friend slide_view;
/* [[no_unique_address]] */ sentinel_t<_Vw> _Last{};
constexpr explicit _Sentinel(sentinel_t<_Vw> _Last_)
noexcept(is_nothrow_move_constructible_v<sentinel_t<_Vw>>) /* strengthened */
: _Last(_STD move(_Last_)) {}
public:
_Sentinel() = default;
_NODISCARD friend constexpr bool operator==(const _Iterator<false>& _Left, const _Sentinel& _Right)
noexcept(noexcept(
_STD _Fake_copy_init<bool>(_Left._Get_last_element() == _Right._Last))) /* strengthened */ {
return _Left._Get_last_element() == _Right._Last;
}
_NODISCARD friend constexpr range_difference_t<_Vw> operator-(const _Iterator<false>& _Left,
const _Sentinel& _Right) noexcept(noexcept(_Left._Get_last_element() - _Right._Last)) /* strengthened */
requires sized_sentinel_for<sentinel_t<_Vw>, iterator_t<_Vw>>
{
return _Left._Get_last_element() - _Right._Last;
}
_NODISCARD friend constexpr range_difference_t<_Vw> operator-(
const _Sentinel& _Left, const _Iterator<false>& _Right)
noexcept(noexcept(_Left._Last - _Right._Get_last_element())) /* strengthened */
requires sized_sentinel_for<sentinel_t<_Vw>, iterator_t<_Vw>>
{
return _Left._Last - _Right._Get_last_element();
}
};
public:
constexpr explicit slide_view(_Vw _Range_, const range_difference_t<_Vw> _Count_)
noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */
: _Range(_STD move(_Range_)), _Count{_Count_} {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Count > 0, "The window size must be positive (N4950 [range.slide.view]/1)");
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) // strengthened
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin()
requires (!(_Simple_view<_Vw> && _Slide_caches_nothing<const _Vw>) )
{
if constexpr (_Slide_caches_first<_Vw>) {
auto _First = _RANGES begin(_Range);
if (this->_Has_cache()) {
return _Iterator<false>{_STD move(_First), this->_Get_cache(_Range), _Count};
}
auto _Current_last = _RANGES next(_First, _Count - 1, _RANGES end(_Range));
this->_Set_cache(_Range, _Current_last);
return _Iterator<false>{_STD move(_First), _STD move(_Current_last), _Count};
} else {
return _Iterator<false>{_RANGES begin(_Range), _Count};
}
}
_NODISCARD constexpr auto begin() const noexcept(
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */
requires _Slide_caches_nothing<const _Vw>
{
return _Iterator<true>{_RANGES begin(_Range), _Count};
}
_NODISCARD constexpr auto end()
requires (!(_Simple_view<_Vw> && _Slide_caches_nothing<const _Vw>) )
{
if constexpr (_Slide_caches_nothing<_Vw>) {
const auto _Size = _RANGES distance(_Range) - (_Count - 1);
if (_Size < 0) {
return _Iterator<false>{_RANGES begin(_Range), _Count};
}
return _Iterator<false>{_RANGES begin(_Range) + _Size, _Count};
} else if constexpr (_Slide_caches_last<_Vw>) {
if (this->_Has_cache()) {
return _Iterator<false>{this->_Get_cache(_Range), _Count};
}
auto _Current_last = _RANGES prev(_RANGES end(_Range), _Count - 1, _RANGES begin(_Range));
this->_Set_cache(_Range, _Current_last);
return _Iterator<false>{_STD move(_Current_last), _Count};
} else if constexpr (common_range<_Vw>) {
const auto _Last = _RANGES end(_Range);
return _Iterator<false>{_Last, _Last, _Count};
} else {
return _Sentinel{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto end() const
noexcept(is_nothrow_move_constructible_v<iterator_t<_Vw>> && noexcept(_RANGES distance(_Range))
&& noexcept(_RANGES begin(_Range) + _Count)) /* strengthened */
requires _Slide_caches_nothing<const _Vw>
{
const auto _Size = _RANGES distance(_Range) - (_Count - 1);
if (_Size < 0) {
return _Iterator<true>{_RANGES begin(_Range), _Count};
}
return _Iterator<true>{_RANGES begin(_Range) + _Size, _Count};
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES distance(_Range))) /* strengthened */
requires sized_range<_Vw>
{
auto _Size = _RANGES distance(_Range) - (_Count - 1);
if (_Size < 0) {
_Size = 0;
}
return _To_unsigned_like(_Size);
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES distance(_Range))) /* strengthened */
requires sized_range<const _Vw>
{
auto _Size = _RANGES distance(_Range) - (_Count - 1);
if (_Size < 0) {
_Size = 0;
}
return _To_unsigned_like(_Size);
}
};
template <class _Rng>
slide_view(_Rng&&, range_difference_t<_Rng>) -> slide_view<views::all_t<_Rng>>;
template <class _Vw>
constexpr bool enable_borrowed_range<slide_view<_Vw>> = enable_borrowed_range<_Vw>;
template <class _Rng>
constexpr auto _Compile_time_max_size<slide_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const slide_view<_Rng>> = _Compile_time_max_size<const _Rng>;
namespace views {
struct _Slide_fn {
template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Rng&& _Range, const range_difference_t<_Rng> _Count) _CONST_CALL_OPERATOR
noexcept(noexcept(slide_view(_STD forward<_Rng>(_Range), _Count)))
requires requires { slide_view(_STD forward<_Rng>(_Range), _Count); }
{
return slide_view(_STD forward<_Rng>(_Range), _Count);
}
template <class _Ty>
requires constructible_from<decay_t<_Ty>, _Ty>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty&& _Count) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Ty>, _Ty>) {
return _Range_closure<_Slide_fn, decay_t<_Ty>>{_STD forward<_Ty>(_Count)};
}
};
_EXPORT_STD inline constexpr _Slide_fn slide;
} // namespace views
template <class _Pr>
struct _Negated_pred {
template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool operator()(_Ty1&& _Left, _Ty2&& _Right) {
return !_STD invoke(_Pred, _STD forward<_Ty1>(_Left), _STD forward<_Ty2>(_Right));
}
_Pr& _Pred;
};
template <class _Pr>
struct _Backward_negated_pred {
template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool operator()(_Ty1&& _Left, _Ty2&& _Right) {
return !_STD invoke(_Pred, _STD forward<_Ty2>(_Right), _STD forward<_Ty1>(_Left));
}
_Pr& _Pred;
};
_EXPORT_STD template <forward_range _Vw, indirect_binary_predicate<iterator_t<_Vw>, iterator_t<_Vw>> _Pr>
requires view<_Vw> && is_object_v<_Pr>
class chunk_by_view : public _Cached_position<_Vw, chunk_by_view<_Vw, _Pr>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
/* [[no_unique_address]] */ _Movable_box<_Pr> _Pred{};
class _Iterator {
private:
friend chunk_by_view;
chunk_by_view* _Parent{};
/* [[no_unique_address]] */ iterator_t<_Vw> _Current{};
/* [[no_unique_address]] */ iterator_t<_Vw> _Next{};
constexpr _Iterator(chunk_by_view& _Parent_, iterator_t<_Vw> _Current_, iterator_t<_Vw> _Next_)
noexcept(is_nothrow_move_constructible_v<iterator_t<_Vw>>) // strengthened
: _Parent(_STD addressof(_Parent_)), _Current(_STD move(_Current_)), _Next(_STD move(_Next_)) {}
public:
using value_type = subrange<iterator_t<_Vw>>;
using difference_type = range_difference_t<_Vw>;
using iterator_category = input_iterator_tag;
using iterator_concept =
conditional_t<bidirectional_range<_Vw>, bidirectional_iterator_tag, forward_iterator_tag>;
_Iterator() = default;
_NODISCARD constexpr value_type operator*() const
noexcept(is_nothrow_copy_constructible_v<iterator_t<_Vw>>) /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Current != _Next, "cannot dereference chunk_by_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return subrange{_Current, _Next};
}
constexpr _Iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Current != _Next, "cannot increment chunk_by_view iterator past end");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Current = _Next;
_Next = _Parent->_Find_next(_Next);
return *this;
}
constexpr _Iterator operator++(int) {
auto _Tmp = *this;
++*this;
return _Tmp;
}
constexpr _Iterator& operator--()
requires bidirectional_range<_Vw>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Parent != nullptr, "cannot decrement value-initialized chunk_by_view iterator");
_STL_VERIFY(
_Current != _RANGES begin(_Parent->_Range), "cannot decrement chunk_by_view iterator before begin");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Next = _Current;
_Current = _Parent->_Find_prev(_Current);
return *this;
}
constexpr _Iterator operator--(int)
requires bidirectional_range<_Vw>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Current == _Right._Current))) /* strengthened */ {
return _Left._Current == _Right._Current;
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, default_sentinel_t)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Current == _Left._Next))) /* strengthened */ {
return _Left._Current == _Left._Next;
}
};
_NODISCARD constexpr iterator_t<_Vw> _Find_next(iterator_t<_Vw> _It) {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Pred, "cannot increment a chunk_by_view iterator whose parent view has no predicate");
#endif // _ITERATOR_DEBUG_LEVEL != 0
const auto _Before_next = _RANGES adjacent_find(_It, _RANGES end(_Range), _Negated_pred<_Pr>{*_Pred});
return _RANGES next(_Before_next, 1, _RANGES end(_Range));
}
_NODISCARD constexpr iterator_t<_Vw> _Find_prev(iterator_t<_Vw> _It) {
_STL_INTERNAL_STATIC_ASSERT(bidirectional_range<_Vw>);
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Pred, "cannot decrement a chunk_by_view iterator whose parent view has no predicate");
#endif // _ITERATOR_DEBUG_LEVEL != 0
reverse_view _Rv{subrange{_RANGES begin(_Range), _It}};
const auto _After_prev = _RANGES adjacent_find(_Rv, _Backward_negated_pred<_Pr>{*_Pred});
return _RANGES prev(_After_prev.base(), 1, _RANGES begin(_Range));
}
public:
chunk_by_view()
requires default_initializable<_Vw> && default_initializable<_Pr>
= default;
constexpr explicit chunk_by_view(_Vw _Range_, _Pr _Pred_)
noexcept(is_nothrow_move_constructible_v<_Vw> && is_nothrow_move_constructible_v<_Pr>) // strengthened
: _Range(_STD move(_Range_)), _Pred{in_place, _STD move(_Pred_)} {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Pred, "chunk_by_view has no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
return *_Pred;
}
_NODISCARD constexpr _Iterator begin() {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Pred, "cannot call begin on a chunk_by_view with no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
const auto _First = _RANGES begin(_Range);
if (this->_Has_cache()) {
return _Iterator{*this, _First, this->_Get_cache(_Range)};
}
const auto _Result = _Find_next(_First);
this->_Set_cache(_Range, _Result);
return _Iterator{*this, _First, _Result};
}
_NODISCARD constexpr auto end() {
if constexpr (common_range<_Vw>) {
const auto _Last = _RANGES end(_Range);
return _Iterator{*this, _Last, _Last};
} else {
return default_sentinel;
}
}
};
template <class _Rng, class _Pr>
chunk_by_view(_Rng&&, _Pr) -> chunk_by_view<views::all_t<_Rng>, _Pr>;
template <class _Rng, class _Pr>
constexpr auto _Compile_time_max_size<chunk_by_view<_Rng, _Pr>> = _Compile_time_max_size<_Rng>;
namespace views {
struct _Chunk_by_fn {
template <viewable_range _Rng, class _Pr>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range, _Pr&& _Pred) _CONST_CALL_OPERATOR
noexcept(noexcept(chunk_by_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred))))
requires requires { chunk_by_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred)); }
{
return chunk_by_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred));
}
template <class _Pr>
requires constructible_from<decay_t<_Pr>, _Pr>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Pr&& _Pred) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Pr>, _Pr>) {
return _Range_closure<_Chunk_by_fn, decay_t<_Pr>>{_STD forward<_Pr>(_Pred)};
}
};
_EXPORT_STD inline constexpr _Chunk_by_fn chunk_by;
} // namespace views
_EXPORT_STD template <input_range _Vw>
requires view<_Vw>
class stride_view : public view_interface<stride_view<_Vw>> {
private:
/* [[no_unique_address]] */ _Vw _Range;
range_difference_t<_Vw> _Stride;
template <class _BaseTy>
class _Category_base {};
template <forward_range _BaseTy>
class _Category_base<_BaseTy> {
private:
using _BaseCategory = iterator_traits<iterator_t<_BaseTy>>::iterator_category;
public:
using iterator_category = conditional_t<derived_from<_BaseCategory, random_access_iterator_tag>,
random_access_iterator_tag, _BaseCategory>;
};
template <bool _Const>
class _Iterator : public _Category_base<_Maybe_const<_Const, _Vw>> {
private:
friend stride_view;
using _ParentTy = _Maybe_const<_Const, stride_view>;
using _Base = _Maybe_const<_Const, _Vw>;
using _Base_iterator = iterator_t<_Base>;
using _Base_sentinel = sentinel_t<_Base>;
/* [[no_unique_address]] */ _Base_iterator _Current{};
/* [[no_unique_address]] */ _Base_sentinel _End{};
range_difference_t<_Base> _Stride = 0;
range_difference_t<_Base> _Missing = 0;
constexpr _Iterator(_ParentTy* _Parent, _Base_iterator _Current_,
range_difference_t<_Base> _Missing_ = 0) //
noexcept(noexcept(_RANGES end(_Parent->_Range)) && is_nothrow_move_constructible_v<_Base_iterator> //
&& is_nothrow_move_constructible_v<_Base_sentinel>) // strengthened
: _Current(_STD move(_Current_)), _End(_RANGES end(_Parent->_Range)), _Stride(_Parent->_Stride),
_Missing(_Missing_) {}
public:
using difference_type = range_difference_t<_Base>;
using value_type = range_value_t<_Base>;
using iterator_concept = conditional_t<random_access_range<_Base>, random_access_iterator_tag,
conditional_t<bidirectional_range<_Base>, bidirectional_iterator_tag,
conditional_t<forward_range<_Base>, forward_iterator_tag, input_iterator_tag>>>;
_Iterator()
requires default_initializable<_Base_iterator>
= default;
constexpr _Iterator(_Iterator<!_Const> _Other)
noexcept(is_nothrow_constructible_v<_Base_iterator, iterator_t<_Vw>>
&& is_nothrow_constructible_v<_Base_sentinel, sentinel_t<_Vw>>) /* strengthened */
requires _Const && convertible_to<iterator_t<_Vw>, _Base_iterator>
&& convertible_to<sentinel_t<_Vw>, _Base_sentinel>
: _Current(_STD move(_Other._Current)), _End(_STD move(_Other._End)), _Stride(_Other._Stride),
_Missing(_Other._Missing) {}
_NODISCARD constexpr _Base_iterator base() && noexcept(
is_nothrow_move_constructible_v<_Base_iterator>) /* strengthened */ {
return _STD move(_Current);
}
_NODISCARD constexpr const _Base_iterator& base() const& noexcept {
return _Current;
}
_NODISCARD constexpr decltype(auto) operator*() const noexcept(noexcept(*_Current)) /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Current != _End, "cannot dereference stride_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return *_Current;
}
constexpr _Iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Current != _End, "cannot increment stride_view end iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Missing = _RANGES advance(_Current, _Stride, _End);
return *this;
}
constexpr void operator++(int) {
++*this;
}
constexpr _Iterator operator++(int)
requires forward_range<_Base>
{
auto _Tmp = *this;
++*this;
return _Tmp;
}
constexpr _Iterator& operator--()
requires bidirectional_range<_Base>
{
_RANGES advance(_Current, _Missing - _Stride);
_Missing = 0;
return *this;
}
constexpr _Iterator operator--(int)
requires bidirectional_range<_Base>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
constexpr _Iterator& operator+=(const difference_type _Off)
requires random_access_range<_Base>
{
if (_Off > 0) {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Stride <= (numeric_limits<difference_type>::max)() / _Off,
"cannot advance stride_view iterator past end (integer overflow)");
if constexpr (sized_sentinel_for<_Base_sentinel, _Base_iterator>) {
_STL_VERIFY(_End - _Current > _Stride * (_Off - 1), //
"cannot advance stride_view iterator past end");
}
#endif // _ITERATOR_DEBUG_LEVEL != 0
if constexpr (sized_sentinel_for<_Base_sentinel, _Base_iterator>) {
_Missing = _RANGES advance(_Current, _Stride * _Off, _End);
} else {
_Current += static_cast<difference_type>(_Stride * (_Off - 1));
_Missing = _RANGES advance(_Current, _Stride, _End);
}
} else if (_Off < 0) {
_Current += static_cast<difference_type>(_Stride * _Off + _Missing);
_Missing = 0;
}
return *this;
}
constexpr _Iterator& operator-=(const difference_type _Off)
requires random_access_range<_Base>
{
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Off != (numeric_limits<difference_type>::min)(),
"cannot advance stride_view iterator past end (integer overflow)");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return *this += -_Off;
}
_NODISCARD constexpr decltype(auto) operator[](const difference_type _Off) const
noexcept(noexcept(*(*this + _Off))) /* strengthened */
requires random_access_range<_Base>
{
return *(*this + _Off);
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _It, default_sentinel_t)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_It._Current == _It._End))) /* strengthened */ {
return _It._Current == _It._End;
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Current == _Right._Current))) // strengthened
requires equality_comparable<_Base_iterator>
{
return _Left._Current == _Right._Current;
}
_NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Current < _Right._Current))) // strengthened
requires random_access_range<_Base>
{
return _Left._Current < _Right._Current;
}
_NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Right._Current < _Left._Current))) // strengthened
requires random_access_range<_Base>
{
return _Right._Current < _Left._Current;
}
_NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(!(_Right._Current < _Left._Current)))) // strengthened
requires random_access_range<_Base>
{
return !(_Right._Current < _Left._Current);
}
_NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_STD _Fake_copy_init<bool>(!(_Left._Current < _Right._Current)))) // strengthened
requires random_access_range<_Base>
{
return !(_Left._Current < _Right._Current);
}
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current <=> _Right._Current)) // strengthened
requires random_access_range<_Base> && three_way_comparable<_Base_iterator>
{
return _Left._Current <=> _Right._Current;
}
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off)
requires random_access_range<_Base>
{
auto _Copy = _It;
_Copy += _Off;
return _Copy;
}
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It)
requires random_access_range<_Base>
{
auto _Copy = _It;
_Copy += _Off;
return _Copy;
}
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off)
requires random_access_range<_Base>
{
auto _Copy = _It;
_Copy -= _Off;
return _Copy;
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) //
noexcept(noexcept(_Left._Current - _Right._Current)) // strengthened
requires sized_sentinel_for<_Base_iterator, _Base_iterator>
{
const auto _Diff = _Left._Current - _Right._Current;
if constexpr (forward_range<_Base>) {
return (_Diff + _Left._Missing - _Right._Missing) / _Left._Stride;
} else {
if (_Diff < 0) {
return -_Div_ceil(-_Diff, _Left._Stride);
} else {
return _Div_ceil(_Diff, _Left._Stride);
}
}
}
_NODISCARD friend constexpr difference_type operator-(default_sentinel_t, const _Iterator& _It)
noexcept(noexcept(_It._End - _It._Current)) // strengthened
requires sized_sentinel_for<_Base_sentinel, _Base_iterator>
{
return _Div_ceil(_It._End - _It._Current, _It._Stride);
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _It, default_sentinel_t)
noexcept(noexcept(_It._End - _It._Current)) // strengthened
requires sized_sentinel_for<_Base_sentinel, _Base_iterator>
{
return -_Div_ceil(_It._End - _It._Current, _It._Stride);
}
_NODISCARD friend constexpr range_rvalue_reference_t<_Base> iter_move(const _Iterator& _It)
noexcept(noexcept(_RANGES iter_move(_It._Current))) {
return _RANGES iter_move(_It._Current);
}
friend constexpr void iter_swap(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_RANGES iter_swap(_Left._Current, _Right._Current)))
requires indirectly_swappable<_Base_iterator>
{
return _RANGES iter_swap(_Left._Current, _Right._Current);
}
};
public:
constexpr explicit stride_view(_Vw _Range_, range_difference_t<_Vw> _Stride_)
noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Range(_STD move(_Range_)), _Stride(_Stride_) {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Stride > 0, "stride must be greater than 0");
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) // strengthened
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr range_difference_t<_Vw> stride() const noexcept {
return _Stride;
}
_NODISCARD constexpr auto begin() noexcept(
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) // strengthened
requires (!_Simple_view<_Vw>)
{
return _Iterator<false>{this, _RANGES begin(_Range)};
}
_NODISCARD constexpr auto begin() const noexcept(
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<const _Vw>>) // strengthened
requires range<const _Vw>
{
return _Iterator<true>{this, _RANGES begin(_Range)};
}
_NODISCARD constexpr auto end() noexcept(noexcept(_RANGES distance(_Range)) && noexcept(_RANGES end(_Range))
&& is_nothrow_move_constructible_v<iterator_t<_Vw>>) // strengthened
requires (!_Simple_view<_Vw>)
{
if constexpr (common_range<_Vw> && sized_range<_Vw> && forward_range<_Vw>) {
const auto _Missing =
static_cast<range_difference_t<_Vw>>(_Stride - _RANGES distance(_Range) % _Stride);
if (_Missing == _Stride) {
return _Iterator<false>{this, _RANGES end(_Range)};
} else {
return _Iterator<false>{this, _RANGES end(_Range), _Missing};
}
} else if constexpr (common_range<_Vw> && !bidirectional_range<_Vw>) {
return _Iterator<false>{this, _RANGES end(_Range)};
} else {
return default_sentinel;
}
}
_NODISCARD constexpr auto end() const
noexcept(noexcept(_RANGES distance(_Range)) && noexcept(_RANGES end(_Range))
&& is_nothrow_move_constructible_v<iterator_t<const _Vw>>) // strengthened
requires range<const _Vw>
{
if constexpr (common_range<const _Vw> && sized_range<const _Vw> && forward_range<const _Vw>) {
const auto _Missing =
static_cast<range_difference_t<_Vw>>(_Stride - _RANGES distance(_Range) % _Stride);
if (_Missing == _Stride) {
return _Iterator<true>{this, _RANGES end(_Range)};
} else {
return _Iterator<true>{this, _RANGES end(_Range), _Missing};
}
} else if constexpr (common_range<const _Vw> && !bidirectional_range<const _Vw>) {
return _Iterator<true>{this, _RANGES end(_Range)};
} else {
return default_sentinel;
}
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES distance(_Range))) // strengthened
requires sized_range<_Vw>
{
return _To_unsigned_like(_Div_ceil(_RANGES distance(_Range), _Stride));
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES distance(_Range))) // strengthened
requires sized_range<const _Vw>
{
return _To_unsigned_like(_Div_ceil(_RANGES distance(_Range), _Stride));
}
};
template <class _Rng>
stride_view(_Rng&&, range_difference_t<_Rng>) -> stride_view<views::all_t<_Rng>>;
template <class _Vw>
constexpr bool enable_borrowed_range<stride_view<_Vw>> = enable_borrowed_range<_Vw>;
template <class _Rng>
constexpr auto _Compile_time_max_size<stride_view<_Rng>> = _Compile_time_max_size<_Rng>;
template <class _Rng>
constexpr auto _Compile_time_max_size<const stride_view<_Rng>> = _Compile_time_max_size<const _Rng>;
namespace views {
struct _Stride_fn {
template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Rng&& _Range, const range_difference_t<_Rng> _Stride) _CONST_CALL_OPERATOR
noexcept(noexcept(stride_view(_STD forward<_Rng>(_Range), _Stride)))
requires requires { stride_view(_STD forward<_Rng>(_Range), _Stride); }
{
return stride_view(_STD forward<_Rng>(_Range), _Stride);
}
template <class _Ty>
requires constructible_from<decay_t<_Ty>, _Ty>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty&& _Stride) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Ty>, _Ty>) {
return _Range_closure<_Stride_fn, decay_t<_Ty>>{_STD forward<_Ty>(_Stride)};
}
};
_EXPORT_STD inline constexpr _Stride_fn stride;
} // namespace views
template <class... _RangeTypes>
concept _Zip_is_common = (sizeof...(_RangeTypes) == 1 && (common_range<_RangeTypes> && ...))
|| (!(bidirectional_range<_RangeTypes> && ...) && (common_range<_RangeTypes> && ...))
|| ((random_access_range<_RangeTypes> && ...) && (sized_range<_RangeTypes> && ...));
template <class _CallbackType>
constexpr auto _Tuple_transform_closure(_CallbackType& _Callback) noexcept {
return [&_Callback]<class... _ViewTupleTypes>(_ViewTupleTypes&&... _View_tuples) noexcept(
noexcept(tuple<invoke_result_t<_CallbackType&, _ViewTupleTypes>...>{
_STD invoke(_Callback, _STD forward<_ViewTupleTypes>(_View_tuples))...})) {
return tuple<invoke_result_t<_CallbackType&, _ViewTupleTypes>...>{
_STD invoke(_Callback, _STD forward<_ViewTupleTypes>(_View_tuples))...};
};
}
template <class _CallbackType, class _TupleType>
constexpr auto _Tuple_transform(_CallbackType&& _Callback, _TupleType&& _Tuple) noexcept(noexcept(
_STD apply(_Tuple_transform_closure(_Callback), _STD forward<_TupleType>(_Tuple)))) /* strengthened */ {
return _STD apply(_Tuple_transform_closure(_Callback), _STD forward<_TupleType>(_Tuple));
}
template <class _CallbackType>
constexpr auto _Tuple_for_each_closure(_CallbackType& _Callback) noexcept {
return [&_Callback]<class... _ViewTupleTypes>(_ViewTupleTypes&&... _View_tuples) noexcept(
noexcept(((void) (_STD invoke(_Callback, _STD forward<_ViewTupleTypes>(_View_tuples))), ...))) {
((void) (_STD invoke(_Callback, _STD forward<_ViewTupleTypes>(_View_tuples))), ...);
};
}
template <class _CallbackType, class _TupleType>
constexpr void _Tuple_for_each(_CallbackType&& _Callback, _TupleType&& _Tuple) noexcept(
noexcept(_STD apply(_Tuple_for_each_closure(_Callback), _STD forward<_TupleType>(_Tuple)))) /* strengthened */ {
_STD apply(_Tuple_for_each_closure(_Callback), _STD forward<_TupleType>(_Tuple));
}
template <bool _IsConst, class... _Views>
concept _All_random_access = (random_access_range<_Maybe_const<_IsConst, _Views>> && ...);
template <bool _IsConst, class... _Views>
concept _All_bidirectional = (bidirectional_range<_Maybe_const<_IsConst, _Views>> && ...);
template <bool _IsConst, class... _Views>
concept _All_forward = (forward_range<_Maybe_const<_IsConst, _Views>> && ...);
template <class _ResultType, class... _LHSTupleTypes, class... _RHSTupleTypes>
requires (sizeof...(_LHSTupleTypes) == sizeof...(_RHSTupleTypes))
_NODISCARD constexpr _ResultType _Zip_get_smallest_distance(
const tuple<_LHSTupleTypes...>& _Lhs_tuple, const tuple<_RHSTupleTypes...>& _Rhs_tuple)
// clang-format off
noexcept((noexcept(static_cast<_ResultType>(
_STD declval<const _LHSTupleTypes&>() - _STD declval<const _RHSTupleTypes&>())) && ...)) {
constexpr bool _Is_noexcept = (noexcept(static_cast<_ResultType>(
_STD declval<const _LHSTupleTypes&>() - _STD declval<const _RHSTupleTypes&>())) && ...);
// clang-format on
const auto _Get_smallest_distance_closure = [&_Lhs_tuple,
&_Rhs_tuple]<size_t _FirstIdx /* = 0 */, size_t... _Idxs>(
index_sequence<_FirstIdx, _Idxs...>) noexcept(_Is_noexcept) {
const _ResultType _First_size = static_cast<_ResultType>(_STD get<0>(_Lhs_tuple) - _STD get<0>(_Rhs_tuple));
if (_First_size == 0) {
return static_cast<_ResultType>(0);
}
const initializer_list<_ResultType> _Sizes = {
_First_size, (_STD get<_Idxs>(_Lhs_tuple) - _STD get<_Idxs>(_Rhs_tuple))...};
return _First_size < 0 ? static_cast<_ResultType>((_RANGES max)(_Sizes))
: static_cast<_ResultType>((_RANGES min)(_Sizes));
};
return _Get_smallest_distance_closure(index_sequence_for<_LHSTupleTypes...>{});
}
template <class... _LHSTupleTypes, class... _RHSTupleTypes>
requires (sizeof...(_LHSTupleTypes) == sizeof...(_RHSTupleTypes))
_NODISCARD constexpr bool _Zip_iterator_sentinel_equal(
const tuple<_LHSTupleTypes...>& _Lhs_tuple, const tuple<_RHSTupleTypes...>& _Rhs_tuple)
noexcept((noexcept(_STD declval<const _LHSTupleTypes&>() == _STD declval<const _RHSTupleTypes&>()) && ...)) {
const auto _Evaluate_equality_closure =
[&_Lhs_tuple, &_Rhs_tuple]<size_t... _Indices>(index_sequence<_Indices...>) noexcept(
(noexcept(_STD declval<const _LHSTupleTypes&>() == _STD declval<const _RHSTupleTypes&>())&&...)) {
return ((_STD get<_Indices>(_Lhs_tuple) == _STD get<_Indices>(_Rhs_tuple)) || ... || false);
};
return _Evaluate_equality_closure(index_sequence_for<_LHSTupleTypes...>{});
}
template <class _Func, class... _Views>
concept _Zip_transform_constraints =
move_constructible<_Func> && is_object_v<_Func> && (sizeof...(_Views) > 0) && (input_range<_Views> && ...)
&& (view<_Views> && ...) && regular_invocable<_Func&, range_reference_t<_Views>...>
&& _Can_reference<invoke_result_t<_Func&, range_reference_t<_Views>...>>;
_EXPORT_STD template <input_range... _ViewTypes>
requires (view<_ViewTypes> && ...) && (sizeof...(_ViewTypes) > 0)
class zip_view : public view_interface<zip_view<_ViewTypes...>> {
private:
/* [[no_unique_address]] */ tuple<_ViewTypes...> _Views;
template <bool _IsConst>
struct _Category_base {};
template <bool _IsConst>
requires _All_forward<_IsConst, _ViewTypes...>
struct _Category_base<_IsConst> {
using iterator_category = input_iterator_tag;
};
template <bool _IsConst>
class _Iterator : public _Category_base<_IsConst> {
private:
friend zip_view;
#if defined(__clang__) && __clang_major__ <= 18 // TRANSITION, Clang 19 (was thought to be LLVM-61763)
public:
#else // ^^^ workaround / no workaround vvv
template <class _Func, class... _OtherViews>
requires _Zip_transform_constraints<_Func, _OtherViews...>
friend class zip_transform_view;
#endif // ^^^ no workaround ^^^
using _My_tuple = tuple<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>...>;
/* [[no_unique_address]] */ _My_tuple _Current;
constexpr explicit _Iterator(_My_tuple _Current_)
noexcept(is_nothrow_move_constructible_v<_My_tuple>) // strengthened
: _Current(_STD move(_Current_)) {}
public:
using iterator_concept = conditional_t<_All_random_access<_IsConst, _ViewTypes...>,
random_access_iterator_tag,
conditional_t<_All_bidirectional<_IsConst, _ViewTypes...>, bidirectional_iterator_tag,
conditional_t<_All_forward<_IsConst, _ViewTypes...>, forward_iterator_tag, input_iterator_tag>>>;
using value_type = tuple<range_value_t<_Maybe_const<_IsConst, _ViewTypes>>...>;
using difference_type = common_type_t<range_difference_t<_Maybe_const<_IsConst, _ViewTypes>>...>;
_Iterator() = default;
constexpr _Iterator(_Iterator<!_IsConst> _Rhs) noexcept(
(is_nothrow_convertible_v<iterator_t<_ViewTypes>, iterator_t<const _ViewTypes>> && ...)) // strengthened
requires (_IsConst && (convertible_to<iterator_t<_ViewTypes>, iterator_t<const _ViewTypes>> && ...))
: _Current(_STD move(_Rhs._Current)) {}
_NODISCARD constexpr auto operator*() const
noexcept((noexcept(*(_STD declval<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>&>()))
&& ...)) /* strengthened */ {
return _Tuple_transform(
[](auto& _Itr) _STATIC_CALL_OPERATOR noexcept(noexcept(*_Itr)) -> decltype(auto) { return *_Itr; },
_Current);
}
constexpr _Iterator& operator++() noexcept(
noexcept(_Tuple_for_each([](auto& _Itr) _STATIC_CALL_OPERATOR noexcept(noexcept(++_Itr)) { ++_Itr; },
_Current))) /* strengthened */ {
_Tuple_for_each([](auto& _Itr) _STATIC_CALL_OPERATOR noexcept(noexcept(++_Itr)) { ++_Itr; }, _Current);
return *this;
}
constexpr void operator++(int) noexcept(noexcept(++(_STD declval<_Iterator>()))) /* strengthened */ {
++*this;
}
constexpr _Iterator operator++(int) noexcept(
noexcept(++(_STD declval<_Iterator>())) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires _All_forward<_IsConst, _ViewTypes...>
{
auto _Temp = *this;
++*this;
return _Temp;
}
constexpr _Iterator& operator--() noexcept(noexcept(_Tuple_for_each(
[](auto& _Itr) _STATIC_CALL_OPERATOR noexcept(noexcept(--_Itr)) { --_Itr; }, _Current))) // strengthened
requires _All_bidirectional<_IsConst, _ViewTypes...>
{
_Tuple_for_each([](auto& _Itr) _STATIC_CALL_OPERATOR noexcept(noexcept(--_Itr)) { --_Itr; }, _Current);
return *this;
}
constexpr _Iterator operator--(int) noexcept(
noexcept(--(_STD declval<_Iterator>())) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires _All_bidirectional<_IsConst, _ViewTypes...>
{
auto _Temp = *this;
--*this;
return _Temp;
}
constexpr _Iterator& operator+=(const difference_type _Off)
noexcept((noexcept(_STD declval<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>&>() +=
static_cast<iter_difference_t<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>>>(_Off))
&& ...)) // strengthened
requires _All_random_access<_IsConst, _ViewTypes...>
{
_Tuple_for_each(
[&_Off]<class _IteratorType>(_IteratorType& _Itr) noexcept(
noexcept(_Itr += static_cast<iter_difference_t<_IteratorType>>(_Off))) {
_Itr += static_cast<iter_difference_t<_IteratorType>>(_Off);
},
_Current);
return *this;
}
constexpr _Iterator& operator-=(const difference_type _Off)
noexcept((noexcept(_STD declval<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>&>() -=
static_cast<iter_difference_t<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>>>(_Off))
&& ...)) // strengthened
requires _All_random_access<_IsConst, _ViewTypes...>
{
_Tuple_for_each(
[&_Off]<class _IteratorType>(_IteratorType& _Itr) noexcept(
noexcept(_Itr -= static_cast<iter_difference_t<_IteratorType>>(_Off))) {
_Itr -= static_cast<iter_difference_t<_IteratorType>>(_Off);
},
_Current);
return *this;
}
_NODISCARD constexpr auto operator[](const difference_type _Where) const noexcept(
(noexcept((_STD declval<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>&>())
[static_cast<iter_difference_t<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>>>(_Where)])
&& ...)) // strengthened
requires _All_random_access<_IsConst, _ViewTypes...>
{
return _Tuple_transform(
[&_Where]<class _IteratorType>(_IteratorType& _Itr) noexcept(
noexcept(_Itr[static_cast<iter_difference_t<_IteratorType>>(_Where)])) -> decltype(auto) {
return _Itr[static_cast<iter_difference_t<_IteratorType>>(_Where)];
},
_Current);
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Lhs, const _Iterator& _Rhs)
noexcept(noexcept(_Zip_iterator_sentinel_equal(_Lhs._Current, _Rhs._Current))) // strengthened
requires (equality_comparable<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>> && ...)
{
if constexpr (!_Zip_is_common<_Maybe_const<_IsConst, _ViewTypes>...>
|| _All_random_access<_IsConst, _ViewTypes...> || sizeof...(_ViewTypes) == 1) {
return _STD get<0>(_Lhs._Current) == _STD get<0>(_Rhs._Current);
} else {
return _Zip_iterator_sentinel_equal(_Lhs._Current, _Rhs._Current);
}
}
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Lhs, const _Iterator& _Rhs)
requires _All_random_access<_IsConst, _ViewTypes...>
{
return _Lhs._Current <=> _Rhs._Current;
}
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _Lhs, const difference_type _Rhs)
noexcept(noexcept(_STD declval<_Iterator&>() += _Rhs)
&& is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires _All_random_access<_IsConst, _ViewTypes...>
{
auto _Modified_iterator = _Lhs;
_Modified_iterator += _Rhs;
return _Modified_iterator;
}
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Lhs, const _Iterator& _Rhs)
noexcept(noexcept(_Rhs + _Lhs)) /* strengthened */
requires _All_random_access<_IsConst, _ViewTypes...>
{
return _Rhs + _Lhs;
}
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _Lhs, const difference_type _Rhs)
noexcept(noexcept(_STD declval<_Iterator&>() -= _Rhs)
&& is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires _All_random_access<_IsConst, _ViewTypes...>
{
auto _Modified_iterator = _Lhs;
_Modified_iterator -= _Rhs;
return _Modified_iterator;
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Lhs, const _Iterator& _Rhs)
noexcept(noexcept(_Zip_get_smallest_distance<difference_type>(_STD declval<_My_tuple>(),
_STD declval<_My_tuple>()))) // strengthened
requires (sized_sentinel_for<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>,
iterator_t<_Maybe_const<_IsConst, _ViewTypes>>>
&& ...)
{
return _Zip_get_smallest_distance<difference_type>(_Lhs._Current, _Rhs._Current);
}
_NODISCARD friend constexpr auto iter_move(const _Iterator& _Itr) noexcept(
(noexcept(_RANGES iter_move(_STD declval<const iterator_t<_Maybe_const<_IsConst, _ViewTypes>>&>()))
&& ...)
&& (is_nothrow_move_constructible_v<range_rvalue_reference_t<_Maybe_const<_IsConst, _ViewTypes>>>
&& ...)) {
return _Tuple_transform(_RANGES iter_move, _Itr._Current);
}
friend constexpr void iter_swap(const _Iterator& _Lhs, const _Iterator& _Rhs)
noexcept((noexcept(_RANGES iter_swap(_STD declval<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>&>(),
_STD declval<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>&>()))
&& ...))
requires (indirectly_swappable<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>> && ...)
{
const auto _Swap_every_pair_closure =
[&_Lhs, &_Rhs]<size_t... _Indices>(index_sequence<_Indices...>) noexcept(noexcept(
((_RANGES iter_swap(_STD get<_Indices>(_Lhs._Current), _STD get<_Indices>(_Rhs._Current))),
...))) {
((_RANGES iter_swap(_STD get<_Indices>(_Lhs._Current), _STD get<_Indices>(_Rhs._Current))),
...);
};
_Swap_every_pair_closure(index_sequence_for<_ViewTypes...>{});
}
};
template <bool _IsConst>
class _Sentinel {
private:
friend zip_view;
using _My_tuple = tuple<sentinel_t<_Maybe_const<_IsConst, _ViewTypes>>...>;
/* [[no_unique_address]] */ _My_tuple _End;
constexpr explicit _Sentinel(_My_tuple _End_)
noexcept(is_nothrow_copy_constructible_v<_My_tuple>) // strengthened
: _End(_End_) {}
template <bool _IteratorConst>
_NODISCARD static constexpr const auto& _Get_iterator_tuple(
const _Iterator<_IteratorConst>& _Itr) noexcept {
// NOTE: This function is necessary because friend functions are never
// member functions, and friendship is not transitive.
return _Itr._Current;
}
public:
_Sentinel() = default;
constexpr _Sentinel(_Sentinel<!_IsConst> _Rhs) noexcept(
(is_nothrow_convertible_v<sentinel_t<_ViewTypes>, sentinel_t<const _ViewTypes>> && ...)) // strengthened
requires (_IsConst && (convertible_to<sentinel_t<_ViewTypes>, sentinel_t<const _ViewTypes>> && ...))
: _End(_STD move(_Rhs._End)) {}
template <bool _IteratorConst>
requires (sentinel_for<sentinel_t<_Maybe_const<_IsConst, _ViewTypes>>,
iterator_t<_Maybe_const<_IteratorConst, _ViewTypes>>>
&& ...)
_NODISCARD friend constexpr bool operator==(const _Iterator<_IteratorConst>& _Lhs, const _Sentinel& _Rhs)
noexcept(
noexcept(_Zip_iterator_sentinel_equal(_Get_iterator_tuple(_Lhs), _Rhs._End))) /* strengthened */ {
return _Zip_iterator_sentinel_equal(_Get_iterator_tuple(_Lhs), _Rhs._End);
}
template <bool _IteratorConst>
requires (sized_sentinel_for<sentinel_t<_Maybe_const<_IsConst, _ViewTypes>>,
iterator_t<_Maybe_const<_IteratorConst, _ViewTypes>>>
&& ...)
_NODISCARD friend constexpr common_type_t<range_difference_t<_Maybe_const<_IteratorConst, _ViewTypes>>...>
operator-(const _Iterator<_IteratorConst>& _Lhs, const _Sentinel& _Rhs)
noexcept(noexcept(_Zip_get_smallest_distance<
common_type_t<range_difference_t<_Maybe_const<_IteratorConst, _ViewTypes>>...>>(
_Get_iterator_tuple(_Lhs), _Rhs._End))) /* strengthened */ {
using _Difference_type = common_type_t<range_difference_t<_Maybe_const<_IteratorConst, _ViewTypes>>...>;
return _Zip_get_smallest_distance<_Difference_type>(_Get_iterator_tuple(_Lhs), _Rhs._End);
}
template <bool _IteratorConst>
requires (sized_sentinel_for<sentinel_t<_Maybe_const<_IsConst, _ViewTypes>>,
iterator_t<_Maybe_const<_IteratorConst, _ViewTypes>>>
&& ...)
_NODISCARD friend constexpr common_type_t<range_difference_t<_Maybe_const<_IteratorConst, _ViewTypes>>...>
operator-(const _Sentinel& _Lhs, const _Iterator<_IteratorConst>& _Rhs)
noexcept(noexcept(-(_Rhs - _Lhs))) /* strengthened */ {
return -(_Rhs - _Lhs);
}
};
template <bool _IsConst>
_NODISCARD static consteval bool _Is_end_noexcept() noexcept {
if constexpr (!_Zip_is_common<_Maybe_const<_IsConst, _ViewTypes>...>) {
return noexcept(_Sentinel<_IsConst>{
_Tuple_transform(_RANGES end, _STD declval<_Maybe_const<_IsConst, tuple<_ViewTypes...>>&>())});
} else if constexpr ((random_access_range<_Maybe_const<_IsConst, _ViewTypes>> && ...)) {
// Operations on iter_difference_t values must be noexcept, so we only
// need to check the noexcept of begin().
return noexcept(_STD declval<_Maybe_const<_IsConst, zip_view>&>().begin());
} else {
return noexcept(_Iterator<_IsConst>{
_Tuple_transform(_RANGES end, _STD declval<_Maybe_const<_IsConst, tuple<_ViewTypes...>>&>())});
}
}
static constexpr auto _Size_closure = [](auto... _Sizes) _STATIC_CALL_OPERATOR noexcept {
using _Common_unsigned_type = _Make_unsigned_like_t<common_type_t<decltype(_Sizes)...>>;
return (_RANGES min)({static_cast<_Common_unsigned_type>(_Sizes)...});
};
public:
zip_view() noexcept((is_nothrow_default_constructible_v<_ViewTypes> && ...)) = default;
constexpr explicit zip_view(_ViewTypes... _Args)
noexcept((is_nothrow_move_constructible_v<_ViewTypes> && ...)) // strengthened
: _Views(_STD move(_Args)...) {}
_NODISCARD constexpr auto begin()
noexcept(noexcept(_Iterator<false>{_Tuple_transform(_RANGES begin, _Views)})) // strengthened
requires (!(_Simple_view<_ViewTypes> && ...))
{
return _Iterator<false>{_Tuple_transform(_RANGES begin, _Views)};
}
_NODISCARD constexpr auto begin() const
noexcept(noexcept(_Iterator<true>{_Tuple_transform(_RANGES begin, _Views)})) // strengthened
requires (range<const _ViewTypes> && ...)
{
return _Iterator<true>{_Tuple_transform(_RANGES begin, _Views)};
}
_NODISCARD constexpr auto end() noexcept(_Is_end_noexcept<false>()) // strengthened
requires (!(_Simple_view<_ViewTypes> && ...))
{
if constexpr (!_Zip_is_common<_ViewTypes...>) {
return _Sentinel<false>{_Tuple_transform(_RANGES end, _Views)};
} else if constexpr ((random_access_range<_ViewTypes> && ...)) {
return begin() + static_cast<iter_difference_t<_Iterator<false>>>(size());
} else {
return _Iterator<false>{_Tuple_transform(_RANGES end, _Views)};
}
}
_NODISCARD constexpr auto end() const noexcept(_Is_end_noexcept<true>()) // strengthened
requires (range<const _ViewTypes> && ...)
{
if constexpr (!_Zip_is_common<const _ViewTypes...>) {
return _Sentinel<true>{_Tuple_transform(_RANGES end, _Views)};
} else if constexpr ((random_access_range<const _ViewTypes> && ...)) {
return begin() + static_cast<iter_difference_t<_Iterator<true>>>(size());
} else {
return _Iterator<true>{_Tuple_transform(_RANGES end, _Views)};
}
}
_NODISCARD constexpr auto size()
noexcept(noexcept(_STD apply(_Size_closure, _Tuple_transform(_RANGES size, _Views)))) // strengthened
requires (sized_range<_ViewTypes> && ...)
{
return _STD apply(_Size_closure, _Tuple_transform(_RANGES size, _Views));
}
_NODISCARD constexpr auto size() const
noexcept(noexcept(_STD apply(_Size_closure, _Tuple_transform(_RANGES size, _Views)))) // strengthened
requires (sized_range<const _ViewTypes> && ...)
{
return _STD apply(_Size_closure, _Tuple_transform(_RANGES size, _Views));
}
};
template <class... _RangeTypes>
zip_view(_RangeTypes&&...) -> zip_view<views::all_t<_RangeTypes>...>;
template <class... _ViewTypes>
constexpr bool enable_borrowed_range<zip_view<_ViewTypes...>> = (enable_borrowed_range<_ViewTypes> && ...);
template <class... _Rngs>
_NODISCARD consteval auto _Zip_view_compile_time_max_size() {
using _Size_type = common_type_t<decltype(_Compile_time_max_size<_Rngs>)...>;
return (_STD min)({static_cast<_Size_type>(_Compile_time_max_size<_Rngs>)...});
}
template <class... _Rngs>
constexpr auto _Compile_time_max_size<zip_view<_Rngs...>> = _Zip_view_compile_time_max_size<_Rngs...>();
template <class... _Rngs>
constexpr auto _Compile_time_max_size<const zip_view<_Rngs...>> = _Zip_view_compile_time_max_size<const _Rngs...>();
namespace views {
struct _Zip_fn {
private:
template <class... _Types>
_NODISCARD static consteval bool _Is_invocation_noexcept() {
if constexpr (sizeof...(_Types) == 0) {
// NOTE: views::empty<tuple<>> is nothrow copy-constructible.
return true;
} else {
return noexcept(zip_view<views::all_t<_Types>...>(_STD declval<_Types>()...));
}
}
public:
template <class... _Types>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Types&&... _Args) _CONST_CALL_OPERATOR
noexcept(_Is_invocation_noexcept<_Types...>())
requires (sizeof...(_Types) == 0)
|| requires { zip_view<views::all_t<_Types>...>(_STD forward<_Types>(_Args)...); }
{
if constexpr (sizeof...(_Types) == 0) {
return empty_view<tuple<>>{};
} else {
return zip_view<views::all_t<_Types>...>(_STD forward<_Types>(_Args)...);
}
}
};
_EXPORT_STD inline constexpr _Zip_fn zip{};
} // namespace views
template <class _Func, class... _ViewTypes>
concept _Can_const_iterate_zip_transform_view =
range<const zip_view<_ViewTypes...>> && regular_invocable<const _Func&, range_reference_t<const _ViewTypes>...>;
_EXPORT_STD template <class _Func, class... _ViewTypes>
requires _Zip_transform_constraints<_Func, _ViewTypes...>
class zip_transform_view : public view_interface<zip_transform_view<_Func, _ViewTypes...>> {
private:
using _Inner_view = zip_view<_ViewTypes...>;
/* [[no_unique_address]] */ _Movable_box<_Func> _Function;
/* [[no_unique_address]] */ _Inner_view _Zip;
template <bool _IsConst>
using _Ziperator = iterator_t<_Maybe_const<_IsConst, _Inner_view>>;
template <bool _IsConst>
using _Zentinel = sentinel_t<_Maybe_const<_IsConst, _Inner_view>>;
template <bool _IsConst>
struct _Category_base {};
template <bool _IsConst>
requires forward_range<_Maybe_const<_IsConst, _Inner_view>>
struct _Category_base<_IsConst> {
private:
template <class _Tag_type>
static constexpr bool _Iterators_derive_from_tag =
(derived_from<
typename iterator_traits<iterator_t<_Maybe_const<_IsConst, _ViewTypes>>>::iterator_category,
_Tag_type>
&& ...);
using _Invoke_t = invoke_result_t<_Maybe_const<_IsConst, _Func>&,
range_reference_t<_Maybe_const<_IsConst, _ViewTypes>>...>;
public:
using iterator_category = conditional_t<!is_reference_v<_Invoke_t>, input_iterator_tag,
conditional_t<_Iterators_derive_from_tag<random_access_iterator_tag>, random_access_iterator_tag,
conditional_t<_Iterators_derive_from_tag<bidirectional_iterator_tag>, bidirectional_iterator_tag,
conditional_t<_Iterators_derive_from_tag<forward_iterator_tag>, forward_iterator_tag,
input_iterator_tag>>>>;
};
template <bool _IsConst>
class _Iterator : public _Category_base<_IsConst> {
private:
friend zip_transform_view;
using _Parent_t = _Maybe_const<_IsConst, zip_transform_view>;
using _Base_t = _Maybe_const<_IsConst, _Inner_view>;
_Parent_t* _Parent = nullptr;
/* [[no_unique_address]] */ _Ziperator<_IsConst> _Inner;
constexpr _Iterator(_Parent_t& _Parent_, _Ziperator<_IsConst> _Inner_)
noexcept(is_nothrow_move_constructible_v<_Ziperator<_IsConst>>) // strengthened
: _Parent(_STD addressof(_Parent_)), _Inner(_STD move(_Inner_)) {}
public:
using iterator_concept = _Ziperator<_IsConst>::iterator_concept;
using value_type = remove_cvref_t<invoke_result_t<_Maybe_const<_IsConst, _Func>&,
range_reference_t<_Maybe_const<_IsConst, _ViewTypes>>...>>;
using difference_type = range_difference_t<_Base_t>;
_Iterator() = default;
constexpr _Iterator(_Iterator<!_IsConst> _Rhs)
noexcept(is_nothrow_convertible_v<_Ziperator<false>, _Ziperator<_IsConst>>) // strengthened
requires (_IsConst && convertible_to<_Ziperator<false>, _Ziperator<_IsConst>>)
: _Parent(_Rhs._Parent), _Inner(_STD move(_Rhs._Inner)) {}
_NODISCARD constexpr decltype(auto) operator*() const
noexcept(noexcept(_STD apply(_Dereference_closure(), _Inner._Current))) {
return _STD apply(_Dereference_closure(), _Inner._Current);
}
constexpr _Iterator& operator++() noexcept(noexcept(++_Inner)) /* strengthened */ {
++_Inner;
return *this;
}
constexpr void operator++(int) noexcept(noexcept(++_STD declval<_Iterator&>())) /* strengthened */ {
++*this;
}
constexpr _Iterator operator++(int) noexcept(is_nothrow_copy_constructible_v<_Iterator> //
&& noexcept(++*this)) // strengthened
requires forward_range<_Base_t>
{
auto _Temp = *this;
++*this;
return _Temp;
}
constexpr _Iterator& operator--() noexcept(noexcept(--_Inner)) // strengthened
requires bidirectional_range<_Base_t>
{
--_Inner;
return *this;
}
constexpr _Iterator operator--(int) noexcept(is_nothrow_copy_constructible_v<_Iterator> //
&& noexcept(--*this)) // strengthened
requires bidirectional_range<_Base_t>
{
auto _Temp = *this;
--*this;
return _Temp;
}
constexpr _Iterator& operator+=(const difference_type _Off)
noexcept(noexcept(_Inner += _Off)) // strengthened
requires random_access_range<_Base_t>
{
_Inner += _Off;
return *this;
}
constexpr _Iterator& operator-=(const difference_type _Off)
noexcept(noexcept(_Inner -= _Off)) // strengthened
requires random_access_range<_Base_t>
{
_Inner -= _Off;
return *this;
}
_NODISCARD constexpr decltype(auto) operator[](const difference_type _Where) const
noexcept(noexcept(_STD apply(_Subscript_closure(_Where), _Inner._Current))) // strengthened
requires random_access_range<_Base_t>
{
return _STD apply(_Subscript_closure(_Where), _Inner._Current);
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Lhs, const _Iterator& _Rhs)
noexcept(noexcept(_Lhs._Inner == _Rhs._Inner)) // strengthened
requires equality_comparable<_Ziperator<_IsConst>>
{
return _Lhs._Inner == _Rhs._Inner;
}
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Lhs, const _Iterator& _Rhs)
noexcept(noexcept(_Lhs._Inner <=> _Rhs._Inner)) // strengthened
requires random_access_range<_Base_t>
{
return _Lhs._Inner <=> _Rhs._Inner;
}
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _Lhs, const difference_type _Rhs)
noexcept(noexcept(_Iterator{*_Lhs._Parent, _Lhs._Inner + _Rhs})) // strengthened
requires random_access_range<_Base_t>
{
return _Iterator{*_Lhs._Parent, _Lhs._Inner + _Rhs};
}
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Lhs, const _Iterator& _Rhs)
noexcept(noexcept(_Iterator{*_Rhs._Parent, _Rhs._Inner + _Lhs})) // strengthened
requires random_access_range<_Base_t>
{
return _Iterator{*_Rhs._Parent, _Rhs._Inner + _Lhs};
}
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _Lhs, const difference_type _Rhs)
noexcept(noexcept(_Iterator{*_Lhs._Parent, _Lhs._Inner - _Rhs})) // strengthened
requires random_access_range<_Base_t>
{
return _Iterator{*_Lhs._Parent, _Lhs._Inner - _Rhs};
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Lhs,
const _Iterator& _Rhs) noexcept(noexcept(_Lhs._Inner - _Rhs._Inner)) // strengthened
requires sized_sentinel_for<_Ziperator<_IsConst>, _Ziperator<_IsConst>>
{
return _Lhs._Inner - _Rhs._Inner;
}
private:
_NODISCARD constexpr auto _Dereference_closure() const noexcept {
return [this](const auto&... _Itrs) noexcept(noexcept(_STD invoke(*_Parent->_Function,
*_Itrs...))) -> decltype(auto) { return _STD invoke(*_Parent->_Function, *_Itrs...); };
}
_NODISCARD constexpr auto _Subscript_closure(const difference_type _Where) const noexcept {
return [this, _Where]<class... _Iterator_types>(const _Iterator_types&... _Iters) noexcept(
noexcept(_STD invoke(*_Parent->_Function,
_Iters[static_cast<iter_difference_t<_Iterator_types>>(_Where)]...))) -> decltype(auto) {
return _STD invoke(
*_Parent->_Function, _Iters[static_cast<iter_difference_t<_Iterator_types>>(_Where)]...);
};
}
};
template <bool _IsConst>
class _Sentinel {
private:
friend zip_transform_view;
// TRANSITION, DevCom-10253131
template <bool _IteratorConst>
using _Iter_sent_difference_type = range_difference_t<_Maybe_const<_IteratorConst, _Inner_view>>;
/* [[no_unique_address]] */ _Zentinel<_IsConst> _Inner;
constexpr explicit _Sentinel(_Zentinel<_IsConst> _Inner_)
noexcept(is_nothrow_copy_constructible_v<_Zentinel<_IsConst>>) // strengthened
: _Inner(_Inner_) {}
template <bool _IteratorConst>
_NODISCARD static constexpr const auto& _Get_iterator_inner(
const _Iterator<_IteratorConst>& _Itr) noexcept {
return _Itr._Inner;
}
public:
_Sentinel() = default;
constexpr _Sentinel(_Sentinel<!_IsConst> _Rhs)
noexcept(is_nothrow_convertible_v<_Zentinel<false>, _Zentinel<_IsConst>>) // strengthened
requires (_IsConst && convertible_to<_Zentinel<false>, _Zentinel<_IsConst>>)
: _Inner(_STD move(_Rhs._Inner)) {}
template <bool _IteratorConst>
requires sentinel_for<_Zentinel<_IsConst>, _Ziperator<_IteratorConst>>
_NODISCARD friend constexpr bool operator==(const _Iterator<_IteratorConst>& _Lhs, const _Sentinel& _Rhs)
noexcept(noexcept(_Get_iterator_inner(_Lhs) == _Rhs._Inner)) /* strengthened */ {
return _Get_iterator_inner(_Lhs) == _Rhs._Inner;
}
template <bool _IteratorConst>
requires sized_sentinel_for<_Zentinel<_IsConst>, _Ziperator<_IteratorConst>>
_NODISCARD friend constexpr _Iter_sent_difference_type<_IteratorConst> // TRANSITION, DevCom-10253131
operator-(const _Iterator<_IteratorConst>& _Lhs, const _Sentinel & _Rhs)
noexcept(noexcept(_Get_iterator_inner(_Lhs) - _Rhs._Inner)) /* strengthened */ {
return _Get_iterator_inner(_Lhs) - _Rhs._Inner;
}
template <bool _IteratorConst>
requires sized_sentinel_for<_Zentinel<_IsConst>, _Ziperator<_IteratorConst>>
_NODISCARD friend constexpr _Iter_sent_difference_type<_IteratorConst> // TRANSITION, DevCom-10253131
operator-(const _Sentinel & _Lhs, const _Iterator<_IteratorConst>& _Rhs)
noexcept(noexcept(_Lhs._Inner - _Get_iterator_inner(_Rhs))) /* strengthened */ {
return _Lhs._Inner - _Get_iterator_inner(_Rhs);
}
};
template <bool _IsConst>
_NODISCARD static consteval bool _Is_end_noexcept() noexcept {
if constexpr (common_range<_Maybe_const<_IsConst, _Inner_view>>) {
return noexcept(_Iterator<_IsConst>{_STD declval<_Maybe_const<_IsConst, zip_transform_view>&>(),
_STD declval<_Maybe_const<_IsConst, _Inner_view>&>().end()});
} else {
return noexcept(_Sentinel<_IsConst>{_STD declval<_Maybe_const<_IsConst, _Inner_view>&>().end()});
}
}
public:
zip_transform_view() = default;
constexpr explicit zip_transform_view(_Func _Function_, _ViewTypes... _Views)
noexcept(is_nothrow_move_constructible_v<_Func>
&& is_nothrow_constructible_v<_Inner_view, remove_reference_t<_ViewTypes>&&...>) // strengthened
: _Function(in_place, _STD move(_Function_)), _Zip(_STD move(_Views)...) {}
_NODISCARD constexpr auto begin() noexcept(noexcept(_Iterator<false>{*this, _Zip.begin()})) /* strengthened */ {
return _Iterator<false>{*this, _Zip.begin()};
}
_NODISCARD constexpr auto begin() const noexcept(noexcept(_Iterator<true>{*this, _Zip.begin()})) // strengthened
requires _Can_const_iterate_zip_transform_view<_Func, _ViewTypes...>
{
return _Iterator<true>{*this, _Zip.begin()};
}
_NODISCARD constexpr auto end() noexcept(_Is_end_noexcept<false>()) /* strengthened */ {
if constexpr (common_range<_Inner_view>) {
return _Iterator<false>{*this, _Zip.end()};
} else {
return _Sentinel<false>{_Zip.end()};
}
}
_NODISCARD constexpr auto end() const noexcept(_Is_end_noexcept<true>()) // strengthened
requires _Can_const_iterate_zip_transform_view<_Func, _ViewTypes...>
{
if constexpr (common_range<const _Inner_view>) {
return _Iterator<true>{*this, _Zip.end()};
} else {
return _Sentinel<true>{_Zip.end()};
}
}
_NODISCARD constexpr auto size() noexcept(noexcept(_Zip.size())) // strengthened
requires sized_range<_Inner_view>
{
return _Zip.size();
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_Zip.size())) // strengthened
requires sized_range<const _Inner_view>
{
return _Zip.size();
}
};
template <class _Func, class... _Ranges>
zip_transform_view(_Func, _Ranges&&...) -> zip_transform_view<_Func, views::all_t<_Ranges>...>;
template <class _Fn, class... _Rngs>
constexpr auto _Compile_time_max_size<zip_transform_view<_Fn, _Rngs...>> =
_Compile_time_max_size<zip_view<_Rngs...>>;
template <class _Fn, class... _Rngs>
constexpr auto _Compile_time_max_size<const zip_transform_view<_Fn, _Rngs...>> =
_Compile_time_max_size<const zip_view<_Rngs...>>;
namespace views {
struct _Zip_transform_fn {
private:
template <class _Func, class... _Types>
_NODISCARD static consteval bool _Is_invocation_noexcept() {
if constexpr (sizeof...(_Types) == 0) {
return true;
} else {
return noexcept(zip_transform_view(_STD declval<_Func>(), _STD declval<_Types>()...));
}
}
template <class _Func, class... _Types>
_NODISCARD static consteval bool _Enable_cpo() {
if constexpr (sizeof...(_Types) == 0) {
// This is a more efficient implementation of the CPO requirements listed in
// N4950 [range.zip.transform.overview]/2.1.1.
using _Decayed_func = decay_t<_Func>;
if constexpr (move_constructible<_Decayed_func> && regular_invocable<_Decayed_func&>) {
return !is_void_v<invoke_result_t<_Decayed_func&>>;
} else {
return false;
}
} else {
return requires(_Func&& _Function, _Types&&... _Args) {
zip_transform_view(_STD forward<_Func>(_Function), _STD forward<_Types>(_Args)...);
};
}
}
public:
template <class _Func, class... _Types>
requires (_Enable_cpo<_Func, _Types...>())
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
_Func&& _Function, _Types&&... _Args) _CONST_CALL_OPERATOR
noexcept(_Is_invocation_noexcept<_Func, _Types...>()) /* strengthened */ {
if constexpr (sizeof...(_Types) == 0) {
using _Decayed_func = decay_t<_Func>;
return empty_view<decay_t<invoke_result_t<_Decayed_func&>>>{};
} else {
return zip_transform_view(_STD forward<_Func>(_Function), _STD forward<_Types>(_Args)...);
}
}
};
_EXPORT_STD inline constexpr _Zip_transform_fn zip_transform{};
} // namespace views
template <class _Ty, size_t>
using _Repeat_type = _Ty;
template <class _Ty, class _Indices>
struct _Repeated_tuple_impl;
template <class _Ty, size_t... _Indices>
struct _Repeated_tuple_impl<_Ty, index_sequence<_Indices...>> {
using type = tuple<_Repeat_type<_Ty, _Indices>...>;
};
template <class _Ty, size_t _Nx>
using _Repeated_tuple = _Repeated_tuple_impl<_Ty, make_index_sequence<_Nx>>::type;
template <class _Fn, class _Ty, class _Indices>
constexpr bool _Regular_invocable_with_repeated_type_impl = false;
template <class _Fn, class _Ty, size_t... _Indices>
constexpr bool _Regular_invocable_with_repeated_type_impl<_Fn, _Ty, index_sequence<_Indices...>> =
regular_invocable<_Fn, _Repeat_type<_Ty, _Indices>...>;
template <class _Fn, class _Ty, size_t _Nx>
concept _Regular_invocable_with_repeated_type =
_Regular_invocable_with_repeated_type_impl<_Fn, _Ty, make_index_sequence<_Nx>>;
template <class _Fn, class _Ty, class _Indices>
struct _Invoke_result_with_repeated_type_impl;
template <class _Fn, class _Ty, size_t... _Indices>
struct _Invoke_result_with_repeated_type_impl<_Fn, _Ty, index_sequence<_Indices...>> {
using type = invoke_result_t<_Fn, _Repeat_type<_Ty, _Indices>...>;
};
template <class _Fn, class _Ty, size_t _Nx>
using _Invoke_result_with_repeated_type =
_Invoke_result_with_repeated_type_impl<_Fn, _Ty, make_index_sequence<_Nx>>::type;
template <class _Vw, class _Fn, size_t _Nx>
concept _Adjacent_transform_constraints =
(_Nx > 0) && forward_range<_Vw> && view<_Vw> && is_object_v<_Fn> && move_constructible<_Fn>
&& _Regular_invocable_with_repeated_type<_Fn&, range_reference_t<_Vw>, _Nx>
&& _Can_reference<_Invoke_result_with_repeated_type<_Fn&, range_reference_t<_Vw>, _Nx>>;
_EXPORT_STD template <class _Vw, class _Fn, size_t _Nx>
requires _Adjacent_transform_constraints<_Vw, _Fn, _Nx>
class adjacent_transform_view;
_EXPORT_STD template <forward_range _Vw, size_t _Nx>
requires view<_Vw> && (_Nx > 0)
class adjacent_view : public view_interface<adjacent_view<_Vw, _Nx>> {
private:
/* [[no_unique_address]] */ _Vw _Range{};
struct _As_sentinel {
explicit _As_sentinel() = default;
};
template <bool _Const>
class _Iterator {
private:
friend adjacent_view;
#if defined(__clang__) && __clang_major__ <= 18 // TRANSITION, Clang 19 (was thought to be LLVM-61763)
public:
#else // ^^^ workaround / no workaround vvv
template <class _Vw2, class _Fn, size_t _Nx2>
requires _Adjacent_transform_constraints<_Vw2, _Fn, _Nx2>
friend class adjacent_transform_view;
#endif // ^^^ no workaround ^^^
using _Base = _Maybe_const<_Const, _Vw>;
using _Base_iterator = iterator_t<_Base>;
array<_Base_iterator, _Nx> _Current{};
constexpr _Iterator(_Base_iterator _First, sentinel_t<_Base> _Last) {
_Current.front() = _First;
for (size_t _Ix = 1; _Ix < _Nx; ++_Ix) {
_RANGES advance(_First, 1, _Last);
_Current[_Ix] = _First;
}
}
constexpr _Iterator(_As_sentinel, _Base_iterator _First, _Base_iterator _Last) {
if constexpr (!bidirectional_range<_Base>) {
_Current.fill(_Last);
} else {
_Current.back() = _Last;
for (size_t _Ix = 1; _Ix < _Nx; ++_Ix) {
_RANGES advance(_Last, -1, _First);
_Current[_Nx - 1 - _Ix] = _Last;
}
}
}
template <size_t... _Indices>
constexpr _Iterator(_Iterator<!_Const>& _Other, index_sequence<_Indices...>)
noexcept(is_nothrow_convertible_v<iterator_t<_Vw>, _Base_iterator>)
requires _Const && convertible_to<iterator_t<_Vw>, _Base_iterator>
: _Current{_STD move(_Other._Current[_Indices])...} {}
public:
using iterator_category = input_iterator_tag;
using iterator_concept = conditional_t<random_access_range<_Base>, random_access_iterator_tag,
conditional_t<bidirectional_range<_Base>, bidirectional_iterator_tag, forward_iterator_tag>>;
using value_type = _Repeated_tuple<range_value_t<_Base>, _Nx>;
using difference_type = range_difference_t<_Base>;
_Iterator() = default;
constexpr _Iterator(_Iterator<!_Const> _Other)
noexcept(is_nothrow_convertible_v<iterator_t<_Vw>, _Base_iterator>) // strengthened
requires _Const && convertible_to<iterator_t<_Vw>, _Base_iterator>
: _Iterator(_Other, make_index_sequence<_Nx>{}) {}
_NODISCARD constexpr auto operator*() const {
return _RANGES _Tuple_transform(
[](auto& _It) _STATIC_CALL_OPERATOR -> decltype(auto) { return *_It; }, _Current);
}
constexpr _Iterator& operator++() noexcept(noexcept(++_Current.front())) /* strengthened */ {
for (_Base_iterator& _It : _Current) {
++_It;
}
return *this;
}
constexpr _Iterator operator++(int)
noexcept(noexcept(++*this) && is_nothrow_copy_constructible_v<_Iterator>) /* strengthened */ {
auto _Tmp = *this;
++*this;
return _Tmp;
}
constexpr _Iterator& operator--() noexcept(noexcept(--_Current.back())) // strengthened
requires bidirectional_range<_Base>
{
for (_Base_iterator& _It : _Current) {
--_It;
}
return *this;
}
constexpr _Iterator operator--(int)
noexcept(noexcept(--*this) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires bidirectional_range<_Base>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
constexpr _Iterator& operator+=(const difference_type _Off)
noexcept(noexcept(_Current.back() += _Off)) // strengthened
requires random_access_range<_Base>
{
for (_Base_iterator& _It : _Current) {
_It += _Off;
}
return *this;
}
constexpr _Iterator& operator-=(const difference_type _Off)
noexcept(noexcept(_Current.back() -= _Off)) // strengthened
requires random_access_range<_Base>
{
for (_Base_iterator& _It : _Current) {
_It -= _Off;
}
return *this;
}
_NODISCARD constexpr auto operator[](const difference_type _Off) const
requires random_access_range<_Base>
{
return _RANGES _Tuple_transform([&](auto& _It) -> decltype(auto) { return _It[_Off]; }, _Current);
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept(
noexcept(_STD _Fake_copy_init<bool>(_Left._Current.back() == _Right._Current.back()))) // strengthened
{
return _Left._Current.back() == _Right._Current.back();
}
_NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept(
noexcept(_STD _Fake_copy_init<bool>(_Left._Current.back() < _Right._Current.back()))) // strengthened
requires random_access_range<_Base>
{
return _Left._Current.back() < _Right._Current.back();
}
_NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Right < _Left)) // strengthened
requires random_access_range<_Base>
{
return _Right < _Left;
}
_NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(!(_Right < _Left))) // strengthened
requires random_access_range<_Base>
{
return !(_Right < _Left);
}
_NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(!(_Left < _Right))) // strengthened
requires random_access_range<_Base>
{
return !(_Left < _Right);
}
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current.back() <=> _Right._Current.back())) // strengthened
requires random_access_range<_Base> && three_way_comparable<_Base_iterator>
{
return _Left._Current.back() <=> _Right._Current.back();
}
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off)
noexcept(noexcept(_STD declval<_Iterator&>() += _Off)
&& is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires random_access_range<_Base>
{
auto _Tmp = _It;
_Tmp += _Off;
return _Tmp;
}
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It)
noexcept(noexcept(_STD declval<_Iterator&>() += _Off)
&& is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires random_access_range<_Base>
{
auto _Tmp = _It;
_Tmp += _Off;
return _Tmp;
}
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off)
noexcept(noexcept(_STD declval<_Iterator&>() -= _Off)
&& is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires random_access_range<_Base>
{
auto _Tmp = _It;
_Tmp -= _Off;
return _Tmp;
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Current.back() - _Right._Current.back())) // strengthened
requires sized_sentinel_for<_Base_iterator, _Base_iterator>
{
return _Left._Current.back() - _Right._Current.back();
}
_NODISCARD friend constexpr auto iter_move(const _Iterator& _It)
noexcept(noexcept(_RANGES iter_move(_STD declval<const _Base_iterator&>()))
&& is_nothrow_move_constructible_v<range_rvalue_reference_t<_Base>>) {
return _RANGES _Tuple_transform(_RANGES iter_move, _It._Current);
}
friend constexpr void iter_swap(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_RANGES iter_swap(_STD declval<_Base_iterator>(), _STD declval<_Base_iterator>())))
requires indirectly_swappable<_Base_iterator>
{
for (size_t _Ix = 0; _Ix < _Nx; ++_Ix) {
_RANGES iter_swap(_Left._Current[_Ix], _Right._Current[_Ix]);
}
}
};
template <bool _Const>
class _Sentinel {
private:
friend adjacent_view;
using _Base = _Maybe_const<_Const, _Vw>;
using _Base_sentinel = sentinel_t<_Base>;
/* [[no_unique_address]] */ _Base_sentinel _End{};
constexpr explicit _Sentinel(_Base_sentinel _Last_)
noexcept(is_nothrow_move_constructible_v<_Base_sentinel>) // strengthened
: _End(_STD move(_Last_)) {}
template <bool _OtherConst>
requires sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD constexpr bool _Equal(const _Iterator<_OtherConst>& _It) const
noexcept(noexcept(_STD _Fake_copy_init<bool>(_It._Current.back() == _End))) {
return _It._Current.back() == _End;
}
template <bool _OtherConst>
requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> _Distance_from(
const _Iterator<_OtherConst>& _It) const noexcept(noexcept(_End - _It._Current.back())) {
return _End - _It._Current.back();
}
public:
_Sentinel() = default;
constexpr _Sentinel(_Sentinel<!_Const> _Other)
noexcept(is_nothrow_convertible_v<sentinel_t<_Vw>, _Base_sentinel>) // strengthened
requires _Const && convertible_to<sentinel_t<_Vw>, _Base_sentinel>
: _End(_STD move(_Other._End)) {}
template <bool _OtherConst>
requires sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _It, const _Sentinel& _Se)
noexcept(noexcept(_Se._Equal(_It))) /* strengthened */ {
return _Se._Equal(_It);
}
template <bool _OtherConst>
requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(
const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) noexcept( //
noexcept(_Se._Distance_from(_It))) /* strengthened */ {
return -_Se._Distance_from(_It);
}
template <bool _OtherConst>
requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(
const _Sentinel& _Se, const _Iterator<_OtherConst>& _It) noexcept( //
noexcept(_Se._Distance_from(_It))) /* strengthened */ {
return _Se._Distance_from(_It);
}
};
public:
adjacent_view()
requires default_initializable<_Vw>
= default;
constexpr explicit adjacent_view(_Vw _Range_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
: _Range(_STD move(_Range_)) {}
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) // strengthened
requires copy_constructible<_Vw>
{
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}
_NODISCARD constexpr auto begin()
requires (!_Simple_view<_Vw>)
{
return _Iterator<false>{_RANGES begin(_Range), _RANGES end(_Range)};
}
_NODISCARD constexpr auto begin() const
requires range<const _Vw>
{
return _Iterator<true>{_RANGES begin(_Range), _RANGES end(_Range)};
}
_NODISCARD constexpr auto end()
requires (!_Simple_view<_Vw>)
{
if constexpr (common_range<_Vw>) {
return _Iterator<false>{_As_sentinel{}, _RANGES begin(_Range), _RANGES end(_Range)};
} else {
return _Sentinel<false>{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto end() const
requires range<const _Vw>
{
if constexpr (common_range<const _Vw>) {
return _Iterator<true>{_As_sentinel{}, _RANGES begin(_Range), _RANGES end(_Range)};
} else {
return _Sentinel<true>{_RANGES end(_Range)};
}
}
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Range))) // strengthened
requires sized_range<_Vw>
{
using _Size_type = decltype(_RANGES size(_Range));
using _Common_size_type = common_type_t<_Size_type, size_t>;
auto _Size = static_cast<_Common_size_type>(_RANGES size(_Range));
_Size -= (_STD min)(_Size, static_cast<_Common_size_type>(_Nx - 1));
return static_cast<_Size_type>(_Size);
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Range))) // strengthened
requires sized_range<const _Vw>
{
using _Size_type = decltype(_RANGES size(_Range));
using _Common_size_type = common_type_t<_Size_type, size_t>;
auto _Size = static_cast<_Common_size_type>(_RANGES size(_Range));
_Size -= (_STD min)(_Size, static_cast<_Common_size_type>(_Nx - 1));
return static_cast<_Size_type>(_Size);
}
};
template <class _Rng, size_t _Nx>
constexpr bool enable_borrowed_range<adjacent_view<_Rng, _Nx>> = enable_borrowed_range<_Rng>;
template <class _Rng, size_t _Nx>
_NODISCARD consteval auto _Adjacent_view_compile_time_max_size() {
using _Size_type = common_type_t<decltype(_Compile_time_max_size<_Rng>), size_t>;
auto _Size = static_cast<_Size_type>(_Compile_time_max_size<_Rng>);
_Size -= (_STD min)(_Size, static_cast<_Size_type>(_Nx - 1));
return static_cast<_Size_type>(_Size);
}
template <class _Rng, size_t _Nx>
constexpr auto _Compile_time_max_size<adjacent_view<_Rng, _Nx>> = _Adjacent_view_compile_time_max_size<_Rng, _Nx>();
template <class _Rng, size_t _Nx>
constexpr auto _Compile_time_max_size<const adjacent_view<_Rng, _Nx>> =
_Adjacent_view_compile_time_max_size<const _Rng, _Nx>();
namespace views {
template <size_t _Nx>
class _Adjacent_fn : public _Pipe::_Base<_Adjacent_fn<_Nx>> {
public:
template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range) _CONST_CALL_OPERATOR
noexcept(noexcept(adjacent_view<views::all_t<_Rng>, _Nx>{_STD forward<_Rng>(_Range)}))
requires requires { adjacent_view<views::all_t<_Rng>, _Nx>{_STD forward<_Rng>(_Range)}; }
{
return adjacent_view<views::all_t<_Rng>, _Nx>{_STD forward<_Rng>(_Range)};
}
template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&&) _CONST_CALL_OPERATOR noexcept
requires (_Nx == 0) && forward_range<_Rng>
{
return empty_view<tuple<>>{};
}
};
_EXPORT_STD template <size_t _Nx>
constexpr _Adjacent_fn<_Nx> adjacent;
_EXPORT_STD inline constexpr _Adjacent_fn<2> pairwise;
} // namespace views
_EXPORT_STD template <class _Vw, class _Fn, size_t _Nx>
requires _Adjacent_transform_constraints<_Vw, _Fn, _Nx>
class adjacent_transform_view : public view_interface<adjacent_transform_view<_Vw, _Fn, _Nx>> {
private:
using _Inner_view = adjacent_view<_Vw, _Nx>;
template <bool _Const>
using _Inner_iterator = iterator_t<_Maybe_const<_Const, _Inner_view>>;
template <bool _Const>
using _Inner_sentinel = sentinel_t<_Maybe_const<_Const, _Inner_view>>;
/* [[no_unique_address]] */ _Movable_box<_Fn> _Func;
/* [[no_unique_address]] */ _Inner_view _Inner;
template <bool _Const>
class _Iterator {
private:
friend adjacent_transform_view;
using _Parent_t = _Maybe_const<_Const, adjacent_transform_view>;
using _Base = _Maybe_const<_Const, _Vw>;
_Parent_t* _Parent = nullptr;
_Inner_iterator<_Const> _Inner;
constexpr _Iterator(_Parent_t& _Parent_, _Inner_iterator<_Const> _Inner_)
noexcept(is_nothrow_move_constructible_v<_Inner_iterator<_Const>>) // strengthened
: _Parent(_STD addressof(_Parent_)), _Inner(_STD move(_Inner_)) {}
_NODISCARD static consteval auto _Get_iterator_category() noexcept {
if constexpr (!is_reference_v<_Invoke_result_with_repeated_type<_Maybe_const<_Const, _Fn>&,
range_reference_t<_Base>, _Nx>>) {
return input_iterator_tag{};
} else {
using _Cat = iterator_traits<iterator_t<_Base>>::iterator_category;
if constexpr (derived_from<_Cat, random_access_iterator_tag>) {
return random_access_iterator_tag{};
} else if constexpr (derived_from<_Cat, bidirectional_iterator_tag>) {
return bidirectional_iterator_tag{};
} else if constexpr (derived_from<_Cat, forward_iterator_tag>) {
return forward_iterator_tag{};
} else {
return input_iterator_tag{};
}
}
}
template <size_t... _Indices>
_NODISCARD static consteval bool _Is_indirection_nothrow(index_sequence<_Indices...>) noexcept {
return noexcept(_STD invoke(_STD declval<_Maybe_const<_Const, _Fn>&>(),
*_STD get<_Indices>(_STD declval<const _Inner_iterator<_Const>&>()._Current)...));
}
public:
using iterator_category = decltype(_Get_iterator_category());
using iterator_concept = _Inner_iterator<_Const>::iterator_concept;
using value_type = remove_cvref_t<
_Invoke_result_with_repeated_type<_Maybe_const<_Const, _Fn>&, range_reference_t<_Base>, _Nx>>;
using difference_type = range_difference_t<_Base>;
_Iterator() = default;
constexpr _Iterator(_Iterator<!_Const> _Other)
requires _Const && convertible_to<_Inner_iterator<false>, _Inner_iterator<_Const>>
: _Parent(_Other._Parent), _Inner(_STD move(_Other._Inner)) {}
_NODISCARD constexpr decltype(auto) operator*() const
noexcept(_Is_indirection_nothrow(make_index_sequence<_Nx>{})) {
return _STD apply(
[&](const auto&... _Iters) -> decltype(auto) { return _STD invoke(*_Parent->_Func, *_Iters...); },
_Inner._Current);
}
constexpr _Iterator& operator++() noexcept(noexcept(++_Inner)) /* strengthened */ {
++_Inner;
return *this;
}
constexpr _Iterator operator++(int)
noexcept(noexcept(++*this) && is_nothrow_copy_constructible_v<_Iterator>) /* strengthened */ {
auto _Tmp = *this;
++*this;
return _Tmp;
}
constexpr _Iterator& operator--() noexcept(noexcept(--_Inner)) /* strengthened */
requires bidirectional_range<_Base>
{
--_Inner;
return *this;
}
constexpr _Iterator operator--(int)
noexcept(noexcept(--*this) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened
requires bidirectional_range<_Base>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
constexpr _Iterator& operator+=(const difference_type _Off)
noexcept(noexcept(_Inner += _Off)) // strengthened
requires random_access_range<_Base>
{
_Inner += _Off;
return *this;
}
constexpr _Iterator& operator-=(const difference_type _Off)
noexcept(noexcept(_Inner -= _Off)) // strengthened
requires random_access_range<_Base>
{
_Inner -= _Off;
return *this;
}
_NODISCARD constexpr decltype(auto) operator[](const difference_type _Off) const
requires random_access_range<_Base>
{
return _STD apply(
[&](const auto&... _Iters) -> decltype(auto) {
return _STD invoke(*_Parent->_Func, _Iters[_Off]...);
},
_Inner._Current);
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Inner == _Right._Inner)) /* strengthened */ {
return _Left._Inner == _Right._Inner;
}
_NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Inner < _Right._Inner)) // strengthened
requires random_access_range<_Base>
{
return _Left._Inner < _Right._Inner;
}
_NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Inner > _Right._Inner)) // strengthened
requires random_access_range<_Base>
{
return _Left._Inner > _Right._Inner;
}
_NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Inner <= _Right._Inner)) // strengthened
requires random_access_range<_Base>
{
return _Left._Inner <= _Right._Inner;
}
_NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Inner >= _Right._Inner)) // strengthened
requires random_access_range<_Base>
{
return _Left._Inner >= _Right._Inner;
}
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right)
noexcept(noexcept(_Left._Inner <=> _Right._Inner)) // strengthened
requires random_access_range<_Base> && three_way_comparable<_Inner_iterator<_Const>>
{
return _Left._Inner <=> _Right._Inner;
}
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept(
noexcept(_It._Inner + _Off) && is_nothrow_move_constructible_v<_Inner_iterator<_Const>>) // strengthened
requires random_access_range<_Base>
{
return _Iterator{*_It._Parent, _It._Inner + _Off};
}
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept(
noexcept(_It._Inner + _Off) && is_nothrow_move_constructible_v<_Inner_iterator<_Const>>) // strengthened
requires random_access_range<_Base>
{
return _Iterator{*_It._Parent, _It._Inner + _Off};
}
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept(
noexcept(_It._Inner - _Off) && is_nothrow_move_constructible_v<_Inner_iterator<_Const>>) // strengthened
requires random_access_range<_Base>
{
return _Iterator{*_It._Parent, _It._Inner - _Off};
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) //
noexcept(noexcept(_Left._Inner - _Right._Inner)) // strengthened
requires sized_sentinel_for<_Inner_iterator<_Const>, _Inner_iterator<_Const>>
{
return _Left._Inner - _Right._Inner;
}
};
template <bool _Const>
class _Sentinel {
private:
friend adjacent_transform_view;
/* [[no_unique_address]] */ _Inner_sentinel<_Const> _Inner;
constexpr explicit _Sentinel(_Inner_sentinel<_Const> _Inner_) : _Inner(_Inner_) {}
template <bool _OtherConst>
requires sentinel_for<_Inner_sentinel<_Const>, _Inner_iterator<_OtherConst>>
_NODISCARD constexpr bool _Equal(const _Iterator<_OtherConst>& _It) const
noexcept(noexcept(_It._Inner == _Inner)) {
return _It._Inner == _Inner;
}
template <bool _OtherConst>
requires sized_sentinel_for<_Inner_sentinel<_Const>, _Inner_iterator<_OtherConst>>
_NODISCARD constexpr range_difference_t<_Maybe_const<_OtherConst, _Inner_view>> _Distance_from(
const _Iterator<_OtherConst>& _It) const noexcept(noexcept(_Inner - _It._Inner)) {
return _Inner - _It._Inner;
}
public:
_Sentinel() = default;
constexpr _Sentinel(_Sentinel<!_Const> _Other)
requires _Const && convertible_to<_Inner_sentinel<false>, _Inner_sentinel<_Const>>
: _Inner(_STD move(_Other._Inner)) {}
template <bool _OtherConst>
requires sentinel_for<_Inner_sentinel<_Const>, _Inner_iterator<_OtherConst>>
_NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _It, const _Sentinel& _Se)
noexcept(noexcept(_Se._Equal(_It))) /* strengthened */ {
return _Se._Equal(_It);
}
template <bool _OtherConst>
requires sized_sentinel_for<_Inner_sentinel<_Const>, _Inner_iterator<_OtherConst>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Inner_view>> operator-(
const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) noexcept( //
noexcept(_Se._Distance_from(_It))) /* strengthened */ {
return -_Se._Distance_from(_It);
}
template <bool _OtherConst>
requires sized_sentinel_for<_Inner_sentinel<_Const>, _Inner_iterator<_OtherConst>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Inner_view>> operator-(
const _Sentinel& _Se, const _Iterator<_OtherConst>& _It) noexcept( //
noexcept(_Se._Distance_from(_It))) /* strengthened */ {
return _Se._Distance_from(_It);
}
};
public:
adjacent_transform_view() = default;
constexpr explicit adjacent_transform_view(_Vw _Range_, _Fn _Func_)
noexcept(is_nothrow_move_constructible_v<_Vw> && is_nothrow_move_constructible_v<_Fn>) // strengthened
: _Func(in_place, _STD move(_Func_)), _Inner(_STD move(_Range_)) {}
_NODISCARD constexpr _Vw base() const& noexcept(noexcept(_Inner.base())) // strengthened
requires copy_constructible<_Vw>
{
return _Inner.base();
}
_NODISCARD constexpr _Vw base() && noexcept(noexcept(_STD move(_Inner).base())) /* strengthened */ {
return _STD move(_Inner).base();
}
_NODISCARD constexpr auto begin() {
return _Iterator<false>{*this, _Inner.begin()};
}
_NODISCARD constexpr auto begin() const
requires range<const _Inner_view>
&& _Regular_invocable_with_repeated_type<const _Fn&, range_reference_t<const _Vw>, _Nx>
{
return _Iterator<true>{*this, _Inner.begin()};
}
_NODISCARD constexpr auto end() {
if constexpr (common_range<_Inner_view>) {
return _Iterator<false>{*this, _Inner.end()};
} else {
return _Sentinel<false>{_Inner.end()};
}
}
_NODISCARD constexpr auto end() const
requires range<const _Inner_view>
&& _Regular_invocable_with_repeated_type<const _Fn&, range_reference_t<const _Vw>, _Nx>
{
if constexpr (common_range<const _Inner_view>) {
return _Iterator<true>{*this, _Inner.end()};
} else {
return _Sentinel<true>{_Inner.end()};
}
}
_NODISCARD constexpr auto size() noexcept(noexcept(_Inner.size())) // strengthened
requires sized_range<_Inner_view>
{
return _Inner.size();
}
_NODISCARD constexpr auto size() const noexcept(noexcept(_Inner.size())) // strengthened
requires sized_range<const _Inner_view>
{
return _Inner.size();
}
};
template <class _Rng, class _Fn, size_t _Nx>
constexpr auto _Compile_time_max_size<adjacent_transform_view<_Rng, _Fn, _Nx>> =
_Compile_time_max_size<adjacent_view<_Rng, _Nx>>;
template <class _Rng, class _Fn, size_t _Nx>
constexpr auto _Compile_time_max_size<const adjacent_transform_view<_Rng, _Fn, _Nx>> =
_Compile_time_max_size<const adjacent_view<_Rng, _Nx>>;
namespace views {
template <size_t _Nx>
class _Adjacent_transform_fn {
public:
template <viewable_range _Rng, class _Fn>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&&, _Fn&& _Func) _CONST_CALL_OPERATOR
noexcept(noexcept(views::zip_transform(_STD forward<_Fn>(_Func))))
requires (_Nx == 0)
&& forward_range<_Rng> && requires { views::zip_transform(_STD forward<_Fn>(_Func)); }
{
return views::zip_transform(_STD forward<_Fn>(_Func));
}
template <viewable_range _Rng, class _Fn>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range, _Fn&& _Func) _CONST_CALL_OPERATOR
noexcept(noexcept(adjacent_transform_view<views::all_t<_Rng>, decay_t<_Fn>, _Nx>(
_STD forward<_Rng>(_Range), _STD forward<_Fn>(_Func))))
requires requires {
adjacent_transform_view<views::all_t<_Rng>, decay_t<_Fn>, _Nx>(
_STD forward<_Rng>(_Range), _STD forward<_Fn>(_Func));
}
{
return adjacent_transform_view<views::all_t<_Rng>, decay_t<_Fn>, _Nx>(
_STD forward<_Rng>(_Range), _STD forward<_Fn>(_Func));
}
template <class _Fn>
requires constructible_from<decay_t<_Fn>, _Fn>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Fn&& _Func) _CONST_CALL_OPERATOR
noexcept(is_nothrow_constructible_v<decay_t<_Fn>, _Fn>) {
return _Range_closure<_Adjacent_transform_fn, decay_t<_Fn>>{_STD forward<_Fn>(_Func)};
}
};
_EXPORT_STD template <size_t _Nx>
constexpr _Adjacent_transform_fn<_Nx> adjacent_transform;
_EXPORT_STD inline constexpr _Adjacent_transform_fn<2> pairwise_transform;
} // namespace views
template <bool _Const, class _First, class... _Rest>
concept _Cartesian_product_is_random_access =
(random_access_range<_Maybe_const<_Const, _First>> && ...
&& (random_access_range<_Maybe_const<_Const, _Rest>> && sized_range<_Maybe_const<_Const, _Rest>>) );
template <class _Rng>
concept _Cartesian_product_common_arg = common_range<_Rng> || (sized_range<_Rng> && random_access_range<_Rng>);
template <bool _Const, class _First, class... _Rest>
concept _Cartesian_product_is_bidirectional = (bidirectional_range<_Maybe_const<_Const, _First>> && ...
&& (bidirectional_range<_Maybe_const<_Const, _Rest>>
&& _Cartesian_product_common_arg<_Maybe_const<_Const, _Rest>>) );
template <class _First /*, class... _Rest*/>
concept _Cartesian_product_is_common = _Cartesian_product_common_arg<_First>;
template <class... _Rngs>
concept _Cartesian_product_is_sized = (sized_range<_Rngs> && ...);
template <bool _Const, template <class> class _FirstSent, class _First, class... _Rest>
concept _Cartesian_is_sized_sentinel =
(sized_sentinel_for<_FirstSent<_Maybe_const<_Const, _First>>, iterator_t<_Maybe_const<_Const, _First>>> && ...
&& (sized_range<_Maybe_const<_Const, _Rest>>
&& sized_sentinel_for<iterator_t<_Maybe_const<_Const, _Rest>>,
iterator_t<_Maybe_const<_Const, _Rest>>>) );
template <_Cartesian_product_common_arg _Rng>
_NODISCARD constexpr auto _Cartesian_common_arg_end(_Rng& _Range) {
if constexpr (common_range<_Rng>) {
return _RANGES end(_Range);
} else {
return _RANGES begin(_Range) + _RANGES distance(_Range);
}
}
template <class _Rng>
_NODISCARD consteval int _Cartesian_product_max_size_bit_width() {
using _Size_type = decltype(_Compile_time_max_size<_Rng>);
if constexpr (requires { _STD bit_width(_Compile_time_max_size<_Rng>); }) {
return _STD bit_width(_Compile_time_max_size<_Rng>);
} else {
return numeric_limits<_Size_type>::digits;
}
}
template <class... _Rngs>
requires (sizeof...(_Rngs) > 0)
_NODISCARD consteval auto _Cartesian_product_optimal_size_type() noexcept {
constexpr int _Optimal_size_type_bit_width = (_Cartesian_product_max_size_bit_width<_Rngs>() + ...);
if constexpr (_Optimal_size_type_bit_width <= 8) {
return uint8_t{};
} else if constexpr (_Optimal_size_type_bit_width <= 16) {
return uint16_t{};
} else if constexpr (_Optimal_size_type_bit_width <= 32) {
return uint32_t{};
} else if constexpr (_Optimal_size_type_bit_width <= 64) {
return uint64_t{};
} else {
return _Unsigned128{};
}
}
_EXPORT_STD template <input_range _First, forward_range... _Rest>
requires (view<_First> && ... && view<_Rest>)
class cartesian_product_view : public view_interface<cartesian_product_view<_First, _Rest...>> {
private:
template <bool _Const>
using _Optimal_size_type = decltype(_Cartesian_product_optimal_size_type<_Maybe_const<_Const, _First>,
_Maybe_const<_Const, _Rest>...>());
template <bool _Const>
using _Difference_type = common_type_t<_Make_signed_like_t<_Optimal_size_type<_Const>>,
range_difference_t<_Maybe_const<_Const, _First>>, range_difference_t<_Maybe_const<_Const, _Rest>>...>;
template <bool _Const>
using _Size_type = common_type_t<_Optimal_size_type<_Const>, range_size_t<_Maybe_const<_Const, _First>>,
range_size_t<_Maybe_const<_Const, _Rest>>...>;
/* [[no_unique_address]] */ tuple<_First, _Rest...> _Bases;
template <bool _Const>
class _Iterator {
private:
friend cartesian_product_view;
using _Parent_t = _Maybe_const<_Const, cartesian_product_view>;
_Parent_t* _Parent = nullptr;
tuple<iterator_t<_Maybe_const<_Const, _First>>, iterator_t<_Maybe_const<_Const, _Rest>>...> _Current;
template <size_t _Index = sizeof...(_Rest)>
constexpr void _Next() {
auto& _It = _STD get<_Index>(_Current);
++_It;
if constexpr (_Index > 0) {
auto& _Range = _STD get<_Index>(_Parent->_Bases);
if (_It == _RANGES end(_Range)) {
_It = _RANGES begin(_Range);
_Next<_Index - 1>();
}
}
}
template <size_t _Index = sizeof...(_Rest)>
constexpr void _Prev() {
auto& _It = _STD get<_Index>(_Current);
if constexpr (_Index > 0) {
auto& _Range = _STD get<_Index>(_Parent->_Bases);
if (_It == _RANGES begin(_Range)) {
_It = _Cartesian_common_arg_end(_Range);
_Prev<_Index - 1>();
}
}
--_It;
}
template <size_t... _Indices>
_NODISCARD constexpr bool _Entire_tail_at_begin(index_sequence<_Indices...>) const {
return ((_STD get<_Indices + 1>(_Current) == _RANGES begin(_STD get<_Indices + 1>(_Parent->_Bases)))
&& ...);
}
template <size_t _Index = sizeof...(_Rest)>
constexpr void _Advance(const _Difference_type<_Const> _Off) {
if (_Off == 0) {
return;
}
auto& _Range = _STD get<_Index>(_Parent->_Bases);
auto& _It = _STD get<_Index>(_Current);
using _Iter = remove_reference_t<decltype(_It)>;
using _Diff = _Difference_type<_Const>;
if constexpr (_Index > 0) {
const auto _Size = static_cast<_Diff>(_RANGES ssize(_Range));
const auto _Begin = _RANGES begin(_Range);
const auto _It_off = static_cast<_Diff>(_It - _Begin);
const auto _It_new_off = static_cast<_Diff>((_It_off + _Off) % _Size);
const auto _Next_off = static_cast<_Diff>((_It_off + _Off) / _Size);
if (_It_new_off < 0) {
_It = _Begin + static_cast<iter_difference_t<_Iter>>(_It_new_off + _Size);
_Advance<_Index - 1>(_Next_off - 1);
} else {
_It = _Begin + static_cast<iter_difference_t<_Iter>>(_It_new_off);
_Advance<_Index - 1>(_Next_off);
}
} else {
#if _ITERATOR_DEBUG_LEVEL != 0
const auto _It_off = static_cast<_Diff>(_It - _RANGES begin(_Range));
_STL_VERIFY(_It_off + _Off >= 0, "Cannot advance cartesian_product_view iterator before begin "
"(N4950 [range.cartesian.iterator]/19).");
if constexpr (sized_range<decltype(_Range)>) {
const auto _Size = static_cast<_Diff>(_RANGES ssize(_Range));
_STL_VERIFY(_It_off + _Off < _Size
|| (_It_off + _Off == _Size
&& _Entire_tail_at_begin(make_index_sequence<sizeof...(_Rest)>{})),
"Cannot advance cartesian_product_view iterator past end (N4950 "
"[range.cartesian.iterator]/19).");
}
#endif // _ITERATOR_DEBUG_LEVEL != 0
_It += static_cast<iter_difference_t<_Iter>>(_Off);
}
}
template <size_t... _Indices>
_NODISCARD constexpr bool _Is_end(index_sequence<_Indices...>) const {
return ((_STD get<_Indices>(_Current) == _RANGES end(_STD get<_Indices>(_Parent->_Bases))) || ...);
}
template <size_t... _Indices>
_NODISCARD constexpr auto _End_tuple(index_sequence<_Indices...>) const {
return tuple<sentinel_t<_Maybe_const<_Const, _First>>, iterator_t<_Maybe_const<_Const, _Rest>>...>{
_RANGES end(_STD get<0>(_Parent->_Bases)),
_RANGES begin(_STD get<_Indices + 1>(_Parent->_Bases))...};
}
template <size_t _Index = sizeof...(_Rest), class _Tuple>
_NODISCARD constexpr _Difference_type<_Const> _Distance_from(const _Tuple& _Tpl) const {
const auto _Diff =
static_cast<_Difference_type<_Const>>(_STD get<_Index>(_Current) - _STD get<_Index>(_Tpl));
if constexpr (_Index > 0) {
_Difference_type<_Const> _Result{1};
const auto _Size =
static_cast<_Difference_type<_Const>>(_RANGES size(_STD get<_Index>(_Parent->_Bases)));
[[maybe_unused]] const bool _Overflow =
_Mul_overflow(_Size, _Distance_from<_Index - 1>(_Tpl), _Result)
|| _Add_overflow(_Result, _Diff, _Result);
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(!_Overflow, "Scaled-sum cannot be represented by difference_type (N4950 "
"[range.cartesian.iterator]/8).");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Result;
} else {
return _Diff;
}
}
template <size_t... _Indices>
_NODISCARD static consteval bool _Is_iter_move_nothrow(index_sequence<_Indices...>) noexcept {
return conjunction_v<
is_nothrow_move_constructible<range_rvalue_reference_t<_Maybe_const<_Const, _First>>>,
is_nothrow_move_constructible<range_rvalue_reference_t<_Maybe_const<_Const, _Rest>>>...>
&& (noexcept(_RANGES iter_move(_STD get<_Indices>(_STD declval<const _Iterator&>()._Current)))
&& ...);
}
template <size_t... _Indices>
_NODISCARD static consteval bool _Is_iter_swap_nothrow(index_sequence<_Indices...>) noexcept {
return (noexcept(_RANGES iter_swap(_STD get<_Indices>(_STD declval<const _Iterator&>()._Current),
_STD get<_Indices>(_STD declval<const _Iterator&>()._Current)))
&& ...);
}
constexpr _Iterator(_Parent_t& _Parent_,
tuple<iterator_t<_Maybe_const<_Const, _First>>, iterator_t<_Maybe_const<_Const, _Rest>>...> _Current_)
: _Parent(_STD addressof(_Parent_)), _Current(_STD move(_Current_)) {}
public:
using iterator_category = input_iterator_tag;
using iterator_concept = conditional_t<_Cartesian_product_is_random_access<_Const, _First, _Rest...>,
random_access_iterator_tag,
conditional_t<_Cartesian_product_is_bidirectional<_Const, _First, _Rest...>, bidirectional_iterator_tag,
conditional_t<forward_range<_Maybe_const<_Const, _First>>, forward_iterator_tag,
input_iterator_tag>>>;
using value_type =
tuple<range_value_t<_Maybe_const<_Const, _First>>, range_value_t<_Maybe_const<_Const, _Rest>>...>;
using reference = tuple<range_reference_t<_Maybe_const<_Const, _First>>,
range_reference_t<_Maybe_const<_Const, _Rest>>...>;
using difference_type = _Difference_type<_Const>;
_Iterator() = default;
constexpr _Iterator(_Iterator<!_Const> _It)
requires _Const
&& (convertible_to<iterator_t<_First>, iterator_t<const _First>> && ...
&& convertible_to<iterator_t<_Rest>, iterator_t<const _Rest>>)
: _Parent(_It._Parent), _Current(_STD move(_It._Current)) {}
_NODISCARD constexpr auto operator*() const {
return _RANGES _Tuple_transform(
[](auto& _It) _STATIC_CALL_OPERATOR -> decltype(auto) { return *_It; }, _Current);
}
constexpr _Iterator& operator++() {
_Next();
return *this;
}
constexpr void operator++(int) {
++*this;
}
constexpr _Iterator operator++(int)
requires forward_range<_Maybe_const<_Const, _First>>
{
auto _Tmp = *this;
++*this;
return _Tmp;
}
constexpr _Iterator& operator--()
requires _Cartesian_product_is_bidirectional<_Const, _First, _Rest...>
{
_Prev();
return *this;
}
constexpr _Iterator operator--(int)
requires _Cartesian_product_is_bidirectional<_Const, _First, _Rest...>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}
constexpr _Iterator& operator+=(const difference_type _Off)
requires _Cartesian_product_is_random_access<_Const, _First, _Rest...>
{
_Advance(_Off);
return *this;
}
constexpr _Iterator& operator-=(const difference_type _Off)
requires _Cartesian_product_is_random_access<_Const, _First, _Rest...>
{
_Advance(-_Off);
return *this;
}
_NODISCARD constexpr reference operator[](const difference_type _Off) const
requires _Cartesian_product_is_random_access<_Const, _First, _Rest...>
{
return *(*this + _Off);
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right)
requires equality_comparable<iterator_t<_Maybe_const<_Const, _First>>>
{
return _Left._Current == _Right._Current;
}
_NODISCARD friend constexpr bool operator==(const _Iterator& _It, default_sentinel_t) {
return _It._Is_end(make_index_sequence<1 + sizeof...(_Rest)>{});
}
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right)
requires _All_random_access<_Const, _First, _Rest...>
{
return _Left._Current <=> _Right._Current;
}
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off)
requires _Cartesian_product_is_random_access<_Const, _First, _Rest...>
{
return _Iterator{_It} += _Off;
}
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It)
requires _Cartesian_product_is_random_access<_Const, _First, _Rest...>
{
return _It + _Off;
}
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off)
requires _Cartesian_product_is_random_access<_Const, _First, _Rest...>
{
return _Iterator{_It} -= _Off;
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right)
requires _Cartesian_is_sized_sentinel<_Const, iterator_t, _First, _Rest...>
{
return _Left._Distance_from(_Right._Current);
}
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _It, default_sentinel_t)
requires _Cartesian_is_sized_sentinel<_Const, sentinel_t, _First, _Rest...>
{
return _It._Distance_from(_It._End_tuple(make_index_sequence<sizeof...(_Rest)>{}));
}
_NODISCARD friend constexpr difference_type operator-(default_sentinel_t _Se, const _Iterator& _It)
requires _Cartesian_is_sized_sentinel<_Const, sentinel_t, _First, _Rest...>
{
return -(_It - _Se);
}
_NODISCARD friend constexpr auto iter_move(const _Iterator& _It)
noexcept(_Is_iter_move_nothrow(make_index_sequence<1 + sizeof...(_Rest)>{})) {
return _RANGES _Tuple_transform(_RANGES iter_move, _It._Current);
}
friend constexpr void iter_swap(const _Iterator& _Left, const _Iterator& _Right)
noexcept(_Is_iter_swap_nothrow(make_index_sequence<1 + sizeof...(_Rest)>{}))
requires (indirectly_swappable<iterator_t<_Maybe_const<_Const, _First>>> && ...
&& indirectly_swappable<iterator_t<_Maybe_const<_Const, _Rest>>>)
{
[&]<size_t... _Indices>(index_sequence<_Indices...>) {
(_RANGES iter_swap(_STD get<_Indices>(_Left._Current), _STD get<_Indices>(_Right._Current)), ...);
}(make_index_sequence<1 + sizeof...(_Rest)>{});
}
};
template <size_t _Index>
_NODISCARD constexpr auto _Begin_or_first_end([[maybe_unused]] const bool _Is_empty) {
if constexpr (_Index == 0) {
return _Is_empty ? _RANGES begin(_STD get<_Index>(_Bases))
: _Cartesian_common_arg_end(_STD get<_Index>(_Bases));
} else {
return _RANGES begin(_STD get<_Index>(_Bases));
}
}
template <size_t _Index>
_NODISCARD constexpr auto _Begin_or_first_end([[maybe_unused]] const bool _Is_empty) const {
if constexpr (_Index == 0) {
return _Is_empty ? _RANGES begin(_STD get<_Index>(_Bases))
: _Cartesian_common_arg_end(_STD get<_Index>(_Bases));
} else {
return _RANGES begin(_STD get<_Index>(_Bases));
}
}
public:
constexpr cartesian_product_view() = default;
constexpr explicit cartesian_product_view(_First _First_base, _Rest... _Other_bases) noexcept(
(is_nothrow_move_constructible_v<_First> && ... && is_nothrow_move_constructible_v<_Rest>) ) // strengthened
: _Bases(_STD move(_First_base), _STD move(_Other_bases)...) {}
_NODISCARD constexpr _Iterator<false> begin()
requires (!_Simple_view<_First> || ... || !_Simple_view<_Rest>)
{
return _Iterator<false>{*this, _RANGES _Tuple_transform(_RANGES begin, _Bases)};
}
_NODISCARD constexpr _Iterator<true> begin() const
requires (range<const _First> && ... && range<const _Rest>)
{
return _Iterator<true>{*this, _RANGES _Tuple_transform(_RANGES begin, _Bases)};
}
_NODISCARD constexpr _Iterator<false> end()
requires ((!_Simple_view<_First> || ... || !_Simple_view<_Rest>) && _Cartesian_product_is_common<_First>)
{
const bool _Is_empty = [&]<size_t... _Indices>(index_sequence<_Indices...>) {
return (_RANGES empty(_STD get<_Indices + 1>(_Bases)) || ... || false);
}(make_index_sequence<sizeof...(_Rest)>{});
const auto _Make_iter_tuple = [&]<size_t... _Indices>(index_sequence<_Indices...>) {
return tuple<iterator_t<_First>, iterator_t<_Rest>...>{_Begin_or_first_end<_Indices>(_Is_empty)...};
};
return _Iterator<false>{*this, _Make_iter_tuple(make_index_sequence<1 + sizeof...(_Rest)>{})};
}
_NODISCARD constexpr _Iterator<true> end() const
requires _Cartesian_product_is_common<const _First>
{
const bool _Is_empty = [&]<size_t... _Indices>(index_sequence<_Indices...>) {
return (_RANGES empty(_STD get<_Indices + 1>(_Bases)) || ... || false);
}(make_index_sequence<sizeof...(_Rest)>{});
const auto _Make_iter_tuple = [&]<size_t... _Indices>(index_sequence<_Indices...>) {
return tuple<iterator_t<const _First>, iterator_t<const _Rest>...>{
_Begin_or_first_end<_Indices>(_Is_empty)...};
};
return _Iterator<true>{*this, _Make_iter_tuple(make_index_sequence<1 + sizeof...(_Rest)>{})};
}
_NODISCARD constexpr default_sentinel_t end() const noexcept {
return default_sentinel;
}
_NODISCARD constexpr auto size()
requires _Cartesian_product_is_sized<_First, _Rest...>
{
return [&]<size_t... _Indices>(index_sequence<_Indices...>) {
#if _CONTAINER_DEBUG_LEVEL > 0
const array _Sizes = {static_cast<_Size_type<false>>(_RANGES size(_STD get<_Indices>(_Bases)))...};
const bool _Any_zero = ((_Sizes[_Indices] == 0) || ...);
if (_Any_zero) {
return _Size_type<false>{0};
}
_Size_type<false> _Product{1};
const bool _Overflow = (_Mul_overflow(_Product, _Sizes[_Indices], _Product) || ...);
_STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4950 "
"[range.cartesian.view]/10).");
return _Product;
#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL == 0 vvv
return (static_cast<_Size_type<false>>(_RANGES size(_STD get<_Indices>(_Bases))) * ...);
#endif // ^^^ _CONTAINER_DEBUG_LEVEL == 0 ^^^
}(make_index_sequence<1 + sizeof...(_Rest)>{});
}
_NODISCARD constexpr auto size() const
requires _Cartesian_product_is_sized<const _First, const _Rest...>
{
return [&]<size_t... _Indices>(index_sequence<_Indices...>) {
#if _CONTAINER_DEBUG_LEVEL > 0
const array _Sizes = {static_cast<_Size_type<true>>(_RANGES size(_STD get<_Indices>(_Bases)))...};
const bool _Any_zero = ((_Sizes[_Indices] == 0) || ...);
if (_Any_zero) {
return _Size_type<true>{0};
}
_Size_type<true> _Product{1};
const bool _Overflow = (_Mul_overflow(_Product, _Sizes[_Indices], _Product) || ...);
_STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4950 "
"[range.cartesian.view]/10).");
return _Product;
#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL == 0 vvv
return (static_cast<_Size_type<true>>(_RANGES size(_STD get<_Indices>(_Bases))) * ...);
#endif // ^^^ _CONTAINER_DEBUG_LEVEL == 0 ^^^
}(make_index_sequence<1 + sizeof...(_Rest)>{});
}
};
template <class... _Rngs>
cartesian_product_view(_Rngs&&...) -> cartesian_product_view<views::all_t<_Rngs>...>;
template <class... _Rngs>
_NODISCARD consteval auto _Cartesian_product_view_compile_time_max_size() {
using _Size_type = common_type_t<decltype(_Cartesian_product_optimal_size_type<_Rngs...>()),
decltype(_Compile_time_max_size<_Rngs>)...>;
_Size_type _Result{1};
const bool _Overflow =
(_Mul_overflow(static_cast<_Size_type>(_Compile_time_max_size<_Rngs>), _Result, _Result) || ...);
if (_Overflow) {
return (numeric_limits<_Size_type>::max)();
} else {
return _Result;
}
}
template <class... _Rngs>
constexpr auto _Compile_time_max_size<cartesian_product_view<_Rngs...>> =
_Cartesian_product_view_compile_time_max_size<_Rngs...>();
template <class... _Rngs>
constexpr auto _Compile_time_max_size<const cartesian_product_view<_Rngs...>> =
_Cartesian_product_view_compile_time_max_size<const _Rngs...>();
namespace views {
class _Cartesian_product_fn {
public:
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()() _CONST_CALL_OPERATOR noexcept {
return views::single(tuple{});
}
template <class... _Rngs>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rngs&&... _Ranges) _CONST_CALL_OPERATOR
noexcept(noexcept(cartesian_product_view<views::all_t<_Rngs>...>{_STD forward<_Rngs>(_Ranges)...}))
requires requires { cartesian_product_view<views::all_t<_Rngs>...>{_STD forward<_Rngs>(_Ranges)...}; }
{
return cartesian_product_view<views::all_t<_Rngs>...>{_STD forward<_Rngs>(_Ranges)...};
}
};
_EXPORT_STD inline constexpr _Cartesian_product_fn cartesian_product;
} // namespace views
#endif // _HAS_CXX23
} // namespace ranges
_EXPORT_STD namespace views = ranges::views;
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // ^^^ _HAS_CXX20 ^^^
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _RANGES_