From cf15430baa3e983dfbc5f7bce02ddc7034e4be39 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 2 Jun 2024 15:12:49 +0800 Subject: [PATCH 1/9] Reduce inclusion for `` and `` --- stl/CMakeLists.txt | 2 + stl/inc/__msvc_heap_algorithms.hpp | 150 +++ stl/inc/__msvc_transform_view_to.hpp | 1190 ++++++++++++++++++++++ stl/inc/algorithm | 124 +-- stl/inc/header-units.json | 2 + stl/inc/queue | 5 +- stl/inc/ranges | 1377 +++----------------------- stl/inc/stack | 3 +- 8 files changed, 1463 insertions(+), 1390 deletions(-) create mode 100644 stl/inc/__msvc_heap_algorithms.hpp create mode 100644 stl/inc/__msvc_transform_view_to.hpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 60bfcbd83df..22867b2503c 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -13,6 +13,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_filebuf.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_format_ucd_tables.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_formatter.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_heap_algorithms.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_int128.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_iter_core.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_minmax.hpp @@ -21,6 +22,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_string_view.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_system_error_abi.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_threads_core.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_transform_view_to.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_tzdb.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_xlocinfo_types.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/algorithm diff --git a/stl/inc/__msvc_heap_algorithms.hpp b/stl/inc/__msvc_heap_algorithms.hpp new file mode 100644 index 00000000000..3a06b593456 --- /dev/null +++ b/stl/inc/__msvc_heap_algorithms.hpp @@ -0,0 +1,150 @@ +// __msvc_heap_algorithms.hpp internal header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef __MSVC_HEAP_ALGORITHMS_HPP +#define __MSVC_HEAP_ALGORITHMS_HPP +#include +#if _STL_COMPILER_PREPROCESSOR + +#include + +#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 +template +_CONSTEXPR20 void _Push_heap_by_index( + _RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Top, _Ty&& _Val, _Pr _Pred) { + // percolate _Hole to _Top or where _Val belongs + using _Diff = _Iter_diff_t<_RanIt>; + for (_Diff _Idx = (_Hole - 1) >> 1; // shift for codegen + _Top < _Hole && _DEBUG_LT_PRED(_Pred, *(_First + _Idx), _Val); _Idx = (_Hole - 1) >> 1) { // shift for codegen + // move _Hole up to parent + *(_First + _Hole) = _STD move(*(_First + _Idx)); + _Hole = _Idx; + } + + *(_First + _Hole) = _STD forward<_Ty>(_Val); // drop _Val into final hole +} + +_EXPORT_STD template +_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // push *(_Last - 1) onto heap at [_First, _Last - 1) + _STD _Adl_verify_range(_First, _Last); + const auto _UFirst = _STD _Get_unwrapped(_First); + auto _ULast = _STD _Get_unwrapped(_Last); + using _Diff = _Iter_diff_t<_RanIt>; + _Diff _Count = _ULast - _UFirst; + if (2 <= _Count) { + _Iter_value_t<_RanIt> _Val(_STD move(*--_ULast)); + _STD _Push_heap_by_index(_UFirst, --_Count, _Diff(0), _STD move(_Val), _STD _Pass_fn(_Pred)); + } +} + +_EXPORT_STD template +_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last) { + // push *(_Last - 1) onto heap at [_First, _Last - 1) + _STD push_heap(_First, _Last, less<>{}); +} + +template +_CONSTEXPR20 void _Pop_heap_hole_by_index( + _RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Bottom, _Ty&& _Val, _Pr _Pred) { + // percolate _Hole to _Bottom, then push _Val + _STL_INTERNAL_CHECK(_Bottom > 0); + + using _Diff = _Iter_diff_t<_RanIt>; + const _Diff _Top = _Hole; + _Diff _Idx = _Hole; + + // Check whether _Idx can have a child before calculating that child's index, since + // calculating the child's index can trigger integer overflows + const _Diff _Max_sequence_non_leaf = (_Bottom - 1) >> 1; // shift for codegen + while (_Idx < _Max_sequence_non_leaf) { // move _Hole down to larger child + _Idx = 2 * _Idx + 2; + if (_DEBUG_LT_PRED(_Pred, *(_First + _Idx), *(_First + (_Idx - 1)))) { + --_Idx; + } + *(_First + _Hole) = _STD move(*(_First + _Idx)); + _Hole = _Idx; + } + + if (_Idx == _Max_sequence_non_leaf && _Bottom % 2 == 0) { // only child at bottom, move _Hole down to it + *(_First + _Hole) = _STD move(*(_First + (_Bottom - 1))); + _Hole = _Bottom - 1; + } + + _STD _Push_heap_by_index(_First, _Hole, _Top, _STD forward<_Ty>(_Val), _Pred); +} + +template +_CONSTEXPR20 void _Pop_heap_hole_unchecked(_RanIt _First, _RanIt _Last, _RanIt _Dest, _Ty&& _Val, _Pr _Pred) { + // pop *_First to *_Dest and reheap + // precondition: _First != _Last + // precondition: _First != _Dest + *_Dest = _STD move(*_First); + using _Diff = _Iter_diff_t<_RanIt>; + _STD _Pop_heap_hole_by_index( + _First, static_cast<_Diff>(0), static_cast<_Diff>(_Last - _First), _STD forward<_Ty>(_Val), _Pred); +} + +template +_CONSTEXPR20 void _Pop_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // pop *_First to *(_Last - 1) and reheap + if (2 <= _Last - _First) { + --_Last; + _Iter_value_t<_RanIt> _Val(_STD move(*_Last)); + _STD _Pop_heap_hole_unchecked(_First, _Last, _Last, _STD move(_Val), _Pred); + } +} + +_EXPORT_STD template +_CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // pop *_First to *(_Last - 1) and reheap + _STD _Adl_verify_range(_First, _Last); + _STD _Pop_heap_unchecked(_STD _Get_unwrapped(_First), _STD _Get_unwrapped(_Last), _STD _Pass_fn(_Pred)); +} + +_EXPORT_STD template +_CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last) { + // pop *_First to *(_Last - 1) and reheap + _STD pop_heap(_First, _Last, less<>{}); +} + +template +_CONSTEXPR20 void _Make_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // make [_First, _Last) into a heap + using _Diff = _Iter_diff_t<_RanIt>; + _Diff _Bottom = _Last - _First; + for (_Diff _Hole = _Bottom >> 1; _Hole > 0;) { // shift for codegen + // reheap top half, bottom to top + --_Hole; + _Iter_value_t<_RanIt> _Val(_STD move(*(_First + _Hole))); + _STD _Pop_heap_hole_by_index(_First, _Hole, _Bottom, _STD move(_Val), _Pred); + } +} + +_EXPORT_STD template +_CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // make [_First, _Last) into a heap + _STD _Adl_verify_range(_First, _Last); + _STD _Make_heap_unchecked(_STD _Get_unwrapped(_First), _STD _Get_unwrapped(_Last), _STD _Pass_fn(_Pred)); +} + +_EXPORT_STD template +_CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last) { // make [_First, _Last) into a heap + _STD make_heap(_First, _Last, less<>{}); +} +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // _STL_COMPILER_PREPROCESSOR +#endif // __MSVC_HEAP_ALGORITHMS_HPP diff --git a/stl/inc/__msvc_transform_view_to.hpp b/stl/inc/__msvc_transform_view_to.hpp new file mode 100644 index 00000000000..5ef5118cd74 --- /dev/null +++ b/stl/inc/__msvc_transform_view_to.hpp @@ -0,0 +1,1190 @@ +// __msvc_transform_view_to.hpp internal header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef __MSVC_TRANSFORM_VIEW_TO_HPP +#define __MSVC_TRANSFORM_VIEW_TO_HPP +#include +#if _STL_COMPILER_PREPROCESSOR + +#if !_HAS_CXX20 +#error The contents of are only available with C++20. (Also, you should not include this internal header.) +#endif // !_HAS_CXX20 + +#include +#if _HAS_CXX23 +#include +#endif // _HAS_CXX23 +#include + +#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 { + template + constexpr bool _Is_initializer_list = _Is_specialization_v, initializer_list>; + + // clang-format off + _EXPORT_STD template + concept viewable_range = range<_Rng> + && ((view> && constructible_from, _Rng>) + || (!view> + && (is_lvalue_reference_v<_Rng> + || (movable> && !_Is_initializer_list<_Rng>)))); + // clang-format on + + namespace _Pipe { + template + struct _Base {}; + + template + _Ty* _Derived_from_range_adaptor_closure(_Base<_Ty>&); // not defined + + template + concept _Range_adaptor_closure_object = !range> && requires(remove_cvref_t<_Ty>& __t) { + { _Pipe::_Derived_from_range_adaptor_closure(__t) } -> same_as*>; + }; + + template + 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 + 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)) {} + + void operator()(auto&&) & = delete; + void operator()(auto&&) const& = delete; + void operator()(auto&&) && = delete; + void operator()(auto&&) const&& = delete; + + template + _NODISCARD constexpr decltype(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 + _NODISCARD constexpr decltype(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 + _NODISCARD constexpr decltype(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 + _NODISCARD constexpr decltype(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 + _Pipeline(_Ty1, _Ty2) -> _Pipeline<_Ty1, _Ty2>; + + _EXPORT_STD template + requires _Range_adaptor_closure_object<_Left> && _Range_adaptor_closure_object<_Right> + && constructible_from, _Left> + && constructible_from, _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 + requires (_Range_adaptor_closure_object<_Right> && range<_Left>) + _NODISCARD constexpr decltype(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 + concept _Valid_movable_box_object = +#if _HAS_CXX23 + move_constructible<_Ty> +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv + copy_constructible<_Ty> +#endif // ^^^ !_HAS_CXX23 ^^^ + && _Destructible_object<_Ty>; + + // 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 + 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(_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(_That._Val); + } else { + _Val.~_Ty(); + _Engaged = false; + } + } else { + if (_That._Engaged) { + _STD _Construct_in_place(_Val, static_cast(_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(_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 + concept _Use_simple_movable_box_wrapper = + (copy_constructible<_Ty> + // 1. If copy_constructible is true, movable-box should store only a T if either T models + // copyable, or is_nothrow_move_constructible_v && is_nothrow_copy_constructible_v is true. + ? copyable<_Ty> || (is_nothrow_move_constructible_v<_Ty> && is_nothrow_copy_constructible_v<_Ty>) + // 2. Otherwise, movable-box should store only a T if either T models movable or + // is_nothrow_move_constructible_v is true. + : movable<_Ty> || is_nothrow_move_constructible_v<_Ty>); + + template + 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 + 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(_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(_That._Val); + } else { + if (_STD addressof(_That) != this) { + _Val.~_Ty(); + _STD _Construct_in_place(_Val, static_cast(_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 + 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, _Types> && ...)); + _STL_INTERNAL_STATIC_ASSERT(is_empty_v<_Fn>&& is_default_constructible_v<_Fn>); + + template + requires (same_as, _Types> && ...) + constexpr explicit _Range_closure(_UTypes&&... _Args) noexcept( + conjunction_v...>) + : _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 + 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 + 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 + 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 + 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 + 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, _Indices>); + return _Fn{}(_STD forward<_Ty>(_Arg), _STD get<_Idx>(_STD forward<_SelfTy>(_Self)._Captures)...); + } + + tuple<_Types...> _Captures; + }; + + _EXPORT_STD template + requires is_object_v<_Rng> + class ref_view : public view_interface> { + private: + _Rng* _Range; + + static void _Rvalue_poison(_Rng&); + static void _Rvalue_poison(_Rng&&) = delete; + + public: + // clang-format off + template <_Different_from _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 + ref_view(_Rng&) -> ref_view<_Rng>; + + template + constexpr bool enable_borrowed_range> = true; + + _EXPORT_STD template + requires (movable<_Rng> && !_Is_initializer_list<_Rng>) + class owning_view : public view_interface> { + 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 + { + return _RANGES begin(_Range); + } + + _NODISCARD constexpr auto end() const noexcept(noexcept(_RANGES end(_Range))) /* strengthened */ + requires range + { + 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 + { + 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 + { + 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 + { + return _RANGES data(_Range); + } + }; + + template + constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; + + namespace views { + template + concept _Can_ref_view = requires(_Rng&& __r) { ref_view{static_cast<_Rng&&>(__r)}; }; + + template + 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 + _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { + if constexpr (view>) { + 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 + static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>(); + + public: + template + requires (_Choice<_Rng>._Strategy != _St::_None) + _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range) _CONST_CALL_OPERATOR + noexcept(_Choice<_Rng>._No_throw) { + constexpr _St _Strat = _Choice<_Rng>._Strategy; + + if constexpr (_Strat == _St::_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 { + _STL_INTERNAL_STATIC_ASSERT(false); // unexpected strategy + } + } + }; + + _EXPORT_STD inline constexpr _All_fn all; + + _EXPORT_STD template + using all_t = decltype(all(_STD declval<_Rng>())); + } // namespace views + + _EXPORT_STD template + requires view<_Vw> && regular_invocable<_Fn&, range_reference_t<_Vw>> + && _Can_reference>> + class transform_view : public view_interface> { + private: + /* [[no_unique_address]] */ _Vw _Range{}; + /* [[no_unique_address]] */ _Movable_box<_Fn> _Fun{}; + + template + struct _Category_base {}; + + template + requires forward_range<_Maybe_const<_Const, _Vw>> + struct _Category_base<_Const> { + using _Base = _Maybe_const<_Const, _Vw>; + using iterator_category = + conditional_t&, range_reference_t<_Base>>>, + conditional_t>, contiguous_iterator_tag>, + random_access_iterator_tag, _Iter_cat_t>>, + input_iterator_tag>; + }; + + template + 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_iterator_tag, + conditional_t, bidirectional_iterator_tag, + conditional_t, forward_iterator_tag, input_iterator_tag>>>; + using value_type = remove_cvref_t&, range_reference_t<_Base>>>; + using difference_type = range_difference_t<_Base>; + + // clang-format off + _Iterator() requires default_initializable> = default; + // clang-format on + + constexpr _Iterator(_Parent_t& _Parent_, iterator_t<_Base> _Current_) noexcept( + is_nothrow_move_constructible_v>) // strengthened + : _Current{_STD move(_Current_)}, _Parent{_STD addressof(_Parent_)} { +#if _ITERATOR_DEBUG_LEVEL != 0 + _STD _Adl_verify_range(_Current, _RANGES end(_Parent_._Range)); + if constexpr (forward_range<_Base>) { + _STD _Adl_verify_range(_RANGES begin(_Parent_._Range), _Current); + } +#endif // _ITERATOR_DEBUG_LEVEL != 0 + } + + constexpr _Iterator(_Iterator _It) noexcept( + is_nothrow_constructible_v, iterator_t<_Vw>>) // strengthened + requires _Const && convertible_to, 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>) /* 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>) ) /* 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>) /* 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>) { + _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, "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> + { +#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); + } + _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> + { +#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, "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>> + { +#if _ITERATOR_DEBUG_LEVEL != 0 + _Left._Same_range(_Right); +#endif // _ITERATOR_DEBUG_LEVEL != 0 + return _Left._Current - _Right._Current; + } + }; + + template + class _Sentinel { + private: + friend transform_view; + + using _Parent_t = _Maybe_const<_Const, transform_view>; + using _Base = _Maybe_const<_Const, _Vw>; + template + using _Maybe_const_iter = iterator_t<_Maybe_const<_OtherConst, _Vw>>; + + sentinel_t<_Base> _Last{}; + + template + _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>) // strengthened + : _Last(_STD move(_Last_)) {} + + constexpr _Sentinel(_Sentinel _Se) noexcept( + is_nothrow_constructible_v, sentinel_t<_Vw>>) // strengthened + requires _Const && convertible_to, sentinel_t<_Base>> + : _Last(_STD move(_Se._Last)) {} + + _NODISCARD constexpr sentinel_t<_Base> base() const + noexcept(is_nothrow_copy_constructible_v>) /* strengthened */ { + return _Last; + } + + template + requires sentinel_for, _Maybe_const_iter<_OtherConst>> + _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_OtherConst>& _Left, + const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) == _Right._Last)) /* strengthened */ { + return _Get_current(_Left) == _Right._Last; + } + + template + requires sized_sentinel_for, _Maybe_const_iter<_OtherConst>> + _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( + const _Iterator<_OtherConst>& _Left, + const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) - _Right._Last)) /* strengthened */ { + return _Get_current(_Left) - _Right._Last; + } + + template + requires sized_sentinel_for, _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 begin() noexcept( + noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v>) /* strengthened */ { + return _Iterator{*this, _RANGES begin(_Range)}; + } + + _NODISCARD constexpr _Iterator begin() const noexcept( + noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v>) /* strengthened */ + requires range && regular_invocable> + { + return _Iterator{*this, _RANGES begin(_Range)}; + } + + _NODISCARD constexpr auto end() noexcept( + noexcept(_RANGES end(_Range)) + && is_nothrow_move_constructible_v) /* strengthened */ { + if constexpr (common_range<_Vw>) { + return _Iterator{*this, _RANGES end(_Range)}; + } else { + return _Sentinel{_RANGES end(_Range)}; + } + } + + _NODISCARD constexpr auto end() const + noexcept(noexcept(_RANGES end(_Range)) + && is_nothrow_move_constructible_v) /* strengthened */ + requires range && regular_invocable> + { + if constexpr (common_range<_Vw>) { + return _Iterator{*this, _RANGES end(_Range)}; + } else { + return _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 + { + return _RANGES size(_Range); + } + }; + + template + transform_view(_Rng&&, _Fn) -> transform_view, _Fn>; + + namespace views { + struct _Transform_fn { + template + _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range, _Fn _Fun) _CONST_CALL_OPERATOR + noexcept(noexcept(transform_view(_STD forward<_Rng>(_Range), _STD move(_Fun)))) + requires requires { transform_view(static_cast<_Rng&&>(_Range), _STD move(_Fun)); } + { + return transform_view(_STD forward<_Rng>(_Range), _STD move(_Fun)); + } + + template + requires constructible_from, _Fn> + _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Fn&& _Fun) _CONST_CALL_OPERATOR + noexcept(is_nothrow_constructible_v, _Fn>) { + return _Range_closure<_Transform_fn, decay_t<_Fn>>{_STD forward<_Fn>(_Fun)}; + } + }; + + _EXPORT_STD inline constexpr _Transform_fn transform; + } // namespace views + +#if _HAS_CXX23 + template + 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>; + { _Cont.max_size() } -> same_as>; + }; + + template + concept _Ref_converts = + !input_range<_Container> || convertible_to, range_value_t<_Container>>; + + template + concept _Common_constructible = + common_range<_Rng> // + && requires { typename iterator_traits>::iterator_category; } + && derived_from>::iterator_category, input_iterator_tag> + && constructible_from<_Container, iterator_t<_Rng>, iterator_t<_Rng>, _Types...>; + + template + concept _Can_emplace_back = requires(_Container& _Cont) { _Cont.emplace_back(_STD declval<_Reference>()); }; + + template + concept _Can_push_back = requires(_Container& _Cont) { _Cont.push_back(_STD declval<_Reference>()); }; + + template + concept _Can_emplace_end = requires(_Container& _Cont) { _Cont.emplace(_Cont.end(), _STD declval<_Reference>()); }; + + template + concept _Can_insert_end = requires(_Container& _Cont) { _Cont.insert(_Cont.end(), _STD declval<_Reference>()); }; + + template + concept _Constructible_appendable = constructible_from<_Container, _Types...> + && (_Can_emplace_back<_Container, range_reference_t<_Rng>> + || _Can_push_back<_Container, range_reference_t<_Rng>> + || _Can_emplace_end<_Container, range_reference_t<_Rng>> + || _Can_insert_end<_Container, range_reference_t<_Rng>>); + + _EXPORT_STD template + 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 (_Ref_converts<_Rng, _Container>) { + if constexpr (constructible_from<_Container, _Rng, _Types...>) { + return _Container(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); + } else if constexpr (constructible_from<_Container, const from_range_t&, _Rng, _Types...>) { // per LWG-3845 + return _Container(from_range, _STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); + } else if constexpr (_Common_constructible<_Rng, _Container, _Types...>) { + return _Container(_RANGES begin(_Range), _RANGES end(_Range), _STD forward<_Types>(_Args)...); + } else if constexpr (_Constructible_appendable<_Rng, _Container, _Types...>) { + _Container _Cont(_STD forward<_Types>(_Args)...); + if constexpr (_Sized_and_reservable<_Rng, _Container>) { + _Cont.reserve(static_cast>(_RANGES size(_Range))); + } + for (auto&& _Elem : _Range) { + using _ElemTy = decltype(_Elem); + if constexpr (_Can_emplace_back<_Container, _ElemTy>) { + _Cont.emplace_back(_STD forward<_ElemTy>(_Elem)); + } else if constexpr (_Can_push_back<_Container, _ElemTy>) { + _Cont.push_back(_STD forward<_ElemTy>(_Elem)); + } else if constexpr (_Can_emplace_end<_Container, _ElemTy>) { + _Cont.emplace(_Cont.end(), _STD forward<_ElemTy>(_Elem)); + } else { + _STL_INTERNAL_STATIC_ASSERT(_Can_insert_end<_Container, _ElemTy>); + _Cont.insert(_Cont.end(), _STD forward<_ElemTy>(_Elem)); + } + } + return _Cont; + } else { + static_assert(false, "ranges::to requires the result to be constructible from the source range, either " + "by using a suitable constructor, or by inserting each element of the range into " + "the default-constructed object. (N4981 [range.utility.conv.to]/2.1.5)"); + } + } else if constexpr (input_range>) { + const auto _Xform = [](auto&& _Elem) _STATIC_CALL_OPERATOR { + return _RANGES to>(_STD forward(_Elem)); + }; + return _RANGES to<_Container>(views::transform(ref_view{_Range}, _Xform), _STD forward<_Types>(_Args)...); + } else { + static_assert(false, + "ranges::to requires the elements of the source range to be either implicitly convertible to the " + "elements of the destination container, or be ranges themselves for ranges::to to be applied " + "recursively. (N4981 [range.utility.conv.to]/2.3)"); + } + } + + template + 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 + _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()( + _Rng&& _Range, _Types&&... _Args) _CONST_CALL_OPERATOR + 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 + 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)...}; + } +#endif // _HAS_CXX23 +} // namespace ranges +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // _STL_COMPILER_PREPROCESSOR +#endif // __MSVC_TRANSFORM_VIEW_TO_HPP diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 7f37e1cdc3f..20fea1810a6 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -7,6 +7,7 @@ #define _ALGORITHM_ #include #if _STL_COMPILER_PREPROCESSOR +#include <__msvc_heap_algorithms.hpp> #include <__msvc_minmax.hpp> #include @@ -6641,41 +6642,6 @@ namespace ranges { } // namespace ranges #endif // _HAS_CXX20 -template -_CONSTEXPR20 void _Push_heap_by_index( - _RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Top, _Ty&& _Val, _Pr _Pred) { - // percolate _Hole to _Top or where _Val belongs - using _Diff = _Iter_diff_t<_RanIt>; - for (_Diff _Idx = (_Hole - 1) >> 1; // shift for codegen - _Top < _Hole && _DEBUG_LT_PRED(_Pred, *(_First + _Idx), _Val); _Idx = (_Hole - 1) >> 1) { // shift for codegen - // move _Hole up to parent - *(_First + _Hole) = _STD move(*(_First + _Idx)); - _Hole = _Idx; - } - - *(_First + _Hole) = _STD forward<_Ty>(_Val); // drop _Val into final hole -} - -_EXPORT_STD template -_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { - // push *(_Last - 1) onto heap at [_First, _Last - 1) - _STD _Adl_verify_range(_First, _Last); - const auto _UFirst = _STD _Get_unwrapped(_First); - auto _ULast = _STD _Get_unwrapped(_Last); - using _Diff = _Iter_diff_t<_RanIt>; - _Diff _Count = _ULast - _UFirst; - if (2 <= _Count) { - _Iter_value_t<_RanIt> _Val(_STD move(*--_ULast)); - _STD _Push_heap_by_index(_UFirst, --_Count, _Diff(0), _STD move(_Val), _STD _Pass_fn(_Pred)); - } -} - -_EXPORT_STD template -_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last) { - // push *(_Last - 1) onto heap at [_First, _Last - 1) - _STD push_heap(_First, _Last, less<>{}); -} - #if _HAS_CXX20 namespace ranges { template @@ -6748,70 +6714,6 @@ namespace ranges { } // namespace ranges #endif // _HAS_CXX20 -template -_CONSTEXPR20 void _Pop_heap_hole_by_index( - _RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Bottom, _Ty&& _Val, _Pr _Pred) { - // percolate _Hole to _Bottom, then push _Val - _STL_INTERNAL_CHECK(_Bottom > 0); - - using _Diff = _Iter_diff_t<_RanIt>; - const _Diff _Top = _Hole; - _Diff _Idx = _Hole; - - // Check whether _Idx can have a child before calculating that child's index, since - // calculating the child's index can trigger integer overflows - const _Diff _Max_sequence_non_leaf = (_Bottom - 1) >> 1; // shift for codegen - while (_Idx < _Max_sequence_non_leaf) { // move _Hole down to larger child - _Idx = 2 * _Idx + 2; - if (_DEBUG_LT_PRED(_Pred, *(_First + _Idx), *(_First + (_Idx - 1)))) { - --_Idx; - } - *(_First + _Hole) = _STD move(*(_First + _Idx)); - _Hole = _Idx; - } - - if (_Idx == _Max_sequence_non_leaf && _Bottom % 2 == 0) { // only child at bottom, move _Hole down to it - *(_First + _Hole) = _STD move(*(_First + (_Bottom - 1))); - _Hole = _Bottom - 1; - } - - _STD _Push_heap_by_index(_First, _Hole, _Top, _STD forward<_Ty>(_Val), _Pred); -} - -template -_CONSTEXPR20 void _Pop_heap_hole_unchecked(_RanIt _First, _RanIt _Last, _RanIt _Dest, _Ty&& _Val, _Pr _Pred) { - // pop *_First to *_Dest and reheap - // precondition: _First != _Last - // precondition: _First != _Dest - *_Dest = _STD move(*_First); - using _Diff = _Iter_diff_t<_RanIt>; - _STD _Pop_heap_hole_by_index( - _First, static_cast<_Diff>(0), static_cast<_Diff>(_Last - _First), _STD forward<_Ty>(_Val), _Pred); -} - -template -_CONSTEXPR20 void _Pop_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { - // pop *_First to *(_Last - 1) and reheap - if (2 <= _Last - _First) { - --_Last; - _Iter_value_t<_RanIt> _Val(_STD move(*_Last)); - _STD _Pop_heap_hole_unchecked(_First, _Last, _Last, _STD move(_Val), _Pred); - } -} - -_EXPORT_STD template -_CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { - // pop *_First to *(_Last - 1) and reheap - _STD _Adl_verify_range(_First, _Last); - _STD _Pop_heap_unchecked(_STD _Get_unwrapped(_First), _STD _Get_unwrapped(_Last), _STD _Pass_fn(_Pred)); -} - -_EXPORT_STD template -_CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last) { - // pop *_First to *(_Last - 1) and reheap - _STD pop_heap(_First, _Last, less<>{}); -} - #if _HAS_CXX20 namespace ranges { template @@ -6911,30 +6813,6 @@ namespace ranges { } // namespace ranges #endif // _HAS_CXX20 -template -_CONSTEXPR20 void _Make_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { - // make [_First, _Last) into a heap - using _Diff = _Iter_diff_t<_RanIt>; - _Diff _Bottom = _Last - _First; - for (_Diff _Hole = _Bottom >> 1; _Hole > 0;) { // shift for codegen - // reheap top half, bottom to top - --_Hole; - _Iter_value_t<_RanIt> _Val(_STD move(*(_First + _Hole))); - _STD _Pop_heap_hole_by_index(_First, _Hole, _Bottom, _STD move(_Val), _Pred); - } -} - -_EXPORT_STD template -_CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // make [_First, _Last) into a heap - _STD _Adl_verify_range(_First, _Last); - _STD _Make_heap_unchecked(_STD _Get_unwrapped(_First), _STD _Get_unwrapped(_Last), _STD _Pass_fn(_Pred)); -} - -_EXPORT_STD template -_CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last) { // make [_First, _Last) into a heap - _STD make_heap(_First, _Last, less<>{}); -} - #if _HAS_CXX20 namespace ranges { template diff --git a/stl/inc/header-units.json b/stl/inc/header-units.json index facf4398afa..5af9bd1700f 100644 --- a/stl/inc/header-units.json +++ b/stl/inc/header-units.json @@ -11,6 +11,7 @@ "__msvc_filebuf.hpp", "__msvc_format_ucd_tables.hpp", "__msvc_formatter.hpp", + "__msvc_heap_algorithms.hpp", "__msvc_int128.hpp", "__msvc_iter_core.hpp", "__msvc_minmax.hpp", @@ -19,6 +20,7 @@ "__msvc_string_view.hpp", "__msvc_system_error_abi.hpp", "__msvc_threads_core.hpp", + "__msvc_transform_view_to.hpp", "__msvc_tzdb.hpp", "__msvc_xlocinfo_types.hpp", "algorithm", diff --git a/stl/inc/queue b/stl/inc/queue index 847ddc5e2e5..e87ca569fb6 100644 --- a/stl/inc/queue +++ b/stl/inc/queue @@ -7,12 +7,13 @@ #define _QUEUE_ #include #if _STL_COMPILER_PREPROCESSOR -#include +#include <__msvc_heap_algorithms.hpp> #include #include #if _HAS_CXX23 -#include +#include <__msvc_transform_view_to.hpp> +#include #endif // _HAS_CXX23 #pragma pack(push, _CRT_PACKING) diff --git a/stl/inc/ranges b/stl/inc/ranges index d93eb0bfc83..f49c4d802c7 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -11,6 +11,7 @@ _EMIT_STL_WARNING(STL4038, "The contents of are available only with C++20 or later."); #else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv #include <__msvc_int128.hpp> +#include <__msvc_transform_view_to.hpp> #include #include #include @@ -21,7 +22,6 @@ _EMIT_STL_WARNING(STL4038, "The contents of are available only with C++ #if _HAS_CXX23 #include #include -#include #endif // _HAS_CXX23 #pragma pack(push, _CRT_PACKING) @@ -35,9 +35,6 @@ _STD_BEGIN namespace ranges { // MUCH machinery defined in - template - constexpr bool _Is_initializer_list = _Is_specialization_v, initializer_list>; - template // _Require_constant is a valid template-id iff E is a constant expression of structural type struct _Require_constant; @@ -88,119 +85,18 @@ namespace ranges { #endif // _HAS_CXX23 // clang-format off - _EXPORT_STD template - concept viewable_range = range<_Rng> - && ((view> && constructible_from, _Rng>) - || (!view> - && (is_lvalue_reference_v<_Rng> - || (movable> && !_Is_initializer_list<_Rng>)))); - template concept _Simple_view = view<_Rng> && range && same_as, iterator_t> && same_as, sentinel_t>; // clang-format on - template - concept _Valid_movable_box_object = -#if _HAS_CXX23 - move_constructible<_Ty> -#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv - copy_constructible<_Ty> -#endif // ^^^ !_HAS_CXX23 ^^^ - && _Destructible_object<_Ty>; - template concept _Has_arrow = input_iterator<_It> && (is_pointer_v<_It> || _Has_member_arrow<_It&>); template using _Maybe_wrapped = conditional_t<_IsWrapped, _Ty, _Unwrapped_t<_Ty>>; - namespace _Pipe { - template - struct _Base {}; - - template - _Ty* _Derived_from_range_adaptor_closure(_Base<_Ty>&); // not defined - - template - concept _Range_adaptor_closure_object = !range> && requires(remove_cvref_t<_Ty>& __t) { - { _Pipe::_Derived_from_range_adaptor_closure(__t) } -> same_as*>; - }; - - template - 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 - 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)) {} - - void operator()(auto&&) & = delete; - void operator()(auto&&) const& = delete; - void operator()(auto&&) && = delete; - void operator()(auto&&) const&& = delete; - - template - _NODISCARD constexpr decltype(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 - _NODISCARD constexpr decltype(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 - _NODISCARD constexpr decltype(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 - _NODISCARD constexpr decltype(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 - _Pipeline(_Ty1, _Ty2) -> _Pipeline<_Ty1, _Ty2>; - - _EXPORT_STD template - requires _Range_adaptor_closure_object<_Left> && _Range_adaptor_closure_object<_Right> - && constructible_from, _Left> - && constructible_from, _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 - requires (_Range_adaptor_closure_object<_Right> && range<_Left>) - _NODISCARD constexpr decltype(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 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."); @@ -296,255 +192,6 @@ namespace ranges { template 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 - 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(_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(_That._Val); - } else { - _Val.~_Ty(); - _Engaged = false; - } - } else { - if (_That._Engaged) { - _STD _Construct_in_place(_Val, static_cast(_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(_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 - concept _Use_simple_movable_box_wrapper = - (copy_constructible<_Ty> - // 1. If copy_constructible is true, movable-box should store only a T if either T models - // copyable, or is_nothrow_move_constructible_v && is_nothrow_copy_constructible_v is true. - ? copyable<_Ty> || (is_nothrow_move_constructible_v<_Ty> && is_nothrow_copy_constructible_v<_Ty>) - // 2. Otherwise, movable-box should store only a T if either T models movable or - // is_nothrow_move_constructible_v is true. - : movable<_Ty> || is_nothrow_move_constructible_v<_Ty>); - - template - 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 - 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(_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(_That._Val); - } else { - if (_STD addressof(_That) != this) { - _Val.~_Ty(); - _STD _Construct_in_place(_Val, static_cast(_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 class _Defaultabox { // a simplified optional that augments movable types with default-constructibility public: @@ -901,70 +548,6 @@ namespace ranges { class range_adaptor_closure : public _Pipe::_Base<_Derived> {}; #endif // _HAS_CXX23 - template - 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, _Types> && ...)); - _STL_INTERNAL_STATIC_ASSERT(is_empty_v<_Fn>&& is_default_constructible_v<_Fn>); - - template - requires (same_as, _Types> && ...) - constexpr explicit _Range_closure(_UTypes&&... _Args) noexcept( - conjunction_v...>) - : _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 - 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 - 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 - 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 - 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 - 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, _Indices>); - return _Fn{}(_STD forward<_Ty>(_Arg), _STD get<_Idx>(_STD forward<_SelfTy>(_Self)._Captures)...); - } - - tuple<_Types...> _Captures; - }; - _EXPORT_STD template requires is_object_v<_Ty> class empty_view : public view_interface> { @@ -1839,159 +1422,13 @@ namespace ranges { constexpr _Istream_fn<_Ty> istream; } // namespace views - _EXPORT_STD template - requires is_object_v<_Rng> - class ref_view : public view_interface> { - private: - _Rng* _Range; - - static void _Rvalue_poison(_Rng&); - static void _Rvalue_poison(_Rng&&) = delete; - - public: - // clang-format off - template <_Different_from _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 - ref_view(_Rng&) -> ref_view<_Rng>; - - template - constexpr bool enable_borrowed_range> = true; - -#if _HAS_CXX23 - template - constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; +#if _HAS_CXX23 + template + constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; template constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; -#endif // _HAS_CXX23 - _EXPORT_STD template - requires (movable<_Rng> && !_Is_initializer_list<_Rng>) - class owning_view : public view_interface> { - 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 - { - return _RANGES begin(_Range); - } - - _NODISCARD constexpr auto end() const noexcept(noexcept(_RANGES end(_Range))) /* strengthened */ - requires range - { - 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 - { - 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 - { - 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 - { - return _RANGES data(_Range); - } - }; - - template - constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; - -#if _HAS_CXX23 template constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; @@ -1999,60 +1436,6 @@ namespace ranges { constexpr auto _Compile_time_max_size> = _Compile_time_max_size; #endif // _HAS_CXX23 - namespace views { - template - concept _Can_ref_view = requires(_Rng&& __r) { ref_view{static_cast<_Rng&&>(__r)}; }; - - template - 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 - _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { - if constexpr (view>) { - 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 - static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>(); - - public: - template - requires (_Choice<_Rng>._Strategy != _St::_None) - _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range) _CONST_CALL_OPERATOR - noexcept(_Choice<_Rng>._No_throw) { - constexpr _St _Strat = _Choice<_Rng>._Strategy; - - if constexpr (_Strat == _St::_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 { - _STL_INTERNAL_STATIC_ASSERT(false); // unexpected strategy - } - } - }; - - _EXPORT_STD inline constexpr _All_fn all; - - _EXPORT_STD template - using all_t = decltype(all(_STD declval<_Rng>())); - } // namespace views - #if _HAS_CXX23 _EXPORT_STD template requires view<_Vw> @@ -2268,525 +1651,110 @@ namespace ranges { _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> - { -#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> - { -#if _ITERATOR_DEBUG_LEVEL != 0 - _Left._Check_dereference(); - _Right._Check_dereference(); -#endif // _ITERATOR_DEBUG_LEVEL != 0 - return _RANGES iter_swap(_Left._Current, _Right._Current); - } - - _NODISCARD constexpr bool _Equal(const sentinel_t<_Vw>& _Last) const - noexcept(noexcept(_STD _Fake_copy_init(_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>) // strengthened - : _Last(_RANGES end(_Parent._Range)) {} - - _NODISCARD constexpr sentinel_t<_Vw> base() const - noexcept(is_nothrow_copy_constructible_v>) /* 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, "N4950 [range.filter.view]/3 forbids calling begin on a filter_view that holds no predicate"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 - if constexpr (forward_range<_Vw>) { - if (this->_Has_cache()) { - return _Iterator{*this, this->_Get_cache(_Range)}; - } - } - - auto _First = _RANGES find_if(_Range, _STD ref(*_Pred)); - if constexpr (forward_range<_Vw>) { - this->_Set_cache(_Range, _First); - } - - return _Iterator{*this, _STD move(_First)}; - } - - _NODISCARD constexpr auto end() { - if constexpr (common_range<_Vw>) { - return _Iterator{*this, _RANGES end(_Range)}; - } else { - return _Sentinel{*this}; - } - } - }; - - template - filter_view(_Rng&&, _Pr) -> filter_view, _Pr>; - -#if _HAS_CXX23 - template - constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; -#endif // _HAS_CXX23 - - namespace views { - struct _Filter_fn { - template - _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range, _Pr&& _Pred) _CONST_CALL_OPERATOR - noexcept(noexcept(filter_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred)))) - requires requires { filter_view(static_cast<_Rng&&>(_Range), _STD forward<_Pr>(_Pred)); } - { - return filter_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred)); - } - - template - requires constructible_from, _Pr> - _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Pr&& _Pred) _CONST_CALL_OPERATOR - noexcept(is_nothrow_constructible_v, _Pr>) { - return _Range_closure<_Filter_fn, decay_t<_Pr>>{_STD forward<_Pr>(_Pred)}; - } - }; - - _EXPORT_STD inline constexpr _Filter_fn filter; - } // namespace views - - _EXPORT_STD template - requires view<_Vw> && regular_invocable<_Fn&, range_reference_t<_Vw>> - && _Can_reference>> - class transform_view : public view_interface> { - private: - /* [[no_unique_address]] */ _Vw _Range{}; - /* [[no_unique_address]] */ _Movable_box<_Fn> _Fun{}; - - template - struct _Category_base {}; - - template - requires forward_range<_Maybe_const<_Const, _Vw>> - struct _Category_base<_Const> { - using _Base = _Maybe_const<_Const, _Vw>; - using iterator_category = - conditional_t&, range_reference_t<_Base>>>, - conditional_t>, contiguous_iterator_tag>, - random_access_iterator_tag, _Iter_cat_t>>, - input_iterator_tag>; - }; - - template - 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_iterator_tag, - conditional_t, bidirectional_iterator_tag, - conditional_t, forward_iterator_tag, input_iterator_tag>>>; - using value_type = remove_cvref_t&, range_reference_t<_Base>>>; - using difference_type = range_difference_t<_Base>; - - // clang-format off - _Iterator() requires default_initializable> = default; - // clang-format on - - constexpr _Iterator(_Parent_t& _Parent_, iterator_t<_Base> _Current_) noexcept( - is_nothrow_move_constructible_v>) // strengthened - : _Current{_STD move(_Current_)}, _Parent{_STD addressof(_Parent_)} { -#if _ITERATOR_DEBUG_LEVEL != 0 - _STD _Adl_verify_range(_Current, _RANGES end(_Parent_._Range)); - if constexpr (forward_range<_Base>) { - _STD _Adl_verify_range(_RANGES begin(_Parent_._Range), _Current); - } -#endif // _ITERATOR_DEBUG_LEVEL != 0 - } - - constexpr _Iterator(_Iterator _It) noexcept( - is_nothrow_constructible_v, iterator_t<_Vw>>) // strengthened - requires _Const && convertible_to, 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>) /* 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>) ) /* 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>) /* 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>) { - _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, "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> - { -#if _ITERATOR_DEBUG_LEVEL != 0 - _Left._Same_range(_Right); -#endif // _ITERATOR_DEBUG_LEVEL != 0 - return _Left._Current == _Right._Current; + _Current = + _RANGES find_if(_STD move(++_Current), _RANGES end(_Parent->_Range), _STD ref(*_Parent->_Pred)); + return *this; } - _NODISCARD_FRIEND constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( - noexcept(_Left._Current < _Right._Current)) /* strengthened */ - requires random_access_range<_Base> + 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 - _Left._Same_range(_Right); + _STL_VERIFY(_Parent != nullptr, "cannot decrement value-initialized filter_view iterator"); #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); - } - _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> - { + do { #if _ITERATOR_DEBUG_LEVEL != 0 - _Left._Same_range(_Right); + _STL_VERIFY(_Current != _RANGES begin(_Parent->_Range), + "cannot decrement filter_view iterator before begin"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return _Left._Current <=> _Right._Current; + --_Current; + } while (!_STD invoke(*_Parent->_Pred, *_Current)); + return *this; } - _NODISCARD_FRIEND constexpr _Iterator operator+(_Iterator _It, const difference_type _Off) noexcept( - noexcept(_It._Current += _Off)) /* strengthened */ - requires random_access_range<_Base> + constexpr _Iterator operator--(int) + requires bidirectional_range<_Vw> { -#if _ITERATOR_DEBUG_LEVEL != 0 - _It._Verify_offset(_Off); -#endif // _ITERATOR_DEBUG_LEVEL != 0 - _It._Current += _Off; - return _It; + auto _Tmp = *this; + --*this; + return _Tmp; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, _Iterator _It) noexcept( - noexcept(_It._Current += _Off)) /* strengthened */ - requires random_access_range<_Base> + + _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) + requires equality_comparable> { #if _ITERATOR_DEBUG_LEVEL != 0 - _It._Verify_offset(_Off); + _STL_VERIFY( + _Left._Parent == _Right._Parent, "cannot compare incompatible filter_view iterators for equality"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - _It._Current += _Off; - return _It; + 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> - { + _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 - _STL_VERIFY(_Off != _Min_possible_v, "integer overflow"); - _It._Verify_offset(-_Off); + _It._Check_dereference(); #endif // _ITERATOR_DEBUG_LEVEL != 0 - _It._Current -= _Off; - return _It; + return _RANGES iter_move(_It._Current); } - _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>> + friend constexpr void iter_swap(const _Iterator& _Left, const _Iterator& _Right) noexcept( + noexcept(_RANGES iter_swap(_Left._Current, _Right._Current))) + requires indirectly_swappable> { #if _ITERATOR_DEBUG_LEVEL != 0 - _Left._Same_range(_Right); + _Left._Check_dereference(); + _Right._Check_dereference(); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return _Left._Current - _Right._Current; + return _RANGES iter_swap(_Left._Current, _Right._Current); + } + + _NODISCARD constexpr bool _Equal(const sentinel_t<_Vw>& _Last) const + noexcept(noexcept(_STD _Fake_copy_init(_Current == _Last))) { + return _Current == _Last; } }; - template class _Sentinel { private: - friend transform_view; - - using _Parent_t = _Maybe_const<_Const, transform_view>; - using _Base = _Maybe_const<_Const, _Vw>; - template - using _Maybe_const_iter = iterator_t<_Maybe_const<_OtherConst, _Vw>>; - - sentinel_t<_Base> _Last{}; - - template - _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; - } + /* [[no_unique_address]] */ sentinel_t<_Vw> _Last{}; public: _Sentinel() = default; - constexpr explicit _Sentinel(sentinel_t<_Base> _Last_) noexcept( - is_nothrow_move_constructible_v>) // strengthened - : _Last(_STD move(_Last_)) {} - - constexpr _Sentinel(_Sentinel _Se) noexcept( - is_nothrow_constructible_v, sentinel_t<_Vw>>) // strengthened - requires _Const && convertible_to, sentinel_t<_Base>> - : _Last(_STD move(_Se._Last)) {} + constexpr explicit _Sentinel(filter_view& _Parent) noexcept( + noexcept(_RANGES end(_Parent._Range)) + && is_nothrow_move_constructible_v>) // strengthened + : _Last(_RANGES end(_Parent._Range)) {} - _NODISCARD constexpr sentinel_t<_Base> base() const - noexcept(is_nothrow_copy_constructible_v>) /* strengthened */ { + _NODISCARD constexpr sentinel_t<_Vw> base() const + noexcept(is_nothrow_copy_constructible_v>) /* strengthened */ { return _Last; } - template - requires sentinel_for, _Maybe_const_iter<_OtherConst>> - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_OtherConst>& _Left, - const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) == _Right._Last)) /* strengthened */ { - return _Get_current(_Left) == _Right._Last; - } - - template - requires sized_sentinel_for, _Maybe_const_iter<_OtherConst>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( - const _Iterator<_OtherConst>& _Left, - const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) - _Right._Last)) /* strengthened */ { - return _Get_current(_Left) - _Right._Last; - } - - template - requires sized_sentinel_for, _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); + _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 - transform_view() requires default_initializable<_Vw> && default_initializable<_Fn> = default; + filter_view() requires default_initializable<_Vw> && default_initializable<_Pr> = 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_)} {} + 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> @@ -2797,84 +1765,78 @@ namespace ranges { return _STD move(_Range); } - _NODISCARD constexpr _Iterator begin() noexcept( - noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v>) /* strengthened */ { - return _Iterator{*this, _RANGES begin(_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() const noexcept( - noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v>) /* strengthened */ - requires range && regular_invocable> - { - return _Iterator{*this, _RANGES begin(_Range)}; - } + _NODISCARD constexpr _Iterator begin() { +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY( + _Pred, "N4950 [range.filter.view]/3 forbids calling begin on a filter_view that holds no predicate"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 + if constexpr (forward_range<_Vw>) { + if (this->_Has_cache()) { + return _Iterator{*this, this->_Get_cache(_Range)}; + } + } - _NODISCARD constexpr auto end() noexcept( - noexcept(_RANGES end(_Range)) - && is_nothrow_move_constructible_v) /* strengthened */ { - if constexpr (common_range<_Vw>) { - return _Iterator{*this, _RANGES end(_Range)}; - } else { - return _Sentinel{_RANGES end(_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() const - noexcept(noexcept(_RANGES end(_Range)) - && is_nothrow_move_constructible_v) /* strengthened */ - requires range && regular_invocable> - { + _NODISCARD constexpr auto end() { if constexpr (common_range<_Vw>) { - return _Iterator{*this, _RANGES end(_Range)}; + return _Iterator{*this, _RANGES end(_Range)}; } else { - return _Sentinel{_RANGES end(_Range)}; + return _Sentinel{*this}; } } - - _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 - { - return _RANGES size(_Range); - } }; - template - transform_view(_Rng&&, _Fn) -> transform_view, _Fn>; + template + filter_view(_Rng&&, _Pr) -> filter_view, _Pr>; #if _HAS_CXX23 - template - constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; - - template - constexpr auto _Compile_time_max_size> = _Compile_time_max_size; + template + constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; #endif // _HAS_CXX23 namespace views { - struct _Transform_fn { - template - _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range, _Fn _Fun) _CONST_CALL_OPERATOR - noexcept(noexcept(transform_view(_STD forward<_Rng>(_Range), _STD move(_Fun)))) - requires requires { transform_view(static_cast<_Rng&&>(_Range), _STD move(_Fun)); } + struct _Filter_fn { + template + _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&& _Range, _Pr&& _Pred) _CONST_CALL_OPERATOR + noexcept(noexcept(filter_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred)))) + requires requires { filter_view(static_cast<_Rng&&>(_Range), _STD forward<_Pr>(_Pred)); } { - return transform_view(_STD forward<_Rng>(_Range), _STD move(_Fun)); + return filter_view(_STD forward<_Rng>(_Range), _STD forward<_Pr>(_Pred)); } - template - requires constructible_from, _Fn> - _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Fn&& _Fun) _CONST_CALL_OPERATOR - noexcept(is_nothrow_constructible_v, _Fn>) { - return _Range_closure<_Transform_fn, decay_t<_Fn>>{_STD forward<_Fn>(_Fun)}; + template + requires constructible_from, _Pr> + _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Pr&& _Pred) _CONST_CALL_OPERATOR + noexcept(is_nothrow_constructible_v, _Pr>) { + return _Range_closure<_Filter_fn, decay_t<_Pr>>{_STD forward<_Pr>(_Pred)}; } }; - _EXPORT_STD inline constexpr _Transform_fn transform; + _EXPORT_STD inline constexpr _Filter_fn filter; } // namespace views +#if _HAS_CXX23 + template + constexpr auto _Compile_time_max_size> = _Compile_time_max_size<_Rng>; + + template + constexpr auto _Compile_time_max_size> = _Compile_time_max_size; +#endif // _HAS_CXX23 + _EXPORT_STD template class take_view : public view_interface> { private: @@ -10298,119 +9260,6 @@ namespace ranges { _EXPORT_STD inline constexpr _Cartesian_product_fn cartesian_product; } // namespace views - template - 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>; - { _Cont.max_size() } -> same_as>; - }; - - template - concept _Ref_converts = - !input_range<_Container> || convertible_to, range_value_t<_Container>>; - - template - concept _Common_constructible = - common_range<_Rng> // - && requires { typename iterator_traits>::iterator_category; } - && derived_from>::iterator_category, input_iterator_tag> - && constructible_from<_Container, iterator_t<_Rng>, iterator_t<_Rng>, _Types...>; - - template - concept _Can_emplace_back = requires(_Container& _Cont) { _Cont.emplace_back(_STD declval<_Reference>()); }; - - template - concept _Can_push_back = requires(_Container& _Cont) { _Cont.push_back(_STD declval<_Reference>()); }; - - template - concept _Can_emplace_end = requires(_Container& _Cont) { _Cont.emplace(_Cont.end(), _STD declval<_Reference>()); }; - - template - concept _Can_insert_end = requires(_Container& _Cont) { _Cont.insert(_Cont.end(), _STD declval<_Reference>()); }; - - template - concept _Constructible_appendable = constructible_from<_Container, _Types...> - && (_Can_emplace_back<_Container, range_reference_t<_Rng>> - || _Can_push_back<_Container, range_reference_t<_Rng>> - || _Can_emplace_end<_Container, range_reference_t<_Rng>> - || _Can_insert_end<_Container, range_reference_t<_Rng>>); - - _EXPORT_STD template - 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 (_Ref_converts<_Rng, _Container>) { - if constexpr (constructible_from<_Container, _Rng, _Types...>) { - return _Container(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); - } else if constexpr (constructible_from<_Container, const from_range_t&, _Rng, _Types...>) { // per LWG-3845 - return _Container(from_range, _STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); - } else if constexpr (_Common_constructible<_Rng, _Container, _Types...>) { - return _Container(_RANGES begin(_Range), _RANGES end(_Range), _STD forward<_Types>(_Args)...); - } else if constexpr (_Constructible_appendable<_Rng, _Container, _Types...>) { - _Container _Cont(_STD forward<_Types>(_Args)...); - if constexpr (_Sized_and_reservable<_Rng, _Container>) { - _Cont.reserve(static_cast>(_RANGES size(_Range))); - } - for (auto&& _Elem : _Range) { - using _ElemTy = decltype(_Elem); - if constexpr (_Can_emplace_back<_Container, _ElemTy>) { - _Cont.emplace_back(_STD forward<_ElemTy>(_Elem)); - } else if constexpr (_Can_push_back<_Container, _ElemTy>) { - _Cont.push_back(_STD forward<_ElemTy>(_Elem)); - } else if constexpr (_Can_emplace_end<_Container, _ElemTy>) { - _Cont.emplace(_Cont.end(), _STD forward<_ElemTy>(_Elem)); - } else { - _STL_INTERNAL_STATIC_ASSERT(_Can_insert_end<_Container, _ElemTy>); - _Cont.insert(_Cont.end(), _STD forward<_ElemTy>(_Elem)); - } - } - return _Cont; - } else { - static_assert(false, "ranges::to requires the result to be constructible from the source range, either " - "by using a suitable constructor, or by inserting each element of the range into " - "the default-constructed object. (N4981 [range.utility.conv.to]/2.1.5)"); - } - } else if constexpr (input_range>) { - const auto _Xform = [](auto&& _Elem) _STATIC_CALL_OPERATOR { - return _RANGES to>(_STD forward(_Elem)); - }; - return _RANGES to<_Container>(views::transform(ref_view{_Range}, _Xform), _STD forward<_Types>(_Args)...); - } else { - static_assert(false, - "ranges::to requires the elements of the source range to be either implicitly convertible to the " - "elements of the destination container, or be ranges themselves for ranges::to to be applied " - "recursively. (N4981 [range.utility.conv.to]/2.3)"); - } - } - - template - 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 - _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()( - _Rng&& _Range, _Types&&... _Args) _CONST_CALL_OPERATOR - 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 - 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 struct _Phony_input_iterator { using iterator_category = input_iterator_tag; diff --git a/stl/inc/stack b/stl/inc/stack index 582e2873fe1..a73f801e29d 100644 --- a/stl/inc/stack +++ b/stl/inc/stack @@ -10,7 +10,8 @@ #include #if _HAS_CXX23 -#include +#include <__msvc_transform_view_to.hpp> +#include #endif // _HAS_CXX23 #pragma pack(push, _CRT_PACKING) From 712982fa7d3d087c26f1537cfcad9f336c603d9f Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 2 Jun 2024 15:46:17 +0800 Subject: [PATCH 2/9] Oops, escape hatch! --- stl/inc/queue | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/stl/inc/queue b/stl/inc/queue index e87ca569fb6..8d1318c01c3 100644 --- a/stl/inc/queue +++ b/stl/inc/queue @@ -7,7 +7,12 @@ #define _QUEUE_ #include #if _STL_COMPILER_PREPROCESSOR +#ifdef _LEGACY_CODE_ASSUMES_QUEUE_INCLUDES_ALGORITHM +#include +#else // ^^^ defined(_LEGACY_CODE_ASSUMES_QUEUE_INCLUDES_ALGORITHM) / + // !defined(_LEGACY_CODE_ASSUMES_QUEUE_INCLUDES_ALGORITHM) vvv #include <__msvc_heap_algorithms.hpp> +#endif // ^^^ !defined(_LEGACY_CODE_ASSUMES_QUEUE_INCLUDES_ALGORITHM) ^^^ #include #include From 14ace79cc61beeefe221022c1ad87986369b903e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 12 Jun 2024 05:31:59 -0700 Subject: [PATCH 3/9] Rename to `<__msvc_ranges_to.hpp>`. --- stl/CMakeLists.txt | 2 +- ...{__msvc_transform_view_to.hpp => __msvc_ranges_to.hpp} | 8 ++++---- stl/inc/header-units.json | 2 +- stl/inc/queue | 2 +- stl/inc/ranges | 2 +- stl/inc/stack | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) rename stl/inc/{__msvc_transform_view_to.hpp => __msvc_ranges_to.hpp} (97%) diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 22867b2503c..376f4ef9cd5 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -18,11 +18,11 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_iter_core.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_minmax.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_print.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_ranges_to.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_sanitizer_annotate_container.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_string_view.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_system_error_abi.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_threads_core.hpp - ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_transform_view_to.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_tzdb.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_xlocinfo_types.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/algorithm diff --git a/stl/inc/__msvc_transform_view_to.hpp b/stl/inc/__msvc_ranges_to.hpp similarity index 97% rename from stl/inc/__msvc_transform_view_to.hpp rename to stl/inc/__msvc_ranges_to.hpp index 5ef5118cd74..baea7593040 100644 --- a/stl/inc/__msvc_transform_view_to.hpp +++ b/stl/inc/__msvc_ranges_to.hpp @@ -1,10 +1,10 @@ -// __msvc_transform_view_to.hpp internal header +// __msvc_ranges_to.hpp internal header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef __MSVC_TRANSFORM_VIEW_TO_HPP -#define __MSVC_TRANSFORM_VIEW_TO_HPP +#ifndef __MSVC_RANGES_TO_HPP +#define __MSVC_RANGES_TO_HPP #include #if _STL_COMPILER_PREPROCESSOR @@ -1187,4 +1187,4 @@ _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _STL_COMPILER_PREPROCESSOR -#endif // __MSVC_TRANSFORM_VIEW_TO_HPP +#endif // __MSVC_RANGES_TO_HPP diff --git a/stl/inc/header-units.json b/stl/inc/header-units.json index 5af9bd1700f..bdd7858fef7 100644 --- a/stl/inc/header-units.json +++ b/stl/inc/header-units.json @@ -16,11 +16,11 @@ "__msvc_iter_core.hpp", "__msvc_minmax.hpp", "__msvc_print.hpp", + "__msvc_ranges_to.hpp", "__msvc_sanitizer_annotate_container.hpp", "__msvc_string_view.hpp", "__msvc_system_error_abi.hpp", "__msvc_threads_core.hpp", - "__msvc_transform_view_to.hpp", "__msvc_tzdb.hpp", "__msvc_xlocinfo_types.hpp", "algorithm", diff --git a/stl/inc/queue b/stl/inc/queue index 8d1318c01c3..39f224afae3 100644 --- a/stl/inc/queue +++ b/stl/inc/queue @@ -17,7 +17,7 @@ #include #if _HAS_CXX23 -#include <__msvc_transform_view_to.hpp> +#include <__msvc_ranges_to.hpp> #include #endif // _HAS_CXX23 diff --git a/stl/inc/ranges b/stl/inc/ranges index f49c4d802c7..5d82ac6347f 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -11,7 +11,7 @@ _EMIT_STL_WARNING(STL4038, "The contents of are available only with C++20 or later."); #else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv #include <__msvc_int128.hpp> -#include <__msvc_transform_view_to.hpp> +#include <__msvc_ranges_to.hpp> #include #include #include diff --git a/stl/inc/stack b/stl/inc/stack index a73f801e29d..6dd94f1104b 100644 --- a/stl/inc/stack +++ b/stl/inc/stack @@ -10,7 +10,7 @@ #include #if _HAS_CXX23 -#include <__msvc_transform_view_to.hpp> +#include <__msvc_ranges_to.hpp> #include #endif // _HAS_CXX23 From a6abdf5c82de3f916e1684b603d57b5e33d41362 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 12 Jun 2024 05:38:13 -0700 Subject: [PATCH 4/9] Add a comment explaining what the header provides. --- stl/inc/__msvc_ranges_to.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stl/inc/__msvc_ranges_to.hpp b/stl/inc/__msvc_ranges_to.hpp index baea7593040..547f17e06c5 100644 --- a/stl/inc/__msvc_ranges_to.hpp +++ b/stl/inc/__msvc_ranges_to.hpp @@ -3,6 +3,8 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// This header provides ranges::to (C++23) and supporting machinery (C++20). + #ifndef __MSVC_RANGES_TO_HPP #define __MSVC_RANGES_TO_HPP #include From ee232ab693766e428c6996e4ad403a4589172869 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 12 Jun 2024 05:38:49 -0700 Subject: [PATCH 5/9] Move `_HAS_CXX23` `` inclusion to avoid disrupting auto-sorting. --- stl/inc/__msvc_ranges_to.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/__msvc_ranges_to.hpp b/stl/inc/__msvc_ranges_to.hpp index 547f17e06c5..86fc47d2435 100644 --- a/stl/inc/__msvc_ranges_to.hpp +++ b/stl/inc/__msvc_ranges_to.hpp @@ -15,10 +15,11 @@ #endif // !_HAS_CXX20 #include +#include + #if _HAS_CXX23 #include #endif // _HAS_CXX23 -#include #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) From 0f807d58f33bb3ca56e12463f7c5914dffa1bb7d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 12 Jun 2024 05:42:26 -0700 Subject: [PATCH 6/9] Transfer all overloads of `ranges::to`. --- stl/inc/__msvc_ranges_to.hpp | 53 ++++++++++++++++++++++++++++++++++++ stl/inc/ranges | 53 ------------------------------------ 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/stl/inc/__msvc_ranges_to.hpp b/stl/inc/__msvc_ranges_to.hpp index 86fc47d2435..bd4cfaea563 100644 --- a/stl/inc/__msvc_ranges_to.hpp +++ b/stl/inc/__msvc_ranges_to.hpp @@ -1181,6 +1181,59 @@ namespace ranges { 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 + 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>; + 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