зеркало из https://github.com/microsoft/STL.git
10353 строки
452 KiB
C++
10353 строки
452 KiB
C++
// ranges standard header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#pragma once
|
|
#ifndef _RANGES_
|
|
#define _RANGES_
|
|
#include <yvals_core.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
#ifndef __cpp_lib_ranges
|
|
_EMIT_STL_WARNING(STL4038, "The contents of <ranges> are available only with C++20 or later.");
|
|
#else // ^^^ !defined(__cpp_lib_ranges) / defined(__cpp_lib_ranges) vvv
|
|
#include <__msvc_int128.hpp>
|
|
#include <iosfwd>
|
|
#include <iterator>
|
|
#include <limits>
|
|
#include <span>
|
|
#include <string_view>
|
|
#include <tuple>
|
|
|
|
#if _HAS_CXX23
|
|
#include <array>
|
|
#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>
|
|
|
|
template <class _Ty>
|
|
inline constexpr bool _Is_initializer_list = _Is_specialization_v<remove_cvref_t<_Ty>, initializer_list>;
|
|
|
|
#if _HAS_CXX23
|
|
_EXPORT_STD template <range _Rng>
|
|
using const_iterator_t = const_iterator<iterator_t<_Rng>>;
|
|
|
|
_EXPORT_STD template <range _Rng>
|
|
using const_sentinel_t = const_sentinel<sentinel_t<_Rng>>;
|
|
|
|
_EXPORT_STD template <range _Rng>
|
|
using range_const_reference_t = iter_const_reference_t<iterator_t<_Rng>>;
|
|
#endif // _HAS_CXX23
|
|
|
|
// clang-format off
|
|
_EXPORT_STD template <class _Rng>
|
|
concept viewable_range = range<_Rng>
|
|
&& ((view<remove_cvref_t<_Rng>> && constructible_from<remove_cvref_t<_Rng>, _Rng>)
|
|
|| (!view<remove_cvref_t<_Rng>>
|
|
&& (is_lvalue_reference_v<_Rng>
|
|
|| (movable<remove_reference_t<_Rng>> && !_Is_initializer_list<_Rng>))));
|
|
|
|
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>>;
|
|
// clang-format on
|
|
|
|
template <class _Ty>
|
|
concept _Valid_movable_box_object =
|
|
#if _HAS_CXX23
|
|
move_constructible<_Ty>
|
|
#else // ^^^ C++23 / C++20 vvv
|
|
copy_constructible<_Ty>
|
|
#endif // C++20
|
|
&& _Destructible_object<_Ty>;
|
|
|
|
template <class _It>
|
|
concept _Has_arrow = input_iterator<_It> && (is_pointer_v<_It> || _Has_member_arrow<_It&>);
|
|
|
|
template <bool _IsConst, class _Ty>
|
|
using _Maybe_const = conditional_t<_IsConst, const _Ty, _Ty>;
|
|
|
|
template <bool _IsWrapped, class _Ty>
|
|
using _Maybe_wrapped = conditional_t<_IsWrapped, _Ty, _Unwrapped_t<_Ty>>;
|
|
|
|
namespace _Pipe {
|
|
template <class _Derived>
|
|
struct _Base {};
|
|
|
|
template <class _Ty>
|
|
_Ty* _Derived_from_range_adaptor_closure(_Base<_Ty>&); // not defined
|
|
|
|
// clang-format off
|
|
template <class _Ty>
|
|
concept _Range_adaptor_closure_object = !range<remove_cvref_t<_Ty>> && requires(remove_cvref_t<_Ty>& __t) {
|
|
{ _Pipe::_Derived_from_range_adaptor_closure(__t) } -> same_as<remove_cvref_t<_Ty>*>;
|
|
};
|
|
// clang-format on
|
|
|
|
template <class _ClosureLeft, class _ClosureRight>
|
|
struct _Pipeline : _Base<_Pipeline<_ClosureLeft, _ClosureRight>> {
|
|
_STL_INTERNAL_STATIC_ASSERT(_Range_adaptor_closure_object<_ClosureLeft>);
|
|
_STL_INTERNAL_STATIC_ASSERT(_Range_adaptor_closure_object<_ClosureRight>);
|
|
|
|
/* [[no_unique_address]] */ _ClosureLeft _Left;
|
|
/* [[no_unique_address]] */ _ClosureRight _Right;
|
|
|
|
template <class _Ty1, class _Ty2>
|
|
constexpr explicit _Pipeline(_Ty1&& _Val1, _Ty2&& _Val2) noexcept(
|
|
is_nothrow_constructible_v<_Ty1, _ClosureLeft>&& is_nothrow_constructible_v<_Ty2, _ClosureRight>)
|
|
: _Left(_STD forward<_Ty1>(_Val1)), _Right(_STD forward<_Ty2>(_Val2)) {}
|
|
|
|
template <class _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Val) & noexcept(
|
|
noexcept(_Right(_Left(_STD forward<_Ty>(_Val)))))
|
|
requires requires { _Right(_Left(_STD forward<_Ty>(_Val))); }
|
|
{
|
|
return _Right(_Left(_STD forward<_Ty>(_Val)));
|
|
}
|
|
|
|
template <class _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Val) const& noexcept(
|
|
noexcept(_Right(_Left(_STD forward<_Ty>(_Val)))))
|
|
requires requires { _Right(_Left(_STD forward<_Ty>(_Val))); }
|
|
{
|
|
return _Right(_Left(_STD forward<_Ty>(_Val)));
|
|
}
|
|
|
|
template <class _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Val) && noexcept(
|
|
noexcept(_STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val)))))
|
|
requires requires { _STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val))); }
|
|
{
|
|
return _STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val)));
|
|
}
|
|
|
|
template <class _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Val) const&& noexcept(
|
|
noexcept(_STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val)))))
|
|
requires requires { _STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val))); }
|
|
{
|
|
return _STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val)));
|
|
}
|
|
};
|
|
|
|
template <class _Ty1, class _Ty2>
|
|
_Pipeline(_Ty1, _Ty2) -> _Pipeline<_Ty1, _Ty2>;
|
|
|
|
_EXPORT_STD template <class _Left, class _Right>
|
|
requires _Range_adaptor_closure_object<_Left> //
|
|
&& _Range_adaptor_closure_object<_Right> //
|
|
&& constructible_from<remove_cvref_t<_Left>, _Left> //
|
|
&& constructible_from<remove_cvref_t<_Right>, _Right> //
|
|
_NODISCARD constexpr auto operator|(_Left&& __l, _Right&& __r) noexcept(
|
|
noexcept(_Pipeline{static_cast<_Left&&>(__l), static_cast<_Right&&>(__r)})) {
|
|
return _Pipeline{static_cast<_Left&&>(__l), static_cast<_Right&&>(__r)};
|
|
}
|
|
|
|
_EXPORT_STD template <class _Left, class _Right>
|
|
requires (_Range_adaptor_closure_object<_Right> && range<_Left>)
|
|
_NODISCARD constexpr auto operator|(_Left&& __l, _Right&& __r) noexcept(
|
|
noexcept(_STD forward<_Right>(__r)(_STD forward<_Left>(__l))))
|
|
requires requires { static_cast<_Right&&>(__r)(static_cast<_Left&&>(__l)); }
|
|
{
|
|
return _STD forward<_Right>(__r)(_STD forward<_Left>(__l));
|
|
}
|
|
} // namespace _Pipe
|
|
|
|
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>>;
|
|
|
|
// A simplified optional that augments copy_constructible types with full copyability,
|
|
// and move_constructible types with full movability.
|
|
// In C++20, this corresponds to copyable-box.
|
|
template <_Valid_movable_box_object _Ty>
|
|
class _Movable_box {
|
|
public:
|
|
constexpr _Movable_box() noexcept(is_nothrow_default_constructible_v<_Ty>)
|
|
requires default_initializable<_Ty>
|
|
: _Val(), _Engaged{true} {}
|
|
|
|
template <class... _Types>
|
|
constexpr _Movable_box(in_place_t, _Types&&... _Args) noexcept(
|
|
is_nothrow_constructible_v<_Ty, _Types...>) // strengthened
|
|
: _Val(_STD forward<_Types>(_Args)...), _Engaged{true} {}
|
|
|
|
constexpr ~_Movable_box() {
|
|
if (_Engaged) {
|
|
_Val.~_Ty();
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
~_Movable_box() requires is_trivially_destructible_v<_Ty> = default;
|
|
|
|
_Movable_box(const _Movable_box&)
|
|
requires copy_constructible<_Ty> && is_trivially_copy_constructible_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Movable_box(const _Movable_box& _That)
|
|
requires copy_constructible<_Ty>
|
|
: _Engaged{_That._Engaged} {
|
|
if (_That._Engaged) {
|
|
_STD _Construct_in_place(_Val, static_cast<const _Ty&>(_That._Val));
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
_Movable_box(_Movable_box&&) requires is_trivially_move_constructible_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Movable_box(_Movable_box&& _That) : _Engaged{_That._Engaged} {
|
|
if (_That._Engaged) {
|
|
_STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val));
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
_Movable_box& operator=(const _Movable_box&) noexcept
|
|
requires copyable<_Ty> && is_trivially_copy_assignable_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Movable_box& operator=(const _Movable_box& _That) noexcept(
|
|
is_nothrow_copy_constructible_v<_Ty>&& is_nothrow_copy_assignable_v<_Ty>) // strengthened
|
|
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;
|
|
}
|
|
|
|
constexpr _Movable_box& operator=(const _Movable_box& _That) noexcept(is_nothrow_copy_constructible_v<_Ty>)
|
|
requires copy_constructible<_Ty>
|
|
{
|
|
if (_STD addressof(_That) == this) {
|
|
return *this;
|
|
}
|
|
|
|
if (_Engaged) {
|
|
_Val.~_Ty();
|
|
_Engaged = false;
|
|
}
|
|
|
|
if (_That._Engaged) {
|
|
_STD _Construct_in_place(_Val, static_cast<const _Ty&>(_That._Val));
|
|
_Engaged = true;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
// clang-format off
|
|
_Movable_box& operator=(_Movable_box&&) noexcept
|
|
requires movable<_Ty> && is_trivially_move_assignable_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Movable_box& operator=(_Movable_box&& _That) noexcept(
|
|
is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) // strengthened
|
|
requires movable<_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 _Movable_box& operator=(_Movable_box&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>) {
|
|
if (_STD addressof(_That) == this) {
|
|
return *this;
|
|
}
|
|
|
|
if (_Engaged) {
|
|
_Val.~_Ty();
|
|
_Engaged = false;
|
|
}
|
|
|
|
if (_That._Engaged) {
|
|
_STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val));
|
|
_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;
|
|
}
|
|
|
|
private:
|
|
union {
|
|
remove_cv_t<_Ty> _Val;
|
|
};
|
|
bool _Engaged;
|
|
};
|
|
|
|
// [range.move.wrap]
|
|
template <class _Ty>
|
|
concept _Use_simple_movable_box_wrapper =
|
|
(copy_constructible<_Ty>
|
|
// 1. If copy_constructible<T> is true, movable-box<T> should store only a T if either T models
|
|
// copyable, or is_nothrow_move_constructible_v<T> && is_nothrow_copy_constructible_v<T> is true.
|
|
? copyable<_Ty> || (is_nothrow_move_constructible_v<_Ty> && is_nothrow_copy_constructible_v<_Ty>)
|
|
// 2. Otherwise, movable-box<T> should store only a T if either T models movable or
|
|
// is_nothrow_move_constructible_v<T> is true.
|
|
: movable<_Ty> || is_nothrow_move_constructible_v<_Ty>);
|
|
|
|
template <class _Ty>
|
|
concept _Copy_constructible_for_box = is_copy_constructible_v<_Ty>;
|
|
|
|
template <_Valid_movable_box_object _Ty>
|
|
requires _Use_simple_movable_box_wrapper<_Ty>
|
|
class _Movable_box<_Ty> { // provide the same API more efficiently when we can avoid the disengaged state
|
|
public:
|
|
// clang-format off
|
|
_Movable_box() requires default_initializable<_Ty> = default;
|
|
// clang-format on
|
|
|
|
template <class... _Types>
|
|
constexpr _Movable_box(in_place_t, _Types&&... _Args) noexcept(
|
|
is_nothrow_constructible_v<_Ty, _Types...>) // strengthened
|
|
: _Val(_STD forward<_Types>(_Args)...) {}
|
|
|
|
// clang-format off
|
|
_Movable_box(const _Movable_box&)
|
|
requires _Copy_constructible_for_box<_Ty> && is_trivially_copy_constructible_v<_Ty> = default;
|
|
_Movable_box(_Movable_box&&) requires is_trivially_move_constructible_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Movable_box(const _Movable_box& _That) noexcept(is_nothrow_copy_constructible_v<_Ty>)
|
|
requires _Copy_constructible_for_box<_Ty>
|
|
: _Val(static_cast<const _Ty&>(_That._Val)) {}
|
|
|
|
constexpr _Movable_box(_Movable_box&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>)
|
|
: _Val(static_cast<_Ty&&>(_That._Val)) {}
|
|
|
|
// clang-format off
|
|
_Movable_box& operator=(const _Movable_box&)
|
|
requires copyable<_Ty> && is_trivially_copy_assignable_v<_Ty> = default;
|
|
_Movable_box& operator=(_Movable_box&&) requires movable<_Ty> && is_trivially_move_assignable_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Movable_box& operator=(const _Movable_box& _That) noexcept(
|
|
is_nothrow_copy_assignable_v<_Ty> || !copyable<_Ty>) // strengthened
|
|
requires copy_constructible<_Ty>
|
|
{
|
|
if constexpr (copyable<_Ty>) {
|
|
static_cast<_Ty&>(_Val) = static_cast<const _Ty&>(_That._Val);
|
|
} else {
|
|
if (_STD addressof(_That) != this) {
|
|
_Val.~_Ty();
|
|
_STD _Construct_in_place(_Val, static_cast<const _Ty&>(_That._Val));
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
constexpr _Movable_box& operator=(_Movable_box&& _That) noexcept(
|
|
is_nothrow_move_assignable_v<_Ty> || !movable<_Ty>) /* strengthened */ {
|
|
if constexpr (movable<_Ty>) {
|
|
static_cast<_Ty&>(_Val) = static_cast<_Ty&&>(_That._Val);
|
|
} else {
|
|
if (_STD addressof(_That) != this) {
|
|
_Val.~_Ty();
|
|
_STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val));
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
constexpr explicit operator bool() const noexcept {
|
|
return true;
|
|
}
|
|
|
|
_NODISCARD constexpr _Ty& operator*() noexcept {
|
|
return _Val;
|
|
}
|
|
_NODISCARD constexpr const _Ty& operator*() const noexcept {
|
|
return _Val;
|
|
}
|
|
|
|
private:
|
|
/* [[no_unique_address]] */ remove_cv_t<_Ty> _Val{};
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
~_Defaultabox() requires is_trivially_destructible_v<_Ty> = default;
|
|
|
|
_Defaultabox(const _Defaultabox&)
|
|
requires copy_constructible<_Ty> && is_trivially_copy_constructible_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Defaultabox(const _Defaultabox& _That)
|
|
requires copy_constructible<_Ty>
|
|
: _Engaged{_That._Engaged} {
|
|
if (_That._Engaged) {
|
|
_STD _Construct_in_place(_Val, static_cast<const _Ty&>(_That._Val));
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
_Defaultabox(_Defaultabox&&) requires is_trivially_move_constructible_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Defaultabox(_Defaultabox&& _That) : _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) : _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) : _Engaged{_That} {
|
|
if (_That) {
|
|
_STD _Construct_in_place(_Val, _STD move(*_That));
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
_Defaultabox& operator=(const _Defaultabox&) noexcept
|
|
requires copyable<_Ty> && is_trivially_copy_assignable_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Defaultabox& operator=(const _Defaultabox& _That) noexcept(
|
|
is_nothrow_copy_constructible_v<_Ty>&& is_nothrow_copy_assignable_v<_Ty>) // strengthened
|
|
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;
|
|
}
|
|
|
|
// clang-format off
|
|
_Defaultabox& operator=(_Defaultabox&&) noexcept requires is_trivially_move_assignable_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Defaultabox& operator=(_Defaultabox&& _That) noexcept(
|
|
is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) /* strengthened */ {
|
|
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) {
|
|
if (_That) {
|
|
_Value = static_cast<_Ty>(*_That);
|
|
}
|
|
}
|
|
|
|
template <_Different_from<_Ty> _Uty>
|
|
requires convertible_to<_Uty, _Ty>
|
|
constexpr _Defaultabox(_Defaultabox<_Uty>&& _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();
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
~_Non_propagating_cache() requires is_trivially_destructible_v<_Ty> = default;
|
|
// clang-format on
|
|
|
|
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
|
|
|
|
template <class _Fn, class... _Types>
|
|
class _Range_closure : public _Pipe::_Base<_Range_closure<_Fn, _Types...>> {
|
|
public:
|
|
// We assume that _Fn is the type of a customization point object. That means
|
|
// 1. The behavior of operator() is independent of cvref qualifiers, so we can use `invocable<_Fn, ` without
|
|
// loss of generality, and
|
|
// 2. _Fn must be default-constructible and stateless, so we can create instances "on-the-fly" and avoid
|
|
// storing a copy.
|
|
|
|
_STL_INTERNAL_STATIC_ASSERT((same_as<decay_t<_Types>, _Types> && ...));
|
|
_STL_INTERNAL_STATIC_ASSERT(is_empty_v<_Fn>&& is_default_constructible_v<_Fn>);
|
|
|
|
template <class... _UTypes>
|
|
requires (same_as<decay_t<_UTypes>, _Types> && ...)
|
|
constexpr explicit _Range_closure(_UTypes&&... _Args) noexcept(
|
|
conjunction_v<is_nothrow_constructible<_Types, _UTypes>...>)
|
|
: _Captures(_STD forward<_UTypes>(_Args)...) {}
|
|
|
|
void operator()(auto&&) & = delete;
|
|
void operator()(auto&&) const& = delete;
|
|
void operator()(auto&&) && = delete;
|
|
void operator()(auto&&) const&& = delete;
|
|
|
|
using _Indices = index_sequence_for<_Types...>;
|
|
|
|
template <class _Ty>
|
|
requires invocable<_Fn, _Ty, _Types&...>
|
|
constexpr decltype(auto) operator()(_Ty&& _Arg) & noexcept(
|
|
noexcept(_Call(*this, _STD forward<_Ty>(_Arg), _Indices{}))) {
|
|
return _Call(*this, _STD forward<_Ty>(_Arg), _Indices{});
|
|
}
|
|
|
|
template <class _Ty>
|
|
requires invocable<_Fn, _Ty, const _Types&...>
|
|
constexpr decltype(auto) operator()(_Ty&& _Arg) const& noexcept(
|
|
noexcept(_Call(*this, _STD forward<_Ty>(_Arg), _Indices{}))) {
|
|
return _Call(*this, _STD forward<_Ty>(_Arg), _Indices{});
|
|
}
|
|
|
|
template <class _Ty>
|
|
requires invocable<_Fn, _Ty, _Types...>
|
|
constexpr decltype(auto) operator()(_Ty&& _Arg) && noexcept(
|
|
noexcept(_Call(_STD move(*this), _STD forward<_Ty>(_Arg), _Indices{}))) {
|
|
return _Call(_STD move(*this), _STD forward<_Ty>(_Arg), _Indices{});
|
|
}
|
|
|
|
template <class _Ty>
|
|
requires invocable<_Fn, _Ty, const _Types...>
|
|
constexpr decltype(auto) operator()(_Ty&& _Arg) const&& noexcept(
|
|
noexcept(_Call(_STD move(*this), _STD forward<_Ty>(_Arg), _Indices{}))) {
|
|
return _Call(_STD move(*this), _STD forward<_Ty>(_Arg), _Indices{});
|
|
}
|
|
|
|
private:
|
|
template <class _SelfTy, class _Ty, size_t... _Idx>
|
|
static constexpr decltype(auto) _Call(_SelfTy&& _Self, _Ty&& _Arg, index_sequence<_Idx...>) noexcept(
|
|
noexcept(_Fn{}(_STD forward<_Ty>(_Arg), _STD get<_Idx>(_STD forward<_SelfTy>(_Self)._Captures)...))) {
|
|
_STL_INTERNAL_STATIC_ASSERT(same_as<index_sequence<_Idx...>, _Indices>);
|
|
return _Fn{}(_STD forward<_Ty>(_Arg), _STD get<_Idx>(_STD forward<_SelfTy>(_Self)._Captures)...);
|
|
}
|
|
|
|
tuple<_Types...> _Captures;
|
|
};
|
|
|
|
_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>
|
|
inline constexpr bool enable_borrowed_range<empty_view<_Ty>> = true;
|
|
|
|
namespace views {
|
|
_EXPORT_STD template <class _Ty>
|
|
inline 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:
|
|
// clang-format off
|
|
single_view() requires default_initializable<_Ty> = default;
|
|
// clang-format on
|
|
|
|
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 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 {
|
|
// clang-format off
|
|
template <class _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Val) const 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));
|
|
}
|
|
// clang-format on
|
|
};
|
|
|
|
_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>>;
|
|
|
|
// clang-format off
|
|
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>>;
|
|
};
|
|
// clang-format on
|
|
|
|
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>;
|
|
|
|
// clang-format off
|
|
_Ioterator() requires default_initializable<_Wi> = default;
|
|
// clang-format on
|
|
|
|
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 // TRANSITION, DevCom-1347136
|
|
|
|
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 // TRANSITION, DevCom-1347136
|
|
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 // TRANSITION, DevCom-1347136
|
|
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:
|
|
// clang-format off
|
|
iota_view() requires default_initializable<_Wi> = default;
|
|
// clang-format on
|
|
|
|
constexpr explicit iota_view(_Wi _Value_) noexcept(
|
|
is_nothrow_move_constructible_v<_Wi>&& is_nothrow_default_constructible_v<_Bo>) // strengthened
|
|
: _Value(_STD move(_Value_)) {}
|
|
|
|
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 constexpr (totally_ordered_with<_Wi, _Bo>) {
|
|
_STL_ASSERT(_Value_ <= _Bound_, "Per N4928 [range.iota.view]/8, the first argument must precede the "
|
|
"second when their types are totally ordered.");
|
|
}
|
|
}
|
|
|
|
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))) {}
|
|
|
|
_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};
|
|
}
|
|
}
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
|
// clang-format off
|
|
_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> {
|
|
// clang-format on
|
|
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)
|
|
};
|
|
|
|
// clang-format off
|
|
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>;
|
|
// clang-format on
|
|
|
|
template <class _Wi, class _Bo>
|
|
inline constexpr bool enable_borrowed_range<iota_view<_Wi, _Bo>> = true;
|
|
|
|
namespace views {
|
|
struct _Iota_fn {
|
|
template <class _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
|
|
noexcept(noexcept(iota_view(static_cast<_Ty&&>(_Val))))
|
|
requires requires { iota_view(static_cast<_Ty&&>(_Val)); }
|
|
{
|
|
return iota_view(static_cast<_Ty&&>(_Val));
|
|
}
|
|
|
|
template <class _Ty1, class _Ty2>
|
|
_NODISCARD constexpr auto operator()(_Ty1&& _Val1, _Ty2&& _Val2) const
|
|
noexcept(noexcept(iota_view(static_cast<_Ty1&&>(_Val1), static_cast<_Ty2&&>(_Val2))))
|
|
requires requires { iota_view(static_cast<_Ty1&&>(_Val1), static_cast<_Ty2&&>(_Val2)); }
|
|
{
|
|
return iota_view(static_cast<_Ty1&&>(_Val1), static_cast<_Ty2&&>(_Val2));
|
|
}
|
|
};
|
|
|
|
_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 = typename _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
|
|
++_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 (_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 += _Off;
|
|
return *this;
|
|
}
|
|
constexpr _Iterator& operator-=(difference_type _Off) noexcept /* strengthened */ {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
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 -= _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:
|
|
// clang-format off
|
|
repeat_view() requires default_initializable<_Ty> = default;
|
|
// clang-format on
|
|
|
|
_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
|
|
}
|
|
_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
|
|
}
|
|
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
|
|
}
|
|
|
|
_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>
|
|
repeat_view(_Ty, _Bo) -> repeat_view<_Ty, _Bo>;
|
|
|
|
namespace views {
|
|
struct _Repeat_fn {
|
|
template <class _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Value) const
|
|
noexcept(noexcept(repeat_view(_STD forward<_Ty>(_Value))))
|
|
requires requires { repeat_view(_STD forward<_Ty>(_Value)); }
|
|
{
|
|
return repeat_view(_STD forward<_Ty>(_Value));
|
|
}
|
|
|
|
template <class _Ty1, class _Ty2>
|
|
_NODISCARD constexpr auto operator()(_Ty1&& _Val1, _Ty2&& _Val2) const
|
|
noexcept(noexcept(repeat_view(_STD forward<_Ty1>(_Val1), _STD forward<_Ty2>(_Val2))))
|
|
requires requires { repeat_view(_STD forward<_Ty1>(_Val1), _STD forward<_Ty2>(_Val2)); }
|
|
{
|
|
return repeat_view(_STD forward<_Ty1>(_Val1), _STD forward<_Ty2>(_Val2));
|
|
}
|
|
};
|
|
|
|
_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 constexpr auto operator()(_StreamTy& _Stream) const
|
|
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>
|
|
inline constexpr _Istream_fn<_Ty> istream;
|
|
} // namespace views
|
|
|
|
_EXPORT_STD template <range _Rng>
|
|
requires is_object_v<_Rng>
|
|
class ref_view : public view_interface<ref_view<_Rng>> {
|
|
private:
|
|
_Rng* _Range;
|
|
|
|
static void _Rvalue_poison(_Rng&);
|
|
static void _Rvalue_poison(_Rng&&) = delete;
|
|
|
|
public:
|
|
// clang-format off
|
|
template <_Different_from<ref_view> _OtherRng>
|
|
constexpr ref_view(_OtherRng&& _Other) noexcept(
|
|
noexcept(static_cast<_Rng&>(_STD forward<_OtherRng>(_Other)))) // strengthened
|
|
requires convertible_to<_OtherRng, _Rng&> && requires {
|
|
_Rvalue_poison(static_cast<_OtherRng&&>(_Other));
|
|
} : _Range{_STD addressof(static_cast<_Rng&>(_STD forward<_OtherRng>(_Other)))} {}
|
|
// clang-format on
|
|
|
|
_NODISCARD constexpr _Rng& base() const noexcept /* strengthened */ {
|
|
return *_Range;
|
|
}
|
|
|
|
_NODISCARD constexpr iterator_t<_Rng> begin() const
|
|
noexcept(noexcept(_RANGES begin(*_Range))) /* strengthened */ {
|
|
return _RANGES begin(*_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr sentinel_t<_Rng> end() const noexcept(noexcept(_RANGES end(*_Range))) /* strengthened */ {
|
|
return _RANGES end(*_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr bool empty() const noexcept(noexcept(_RANGES empty(*_Range))) /* strengthened */
|
|
requires _Can_empty<_Rng>
|
|
{
|
|
return _RANGES empty(*_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(*_Range))) /* strengthened */
|
|
requires sized_range<_Rng>
|
|
{
|
|
return _RANGES size(*_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr auto data() const noexcept(noexcept(_RANGES data(*_Range))) /* strengthened */
|
|
requires contiguous_range<_Rng>
|
|
{
|
|
return _RANGES data(*_Range);
|
|
}
|
|
};
|
|
|
|
template <class _Rng>
|
|
ref_view(_Rng&) -> ref_view<_Rng>;
|
|
|
|
template <class _Rng>
|
|
inline constexpr bool enable_borrowed_range<ref_view<_Rng>> = true;
|
|
|
|
_EXPORT_STD template <range _Rng>
|
|
requires (movable<_Rng> && !_Is_initializer_list<_Rng>)
|
|
class owning_view : public view_interface<owning_view<_Rng>> {
|
|
private:
|
|
_Rng _Range{};
|
|
|
|
public:
|
|
// clang-format off
|
|
owning_view() requires default_initializable<_Rng> = default;
|
|
// clang-format on
|
|
|
|
constexpr owning_view(_Rng&& _Range_) noexcept(is_nothrow_move_constructible_v<_Rng>) // strengthened
|
|
: _Range(_STD move(_Range_)) {}
|
|
|
|
owning_view(owning_view&&) = default;
|
|
owning_view& operator=(owning_view&&) = default;
|
|
|
|
_NODISCARD constexpr _Rng& base() & noexcept {
|
|
return _Range;
|
|
}
|
|
_NODISCARD constexpr const _Rng& base() const& noexcept {
|
|
return _Range;
|
|
}
|
|
_NODISCARD constexpr _Rng&& base() && noexcept {
|
|
return _STD move(_Range);
|
|
}
|
|
_NODISCARD constexpr const _Rng&& base() const&& noexcept {
|
|
return _STD move(_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr iterator_t<_Rng> begin() noexcept(noexcept(_RANGES begin(_Range))) /* strengthened */ {
|
|
return _RANGES begin(_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr sentinel_t<_Rng> end() noexcept(noexcept(_RANGES end(_Range))) /* strengthened */ {
|
|
return _RANGES end(_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr auto begin() const noexcept(noexcept(_RANGES begin(_Range))) /* strengthened */
|
|
requires range<const _Rng>
|
|
{
|
|
return _RANGES begin(_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr auto end() const noexcept(noexcept(_RANGES end(_Range))) /* strengthened */
|
|
requires range<const _Rng>
|
|
{
|
|
return _RANGES end(_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr bool empty() noexcept(noexcept(_RANGES empty(_Range))) /* strengthened */
|
|
requires _Can_empty<_Rng>
|
|
{
|
|
return _RANGES empty(_Range);
|
|
}
|
|
_NODISCARD constexpr bool empty() const noexcept(noexcept(_RANGES empty(_Range))) /* strengthened */
|
|
requires _Can_empty<const _Rng>
|
|
{
|
|
return _RANGES empty(_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Range))) /* strengthened */
|
|
requires sized_range<_Rng>
|
|
{
|
|
return _RANGES size(_Range);
|
|
}
|
|
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Range))) /* strengthened */
|
|
requires sized_range<const _Rng>
|
|
{
|
|
return _RANGES size(_Range);
|
|
}
|
|
|
|
_NODISCARD constexpr auto data() noexcept(noexcept(_RANGES data(_Range))) /* strengthened */
|
|
requires contiguous_range<_Rng>
|
|
{
|
|
return _RANGES data(_Range);
|
|
}
|
|
_NODISCARD constexpr auto data() const noexcept(noexcept(_RANGES data(_Range))) /* strengthened */
|
|
requires contiguous_range<const _Rng>
|
|
{
|
|
return _RANGES data(_Range);
|
|
}
|
|
};
|
|
|
|
template <class _Rng>
|
|
inline constexpr bool enable_borrowed_range<owning_view<_Rng>> = enable_borrowed_range<_Rng>;
|
|
|
|
namespace views {
|
|
template <class _Rng>
|
|
concept _Can_ref_view = requires(_Rng&& __r) { ref_view{static_cast<_Rng&&>(__r)}; };
|
|
|
|
template <class _Rng>
|
|
concept _Ownable = requires(_Rng&& __r) { owning_view{static_cast<_Rng&&>(__r)}; };
|
|
|
|
class _All_fn : public _Pipe::_Base<_All_fn> {
|
|
private:
|
|
enum class _St { _None, _View, _Ref, _Own };
|
|
|
|
template <class _Rng>
|
|
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
|
|
if constexpr (view<remove_cvref_t<_Rng>>) {
|
|
if constexpr (convertible_to<_Rng, remove_cvref_t<_Rng>>) {
|
|
return {_St::_View, is_nothrow_convertible_v<_Rng, remove_cvref_t<_Rng>>};
|
|
}
|
|
} else if constexpr (_Can_ref_view<_Rng>) {
|
|
return {_St::_Ref, noexcept(ref_view{_STD declval<_Rng>()})};
|
|
} else if constexpr (_Ownable<_Rng>) {
|
|
return {_St::_Own, noexcept(owning_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 constexpr auto operator()(_Rng&& _Range) const noexcept(_Choice<_Rng>._No_throw) {
|
|
constexpr _St _Strat = _Choice<_Rng>._Strategy;
|
|
|
|
if constexpr (_Strat == _St::_View) {
|
|
return _STD forward<_Rng>(_Range);
|
|
} else if constexpr (_Strat == _St::_Ref) {
|
|
return ref_view{_STD forward<_Rng>(_Range)};
|
|
} else if constexpr (_Strat == _St::_Own) {
|
|
return owning_view{_STD forward<_Rng>(_Range)};
|
|
} else {
|
|
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
|
}
|
|
}
|
|
};
|
|
|
|
_EXPORT_STD inline constexpr _All_fn all;
|
|
|
|
_EXPORT_STD template <viewable_range _Rng>
|
|
using all_t = decltype(all(_STD declval<_Rng>()));
|
|
} // namespace views
|
|
|
|
#if _HAS_CXX23
|
|
_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:
|
|
// clang-format off
|
|
as_rvalue_view() requires default_initializable<_Vw> = default;
|
|
// clang-format on
|
|
|
|
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>
|
|
inline constexpr bool enable_borrowed_range<as_rvalue_view<_Rng>> = enable_borrowed_range<_Rng>;
|
|
|
|
namespace views {
|
|
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 (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 constexpr auto operator()(_Rng&& _Range) const 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 {
|
|
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
|
}
|
|
}
|
|
};
|
|
|
|
_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>;
|
|
|
|
// clang-format off
|
|
_Iterator() requires default_initializable<iterator_t<_Vw>> = default;
|
|
// clang-format on
|
|
|
|
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
|
|
_Adl_verify_range(_Current, _RANGES end(_Parent_._Range));
|
|
if constexpr (forward_range<_Vw>) {
|
|
_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;
|
|
}
|
|
|
|
// clang-format off
|
|
_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>> {
|
|
// clang-format on
|
|
#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(_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:
|
|
// clang-format off
|
|
filter_view() requires default_initializable<_Vw> && default_initializable<_Pr> = default;
|
|
// clang-format on
|
|
|
|
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, "N4928 [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>;
|
|
|
|
namespace views {
|
|
struct _Filter_fn {
|
|
// clang-format off
|
|
template <viewable_range _Rng, class _Pr>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Pr&& _Pred) const noexcept(noexcept(
|
|
filter_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred)))) requires requires {
|
|
filter_view(static_cast<_Rng&&>(_Range), _STD forward<_Pr>(_Pred));
|
|
} {
|
|
// clang-format on
|
|
return filter_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred));
|
|
}
|
|
|
|
template <class _Pr>
|
|
requires constructible_from<decay_t<_Pr>, _Pr>
|
|
_NODISCARD constexpr auto operator()(_Pr&& _Pred) const
|
|
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
|
|
|
|
#ifdef __clang__
|
|
template <class _Rng, class _Fn> // TRANSITION, LLVM-47414
|
|
concept _Can_const_transform = range<const _Rng> && regular_invocable<const _Fn&, range_reference_t<const _Rng>>;
|
|
#endif // ^^^ workaround ^^^
|
|
|
|
_EXPORT_STD template <input_range _Vw, _Valid_movable_box_object _Fn>
|
|
requires view<_Vw> && regular_invocable<_Fn&, range_reference_t<_Vw>>
|
|
&& _Can_reference<invoke_result_t<_Fn&, range_reference_t<_Vw>>>
|
|
class transform_view : public view_interface<transform_view<_Vw, _Fn>> {
|
|
private:
|
|
/* [[no_unique_address]] */ _Vw _Range{};
|
|
/* [[no_unique_address]] */ _Movable_box<_Fn> _Fun{};
|
|
|
|
template <bool _Const>
|
|
struct _Category_base {};
|
|
|
|
template <bool _Const>
|
|
requires forward_range<_Maybe_const<_Const, _Vw>>
|
|
struct _Category_base<_Const> {
|
|
using _Base = _Maybe_const<_Const, _Vw>;
|
|
using iterator_category =
|
|
conditional_t<is_reference_v<invoke_result_t<_Maybe_const<_Const, _Fn>&, range_reference_t<_Base>>>,
|
|
conditional_t<derived_from<_Iter_cat_t<iterator_t<_Base>>, contiguous_iterator_tag>,
|
|
random_access_iterator_tag, _Iter_cat_t<iterator_t<_Base>>>,
|
|
input_iterator_tag>;
|
|
};
|
|
|
|
template <bool _Const>
|
|
class _Iterator : public _Category_base<_Const> {
|
|
private:
|
|
friend transform_view;
|
|
|
|
using _Parent_t = _Maybe_const<_Const, transform_view>;
|
|
using _Base = _Maybe_const<_Const, _Vw>;
|
|
|
|
iterator_t<_Base> _Current{};
|
|
_Parent_t* _Parent{};
|
|
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
constexpr void _Check_dereference() const noexcept {
|
|
_STL_VERIFY(_Parent != nullptr, "cannot dereference value-initialized transform_view iterator");
|
|
_STL_VERIFY(_Current != _RANGES end(_Parent->_Range), "cannot dereference end transform_view iterator");
|
|
}
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
constexpr void _Same_range(const _Iterator& _Right) const noexcept {
|
|
_STL_VERIFY(_Parent == _Right._Parent, "cannot compare incompatible transform_view iterators");
|
|
}
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
|
|
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<invoke_result_t<_Maybe_const<_Const, _Fn>&, range_reference_t<_Base>>>;
|
|
using difference_type = range_difference_t<_Base>;
|
|
|
|
// clang-format off
|
|
_Iterator() requires default_initializable<iterator_t<_Base>> = default;
|
|
// clang-format on
|
|
|
|
constexpr _Iterator(_Parent_t& _Parent_, iterator_t<_Base> _Current_) noexcept(
|
|
is_nothrow_move_constructible_v<iterator_t<_Base>>) // strengthened
|
|
: _Current{_STD move(_Current_)}, _Parent{_STD addressof(_Parent_)} {
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_Adl_verify_range(_Current, _RANGES end(_Parent_._Range));
|
|
if constexpr (forward_range<_Base>) {
|
|
_Adl_verify_range(_RANGES begin(_Parent_._Range), _Current);
|
|
}
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
}
|
|
|
|
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)), _Parent(_It._Parent) {}
|
|
|
|
_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 invoke(*_Parent->_Fun, *_Current))) {
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_Check_dereference();
|
|
_STL_VERIFY(
|
|
_Parent->_Fun, "Cannot dereference iterator into transform_view with no transformation function");
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
return _STD invoke(*_Parent->_Fun, *_Current);
|
|
}
|
|
|
|
constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ {
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_STL_VERIFY(_Parent != nullptr, "Cannot increment value-initialized transform_view iterator");
|
|
_STL_VERIFY(
|
|
_Current != _RANGES end(_Parent->_Range), "Cannot increment transform_view iterator past end");
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
++_Current;
|
|
return *this;
|
|
}
|
|
|
|
constexpr decltype(auto) operator++(int) noexcept(
|
|
noexcept(++_Current)
|
|
&& (!forward_range<_Base> || is_nothrow_copy_constructible_v<iterator_t<_Base>>) ) /* strengthened */ {
|
|
if constexpr (forward_range<_Base>) {
|
|
auto _Tmp = *this;
|
|
++*this;
|
|
return _Tmp;
|
|
} else {
|
|
++*this;
|
|
}
|
|
}
|
|
|
|
constexpr _Iterator& operator--() noexcept(noexcept(--_Current)) /* strengthened */
|
|
requires bidirectional_range<_Base>
|
|
{
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_STL_VERIFY(_Parent != nullptr, "Cannot decrement value-initialized transform_view iterator");
|
|
if constexpr (forward_range<_Vw>) {
|
|
_STL_VERIFY(_Current != _RANGES begin(_Parent->_Range),
|
|
"Cannot decrement transform_view iterator before begin");
|
|
}
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
--_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;
|
|
--*this;
|
|
return _Tmp;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
constexpr void _Verify_offset(const difference_type _Off) const noexcept
|
|
requires random_access_range<_Base>
|
|
{
|
|
_STL_VERIFY(_Off == 0 || _Parent, "cannot seek value-initialized transform_view iterator");
|
|
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 invoke(*_Parent->_Fun, _Current[_Idx]))) /* strengthened */
|
|
requires random_access_range<_Base>
|
|
{
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_Verify_offset(_Idx);
|
|
_STL_VERIFY(
|
|
_Parent->_Fun, "Cannot dereference iterator into transform_view with no transformation function");
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
return _STD invoke(*_Parent->_Fun, _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>>
|
|
{
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_Left._Same_range(_Right);
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
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>
|
|
{
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_Left._Same_range(_Right);
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
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);
|
|
}
|
|
// clang-format off
|
|
_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>> {
|
|
// clang-format on
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_Left._Same_range(_Right);
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
return _Left._Current <=> _Right._Current;
|
|
}
|
|
|
|
_NODISCARD_FRIEND constexpr _Iterator operator+(_Iterator _It, const difference_type _Off) noexcept(
|
|
noexcept(_It._Current += _Off)) /* strengthened */
|
|
requires random_access_range<_Base>
|
|
{
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_It._Verify_offset(_Off);
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
_It._Current += _Off;
|
|
return _It;
|
|
}
|
|
_NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, _Iterator _It) noexcept(
|
|
noexcept(_It._Current += _Off)) /* strengthened */
|
|
requires random_access_range<_Base>
|
|
{
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_It._Verify_offset(_Off);
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
_It._Current += _Off;
|
|
return _It;
|
|
}
|
|
|
|
_NODISCARD_FRIEND constexpr _Iterator operator-(_Iterator _It, const difference_type _Off) noexcept(
|
|
noexcept(_It._Current -= _Off)) /* 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
|
|
_It._Current -= _Off;
|
|
return _It;
|
|
}
|
|
|
|
_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>>
|
|
{
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_Left._Same_range(_Right);
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
return _Left._Current - _Right._Current;
|
|
}
|
|
};
|
|
|
|
template <bool _Const>
|
|
class _Sentinel {
|
|
private:
|
|
friend transform_view;
|
|
|
|
using _Parent_t = _Maybe_const<_Const, transform_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 {
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_STL_VERIFY(
|
|
_It._Parent != nullptr, "cannot compare transform_view sentinel with value-initialized iterator");
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
|
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_)) {}
|
|
|
|
// clang-format off
|
|
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)) {}
|
|
// clang-format on
|
|
|
|
_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;
|
|
}
|
|
|
|
// clang-format off
|
|
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;
|
|
}
|
|
// clang-format on
|
|
|
|
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:
|
|
// clang-format off
|
|
transform_view() requires default_initializable<_Vw> && default_initializable<_Fn> = default;
|
|
// clang-format on
|
|
|
|
constexpr explicit transform_view(_Vw _Range_, _Fn _Fun_) noexcept(
|
|
is_nothrow_move_constructible_v<_Vw>&& is_nothrow_move_constructible_v<_Fn>) // strengthened
|
|
: _Range(_STD move(_Range_)), _Fun{in_place, _STD move(_Fun_)} {}
|
|
|
|
_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 */ {
|
|
return _Iterator<false>{*this, _RANGES begin(_Range)};
|
|
}
|
|
|
|
_NODISCARD constexpr _Iterator<true> begin() const noexcept(
|
|
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */
|
|
#ifdef __clang__ // TRANSITION, LLVM-47414
|
|
requires _Can_const_transform<_Vw, _Fn>
|
|
#else // ^^^ workaround / no workaround vvv
|
|
requires range<const _Vw> && regular_invocable<const _Fn&, range_reference_t<const _Vw>>
|
|
#endif // TRANSITION, LLVM-47414
|
|
{
|
|
return _Iterator<true>{*this, _RANGES begin(_Range)};
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto end() noexcept(noexcept(
|
|
_RANGES end(_Range)) && is_nothrow_move_constructible_v<decltype(_RANGES end(_Range))>) /* strengthened */ {
|
|
// clang-format on
|
|
if constexpr (common_range<_Vw>) {
|
|
return _Iterator<false>{*this, _RANGES end(_Range)};
|
|
} else {
|
|
return _Sentinel<false>{_RANGES end(_Range)};
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto end() const noexcept(noexcept(
|
|
_RANGES end(_Range)) && is_nothrow_move_constructible_v<decltype(_RANGES end(_Range))>) /* strengthened */
|
|
#ifdef __clang__ // TRANSITION, LLVM-47414
|
|
requires _Can_const_transform<_Vw, _Fn>
|
|
#else // ^^^ workaround / no workaround vvv
|
|
requires range<const _Vw> && regular_invocable<const _Fn&, range_reference_t<const _Vw>>
|
|
#endif // TRANSITION, LLVM-47414
|
|
{
|
|
// clang-format on
|
|
if constexpr (common_range<_Vw>) {
|
|
return _Iterator<true>{*this, _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, class _Fn>
|
|
transform_view(_Rng&&, _Fn) -> transform_view<views::all_t<_Rng>, _Fn>;
|
|
|
|
namespace views {
|
|
struct _Transform_fn {
|
|
// clang-format off
|
|
template <viewable_range _Rng, class _Fn>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Fn _Fun) const noexcept(noexcept(
|
|
transform_view(_STD forward<_Rng>(_Range), _STD move(_Fun)))) requires requires {
|
|
transform_view(static_cast<_Rng&&>(_Range), _STD move(_Fun));
|
|
} {
|
|
// clang-format on
|
|
return transform_view(_STD forward<_Rng>(_Range), _STD move(_Fun));
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires constructible_from<decay_t<_Fn>, _Fn>
|
|
_NODISCARD constexpr auto operator()(_Fn&& _Fun) const
|
|
noexcept(is_nothrow_constructible_v<decay_t<_Fn>, _Fn>) {
|
|
return _Range_closure<_Transform_fn, decay_t<_Fn>>{_STD forward<_Fn>(_Fun)};
|
|
}
|
|
};
|
|
|
|
_EXPORT_STD inline constexpr _Transform_fn transform;
|
|
} // namespace views
|
|
|
|
_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_)) {}
|
|
|
|
// clang-format off
|
|
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)) {}
|
|
// clang-format on
|
|
|
|
_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;
|
|
|
|
// clang-format off
|
|
_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>&> {
|
|
// clang-format on
|
|
return _Sentinel<_Const, false>{_Last._Unwrapped()};
|
|
}
|
|
// clang-format off
|
|
_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>> {
|
|
// clang-format on
|
|
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:
|
|
// clang-format off
|
|
take_view() requires default_initializable<_Vw> = default;
|
|
// clang-format on
|
|
|
|
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_} {}
|
|
|
|
_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);
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto begin() requires (!_Simple_view<_Vw>) {
|
|
// clang-format on
|
|
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);
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto end() requires (!_Simple_view<_Vw>) {
|
|
// clang-format on
|
|
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>
|
|
inline constexpr bool enable_borrowed_range<take_view<_Rng>> = enable_borrowed_range<_Rng>;
|
|
|
|
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 constexpr auto operator()(_Rng&& _Range, range_difference_t<_Rng> _Count) const
|
|
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
|
|
} 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
|
|
} else if constexpr (_Strat == _St::_Reconstruct_subrange) {
|
|
return subrange(_First, _First + _Count);
|
|
} else {
|
|
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _Ty>
|
|
requires constructible_from<decay_t<_Ty>, _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Length) const
|
|
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
|
|
|
|
#ifdef __clang__
|
|
template <class _Vw, class _Pr> // TRANSITION, LLVM-47414
|
|
concept _Can_take_while_const = range<const _Vw> && indirect_unary_predicate<const _Pr, iterator_t<const _Vw>>;
|
|
#endif // ^^^ workaround ^^^
|
|
|
|
_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_) {}
|
|
|
|
// clang-format off
|
|
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) {}
|
|
// clang-format on
|
|
|
|
_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;
|
|
|
|
// clang-format off
|
|
_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>&> {
|
|
// clang-format on
|
|
return _Sentinel<_Const, false>{_Last._Unwrapped(), _Pred};
|
|
}
|
|
// clang-format off
|
|
_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>> {
|
|
// clang-format on
|
|
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:
|
|
// clang-format off
|
|
take_while_view() requires default_initializable<_Vw> && default_initializable<_Pr> = default;
|
|
// clang-format on
|
|
|
|
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 */
|
|
#ifdef __clang__ // TRANSITION, LLVM-47414
|
|
requires _Can_take_while_const<_Vw, _Pr>
|
|
#else // ^^^ workaround / no workaround vvv
|
|
requires range<const _Vw> && indirect_unary_predicate<const _Pr, iterator_t<const _Vw>>
|
|
#endif // TRANSITION, LLVM-47414
|
|
{
|
|
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 */
|
|
#ifdef __clang__ // TRANSITION, LLVM-47414
|
|
requires _Can_take_while_const<_Vw, _Pr>
|
|
#else // ^^^ workaround / no workaround vvv
|
|
requires range<const _Vw> && indirect_unary_predicate<const _Pr, iterator_t<const _Vw>>
|
|
#endif // TRANSITION, LLVM-47414
|
|
{
|
|
#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>;
|
|
|
|
namespace views {
|
|
struct _Take_while_fn {
|
|
template <viewable_range _Rng, class _Pr>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Pr _Pred) const
|
|
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 constexpr auto operator()(_Pr&& _Pred) const
|
|
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:
|
|
// clang-format off
|
|
drop_view() requires default_initializable<_Vw> = default;
|
|
// clang-format on
|
|
|
|
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 (N4928 [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);
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto begin()
|
|
requires (!(_Simple_view<_Vw> && random_access_range<const _Vw> && sized_range<const _Vw>)) {
|
|
// clang-format on
|
|
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;
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto begin() const
|
|
requires random_access_range<const _Vw> && sized_range<const _Vw> {
|
|
// clang-format on
|
|
const auto _Offset = (_STD min)(_RANGES distance(_Range), _Count);
|
|
return _RANGES begin(_Range) + _Offset;
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto end() requires (!_Simple_view<_Vw>) {
|
|
// clang-format on
|
|
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>
|
|
inline constexpr bool enable_borrowed_range<drop_view<_Rng>> = enable_borrowed_range<_Rng>;
|
|
|
|
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 constexpr auto operator()(_Rng&& _Range, range_difference_t<_Rng> _Count) const
|
|
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 {
|
|
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _Ty>
|
|
requires constructible_from<decay_t<_Ty>, _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Length) const
|
|
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:
|
|
// clang-format off
|
|
drop_while_view() requires default_initializable<_Vw> && default_initializable<_Pr> = default;
|
|
// clang-format on
|
|
|
|
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, "N4928 [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>
|
|
inline constexpr bool enable_borrowed_range<drop_while_view<_Rng, _Pr>> = enable_borrowed_range<_Rng>;
|
|
|
|
namespace views {
|
|
struct _Drop_while_fn {
|
|
template <viewable_range _Rng, class _Pr>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Pr _Pred) const
|
|
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 constexpr auto operator()(_Pr&& _Pred) const
|
|
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
|
|
|
|
#ifdef __clang__
|
|
template <class _Rng> // TRANSITION, LLVM-47414
|
|
concept _Can_const_join = forward_range<const _Rng> && is_reference_v<range_reference_t<const _Rng>>
|
|
&& input_range<range_reference_t<const _Rng>>;
|
|
#endif // ^^^ workaround ^^^
|
|
|
|
template <class _Ty>
|
|
_NODISCARD constexpr _Ty& _As_lvalue(_Ty&& _Val) noexcept {
|
|
return static_cast<_Ty&>(_Val);
|
|
}
|
|
|
|
_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(_Not_quite_object::_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
|
|
_Adl_verify_range(this->_Outer, _RANGES end(_Parent_._Range));
|
|
_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(_Not_quite_object::_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(_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:
|
|
// clang-format off
|
|
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>>;
|
|
// clang-format on
|
|
using value_type = range_value_t<_InnerRng<_Const>>;
|
|
using difference_type = common_type_t<range_difference_t<_Base>, range_difference_t<_InnerRng<_Const>>>;
|
|
|
|
// clang-format off
|
|
_Iterator() requires default_initializable<_OuterIter> = default;
|
|
// clang-format on
|
|
|
|
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;
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr _InnerIter operator->() const noexcept(is_nothrow_copy_constructible_v<_InnerIter>)
|
|
/* strengthened */ requires _Has_arrow<_InnerIter> && copyable<_InnerIter> {
|
|
// clang-format on
|
|
#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(_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;
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
constexpr _Iterator& operator--()
|
|
requires _Deref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<_InnerRng<_Const>>
|
|
&& common_range<_InnerRng<_Const>> {
|
|
// clang-format on
|
|
auto& _Outer = _Get_outer();
|
|
if (_Outer == _RANGES end(_Parent->_Range)) {
|
|
--_Outer;
|
|
_Inner = _RANGES end(_As_lvalue(*_Outer));
|
|
}
|
|
while (*_Inner == _RANGES begin(_As_lvalue(*_Outer))) {
|
|
--_Outer;
|
|
*_Inner = _RANGES end(_As_lvalue(*_Outer));
|
|
}
|
|
--*_Inner;
|
|
return *this;
|
|
}
|
|
|
|
// clang-format off
|
|
constexpr _Iterator operator--(int)
|
|
requires _Deref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<_InnerRng<_Const>>
|
|
&& common_range<_InnerRng<_Const>> {
|
|
// clang-format on
|
|
auto _Tmp = *this;
|
|
--*this;
|
|
return _Tmp;
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept(
|
|
noexcept(_Fake_copy_init<bool>(_Left._Outer == _Right._Outer
|
|
&& _Left._Inner == _Right._Inner))) /* strengthened */
|
|
requires _Deref_is_glvalue && forward_range<_Base> && equality_comparable<_InnerIter> {
|
|
// clang-format on
|
|
#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);
|
|
}
|
|
|
|
// clang-format off
|
|
friend constexpr void iter_swap(const _Iterator& _Left, const _Iterator& _Right) noexcept(
|
|
noexcept(_RANGES iter_swap(*_Left._Inner, *_Right._Inner)))
|
|
requires indirectly_swappable<_InnerIter> {
|
|
// clang-format on
|
|
#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{};
|
|
|
|
// clang-format off
|
|
template <bool _OtherConst>
|
|
requires sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
|
|
_NODISCARD constexpr bool _Equal(const _Iterator<_OtherConst>& _It) const noexcept(
|
|
noexcept(_Fake_copy_init<bool>(_It._Get_outer() == _Last))) {
|
|
// clang-format on
|
|
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)) {}
|
|
|
|
// clang-format off
|
|
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)) {}
|
|
// clang-format on
|
|
|
|
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:
|
|
// clang-format off
|
|
join_view() requires default_initializable<_Vw> = default;
|
|
// clang-format on
|
|
|
|
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
|
|
#ifdef __clang__ // TRANSITION, LLVM-47414
|
|
requires _Can_const_join<_Vw>
|
|
#else // ^^^ workaround / no workaround vvv
|
|
requires forward_range<const _Vw> && is_reference_v<_InnerRng<true>> && input_range<_InnerRng<true>>
|
|
#endif // TRANSITION, LLVM-47414
|
|
{
|
|
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
|
|
#ifdef __clang__ // TRANSITION, LLVM-47414
|
|
requires _Can_const_join<_Vw>
|
|
#else // ^^^ workaround / no workaround vvv
|
|
requires forward_range<const _Vw> && is_reference_v<_InnerRng<true>> && input_range<_InnerRng<true>>
|
|
#endif // TRANSITION, LLVM-47414
|
|
{
|
|
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>>;
|
|
|
|
namespace views {
|
|
class _Join_fn : public _Pipe::_Base<_Join_fn> {
|
|
public:
|
|
// clang-format off
|
|
template <viewable_range _Rng>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range) const noexcept(noexcept(
|
|
join_view<views::all_t<_Rng>>{_STD forward<_Rng>(_Range)})) requires requires {
|
|
join_view<views::all_t<_Rng>>{static_cast<_Rng&&>(_Range)};
|
|
} {
|
|
// clang-format on
|
|
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 _Rng, class _Pat>
|
|
concept _Compatible_joinable_ranges =
|
|
common_with<range_value_t<_Rng>, range_value_t<_Pat>>
|
|
&& common_reference_with<range_reference_t<_Rng>, range_reference_t<_Pat>>
|
|
&& common_reference_with<range_rvalue_reference_t<_Rng>, range_rvalue_reference_t<_Pat>>;
|
|
|
|
#ifdef __clang__
|
|
template <class _Rng, class _Pat> // TRANSITION, LLVM-47414
|
|
concept _Can_const_join_with =
|
|
forward_range<const _Rng> && forward_range<const _Pat> && is_reference_v<range_reference_t<const _Rng>>
|
|
&& input_range<range_reference_t<const _Rng>>;
|
|
#endif // ^^^ workaround ^^^
|
|
|
|
_EXPORT_STD template <input_range _Vw, forward_range _Pat>
|
|
requires view<_Vw> && input_range<range_reference_t<_Vw>> && view<_Pat>
|
|
&& _Compatible_joinable_ranges<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(_Not_quite_object::_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>
|
|
&& _Compatible_joinable_ranges<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 _As_lvalue(*_Get_outer());
|
|
} else {
|
|
return _Parent->_Inner._Emplace(_Not_quite_object::_Construct_tag{}, _Get_outer())._Val;
|
|
}
|
|
}
|
|
|
|
_NODISCARD constexpr auto& _Get_inner() noexcept {
|
|
if constexpr (_Deref_is_glvalue) {
|
|
return _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>;
|
|
|
|
// clang-format off
|
|
_Iterator() requires default_initializable<_OuterIter> = default;
|
|
// clang-format on
|
|
|
|
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) -> _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(_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:
|
|
// clang-format off
|
|
join_with_view() requires default_initializable<_Vw> && default_initializable<_Pat> = default;
|
|
// clang-format on
|
|
|
|
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
|
|
#ifdef __clang__ // TRANSITION, LLVM-47414
|
|
requires _Can_const_join_with<_Vw, _Pat>
|
|
#else // ^^^ workaround / no workaround vvv
|
|
requires forward_range<const _Vw> && forward_range<const _Pat> && is_reference_v<_InnerRng<true>>
|
|
&& input_range<_InnerRng<true>>
|
|
#endif // TRANSITION, LLVM-47414
|
|
{
|
|
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
|
|
#ifdef __clang__ // TRANSITION, LLVM-47414
|
|
requires _Can_const_join_with<_Vw, _Pat>
|
|
#else // ^^^ workaround / no workaround vvv
|
|
requires forward_range<const _Vw> && forward_range<const _Pat> && is_reference_v<_InnerRng<true>>
|
|
&& input_range<_InnerRng<true>>
|
|
#endif // TRANSITION, LLVM-47414
|
|
{
|
|
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>>>>;
|
|
|
|
namespace views {
|
|
struct _Join_with_fn {
|
|
// clang-format off
|
|
template <viewable_range _Rng, class _Pat>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Pat&& _Pattern) const 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));
|
|
}
|
|
{ // clang-format on
|
|
return join_with_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern));
|
|
}
|
|
|
|
template <class _Delim>
|
|
requires constructible_from<decay_t<_Delim>, _Delim>
|
|
_NODISCARD constexpr auto operator()(_Delim&& _Delimiter) const
|
|
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 <auto> // _Require_constant<E> is a valid template-id iff E is a constant expression of structural type
|
|
struct _Require_constant;
|
|
|
|
// clang-format off
|
|
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;
|
|
// clang-format on
|
|
|
|
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>> {};
|
|
|
|
// clang-format off
|
|
_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> {
|
|
// clang-format on
|
|
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(_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{};
|
|
|
|
public:
|
|
value_type() = default;
|
|
constexpr explicit value_type(_Outer_iter _First_) noexcept(
|
|
is_nothrow_move_constructible_v<_Outer_iter>) // strengthened
|
|
: _First{_STD move(_First_)} {}
|
|
|
|
_NODISCARD constexpr auto begin() const {
|
|
return _Inner_iter<_Const>{_First};
|
|
}
|
|
|
|
_NODISCARD constexpr default_sentinel_t end() const noexcept {
|
|
return default_sentinel;
|
|
}
|
|
};
|
|
|
|
_Outer_iter() = default;
|
|
|
|
// clang-format off
|
|
constexpr explicit _Outer_iter(_ParentTy& _Parent_) noexcept // strengthened
|
|
requires (!forward_range<_BaseTy>) : _Parent{_STD addressof(_Parent_)} {}
|
|
// clang-format on
|
|
|
|
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} {}
|
|
|
|
_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 = typename 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 = typename _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());
|
|
}
|
|
|
|
// clang-format off
|
|
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>> {
|
|
// clang-format on
|
|
_RANGES iter_swap(_Left._Get_current(), _Right._Get_current());
|
|
}
|
|
};
|
|
|
|
public:
|
|
// clang-format off
|
|
lazy_split_view() requires default_initializable<_Vw> && default_initializable<_Pat> = default;
|
|
// clang-format on
|
|
|
|
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_)) {}
|
|
|
|
// clang-format off
|
|
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))) {}
|
|
// clang-format on
|
|
|
|
_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>>>;
|
|
|
|
namespace views {
|
|
struct _Lazy_split_fn {
|
|
// clang-format off
|
|
template <viewable_range _Rng, class _Pat>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Pat&& _Pattern) const 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));
|
|
} {
|
|
// clang-format on
|
|
return lazy_split_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern));
|
|
}
|
|
|
|
template <class _Delim>
|
|
requires constructible_from<decay_t<_Delim>, _Delim>
|
|
_NODISCARD constexpr auto operator()(_Delim&& _Delimiter) const
|
|
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;
|
|
}
|
|
|
|
#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-1559808
|
|
auto [_Begin, _End] = _RANGES search(subrange{_Current, _Last}, _Parent->_Pattern);
|
|
#else // ^^^ no workaround / workaround vvv
|
|
auto _Match = _RANGES search(subrange{_Current, _Last}, _Parent->_Pattern);
|
|
auto _Begin = _Match.begin();
|
|
auto _End = _Match.end();
|
|
#endif // TRANSITION, DevCom-1559808
|
|
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(_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);
|
|
#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-1559808
|
|
auto [_Begin, _End] = _RANGES search(subrange{_It, _Last}, _Pattern);
|
|
#else // ^^^ no workaround / workaround vvv
|
|
auto _Match = _RANGES search(subrange{_It, _Last}, _Pattern);
|
|
auto _Begin = _Match.begin();
|
|
auto _End = _Match.end();
|
|
#endif // TRANSITION, DevCom-1559808
|
|
if (_Begin != _Last && _RANGES empty(_Pattern)) {
|
|
++_Begin;
|
|
++_End;
|
|
}
|
|
|
|
return {_STD move(_Begin), _STD move(_End)};
|
|
}
|
|
|
|
public:
|
|
// clang-format off
|
|
split_view() requires default_initializable<_Vw> && default_initializable<_Pat> = default;
|
|
// clang-format on
|
|
|
|
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_)) {}
|
|
|
|
// clang-format off
|
|
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))) {}
|
|
// clang-format on
|
|
|
|
_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>>>;
|
|
|
|
namespace views {
|
|
struct _Split_fn {
|
|
// clang-format off
|
|
template <viewable_range _Rng, class _Pat>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Pat&& _Pattern) const noexcept(noexcept(
|
|
split_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern)))) requires requires {
|
|
split_view(static_cast<_Rng&&>(_Range), static_cast<_Pat&&>(_Pattern));
|
|
} {
|
|
// clang-format on
|
|
return split_view(_STD forward<_Rng>(_Range), _STD forward<_Pat>(_Pattern));
|
|
}
|
|
|
|
template <class _Delim>
|
|
requires constructible_from<decay_t<_Delim>, _Delim>
|
|
_NODISCARD constexpr auto operator()(_Delim&& _Delimiter) const
|
|
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:
|
|
// clang-format off
|
|
template <class _It>
|
|
requires (input_or_output_iterator<decay_t<_It>> && _Choice<_It>._Strategy != _St::_None)
|
|
_NODISCARD constexpr auto operator()(_It&& _First, const iter_difference_t<decay_t<_It>> _Count) const
|
|
noexcept(_Choice<_It>._No_throw) {
|
|
// clang-format on
|
|
_STL_ASSERT(_Count >= 0, "The size passed to views::counted must be non-negative");
|
|
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:
|
|
// clang-format off
|
|
common_view() requires default_initializable<_Vw> = default;
|
|
// clang-format on
|
|
|
|
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 */ {
|
|
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() {
|
|
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>
|
|
inline constexpr bool enable_borrowed_range<common_view<_Rng>> = enable_borrowed_range<_Rng>;
|
|
|
|
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 constexpr auto operator()(_Rng&& _Range) const 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 {
|
|
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
|
}
|
|
}
|
|
};
|
|
|
|
_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:
|
|
// clang-format off
|
|
reverse_view() requires default_initializable<_Vw> = default;
|
|
// clang-format on
|
|
|
|
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>
|
|
inline constexpr bool enable_borrowed_range<reverse_view<_Rng>> = enable_borrowed_range<_Rng>;
|
|
|
|
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 constexpr auto operator()(_Rng&& _Range) const 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 {
|
|
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
|
}
|
|
}
|
|
};
|
|
|
|
_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:
|
|
// clang-format off
|
|
as_const_view() requires default_initializable<_Vw> = default;
|
|
// clang-format on
|
|
|
|
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>
|
|
inline constexpr bool enable_borrowed_range<as_const_view<_Rng>> = enable_borrowed_range<_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 constexpr auto operator()(_Rng&& _Range) const 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 {
|
|
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
|
}
|
|
}
|
|
};
|
|
|
|
_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 // ^^^ C++23 / C++20 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 // C++20
|
|
|
|
template <class _Tuple, size_t _Index>
|
|
concept _Returnable_element = is_reference_v<_Tuple> || move_constructible<tuple_element_t<_Index, _Tuple>>;
|
|
|
|
// clang-format off
|
|
_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>> {
|
|
// clang-format on
|
|
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>;
|
|
|
|
// clang-format off
|
|
_Iterator() requires default_initializable<iterator_t<_Base>> = default;
|
|
// clang-format on
|
|
|
|
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);
|
|
}
|
|
|
|
// clang-format off
|
|
_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>> {
|
|
// clang-format on
|
|
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_)) {}
|
|
|
|
// clang-format off
|
|
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)) {}
|
|
// clang-format on
|
|
|
|
_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;
|
|
}
|
|
|
|
// clang-format off
|
|
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 */ {
|
|
// clang-format on
|
|
return _Get_current(_Left) - _Right._Last;
|
|
}
|
|
|
|
// clang-format off
|
|
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 */ {
|
|
// clang-format on
|
|
return _Left._Last - _Get_current(_Right);
|
|
}
|
|
};
|
|
|
|
public:
|
|
// clang-format off
|
|
elements_view() requires default_initializable<_Vw> = default;
|
|
// clang-format on
|
|
|
|
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);
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr _Iterator<false> begin() noexcept(
|
|
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */
|
|
requires (!_Simple_view<_Vw>) {
|
|
// clang-format on
|
|
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)};
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto end() noexcept(noexcept(
|
|
_RANGES end(_Range)) && is_nothrow_move_constructible_v<sentinel_t<_Vw>>) /* strengthened */
|
|
requires (!_Simple_view<_Vw>) {
|
|
// clang-format on
|
|
if constexpr (common_range<_Vw>) {
|
|
return _Iterator<false>{_RANGES end(_Range)};
|
|
} else {
|
|
return _Sentinel<false>{_RANGES end(_Range)};
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto end() const noexcept(noexcept(
|
|
_RANGES end(_Range)) && is_nothrow_move_constructible_v<sentinel_t<const _Vw>>) /* strengthened */
|
|
requires range<const _Vw> {
|
|
// clang-format on
|
|
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>
|
|
inline constexpr bool enable_borrowed_range<elements_view<_Rng, _Index>> = enable_borrowed_range<_Rng>;
|
|
|
|
_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 constexpr auto operator()(_Rng&& _Range) const
|
|
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>
|
|
inline 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>>;
|
|
|
|
// clang-format off
|
|
_Iterator() requires default_initializable<_Base_iterator> = default;
|
|
// clang-format on
|
|
|
|
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 /* strengthened */ {
|
|
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(_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:
|
|
// clang-format off
|
|
constexpr enumerate_view() requires default_initializable<_Vw> = default;
|
|
// clang-format on
|
|
|
|
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 (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 (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>
|
|
inline constexpr bool enable_borrowed_range<enumerate_view<_Rng>> = enable_borrowed_range<_Rng>;
|
|
|
|
namespace views {
|
|
class _Enumerate_fn : public _Pipe::_Base<_Enumerate_fn> {
|
|
public:
|
|
template <viewable_range _Rng>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range) const
|
|
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(_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(_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(_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(_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(_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(_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);
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto begin() noexcept(
|
|
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */
|
|
requires (!_Simple_view<_Vw>) {
|
|
// clang-format on
|
|
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)};
|
|
}
|
|
|
|
// clang-format off
|
|
_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>) {
|
|
// clang-format on
|
|
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;
|
|
}
|
|
}
|
|
|
|
// clang-format off
|
|
_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> {
|
|
// clang-format on
|
|
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>
|
|
inline constexpr bool enable_borrowed_range<chunk_view<_Vw>> = enable_borrowed_range<_Vw> && forward_range<_Vw>;
|
|
|
|
namespace views {
|
|
struct _Chunk_fn {
|
|
// clang-format off
|
|
template <viewable_range _Rng>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, const range_difference_t<_Rng> _Count) const noexcept(
|
|
noexcept(chunk_view(_STD forward<_Rng>(_Range), _Count))) requires requires {
|
|
chunk_view(_STD forward<_Rng>(_Range), _Count);
|
|
} {
|
|
// clang-format on
|
|
return chunk_view(_STD forward<_Rng>(_Range), _Count);
|
|
}
|
|
|
|
template <class _Ty>
|
|
requires constructible_from<decay_t<_Ty>, _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Count) const
|
|
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(_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(_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(_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(_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(_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(_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 (N4928 [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);
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto begin() requires (!(_Simple_view<_Vw> && _Slide_caches_nothing<const _Vw>) ) {
|
|
// clang-format on
|
|
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};
|
|
}
|
|
|
|
// clang-format off
|
|
_NODISCARD constexpr auto end() requires (!(_Simple_view<_Vw> && _Slide_caches_nothing<const _Vw>) ) {
|
|
// clang-format on
|
|
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>
|
|
inline constexpr bool enable_borrowed_range<slide_view<_Vw>> = enable_borrowed_range<_Vw>;
|
|
|
|
namespace views {
|
|
struct _Slide_fn {
|
|
// clang-format off
|
|
template <viewable_range _Rng>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, const range_difference_t<_Rng> _Count) const noexcept(
|
|
noexcept(slide_view(_STD forward<_Rng>(_Range), _Count))) requires requires {
|
|
slide_view(_STD forward<_Rng>(_Range), _Count);
|
|
} {
|
|
// clang-format on
|
|
return slide_view(_STD forward<_Rng>(_Range), _Count);
|
|
}
|
|
|
|
template <class _Ty>
|
|
requires constructible_from<decay_t<_Ty>, _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Count) const
|
|
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(_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(_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:
|
|
// clang-format off
|
|
chunk_by_view() requires default_initializable<_Vw> && default_initializable<_Pr> = default;
|
|
// clang-format on
|
|
|
|
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>;
|
|
|
|
namespace views {
|
|
struct _Chunk_by_fn {
|
|
// clang-format off
|
|
template <viewable_range _Rng, class _Pr>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Pr&& _Pred) const 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));
|
|
} {
|
|
// clang-format on
|
|
return chunk_by_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred));
|
|
}
|
|
|
|
template <class _Pr>
|
|
requires constructible_from<decay_t<_Pr>, _Pr>
|
|
_NODISCARD constexpr auto operator()(_Pr&& _Pred) const
|
|
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 = typename 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>>>;
|
|
|
|
// clang-format off
|
|
_Iterator() requires default_initializable<_Base_iterator> = default;
|
|
// clang-format on
|
|
|
|
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(_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(_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(_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(_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(_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(_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>
|
|
inline constexpr bool enable_borrowed_range<stride_view<_Vw>> = enable_borrowed_range<_Vw>;
|
|
|
|
namespace views {
|
|
struct _Stride_fn {
|
|
// clang-format off
|
|
template <viewable_range _Rng>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, const range_difference_t<_Rng> _Stride) const noexcept(
|
|
noexcept(stride_view(_STD forward<_Rng>(_Range), _Stride))) requires requires {
|
|
stride_view(_STD forward<_Rng>(_Range), _Stride);
|
|
} {
|
|
// clang-format on
|
|
return stride_view(_STD forward<_Rng>(_Range), _Stride);
|
|
}
|
|
|
|
template <class _Ty>
|
|
requires constructible_from<decay_t<_Ty>, _Ty>
|
|
_NODISCARD constexpr auto operator()(_Ty&& _Stride) const
|
|
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)
|
|
// clang-format off
|
|
noexcept((noexcept(_STD declval<const _LHSTupleTypes&>() == _STD declval<const _RHSTupleTypes&>()) && ...)) {
|
|
// clang-format on
|
|
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)) || ...);
|
|
};
|
|
|
|
return _Evaluate_equality_closure(index_sequence_for<_LHSTupleTypes...>{});
|
|
}
|
|
|
|
#ifdef __clang__
|
|
template <bool _IsConst, class... _ViewTypes> // TRANSITION, LLVM-47414
|
|
concept _Zip_iter_converts = _IsConst
|
|
&& (convertible_to<iterator_t<_ViewTypes>, iterator_t<const _ViewTypes>> && ...);
|
|
|
|
template <bool _IsConst, class... _ViewTypes> // TRANSITION, LLVM-47414
|
|
concept _Zip_sent_converts = _IsConst
|
|
&& (convertible_to<sentinel_t<_ViewTypes>, sentinel_t<const _ViewTypes>> && ...);
|
|
#endif // ^^^ workaround ^^^
|
|
|
|
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;
|
|
|
|
template <class _Func, class... _OtherViews>
|
|
requires _Zip_transform_constraints<_Func, _OtherViews...>
|
|
friend class zip_transform_view;
|
|
|
|
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
|
|
#ifdef __clang__ // TRANSITION, LLVM-47414
|
|
requires _Zip_iter_converts<_IsConst, _ViewTypes...>
|
|
#else // ^^^ workaround / no workaround vvv
|
|
requires (_IsConst && (convertible_to<iterator_t<_ViewTypes>, iterator_t<const _ViewTypes>> && ...))
|
|
#endif // __clang__
|
|
: _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) noexcept(noexcept(*_Itr)) -> decltype(auto) { return *_Itr; }, _Current);
|
|
}
|
|
|
|
constexpr _Iterator& operator++() noexcept(noexcept(
|
|
_Tuple_for_each([](auto& _Itr) noexcept(noexcept(++_Itr)) { ++_Itr; }, _Current))) /* strengthened */ {
|
|
_Tuple_for_each([](auto& _Itr) 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) noexcept(noexcept(--_Itr)) { --_Itr; }, _Current))) // strengthened
|
|
requires _All_bidirectional<_IsConst, _ViewTypes...>
|
|
{
|
|
_Tuple_for_each([](auto& _Itr) 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);
|
|
}
|
|
|
|
// clang-format off
|
|
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>>> && ...)
|
|
{
|
|
// clang-format on
|
|
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
|
|
#ifdef __clang__ // TRANSITION, LLVM-47414
|
|
requires _Zip_sent_converts<_IsConst, _ViewTypes...>
|
|
#else // ^^^ workaround / no workaround vvv
|
|
requires (_IsConst && (convertible_to<sentinel_t<_ViewTypes>, sentinel_t<const _ViewTypes>> && ...))
|
|
#endif // __clang__
|
|
: _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...>>&>())});
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
private:
|
|
_NODISCARD static constexpr auto _Size_closure() noexcept {
|
|
return [](auto... _Sizes) noexcept {
|
|
using _Common_unsigned_type = _Make_unsigned_like_t<common_type_t<decltype(_Sizes)...>>;
|
|
return (_RANGES min)({static_cast<_Common_unsigned_type>(_Sizes)...});
|
|
};
|
|
}
|
|
};
|
|
|
|
template <class... _RangeTypes>
|
|
zip_view(_RangeTypes&&...) -> zip_view<views::all_t<_RangeTypes>...>;
|
|
|
|
template <class... _ViewTypes>
|
|
inline constexpr bool enable_borrowed_range<zip_view<_ViewTypes...>> = (enable_borrowed_range<_ViewTypes> && ...);
|
|
|
|
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 constexpr auto operator()(_Types&&... _Args) const 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
|
|
|
|
_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 = typename _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};
|
|
}
|
|
|
|
// clang-format off
|
|
_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>>
|
|
{
|
|
// clang-format on
|
|
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()});
|
|
}
|
|
}
|
|
|
|
static constexpr bool _Enable_const_begin_end =
|
|
(range<const _Inner_view> && regular_invocable<const _Func&, range_reference_t<const _ViewTypes>...>);
|
|
|
|
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 _Enable_const_begin_end
|
|
{
|
|
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 _Enable_const_begin_end
|
|
{
|
|
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>...>;
|
|
|
|
namespace views {
|
|
struct _Zip_transform_fn {
|
|
private:
|
|
template <class _Func, class... _Types>
|
|
static constexpr bool _Is_invocation_noexcept = []() 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>
|
|
static constexpr bool _Enable_cpo = []() noexcept {
|
|
if constexpr (sizeof...(_Types) == 0) {
|
|
// This is a more efficient implementation of the CPO requirements listed in
|
|
// N4928 [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 {
|
|
// clang-format off
|
|
return requires(_Func&& _Function, _Types&&... _Args)
|
|
{ zip_transform_view(_STD forward<_Func>(_Function), _STD forward<_Types>(_Args)...); };
|
|
// clang-format on
|
|
}
|
|
}();
|
|
|
|
public:
|
|
template <class _Func, class... _Types>
|
|
requires _Enable_cpo<_Func, _Types...>
|
|
_NODISCARD constexpr auto operator()(_Func&& _Function, _Types&&... _Args) const
|
|
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 = typename _Repeated_tuple_impl<_Ty, make_index_sequence<_Nx>>::type;
|
|
|
|
template <class _Fn, class _Ty, class _Indices>
|
|
inline constexpr bool _Regular_invocable_with_repeated_type_impl = false;
|
|
|
|
template <class _Fn, class _Ty, size_t... _Indices>
|
|
inline 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...>> {
|
|
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1761088
|
|
using type = invoke_result_t<_Fn, _Repeat_type<_Ty, _Indices>...>;
|
|
#else // ^^^ no workaround / workaround vvv
|
|
using type = decltype(_STD invoke(_STD declval<_Fn>(), _STD declval<_Repeat_type<_Ty, _Indices>>()...));
|
|
#endif // ^^^ workaround ^^^
|
|
};
|
|
|
|
template <class _Fn, class _Ty, size_t _Nx>
|
|
using _Invoke_result_with_repeated_type =
|
|
typename _Invoke_result_with_repeated_type_impl<_Fn, _Ty, make_index_sequence<_Nx>>::type;
|
|
|
|
_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;
|
|
|
|
template <forward_range _Vw2, move_constructible _Fn, size_t _Nx2>
|
|
requires view<_Vw2> && (_Nx2 > 0)
|
|
&& is_object_v<_Fn> && _Regular_invocable_with_repeated_type<_Fn&, range_reference_t<_Vw2>, _Nx2>
|
|
&& _Can_reference<_Invoke_result_with_repeated_type<_Fn&, range_reference_t<_Vw2>, _Nx2>>
|
|
friend class adjacent_transform_view;
|
|
|
|
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) -> 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(_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(_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(_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:
|
|
// clang-format off
|
|
adjacent_view() requires default_initializable<_Vw> = default;
|
|
// clang-format on
|
|
|
|
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>
|
|
inline constexpr bool enable_borrowed_range<adjacent_view<_Rng, _Nx>> = enable_borrowed_range<_Rng>;
|
|
|
|
namespace views {
|
|
template <size_t _Nx>
|
|
class _Adjacent_fn : public _Pipe::_Base<_Adjacent_fn<_Nx>> {
|
|
public:
|
|
template <viewable_range _Rng>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range) const
|
|
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 constexpr auto operator()(_Rng&&) const noexcept
|
|
requires (_Nx == 0)
|
|
{
|
|
return empty_view<tuple<>>{};
|
|
}
|
|
};
|
|
|
|
_EXPORT_STD template <size_t _Nx>
|
|
inline constexpr _Adjacent_fn<_Nx> adjacent;
|
|
_EXPORT_STD inline constexpr _Adjacent_fn<2> pairwise;
|
|
} // namespace views
|
|
|
|
_EXPORT_STD template <forward_range _Vw, move_constructible _Fn, size_t _Nx>
|
|
requires view<_Vw> && (_Nx > 0)
|
|
&& is_object_v<_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>>
|
|
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 = typename 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 = typename _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<_Inner_view>
|
|
{
|
|
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();
|
|
}
|
|
};
|
|
|
|
namespace views {
|
|
template <size_t _Nx>
|
|
class _Adjacent_transform_fn {
|
|
public:
|
|
template <viewable_range _Rng, class _Fn>
|
|
_NODISCARD constexpr auto operator()(_Rng&&, _Fn&& _Func) const
|
|
noexcept(noexcept(views::zip_transform(_STD forward<_Fn>(_Func))))
|
|
requires (_Nx == 0)
|
|
#ifndef __clang__ // TRANSITION, Clang 16
|
|
&& requires { views::zip_transform(_STD forward<_Fn>(_Func)); }
|
|
#endif // __clang__
|
|
{
|
|
return views::zip_transform(_STD forward<_Fn>(_Func));
|
|
}
|
|
|
|
template <viewable_range _Rng, class _Fn>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Fn&& _Func) const
|
|
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 constexpr auto operator()(_Fn&& _Func) const
|
|
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>
|
|
inline constexpr _Adjacent_transform_fn<_Nx> adjacent_transform;
|
|
_EXPORT_STD inline constexpr _Adjacent_transform_fn<2> pairwise_transform;
|
|
} // namespace views
|
|
|
|
template <_Integer_like _Int>
|
|
_NODISCARD constexpr bool _Add_with_overflow_check(const _Int _Left, const _Int _Right, _Int& _Out) {
|
|
#ifdef __clang__
|
|
if constexpr (integral<_Int>) {
|
|
return __builtin_add_overflow(_Left, _Right, &_Out);
|
|
} else
|
|
#endif // __clang__
|
|
{
|
|
if constexpr (!_Signed_integer_like<_Int>) {
|
|
_Out = static_cast<_Int>(_Left + _Right);
|
|
return _Out < _Left || _Out < _Right;
|
|
} else {
|
|
using _UInt = _Make_unsigned_like_t<_Int>;
|
|
_Out = static_cast<_Int>(static_cast<_UInt>(_Left) + static_cast<_UInt>(_Right));
|
|
return (_Left > 0 && _Right > 0 && _Out <= 0) || (_Left < 0 && _Right < 0 && _Out >= 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <_Integer_like _Int>
|
|
_NODISCARD constexpr bool _Multiply_with_overflow_check(const _Int _Left, const _Int _Right, _Int& _Out) {
|
|
#ifdef __clang__
|
|
if constexpr (integral<_Int>) {
|
|
return __builtin_mul_overflow(_Left, _Right, &_Out);
|
|
} else
|
|
#endif // __clang__
|
|
{
|
|
if constexpr (!_Signed_integer_like<_Int>) {
|
|
_Out = static_cast<_Int>(_Left * _Right);
|
|
return _Left != 0 && _Right > (numeric_limits<_Int>::max)() / _Left;
|
|
} else {
|
|
// vvv Based on llvm::MulOverflow vvv
|
|
// https://github.com/llvm/llvm-project/blob/88e5206/llvm/include/llvm/Support/MathExtras.h#L725-L750
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
using _UInt = _Make_unsigned_like_t<_Int>;
|
|
const _UInt _ULeft = _Left < 0 ? (0 - static_cast<_UInt>(_Left)) : static_cast<_UInt>(_Left);
|
|
const _UInt _URight = _Right < 0 ? (0 - static_cast<_UInt>(_Right)) : static_cast<_UInt>(_Right);
|
|
const _UInt _UResult = static_cast<_UInt>(_ULeft * _URight);
|
|
|
|
const bool _Negative = (_Left < 0) != (_Right < 0);
|
|
_Out = static_cast<_Int>(_Negative ? (0 - _UResult) : _UResult);
|
|
if (_ULeft == 0 || _URight == 0) {
|
|
return false;
|
|
}
|
|
|
|
if (_Negative) {
|
|
return _ULeft > (static_cast<_UInt>((numeric_limits<_Int>::max)()) + _UInt{1}) / _URight;
|
|
} else {
|
|
return _ULeft > static_cast<_UInt>((numeric_limits<_Int>::max)()) / _URight;
|
|
}
|
|
// ^^^ Based on llvm::MulOverflow ^^^
|
|
}
|
|
}
|
|
}
|
|
|
|
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 <sized_range _Ty>
|
|
inline constexpr auto _Compile_time_max_size = (numeric_limits<range_size_t<_Ty>>::max)();
|
|
|
|
template <class _Ty>
|
|
concept _Constant_sized_range =
|
|
sized_range<_Ty> && requires { typename _Require_constant<remove_reference_t<_Ty>::size()>; };
|
|
|
|
template <_Constant_sized_range _Ty>
|
|
inline constexpr auto _Compile_time_max_size<_Ty> = remove_reference_t<_Ty>::size();
|
|
|
|
template <class _Ty, size_t _Size>
|
|
inline constexpr auto _Compile_time_max_size<array<_Ty, _Size>> = _Size;
|
|
|
|
template <class _Ty, size_t _Size>
|
|
inline constexpr auto _Compile_time_max_size<const array<_Ty, _Size>> = _Size;
|
|
|
|
template <class _Ty, size_t _Extent>
|
|
requires (_Extent != dynamic_extent)
|
|
inline constexpr auto _Compile_time_max_size<span<_Ty, _Extent>> = _Extent;
|
|
|
|
template <class _Ty, size_t _Extent>
|
|
requires (_Extent != dynamic_extent)
|
|
inline constexpr auto _Compile_time_max_size<const span<_Ty, _Extent>> = _Extent;
|
|
|
|
template <class _Ty>
|
|
inline constexpr auto _Compile_time_max_size<ref_view<_Ty>> = _Compile_time_max_size<_Ty>;
|
|
|
|
template <class _Ty>
|
|
requires sized_range<const _Ty>
|
|
inline constexpr auto _Compile_time_max_size<const ref_view<_Ty>> = _Compile_time_max_size<const _Ty>;
|
|
|
|
template <class _Ty>
|
|
inline constexpr auto _Compile_time_max_size<owning_view<_Ty>> = _Compile_time_max_size<_Ty>;
|
|
|
|
template <class _Ty>
|
|
requires sized_range<const _Ty>
|
|
inline constexpr auto _Compile_time_max_size<const owning_view<_Ty>> = _Compile_time_max_size<const _Ty>;
|
|
|
|
template <range _Rng>
|
|
_NODISCARD _CONSTEVAL int _Cartesian_product_max_size_bit_width() noexcept {
|
|
if constexpr (sized_range<_Rng>) {
|
|
if constexpr (requires(range_size_t<_Rng> _Val) { _STD bit_width(_Val); }) {
|
|
return _STD bit_width(_Compile_time_max_size<_Rng>);
|
|
} else {
|
|
return numeric_limits<range_size_t<_Rng>>::digits;
|
|
}
|
|
} else {
|
|
return numeric_limits<_Make_unsigned_like_t<range_difference_t<_Rng>>>::digits;
|
|
}
|
|
}
|
|
|
|
template <class _First, class... _Rest>
|
|
_NODISCARD _CONSTEVAL auto _Cartesian_product_optimal_size_type() noexcept {
|
|
constexpr int _Optimal_size_type_bit_width =
|
|
(_Cartesian_product_max_size_bit_width<_First>() + ... + _Cartesian_product_max_size_bit_width<_Rest>());
|
|
if constexpr (_Optimal_size_type_bit_width <= 8) {
|
|
return uint_least8_t{};
|
|
} else if constexpr (_Optimal_size_type_bit_width <= 16) {
|
|
return uint_least16_t{};
|
|
} else if constexpr (_Optimal_size_type_bit_width <= 32) {
|
|
return uint_least32_t{};
|
|
} else if constexpr (_Optimal_size_type_bit_width <= 64) {
|
|
return uint_least64_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 "
|
|
"(N4928 [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 (N4928 "
|
|
"[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 =
|
|
_Multiply_with_overflow_check(_Size, _Distance_from<_Index - 1>(_Tpl), _Result)
|
|
|| _Add_with_overflow_check(_Result, _Diff, _Result);
|
|
#if _ITERATOR_DEBUG_LEVEL != 0
|
|
_STL_VERIFY(!_Overflow, "Scaled-sum cannot be represented by difference_type (N4928 "
|
|
"[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) -> 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>>>)
|
|
{
|
|
return [&]<size_t... _Indices>(index_sequence<_Indices...>) {
|
|
return (_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)) || ...);
|
|
}
|
|
(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)) || ...);
|
|
}
|
|
(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
|
|
_Size_type<false> _Product{1};
|
|
const bool _Overflow =
|
|
(_Multiply_with_overflow_check(
|
|
_Product, static_cast<_Size_type<false>>(_RANGES size(_STD get<_Indices>(_Bases))), _Product)
|
|
|| ...);
|
|
_STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4928 "
|
|
"[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
|
|
_Size_type<true> _Product{1};
|
|
const bool _Overflow =
|
|
(_Multiply_with_overflow_check(
|
|
_Product, static_cast<_Size_type<true>>(_RANGES size(_STD get<_Indices>(_Bases))), _Product)
|
|
|| ...);
|
|
_STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4928 "
|
|
"[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>...>;
|
|
|
|
namespace views {
|
|
class _Cartesian_product_fn {
|
|
public:
|
|
_NODISCARD constexpr auto operator()() const noexcept {
|
|
return views::single(tuple{});
|
|
}
|
|
|
|
template <class... _Rngs>
|
|
_NODISCARD constexpr auto operator()(_Rngs&&... _Ranges) const
|
|
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
|
|
|
|
#ifdef __cpp_lib_ranges_to_container
|
|
// clang-format off
|
|
template <class _Range, class _Container>
|
|
concept _Sized_and_reservable = sized_range<_Range> && sized_range<_Container>
|
|
&& requires(_Container& _Cont, const range_size_t<_Container> _Count) {
|
|
_Cont.reserve(_Count);
|
|
{ _Cont.capacity() } -> same_as<range_size_t<_Container>>;
|
|
{ _Cont.max_size() } -> same_as<range_size_t<_Container>>;
|
|
};
|
|
// clang-format on
|
|
|
|
template <class _Rng, class _Container>
|
|
concept _Ref_converts =
|
|
(!input_range<_Container>) || convertible_to<range_reference_t<_Rng>, range_value_t<_Container>>;
|
|
|
|
template <class _Rng, class _Container, class... _Types>
|
|
concept _Converts_direct_constructible = _Ref_converts<_Rng, _Container> //
|
|
&& constructible_from<_Container, _Rng, _Types...>;
|
|
|
|
template <class _Rng, class _Container, class... _Types>
|
|
concept _Converts_tag_constructible = _Ref_converts<_Rng, _Container>
|
|
// per LWG issue unnumbered as of 2022-08-08
|
|
&& constructible_from<_Container, const from_range_t&, _Rng, _Types...>;
|
|
|
|
template <class _Rng, class _Container, class... _Types>
|
|
concept _Converts_and_common_constructible =
|
|
_Ref_converts<_Rng, _Container> && common_range<_Rng> //
|
|
&& requires { typename iterator_traits<iterator_t<_Rng>>::iterator_category; }
|
|
&& derived_from<typename iterator_traits<iterator_t<_Rng>>::iterator_category, input_iterator_tag>
|
|
&& constructible_from<_Container, iterator_t<_Rng>, iterator_t<_Rng>, _Types...>;
|
|
|
|
template <class _Container, class _Reference>
|
|
concept _Can_push_back = requires(_Container& _Cont) { _Cont.push_back(_STD declval<_Reference>()); };
|
|
|
|
template <class _Container, class _Reference>
|
|
concept _Can_insert_end = requires(_Container& _Cont) { _Cont.insert(_Cont.end(), _STD declval<_Reference>()); };
|
|
|
|
// clang-format off
|
|
template <class _Rng, class _Container, class... _Types>
|
|
concept _Converts_constructible_insertable = _Ref_converts<_Rng, _Container>
|
|
&& constructible_from<_Container, _Types...>
|
|
&& (_Can_push_back<_Container, range_reference_t<_Rng>>
|
|
|| _Can_insert_end<_Container, range_reference_t<_Rng>>);
|
|
// clang-format on
|
|
|
|
template <class _Reference, class _Container>
|
|
_NODISCARD constexpr auto _Container_inserter(_Container& _Cont) {
|
|
if constexpr (_Can_push_back<_Container, _Reference>) {
|
|
return back_insert_iterator{_Cont};
|
|
} else {
|
|
return insert_iterator{_Cont, _Cont.end()};
|
|
}
|
|
}
|
|
|
|
_EXPORT_STD template <class _Container, input_range _Rng, class... _Types>
|
|
requires (!view<_Container>)
|
|
_NODISCARD constexpr _Container to(_Rng&& _Range, _Types&&... _Args) {
|
|
static_assert(!is_const_v<_Container>, "C must not be const. ([range.utility.conv.to])");
|
|
static_assert(!is_volatile_v<_Container>, "C must not be volatile. ([range.utility.conv.to])");
|
|
static_assert(is_class_v<_Container>, "C must be a class type. ([range.utility.conv.to])");
|
|
if constexpr (_Converts_direct_constructible<_Rng, _Container, _Types...>) {
|
|
return _Container(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...);
|
|
} else if constexpr (_Converts_tag_constructible<_Rng, _Container, _Types...>) {
|
|
return _Container(from_range, _STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...);
|
|
} else if constexpr (_Converts_and_common_constructible<_Rng, _Container, _Types...>) {
|
|
return _Container(_RANGES begin(_Range), _RANGES end(_Range), _STD forward<_Types...>(_Args)...);
|
|
} else if constexpr (_Converts_constructible_insertable<_Rng, _Container, _Types...>) {
|
|
_Container _Cont(_STD forward<_Types>(_Args)...);
|
|
if constexpr (_Sized_and_reservable<_Rng, _Container>) {
|
|
_Cont.reserve(static_cast<range_size_t<_Container>>(_RANGES size(_Range)));
|
|
}
|
|
_RANGES copy(_Range, _Container_inserter<range_reference_t<_Rng>>(_Cont));
|
|
return _Cont;
|
|
} else if constexpr (input_range<range_reference_t<_Rng>>) {
|
|
const auto _Xform = [](auto&& _Elem) {
|
|
return _RANGES to<range_value_t<_Container>>(_STD forward<decltype(_Elem)>(_Elem));
|
|
};
|
|
return _RANGES to<_Container>(views::transform(_Range, _Xform), _STD forward<_Types>(_Args)...);
|
|
} else {
|
|
static_assert(_Always_false<_Container>, "the program is ill-formed per N4910 [range.utility.conv.to]/1.3");
|
|
}
|
|
}
|
|
|
|
template <class _Container>
|
|
struct _To_class_fn {
|
|
_STL_INTERNAL_STATIC_ASSERT(!is_const_v<_Container>);
|
|
_STL_INTERNAL_STATIC_ASSERT(!is_volatile_v<_Container>);
|
|
_STL_INTERNAL_STATIC_ASSERT(is_class_v<_Container>);
|
|
_STL_INTERNAL_STATIC_ASSERT(!view<_Container>);
|
|
|
|
template <input_range _Rng, class... _Types>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Types&&... _Args) const
|
|
requires requires { _RANGES to<_Container>(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); }
|
|
{
|
|
return _RANGES to<_Container>(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...);
|
|
}
|
|
};
|
|
|
|
_EXPORT_STD template <class _Container, class... _Types>
|
|
requires (!view<_Container>)
|
|
_NODISCARD constexpr auto to(_Types&&... _Args) {
|
|
static_assert(!is_const_v<_Container>, "C must not be const. ([range.utility.conv.adaptors])");
|
|
static_assert(!is_volatile_v<_Container>, "C must not be volatile. ([range.utility.conv.adaptors])");
|
|
static_assert(is_class_v<_Container>, "C must be a class type. ([range.utility.conv.adaptors])");
|
|
return _Range_closure<_To_class_fn<_Container>, decay_t<_Types>...>{_STD forward<_Types>(_Args)...};
|
|
}
|
|
|
|
template <input_range _Rng>
|
|
struct _Phony_input_iterator {
|
|
using iterator_category = input_iterator_tag;
|
|
using value_type = range_value_t<_Rng>;
|
|
using difference_type = ptrdiff_t;
|
|
using pointer = add_pointer_t<range_reference_t<_Rng>>;
|
|
using reference = range_reference_t<_Rng>;
|
|
|
|
reference operator*() const;
|
|
pointer operator->() const;
|
|
|
|
_Phony_input_iterator& operator++();
|
|
_Phony_input_iterator operator++(int);
|
|
|
|
bool operator==(const _Phony_input_iterator&) const;
|
|
};
|
|
|
|
template <template <class...> class _Cnt, class _Rng, class... _Args>
|
|
auto _To_helper() {
|
|
if constexpr (requires { _Cnt(_STD declval<_Rng>(), _STD declval<_Args>()...); }) {
|
|
return static_cast<decltype(_Cnt(_STD declval<_Rng>(), _STD declval<_Args>()...))*>(nullptr);
|
|
} else if constexpr (requires { _Cnt(from_range, _STD declval<_Rng>(), _STD declval<_Args>()...); }) {
|
|
return static_cast<decltype(_Cnt(from_range, _STD declval<_Rng>(), _STD declval<_Args>()...))*>(nullptr);
|
|
} else if constexpr (requires {
|
|
_Cnt(_STD declval<_Phony_input_iterator<_Rng>>(),
|
|
_STD declval<_Phony_input_iterator<_Rng>>(), _STD declval<_Args>()...);
|
|
}) {
|
|
return static_cast<decltype(_Cnt(_STD declval<_Phony_input_iterator<_Rng>>(),
|
|
_STD declval<_Phony_input_iterator<_Rng>>(), _STD declval<_Args>()...))*>(nullptr);
|
|
}
|
|
}
|
|
|
|
_EXPORT_STD template <template <class...> class _Container, input_range _Rng, class... _Types,
|
|
class _Deduced = remove_pointer_t<decltype(_To_helper<_Container, _Rng, _Types...>())>>
|
|
_NODISCARD constexpr _Deduced to(_Rng&& _Range, _Types&&... _Args) {
|
|
return _RANGES to<_Deduced>(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...);
|
|
}
|
|
|
|
template <template <class...> class _Container>
|
|
struct _To_template_fn {
|
|
template <input_range _Rng, class... _Types,
|
|
class _Deduced = remove_pointer_t<decltype(_To_helper<_Container, _Rng, _Types...>())>>
|
|
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Types&&... _Args) const {
|
|
return _RANGES to<_Deduced>(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...);
|
|
}
|
|
};
|
|
|
|
_EXPORT_STD template <template <class...> class _Container, class... _Types>
|
|
_NODISCARD constexpr auto to(_Types&&... _Args) {
|
|
return _Range_closure<_To_template_fn<_Container>, decay_t<_Types>...>{_STD forward<_Types>(_Args)...};
|
|
}
|
|
#endif // __cpp_lib_ranges_to_container
|
|
#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 // __cpp_lib_ranges
|
|
#endif // _STL_COMPILER_PREPROCESSOR
|
|
#endif // _RANGES_
|