diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 1f798af8cb..a54ef6f99e 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -254,56 +254,6 @@ namespace ranges { return {_STD move(in), found}; } }; - - // clang-format off - template - requires sentinel_for, _Wrapped> - _NODISCARD constexpr auto _Get_final_iterator_unwrapped(const _Unwrapped_t<_Wrapped>& _UFirst, _Se&& _Last) { - // clang-format on - // find the iterator in [_UFirst, _Get_unwrapped(_Last)) which equals _Get_unwrapped(_Last) [possibly O(N)] - auto _ULast = _Get_unwrapped(_STD forward<_Se>(_Last)); - if constexpr (is_same_v, _Wrapped>) { - return _ULast; - } else if constexpr (sized_sentinel_for, _Wrapped>) { - return _RANGES next(_UFirst, _ULast - _UFirst); - } else { - return _RANGES next(_UFirst, _STD move(_ULast)); - } - } - - template - _NODISCARD constexpr auto _Get_final_iterator_unwrapped(_Rng& _Range) { - // find the (unwrapped) iterator in _Range which equals _Uend(_Range) [possibly O(N)] - if constexpr (common_range<_Rng>) { - if constexpr (same_as<_Unwrapped_t<_RANGES iterator_t<_Rng>>, decltype(_Uend(_Range))>) { - return _Uend(_Range); - } else { - return _Get_unwrapped(_RANGES end(_Range)); - } - } else if constexpr (sized_range<_Rng>) { - return _RANGES next(_Ubegin(_Range), _RANGES distance(_Range)); - } else { - return _RANGES next(_Ubegin(_Range), _Uend(_Range)); - } - } - - template - _NODISCARD constexpr auto _Get_final_iterator_unwrapped(_Rng& _Range, const _Unwrapped_t>& _Mid) { - // find the (unwrapped) iterator in _Range which equals _Uend(_Range) [possibly O(N)] - // Pre: [ranges::begin(_Range), _Mid) and [_Mid, ranges::end(_Range)) denote ranges - if constexpr (common_range<_Rng>) { - return _Uend(_Range); - } else if constexpr (sized_range<_Rng>) { - const auto _Dist = _RANGES distance(_Range); - if constexpr (sized_sentinel_for<_Unwrapped_t>, _Unwrapped_t>>) { - return _RANGES next(_Mid, _Dist - (_Mid - _Ubegin(_Range))); - } else { - return _RANGES next(_Ubegin(_Range), _Dist); - } - } else { - return _RANGES next(_Mid, _Uend(_Range)); - } - } } // namespace ranges #endif // __cpp_lib_concepts @@ -1449,9 +1399,9 @@ namespace ranges { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); if constexpr (_Iter_copy_cat::_Bitcopy_assignable) { if (!_STD is_constant_evaluated()) { - auto _Final = _UFirst + _Count; - _Result = _Copy_memmove(_STD move(_UFirst), _Final, _STD move(_Result)); - _Seek_wrapped(_First, _STD move(_Final)); + _Result = _Copy_memmove_n(_UFirst, static_cast(_Count), _STD move(_Result)); + _UFirst += _Count; + _Seek_wrapped(_First, _STD move(_UFirst)); return {_STD move(_First), _STD move(_Result)}; } } diff --git a/stl/inc/deque b/stl/inc/deque index d045c20b5b..ed51e39aba 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -673,12 +673,30 @@ public: _Proxy._Release(); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + deque(from_range_t, _Rng&& _Range) : _Mypair(_Zero_then_variadic_args_t{}) { + _Alproxy_ty _Alproxy(_Getal()); + _Container_proxy_ptr12<_Alproxy_ty> _Proxy(_Alproxy, _Get_data()); + _Construct(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + _Proxy._Release(); + } + + template <_Container_compatible_range<_Ty> _Rng> + deque(from_range_t, _Rng&& _Range, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { + _Alproxy_ty _Alproxy(_Getal()); + _Container_proxy_ptr12<_Alproxy_ty> _Proxy(_Alproxy, _Get_data()); + _Construct(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + _Proxy._Release(); + } +#endif // __cpp_lib_containers_ranges + private: - template - void _Construct(_Iter _First, _Iter _Last) { // initialize from [_First, _Last), input iterators + template + void _Construct(_Iter _First, const _Sent _Last) { // initialize from input range [_First, _Last) _Tidy_guard _Guard{this}; for (; _First != _Last; ++_First) { - emplace_back(*_First); + _Emplace_back_internal(*_First); } _Guard._Target = nullptr; @@ -772,11 +790,55 @@ public: emplace_front(_STD move(_Val)); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + void prepend_range(_Rng&& _Range) { + _Orphan_all(); + + const auto _Oldsize = _Mysize(); + _Restore_old_size_guard<_Pop_direction::_Front> _Guard{this, _Oldsize}; + if constexpr (_RANGES bidirectional_range<_Rng>) { + const auto _UFirst = _RANGES _Ubegin(_Range); + auto _ULast = _RANGES _Get_final_iterator_unwrapped(_Range); + while (_UFirst != _ULast) { + _Emplace_front_internal(*--_ULast); // prepend in order + } + } else { + auto _UFirst = _RANGES _Ubegin(_Range); + const auto _ULast = _RANGES _Uend(_Range); + for (; _UFirst != _ULast; ++_UFirst) { + _Emplace_front_internal(*_UFirst); // prepend flipped + } + + const auto _Num = static_cast(_Mysize() - _Oldsize); + _STD reverse(begin(), begin() + _Num); // Per LWG-3742 + } + _Guard._Container = nullptr; + } +#endif // __cpp_lib_containers_ranges + void push_back(_Ty&& _Val) { _Orphan_all(); _Emplace_back_internal(_STD move(_Val)); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + void append_range(_Rng&& _Range) { + _Orphan_all(); + + const auto _Oldsize = _Mysize(); + auto _UFirst = _RANGES _Ubegin(_Range); + const auto _ULast = _RANGES _Uend(_Range); + + _Restore_old_size_guard<_Pop_direction::_Back> _Guard{this, _Oldsize}; + for (; _UFirst != _ULast; ++_UFirst) { + _Emplace_back_internal(*_UFirst); + } + _Guard._Container = nullptr; + } +#endif // __cpp_lib_containers_ranges + iterator insert(const_iterator _Where, _Ty&& _Val) { return emplace(_Where, _STD move(_Val)); } @@ -784,23 +846,7 @@ public: template decltype(auto) emplace_front(_Valty&&... _Val) { _Orphan_all(); - - if (_Myoff() % _Block_size == 0 && _Mapsize() <= (_Mysize() + _Block_size) / _Block_size) { - _Growmap(1); - } - _Myoff() &= _Mapsize() * _Block_size - 1; - size_type _Newoff = _Myoff() != 0 ? _Myoff() : _Mapsize() * _Block_size; - size_type _Block = _Getblock(--_Newoff); - if (_Map()[_Block] == nullptr) { - _Map()[_Block] = _Getal().allocate(_Block_size); - } - - _Alty_traits::construct( - _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _Block_size), _STD forward<_Valty>(_Val)...); - - _Myoff() = _Newoff; - ++_Mysize(); - + _Emplace_front_internal(_STD forward<_Valty>(_Val)...); #if _HAS_CXX17 return front(); #endif // _HAS_CXX17 @@ -965,8 +1011,9 @@ public: } void resize(_CRT_GUARDOVERFLOW size_type _Newsize) { + _Orphan_all(); while (_Mysize() < _Newsize) { - emplace_back(); + _Emplace_back_internal(); } while (_Mysize() > _Newsize) { @@ -1115,6 +1162,25 @@ private: ++_Mysize(); } + template + void _Emplace_front_internal(_Tys&&... _Vals) { + if (_Myoff() % _Block_size == 0 && _Mapsize() <= (_Mysize() + _Block_size) / _Block_size) { + _Growmap(1); + } + _Myoff() &= _Mapsize() * _Block_size - 1; + size_type _Newoff = _Myoff() != 0 ? _Myoff() : _Mapsize() * _Block_size; + const size_type _Block = _Getblock(--_Newoff); + if (_Map()[_Block] == nullptr) { + _Map()[_Block] = _Getal().allocate(_Block_size); + } + + _Alty_traits::construct( + _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _Block_size), _STD forward<_Tys>(_Vals)...); + + _Myoff() = _Newoff; + ++_Mysize(); + } + public: void push_back(const _Ty& _Val) { _Orphan_all(); @@ -1145,30 +1211,42 @@ public: #endif // _ITERATOR_DEBUG_LEVEL == 2 } - template , int> = 0> - void assign(_Iter _First, _Iter _Last) { +private: + template + void _Assign_range(_Iter _First, const _Sent _Last) { _Orphan_all(); - _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); auto _Myfirst = _Unchecked_begin(); const auto _Mylast = _Unchecked_end(); - for (; _UFirst != _ULast; ++_UFirst) { // try to assign over an element in the container - if (_Myfirst == _Mylast) { // container wasn't big enough, insert what's left at end - do { - emplace_back(*_UFirst); - ++_UFirst; - } while (_UFirst != _ULast); + // Reuse existing elements + for (; _Myfirst != _Mylast; ++_Myfirst, (void) ++_First) { + if (_First == _Last) { + _Erase_last_n(static_cast(_Mylast - _Myfirst)); return; } - *_Myfirst = *_UFirst; - ++_Myfirst; + *_Myfirst = *_First; } - _Erase_last_n(static_cast(_Mylast - _Myfirst)); + // Allocate new elements for remaining tail of values + for (; _First != _Last; ++_First) { + _Emplace_back_internal(*_First); + } } +public: + template , int> = 0> + void assign(_Iter _First, _Iter _Last) { + _Adl_verify_range(_First, _Last); + _Assign_range(_Get_unwrapped(_First), _Get_unwrapped(_Last)); + } + +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + void assign_range(_Rng&& _Range) { + _Assign_range(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } +#endif // __cpp_lib_containers_ranges + void assign(_CRT_GUARDOVERFLOW size_type _Count, const _Ty& _Val) { // assign _Count * _Val _Orphan_all(); auto _Myfirst = _Unchecked_begin(); @@ -1236,52 +1314,87 @@ private: } }; -public: - template , int> = 0> - iterator insert(const_iterator _Where, _Iter _First, _Iter _Last) { - // insert [_First, _Last) at _Where, input iterators - size_type _Off = static_cast(_Where - begin()); + enum class _Is_bidi : bool { _No, _Yes }; + + template <_Is_bidi _Bidi, class _Iter, class _Sent> + iterator _Insert_range(const size_type _Off, _Iter _First, _Sent _Last) { + // insert [_First, _Last) at begin() + _Off + // Pre: _Bidi == _Is_bidi::_Yes implies that _Iter and _Sent are the same type, and that + // _Iter is either a bidirectional_iterator or a Cpp17BidirectionalIterator. #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(_Mysize() >= _Off, "deque insert iterator outside range"); #endif // _ITERATOR_DEBUG_LEVEL == 2 - _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); + if (_First == _Last) { + return begin() + static_cast(_Off); + } - size_type _Oldsize = _Mysize(); + const size_type _Oldsize = _Mysize(); - if (_UFirst != _ULast) { - if (_Off <= _Mysize() / 2) { // closer to front, push to front then rotate - _Restore_old_size_guard<_Pop_direction::_Front> _Guard{this, _Oldsize}; - for (; _UFirst != _ULast; ++_UFirst) { - emplace_front(*_UFirst); // prepend flipped + _Orphan_all(); + if (_Off <= _Oldsize / 2) { // closer to front, push to front then rotate + _Restore_old_size_guard<_Pop_direction::_Front> _Guard{this, _Oldsize}; + if constexpr (_Bidi == _Is_bidi::_Yes) { + while (_First != _Last) { + _Emplace_front_internal(*--_Last); // prepend in order } - - _Guard._Container = nullptr; - - size_type _Num = _Mysize() - _Oldsize; - _STD reverse(begin(), begin() + static_cast(_Num)); // flip new stuff in place - _STD rotate(begin(), begin() + static_cast(_Num), - begin() + static_cast(_Num + _Off)); - } else { // closer to back - _Orphan_all(); - _Restore_old_size_guard<_Pop_direction::_Back> _Guard{this, _Oldsize}; - for (; _UFirst != _ULast; ++_UFirst) { - _Emplace_back_internal(*_UFirst); + } else { + for (; _First != _Last; ++_First) { + _Emplace_front_internal(*_First); // prepend flipped } + } - _Guard._Container = nullptr; + _Guard._Container = nullptr; - _STD rotate(begin() + static_cast(_Off), - begin() + static_cast(_Oldsize), end()); + const auto _Num = static_cast(_Mysize() - _Oldsize); + const auto _Myfirst = _Unchecked_begin(); + const auto _Mymid = _Myfirst + _Num; + if constexpr (_Bidi == _Is_bidi::_No) { + _STD reverse(_Myfirst, _Mymid); // flip new stuff in place } + _STD rotate(_Myfirst, _Mymid, _Mymid + static_cast(_Off)); + return begin() + static_cast(_Off); + } + + _Restore_old_size_guard<_Pop_direction::_Back> _Guard{this, _Oldsize}; + for (; _First != _Last; ++_First) { + _Emplace_back_internal(*_First); } + _Guard._Container = nullptr; + + const auto _Myfirst = _Unchecked_begin(); + _STD rotate(_Myfirst + static_cast(_Off), _Myfirst + static_cast(_Oldsize), + _Unchecked_end()); + return begin() + static_cast(_Off); } +public: + template , int> = 0> + iterator insert(const_iterator _Where, _Iter _First, _Iter _Last) { + // insert [_First, _Last) at _Where + _Adl_verify_range(_First, _Last); + const size_type _Off = static_cast(_Where - begin()); + return _Insert_range(_Is_cpp17_bidi_iter_v<_Iter>)>( + _Off, _Get_unwrapped(_First), _Get_unwrapped(_Last)); + } + +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + iterator insert_range(const_iterator _Where, _Rng&& _Range) { + const size_type _Off = static_cast(_Where - begin()); + + if constexpr (_RANGES bidirectional_range<_Rng>) { + return _Insert_range<_Is_bidi::_Yes>( + _Off, _RANGES _Ubegin(_Range), _RANGES _Get_final_iterator_unwrapped(_Range)); + } else { + return _Insert_range<_Is_bidi::_No>(_Off, _RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } + } +#endif // __cpp_lib_containers_ranges + iterator erase(const_iterator _Where) noexcept(is_nothrow_move_assignable_v) /* strengthened */ { return erase(_Where, _Next_iter(_Where)); } @@ -1577,6 +1690,12 @@ template >, deque(_Iter, _Iter, _Alloc = _Alloc()) -> deque<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 +#ifdef __cpp_lib_containers_ranges +template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, + enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +deque(from_range_t, _Rng&&, _Alloc = _Alloc()) -> deque<_RANGES range_value_t<_Rng>, _Alloc>; +#endif // __cpp_lib_containers_ranges + template void swap(deque<_Ty, _Alloc>& _Left, deque<_Ty, _Alloc>& _Right) noexcept /* strengthened */ { _Left.swap(_Right); diff --git a/stl/inc/forward_list b/stl/inc/forward_list index 918e7df288..9cf8ba41a1 100644 --- a/stl/inc/forward_list +++ b/stl/inc/forward_list @@ -607,6 +607,24 @@ public: _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + forward_list(from_range_t, _Rng&& _Range) : _Mypair(_Zero_then_variadic_args_t{}) { + _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); + _Insert_op._Append_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + _Alloc_proxy(); + _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); + } + + template <_Container_compatible_range<_Ty> _Rng> + forward_list(from_range_t, _Rng&& _Range, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { + _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); + _Insert_op._Append_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + _Alloc_proxy(); + _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); + } +#endif // __cpp_lib_containers_ranges + forward_list(forward_list&& _Right) noexcept // strengthened : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { _Alloc_proxy(); @@ -691,7 +709,7 @@ public: iterator emplace_after(const_iterator _Where, _Valty&&... _Val) { // insert element after _Where #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY( - _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list insert_after iterator outside range"); + _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list emplace_after iterator outside range"); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Insert_after(_Where._Ptr, _STD forward<_Valty>(_Val)...); return _Make_iter(_Where._Ptr->_Next); @@ -899,19 +917,26 @@ public: _Insert_after(_Mypair._Myval2._Before_head(), _Val); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + void prepend_range(_Rng&& _Range) { + _Insert_range_after(_Mypair._Myval2._Before_head(), _RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } +#endif // __cpp_lib_containers_ranges + void pop_front() noexcept /* strengthened */ { _Erase_after(_Mypair._Myval2._Before_head()); } private: template - void _Assign_unchecked(_UIter _UFirst, _Sentinel _ULast) { + void _Assign_unchecked(_UIter _UFirst, const _Sentinel _ULast) { auto _Myfirst = _Mypair._Myval2._Before_head(); for (; _UFirst != _ULast; ++_UFirst) { - auto _Next = _Myfirst->_Next; - if (!_Myfirst->_Next) { + const auto _Next = _Myfirst->_Next; + if (!_Next) { _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); - _Insert_op._Append_range_unchecked(_UFirst, _ULast); + _Insert_op._Append_range_unchecked(_STD move(_UFirst), _ULast); _Insert_op._Attach_after(_Myfirst); return; } @@ -921,7 +946,7 @@ private: } for (auto _To_delete = _STD exchange(_Myfirst->_Next, nullptr); _To_delete;) { - auto _Next = _To_delete->_Next; + const auto _Next = _To_delete->_Next; #if _ITERATOR_DEBUG_LEVEL == 2 _Mypair._Myval2._Orphan_ptr(_To_delete); #endif // _ITERATOR_DEBUG_LEVEL == 2 @@ -937,6 +962,13 @@ public: _Assign_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last)); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + void assign_range(_Rng&& _Range) { + _Assign_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } +#endif // __cpp_lib_containers_ranges + void assign(_CRT_GUARDOVERFLOW size_type _Count, const _Ty& _Val) { clear(); insert_after(before_begin(), _Count, _Val); @@ -944,7 +976,8 @@ public: iterator insert_after(const_iterator _Where, const _Ty& _Val) { // insert _Val after _Where #if _ITERATOR_DEBUG_LEVEL == 2 - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "insert_after location incompatible"); + _STL_VERIFY( + _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list insert_after location incompatible"); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Insert_after(_Where._Ptr, _Val); return _Make_iter(_Where._Ptr->_Next); @@ -966,6 +999,20 @@ public: return _Make_iter(_Where._Ptr); } +private: + template + iterator _Insert_range_after(_Nodeptr _Pnode, _Iter _First, const _Sent _Last) { + // insert [_First, _Last) after _Pnode + if (_First == _Last) { + return _Make_iter(_Pnode); + } + + _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); + _Insert_op._Append_range_unchecked(_STD move(_First), _Last); + return _Make_iter(_Insert_op._Attach_after(_Pnode)); + } + +public: template , int> = 0> iterator insert_after(const_iterator _Where, _Iter _First, _Iter _Last) { // insert [_First, _Last) after _Where @@ -973,18 +1020,20 @@ public: _STL_VERIFY( _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list insert_after location incompatible"); #endif // _ITERATOR_DEBUG_LEVEL == 2 - _Adl_verify_range(_First, _Last); - const auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); - if (_UFirst == _ULast) { - return _Make_iter(_Where._Ptr); - } + return _Insert_range_after(_Where._Ptr, _Get_unwrapped(_First), _Get_unwrapped(_Last)); + } - _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); - _Insert_op._Append_range_unchecked(_UFirst, _ULast); - return _Make_iter(_Insert_op._Attach_after(_Where._Ptr)); +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + iterator insert_range_after(const_iterator _Where, _Rng&& _Range) { +#if _ITERATOR_DEBUG_LEVEL == 2 + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), + "forward_list insert_range_after location incompatible"); +#endif // _ITERATOR_DEBUG_LEVEL == 2 + return _Insert_range_after(_Where._Ptr, _RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); } +#endif // __cpp_lib_containers_ranges private: void _Erase_after(_Nodeptr _Pnode) noexcept { // erase element after _Pnode @@ -1246,7 +1295,7 @@ private: #if _ITERATOR_DEBUG_LEVEL != 0 _DEBUG_ORDER_UNWRAPPED(_Right._Unchecked_begin(), _Default_sentinel{}, _Pred); if constexpr (!_Alnode_traits::is_always_equal::value) { - _STL_VERIFY(_Getal() == _Right._Getal(), "list allocators incompatible for merge"); + _STL_VERIFY(_Getal() == _Right._Getal(), "forward_list allocators incompatible for merge"); } #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -1508,6 +1557,12 @@ template >, forward_list(_Iter, _Iter, _Alloc = _Alloc()) -> forward_list<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 +#ifdef __cpp_lib_containers_ranges +template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, + enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +forward_list(from_range_t, _Rng&&, _Alloc = _Alloc()) -> forward_list<_RANGES range_value_t<_Rng>, _Alloc>; +#endif // __cpp_lib_containers_ranges + template void swap(forward_list<_Ty, _Alloc>& _Left, forward_list<_Ty, _Alloc>& _Right) noexcept /* strengthened */ { _Left.swap(_Right); diff --git a/stl/inc/list b/stl/inc/list index 3168da732a..ed10e1f79b 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -850,12 +850,12 @@ public: } private: - template - void _Construct_range_unchecked(_Iter _First, _Iter _Last) { + template + void _Construct_range_unchecked(_Iter _First, const _Sent _Last) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alnode, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); _List_node_insert_op2<_Alnode> _Appended(_Getal()); - _Appended._Append_range_unchecked(_First, _Last); + _Appended._Append_range_unchecked(_STD move(_First), _Last); _Appended._Attach_head(_Mypair._Myval2); _Proxy._Release(); } @@ -882,6 +882,18 @@ public: _Construct_range_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last)); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + list(from_range_t, _Rng&& _Range) : _Mypair(_Zero_then_variadic_args_t{}) { + _Construct_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } + + template <_Container_compatible_range<_Ty> _Rng> + list(from_range_t, _Rng&& _Range, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { + _Construct_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } +#endif // __cpp_lib_containers_ranges + list(list&& _Right) : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { _Alloc_sentinel_and_proxy(); _Swap_val(_Right); @@ -1024,8 +1036,7 @@ public: assign(_Ilist.begin(), _Ilist.end()); } - iterator insert(const_iterator _Where, - initializer_list<_Ty> _Ilist) { // insert initializer_list + iterator insert(const_iterator _Where, initializer_list<_Ty> _Ilist) { // insert initializer_list return insert(_Where, _Ilist.begin(), _Ilist.end()); } @@ -1225,6 +1236,15 @@ public: _Emplace(_Mypair._Myval2._Myhead->_Next, _Val); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + void prepend_range(_Rng&& _Range) { + _List_node_insert_op2<_Alnode> _Op(_Getal()); + _Op._Append_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + _Op._Attach_before(_Mypair._Myval2, _Mypair._Myval2._Myhead->_Next); + } +#endif // __cpp_lib_containers_ranges + void pop_front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "pop_front called on empty list"); @@ -1237,6 +1257,15 @@ public: _Emplace(_Mypair._Myval2._Myhead, _Val); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + void append_range(_Rng&& _Range) { + _List_node_insert_op2<_Alnode> _Op(_Getal()); + _Op._Append_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + _Op._Attach_at_end(_Mypair._Myval2); + } +#endif // __cpp_lib_containers_ranges + void pop_back() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "pop_back called on empty list"); @@ -1272,12 +1301,46 @@ private: } } + template + void _Assign_unchecked(_Iter _First, const _Sent _Last) { + // assign [_First, _Last) + const auto _Myend = _Mypair._Myval2._Myhead; + auto _Old = _Myend->_Next; + for (;;) { // attempt to reuse a node + if (_First == _Last) { + // input sequence exhausted; destroy and deallocate any tail of unneeded nodes + _Unchecked_erase(_Old, _Myend); + return; + } + + if (_Old == _Myend) { // no more nodes to reuse, append the rest + _List_node_insert_op2<_Alnode> _Op(_Getal()); + _Op._Append_range_unchecked(_STD move(_First), _Last); + _Op._Attach_at_end(_Mypair._Myval2); + return; + } + + // reuse the node + _Old->_Myval = *_First; + _Old = _Old->_Next; + ++_First; + } + } + public: template , int> = 0> void assign(_Iter _First, _Iter _Last) { - _Assign_cast(_Get_unwrapped(_First), _Get_unwrapped(_Last)); + _Adl_verify_range(_First, _Last); + _Assign_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last)); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + void assign_range(_Rng&& _Range) { + _Assign_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } +#endif // __cpp_lib_containers_ranges + void assign(_CRT_GUARDOVERFLOW size_type _Count, const _Ty& _Val) { // assign _Count * _Val const auto _Myend = _Mypair._Myval2._Myhead; auto _Old = _Myend->_Next; @@ -1309,8 +1372,8 @@ public: return _Make_iter(_Emplace(_Where._Ptr, _Val)); } - iterator insert(const_iterator _Where, _CRT_GUARDOVERFLOW size_type _Count, - const _Ty& _Val) { // insert _Count * _Val before _Where + iterator insert(const_iterator _Where, _CRT_GUARDOVERFLOW size_type _Count, const _Ty& _Val) { + // insert _Count * _Val before _Where #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "list insert iterator outside range"); #endif // _ITERATOR_DEBUG_LEVEL == 2 @@ -1330,6 +1393,18 @@ public: return _Make_iter(_Op._Attach_before(_Mypair._Myval2, _Where._Ptr)); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + iterator insert_range(const_iterator _Where, _Rng&& _Range) { +#if _ITERATOR_DEBUG_LEVEL == 2 + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "list insert_range iterator outside range"); +#endif // _ITERATOR_DEBUG_LEVEL == 2 + _List_node_insert_op2<_Alnode> _Op(_Getal()); + _Op._Append_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + return _Make_iter(_Op._Attach_before(_Mypair._Myval2, _Where._Ptr)); + } +#endif // __cpp_lib_containers_ranges + public: iterator erase(const const_iterator _Where) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL == 2 @@ -1785,6 +1860,12 @@ template >, list(_Iter, _Iter, _Alloc = _Alloc()) -> list<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 +#ifdef __cpp_lib_containers_ranges +template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, + enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +list(from_range_t, _Rng&&, _Alloc = _Alloc()) -> list<_RANGES range_value_t<_Rng>, _Alloc>; +#endif // __cpp_lib_containers_ranges + template void swap(list<_Ty, _Alloc>& _Left, list<_Ty, _Alloc>& _Right) noexcept /* strengthened */ { _Left.swap(_Right); diff --git a/stl/inc/map b/stl/inc/map index 66fdd9fc81..96219bd391 100644 --- a/stl/inc/map +++ b/stl/inc/map @@ -134,6 +134,28 @@ public: insert(_First, _Last); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range _Rng> + map(from_range_t, _Rng&& _Range) : _Mybase(key_compare()) { + this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } + + template <_Container_compatible_range _Rng> + map(from_range_t, _Rng&& _Range, const key_compare& _Pred) : _Mybase(_Pred) { + this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } + + template <_Container_compatible_range _Rng> + map(from_range_t, _Rng&& _Range, const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) { + this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } + + template <_Container_compatible_range _Rng> + map(from_range_t, _Rng&& _Range, const allocator_type& _Al) : _Mybase(key_compare(), _Al) { + this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } +#endif // __cpp_lib_containers_ranges + map& operator=(const map& _Right) { _Mybase::operator=(_Right); return *this; @@ -359,6 +381,18 @@ map(_Iter, _Iter, _Alloc) -> map<_Guide_key_t<_Iter>, _Guide_val_t<_Iter>, less< template ::value, int> = 0> map(initializer_list>, _Alloc) -> map<_Kty, _Ty, less<_Kty>, _Alloc>; + +#ifdef __cpp_lib_containers_ranges +template <_RANGES input_range _Rng, class _Pr = less<_Range_key_type<_Rng>>, + class _Alloc = allocator<_Range_to_alloc_type<_Rng>>, + enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> +map(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) + -> map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Pr, _Alloc>; + +template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +map(from_range_t, _Rng&&, _Alloc) + -> map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, less<_Range_key_type<_Rng>>, _Alloc>; +#endif // __cpp_lib_containers_ranges #endif // _HAS_CXX17 template @@ -478,6 +512,28 @@ public: insert(_First, _Last); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range _Rng> + multimap(from_range_t, _Rng&& _Range) : _Mybase(key_compare()) { + this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } + + template <_Container_compatible_range _Rng> + multimap(from_range_t, _Rng&& _Range, const key_compare& _Pred) : _Mybase(_Pred) { + this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } + + template <_Container_compatible_range _Rng> + multimap(from_range_t, _Rng&& _Range, const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) { + this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } + + template <_Container_compatible_range _Rng> + multimap(from_range_t, _Rng&& _Range, const allocator_type& _Al) : _Mybase(key_compare(), _Al) { + this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range)); + } +#endif // __cpp_lib_containers_ranges + multimap& operator=(const multimap& _Right) { _Mybase::operator=(_Right); return *this; @@ -556,6 +612,18 @@ multimap(_Iter, _Iter, _Alloc) -> multimap<_Guide_key_t<_Iter>, _Guide_val_t<_It template ::value, int> = 0> multimap(initializer_list>, _Alloc) -> multimap<_Kty, _Ty, less<_Kty>, _Alloc>; + +#ifdef __cpp_lib_containers_ranges +template <_RANGES input_range _Rng, class _Pr = less<_Range_key_type<_Rng>>, + class _Alloc = allocator<_Range_to_alloc_type<_Rng>>, + enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> +multimap(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) + -> multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Pr, _Alloc>; + +template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +multimap(from_range_t, _Rng&&, _Alloc) + -> multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, less<_Range_key_type<_Rng>>, _Alloc>; +#endif // __cpp_lib_containers_ranges #endif // _HAS_CXX17 template diff --git a/stl/inc/memory b/stl/inc/memory index b1c06adc3c..cfe2372fae 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -118,7 +118,7 @@ _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _ auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); if constexpr (_Iter_copy_cat::_Bitcopy_constructible) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + _UDest = _Copy_memmove_n(_UFirst, static_cast(_Count), _UDest); } else { _Uninitialized_backout _Backout{_UDest}; @@ -253,7 +253,7 @@ pair<_InIt, _NoThrowFwdIt> uninitialized_move_n(_InIt _First, const _Diff _Count auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); if constexpr (_Iter_move_cat::_Bitcopy_constructible) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + _UDest = _Copy_memmove_n(_UFirst, static_cast(_Count), _UDest); _UFirst += _Count; } else { _Uninitialized_backout _Backout{_UDest}; @@ -2184,7 +2184,7 @@ struct _NODISCARD _Reverse_destroy_multidimensional_n_guard { template void _Uninitialized_copy_multidimensional(const _Ty (&_In)[_Size], _Ty (&_Out)[_Size]) { if constexpr (is_trivial_v<_Ty>) { - _Copy_memmove(_In, _In + _Size, _Out); + _Copy_memmove_n(_In, _Size, _Out); } else if constexpr (is_array_v<_Ty>) { _Reverse_destroy_multidimensional_n_guard<_Ty> _Guard{_Out, 0}; for (size_t& _Idx = _Guard._Index; _Idx < _Size; ++_Idx) { @@ -2549,7 +2549,7 @@ template void _Uninitialized_copy_multidimensional_al(const _Ty (&_In)[_Size], _Ty (&_Out)[_Size], _Alloc& _Al) { using _Item = remove_all_extents_t<_Ty>; if constexpr (conjunction_v, _Uses_default_construct<_Alloc, _Item*, const _Item&>>) { - _Copy_memmove(_In, _In + _Size, _Out); + _Copy_memmove_n(_In, _Size, _Out); } else if constexpr (is_array_v<_Ty>) { _Reverse_destroy_multidimensional_n_al_guard<_Ty, _Alloc> _Guard{_Out, 0, _Al}; for (size_t& _Idx = _Guard._Index; _Idx < _Size; ++_Idx) { diff --git a/stl/inc/queue b/stl/inc/queue index d798d5ed4f..c83a66d595 100644 --- a/stl/inc/queue +++ b/stl/inc/queue @@ -12,6 +12,10 @@ #include #include +#ifdef __cpp_lib_containers_ranges +#include +#endif // __cpp_lib_containers_ranges + #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) @@ -42,6 +46,11 @@ public: template , int> = 0> queue(_InIt _First, _InIt _Last) noexcept(is_nothrow_constructible_v<_Container, _InIt, _InIt>) // strengthened : c(_STD move(_First), _STD move(_Last)) {} + +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + queue(from_range_t, _Rng&& _Range) : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range))) {} +#endif // __cpp_lib_containers_ranges #endif // _HAS_CXX23 template , int> = 0> @@ -70,6 +79,12 @@ public: queue(_InIt _First, _InIt _Last, const _Alloc& _Al) noexcept( is_nothrow_constructible_v<_Container, _InIt, _InIt, const _Alloc&>) // strengthened : c(_STD move(_First), _STD move(_Last), _Al) {} + +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng, class _Alloc> + queue(from_range_t, _Rng&& _Range, const _Alloc& _Al) + : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range), _Al)) {} +#endif // __cpp_lib_containers_ranges #endif // _HAS_CXX23 _NODISCARD bool empty() const noexcept(noexcept(c.empty())) /* strengthened */ { @@ -104,6 +119,17 @@ public: c.push_back(_STD move(_Val)); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + void push_range(_Rng&& _Range) { + if constexpr (requires { c.append_range(_Range); }) { + c.append_range(_Range); + } else { + _RANGES copy(_Range, back_insert_iterator{c}); + } + } +#endif // __cpp_lib_containers_ranges + template decltype(auto) emplace(_Valty&&... _Val) { #if _HAS_CXX17 @@ -142,6 +168,13 @@ queue(_Container, _Alloc) -> queue; template >, enable_if_t, _Is_allocator<_Alloc>>, int> = 0> queue(_InIt, _InIt, _Alloc = _Alloc()) -> queue<_Iter_value_t<_InIt>, deque<_Iter_value_t<_InIt>, _Alloc>>; + +#ifdef __cpp_lib_containers_ranges +template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, + enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +queue(from_range_t, _Rng&&, _Alloc = _Alloc()) + -> queue<_RANGES range_value_t<_Rng>, deque<_RANGES range_value_t<_Rng>, _Alloc>>; +#endif // __cpp_lib_containers_ranges #endif // _HAS_CXX23 template @@ -238,6 +271,14 @@ public: _STD make_heap(c.begin(), c.end(), comp); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + priority_queue(from_range_t, _Rng&& _Range, const _Pr& _Pred = _Pr()) + : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range))), comp(_Pred) { + _STD make_heap(c.begin(), c.end(), comp); + } +#endif // __cpp_lib_containers_ranges + template , int> = 0> explicit priority_queue(const _Alloc& _Al) noexcept(is_nothrow_constructible_v<_Container, const _Alloc&>&& is_nothrow_default_constructible_v) // strengthened @@ -296,6 +337,22 @@ public: _STD make_heap(c.begin(), c.end(), comp); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng, class _Alloc, + enable_if_t, int> = 0> + priority_queue(from_range_t, _Rng&& _Range, const _Pr& _Pred, const _Alloc& _Al) + : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range), _Al)), comp(_Pred) { + _STD make_heap(c.begin(), c.end(), comp); + } + + template <_Container_compatible_range<_Ty> _Rng, class _Alloc, + enable_if_t, int> = 0> + priority_queue(from_range_t, _Rng&& _Range, const _Alloc& _Al) + : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range), _Al)), comp() { + _STD make_heap(c.begin(), c.end(), comp); + } +#endif // __cpp_lib_containers_ranges + _NODISCARD bool empty() const noexcept(noexcept(c.empty())) /* strengthened */ { return c.empty(); } @@ -318,6 +375,19 @@ public: _STD push_heap(c.begin(), c.end(), comp); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + void push_range(_Rng&& _Range) { // per LWG-3723 + if constexpr (requires { c.append_range(_Range); }) { + c.append_range(_Range); + } else { + _RANGES copy(_Range, back_insert_iterator{c}); + } + + _STD make_heap(c.begin(), c.end(), comp); + } +#endif // __cpp_lib_containers_ranges + template void emplace(_Valty&&... _Val) { c.emplace_back(_STD forward<_Valty>(_Val)...); @@ -369,6 +439,22 @@ template , uses_allocator<_Container, _Alloc>>, int> = 0> priority_queue(_Iter, _Iter, _Compare, _Container, _Alloc) -> priority_queue; + +#ifdef __cpp_lib_containers_ranges +template <_RANGES input_range _Rng, class _Pr = less<_RANGES range_value_t<_Rng>>, + enable_if_t::value, int> = 0> +priority_queue(from_range_t, _Rng&&, _Pr = _Pr()) + -> priority_queue<_RANGES range_value_t<_Rng>, vector<_RANGES range_value_t<_Rng>>, _Pr>; + +template <_RANGES input_range _Rng, class _Pr, class _Alloc, + enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> +priority_queue(from_range_t, _Rng&&, _Pr, _Alloc) + -> priority_queue<_RANGES range_value_t<_Rng>, vector<_RANGES range_value_t<_Rng>, _Alloc>, _Pr>; + +template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +priority_queue(from_range_t, _Rng&&, _Alloc) + -> priority_queue<_RANGES range_value_t<_Rng>, vector<_RANGES range_value_t<_Rng>, _Alloc>>; +#endif // __cpp_lib_containers_ranges #endif // _HAS_CXX17 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>; + }; + // clang-format on + + template + concept _Ref_converts = convertible_to, range_value_t<_Container>>; + + template + concept _Converts_direct_constructible = _Ref_converts<_Rng, _Container> // + && constructible_from<_Container, _Rng, _Types...>; + + template + concept _Converts_tag_constructible = _Ref_converts<_Rng, _Container> + // per LWG issue unnumbered as of 2022-08-08 + && constructible_from<_Container, const from_range_t&, _Rng, _Types...>; + + template + concept _Converts_and_common_constructible = _Ref_converts<_Rng, _Container> && common_range<_Rng> // + && _Cpp17_input_iterator> // + && constructible_from<_Container, iterator_t<_Rng>, iterator_t<_Rng>, _Types...>; + + template + concept _Can_push_back = requires(_Container& _Cont) { + _Cont.push_back(_STD declval<_Reference>()); + }; + + template + concept _Can_insert_end = requires(_Container& _Cont) { + _Cont.insert(_Cont.end(), _STD declval<_Reference>()); + }; + + // clang-format off + template + concept _Converts_constructible_insertable = _Ref_converts<_Rng, _Container> + && constructible_from<_Container, _Types...> + && (_Can_push_back<_Container, range_reference_t<_Rng>> + || _Can_insert_end<_Container, range_reference_t<_Rng>>); + // clang-format on + + template + _NODISCARD constexpr auto _Container_inserter(_Container& _Cont) { + if constexpr (_Can_push_back<_Container, _Reference>) { + return back_insert_iterator{_Cont}; + } else { + return insert_iterator{_Cont, _Cont.end()}; + } + } + + // clang-format off + template + requires (!view<_Container>) + _NODISCARD constexpr _Container to(_Rng&& _Range, _Types&&... _Args) { + // clang-format on + if constexpr (_Converts_direct_constructible<_Rng, _Container, _Types...>) { + return _Container(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); + } else if constexpr (_Converts_tag_constructible<_Rng, _Container, _Types...>) { + return _Container(from_range, _STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); + } else if constexpr (_Converts_and_common_constructible<_Rng, _Container, _Types...>) { + return _Container(_RANGES begin(_Range), _RANGES end(_Range), _STD forward<_Types...>(_Args)...); + } else if constexpr (_Converts_constructible_insertable<_Rng, _Container, _Types...>) { + _Container _Cont(_STD forward<_Types>(_Args)...); + if constexpr (_Sized_and_reservable<_Rng, _Container>) { + _Cont.reserve(_RANGES size(_Range)); + } + _RANGES copy(_Range, _Container_inserter>(_Cont)); + return _Cont; + } else if constexpr (input_range>) { + const auto _Xform = [](auto&& _Elem) { + return _RANGES to>(_STD forward(_Elem)); + }; + return _RANGES to<_Container>(views::transform(_Range, _Xform), _STD forward<_Types>(_Args)...); + } else { + static_assert(_Always_false<_Container>, "the program is ill-formed per N4910 [range.utility.conv.to]/1.3"); + } + } + + template + struct _To_class_fn { + _STL_INTERNAL_STATIC_ASSERT(!view<_Container>); + + template + _NODISCARD constexpr auto operator()(_Rng&& _Range, _Types&&... _Args) const requires requires { + _RANGES to<_Container>(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); + } + { return _RANGES to<_Container>(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); } + }; + + // clang-format off + template + requires (!view<_Container>) + _NODISCARD constexpr auto to(_Types&&... _Args) { + return _Range_closure<_To_class_fn<_Container>, decay_t<_Types>...>{_STD forward<_Types>(_Args)...}; + } + // clang-format on + + 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