From a47b6d074de271f1f94024b49c80575f95d721ad Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sun, 19 Dec 2021 13:25:09 -0800 Subject: [PATCH 01/37] P1206R7 Conversions From Ranges To Containers ``: Implement `ranges::to`, guarded by `__cpp_lib_ranges_to_container`. The following are all guarded by `__cpp_lib_containers_ranges`: ``: Generalize `_Uninitialized_copy` to iterator+sentinel ranges; add `_Uninitialized_copy_n` for counted ranges. Implement `from_range_t`, `from_range`, and exposition-only helper concepts / type aliases. ``: Promote `_Get_final_iterator_unwrapped` here from ``. Add `_Copy_memmove_n` (`_Copy_n_unchecked`), similar to `_Copy_memmove` (resp. `_Copy_unchecked`) but for counted ranges. Generalize `_Iter_copy_cat` to `_Sent_copy_cat`. ``: Use `_Copy_memmove_n` (see ``) as appropriate. ``: `_HAS_CXX23` controls P1206R7, define `__cpp_lib_containers_ranges` and `__cpp_lib_ranges_to_container`. ``: Implement `from_range_t` constructor(s) and corresponding deduction guide(s), `prepend_range`, `append_range`, `assign_range`, and `insert_range`. ``: Implement `from_range_t` constructor(s) and corresponding deduction guide(s), `prepend_range`, `assign_range`, and `insert_range_after`. ``: Implement `from_range_t` constructor(s) and corresponding deduction guide(s), `prepend_range`, `append_range`, `assign_range`, and `insert_range`. `` and ``: For both `map`, `multimap`, `set`, and `multiset`, implement `from_range_t` constructor(s) and corresponding deduction guide(s). (Inherit `insert_range` from `_Tree`.) ``: For both `queue` and `priority_queue`, implement `from_range_t` constructor(s) and corresponding deduction guide(s), and `push_range`. (I've speculatively implemented `priority_queue::push_range` by calling `append_range` on the container per the resolution I've proposed for an LWG issue I submitted specifically to allow implementation via `append_range`.) ``: Implement `from_range_t` constructor(s) and corresponding deduction guide(s), and `push_range`. `` and ``: For both `unordered_map`, `unordered_multimap`, `unordered_set`, and `unordered_multiset`, implement `from_range_t` constructor(s) and corresponding deduction guide(s). (Inherit `insert_range` from `_Hash`.) ``: For both `vector` and `vector`, implement `from_range_t` constructor(s) and corresponding deduction guide(s), `append_range`, `assign_range`, and `insert_range`. ``: For both `basic_string`, implement `from_range_t` constructor(s) and corresponding deduction guide(s), `append_range`, `assign_range`, `insert_range`, and `replace_with_range`. Test both new feature-test macros in `tests/std/tests/VSO_0157762_feature_test_macros`. Test all new deduction guides in `tests/std/tests/P0433R2_deduction_guides`. Test `_Copy_n_unchecked` in `tests/std/tests/P0784R7_library_machinery`. Add new t`P1206R7_{container}_{operation}` "range algorithm"-style tests for each new container (or container adapter) member function. Add new `P1206R7_from_range` test for `from_range` and `from_range_t`. Add new `P1206R7_ranges_to` test for `ranges::to`. Fixes #2532. --- stl/inc/algorithm | 56 +- stl/inc/deque | 250 +++++-- stl/inc/forward_list | 70 +- stl/inc/list | 96 ++- stl/inc/map | 68 ++ stl/inc/memory | 8 +- stl/inc/queue | 86 +++ stl/inc/ranges | 127 ++++ stl/inc/set | 65 ++ stl/inc/stack | 34 + stl/inc/unordered_map | 153 +++++ stl/inc/unordered_set | 152 +++++ stl/inc/vector | 446 ++++++++++--- stl/inc/xhash | 26 +- stl/inc/xmemory | 84 ++- stl/inc/xstring | 160 ++++- stl/inc/xtree | 26 +- stl/inc/xutility | 132 +++- stl/inc/yvals_core.h | 5 +- tests/std/test.lst | 47 ++ .../tests/P0433R2_deduction_guides/test.cpp | 145 ++++- .../tests/P0784R7_library_machinery/test.cpp | 10 + .../tests/P1206R7_deque_append_range/env.lst | 4 + .../tests/P1206R7_deque_append_range/test.cpp | 87 +++ .../tests/P1206R7_deque_assign_range/env.lst | 4 + .../tests/P1206R7_deque_assign_range/test.cpp | 81 +++ .../tests/P1206R7_deque_from_range/env.lst | 4 + .../tests/P1206R7_deque_from_range/test.cpp | 69 ++ .../tests/P1206R7_deque_insert_range/env.lst | 4 + .../tests/P1206R7_deque_insert_range/test.cpp | 86 +++ .../tests/P1206R7_deque_prepend_range/env.lst | 4 + .../P1206R7_deque_prepend_range/test.cpp | 85 +++ .../P1206R7_forward_list_assign_range/env.lst | 4 + .../test.cpp | 80 +++ .../P1206R7_forward_list_from_range/env.lst | 4 + .../P1206R7_forward_list_from_range/test.cpp | 69 ++ .../P1206R7_forward_list_insert_range/env.lst | 4 + .../test.cpp | 86 +++ .../env.lst | 4 + .../test.cpp | 84 +++ tests/std/tests/P1206R7_from_range/env.lst | 4 + .../P1206R7_from_range/test.compile.pass.cpp | 21 + .../tests/P1206R7_list_append_range/env.lst | 4 + .../tests/P1206R7_list_append_range/test.cpp | 87 +++ .../tests/P1206R7_list_assign_range/env.lst | 4 + .../tests/P1206R7_list_assign_range/test.cpp | 81 +++ .../std/tests/P1206R7_list_from_range/env.lst | 4 + .../tests/P1206R7_list_from_range/test.cpp | 69 ++ .../tests/P1206R7_list_insert_range/env.lst | 4 + .../tests/P1206R7_list_insert_range/test.cpp | 87 +++ .../tests/P1206R7_list_prepend_range/env.lst | 4 + .../tests/P1206R7_list_prepend_range/test.cpp | 85 +++ .../std/tests/P1206R7_map_from_range/env.lst | 4 + .../std/tests/P1206R7_map_from_range/test.cpp | 82 +++ .../tests/P1206R7_map_insert_range/env.lst | 4 + .../tests/P1206R7_map_insert_range/test.cpp | 83 +++ .../tests/P1206R7_multimap_from_range/env.lst | 4 + .../P1206R7_multimap_from_range/test.cpp | 84 +++ .../P1206R7_multimap_insert_range/env.lst | 4 + .../P1206R7_multimap_insert_range/test.cpp | 83 +++ .../tests/P1206R7_multiset_from_range/env.lst | 4 + .../P1206R7_multiset_from_range/test.cpp | 82 +++ .../P1206R7_multiset_insert_range/env.lst | 4 + .../P1206R7_multiset_insert_range/test.cpp | 83 +++ .../P1206R7_priority_queue_from_range/env.lst | 4 + .../test.cpp | 85 +++ .../P1206R7_priority_queue_push_range/env.lst | 4 + .../test.cpp | 102 +++ .../tests/P1206R7_queue_from_range/env.lst | 4 + .../tests/P1206R7_queue_from_range/test.cpp | 83 +++ .../tests/P1206R7_queue_push_range/env.lst | 4 + .../tests/P1206R7_queue_push_range/test.cpp | 101 +++ tests/std/tests/P1206R7_ranges_to/env.lst | 4 + tests/std/tests/P1206R7_ranges_to/test.cpp | 616 ++++++++++++++++++ .../std/tests/P1206R7_set_from_range/env.lst | 4 + .../std/tests/P1206R7_set_from_range/test.cpp | 81 +++ .../tests/P1206R7_set_insert_range/env.lst | 4 + .../tests/P1206R7_set_insert_range/test.cpp | 82 +++ .../tests/P1206R7_stack_from_range/env.lst | 4 + .../tests/P1206R7_stack_from_range/test.cpp | 83 +++ .../tests/P1206R7_stack_push_range/env.lst | 4 + .../tests/P1206R7_stack_push_range/test.cpp | 101 +++ .../tests/P1206R7_string_append_range/env.lst | 4 + .../P1206R7_string_append_range/test.cpp | 128 ++++ .../tests/P1206R7_string_assign_range/env.lst | 4 + .../P1206R7_string_assign_range/test.cpp | 125 ++++ .../tests/P1206R7_string_from_range/env.lst | 4 + .../tests/P1206R7_string_from_range/test.cpp | 148 +++++ .../tests/P1206R7_string_insert_range/env.lst | 4 + .../P1206R7_string_insert_range/test.cpp | 130 ++++ .../P1206R7_string_replace_with_range/env.lst | 4 + .../test.cpp | 144 ++++ .../P1206R7_unordered_map_from_range/env.lst | 4 + .../P1206R7_unordered_map_from_range/test.cpp | 83 +++ .../env.lst | 4 + .../test.cpp | 84 +++ .../env.lst | 4 + .../test.cpp | 85 +++ .../env.lst | 4 + .../test.cpp | 86 +++ .../env.lst | 4 + .../test.cpp | 83 +++ .../env.lst | 4 + .../test.cpp | 84 +++ .../P1206R7_unordered_set_from_range/env.lst | 4 + .../P1206R7_unordered_set_from_range/test.cpp | 83 +++ .../env.lst | 4 + .../test.cpp | 84 +++ .../tests/P1206R7_vector_append_range/env.lst | 4 + .../P1206R7_vector_append_range/test.cpp | 162 +++++ .../tests/P1206R7_vector_assign_range/env.lst | 4 + .../P1206R7_vector_assign_range/test.cpp | 168 +++++ .../tests/P1206R7_vector_from_range/env.lst | 4 + .../tests/P1206R7_vector_from_range/test.cpp | 146 +++++ .../tests/P1206R7_vector_insert_range/env.lst | 4 + .../P1206R7_vector_insert_range/test.cpp | 166 +++++ .../test.compile.pass.cpp | 28 + 117 files changed, 7203 insertions(+), 236 deletions(-) create mode 100644 tests/std/tests/P1206R7_deque_append_range/env.lst create mode 100644 tests/std/tests/P1206R7_deque_append_range/test.cpp create mode 100644 tests/std/tests/P1206R7_deque_assign_range/env.lst create mode 100644 tests/std/tests/P1206R7_deque_assign_range/test.cpp create mode 100644 tests/std/tests/P1206R7_deque_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_deque_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_deque_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_deque_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_deque_prepend_range/env.lst create mode 100644 tests/std/tests/P1206R7_deque_prepend_range/test.cpp create mode 100644 tests/std/tests/P1206R7_forward_list_assign_range/env.lst create mode 100644 tests/std/tests/P1206R7_forward_list_assign_range/test.cpp create mode 100644 tests/std/tests/P1206R7_forward_list_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_forward_list_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_forward_list_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_forward_list_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_forward_list_prepend_range/env.lst create mode 100644 tests/std/tests/P1206R7_forward_list_prepend_range/test.cpp create mode 100644 tests/std/tests/P1206R7_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_from_range/test.compile.pass.cpp create mode 100644 tests/std/tests/P1206R7_list_append_range/env.lst create mode 100644 tests/std/tests/P1206R7_list_append_range/test.cpp create mode 100644 tests/std/tests/P1206R7_list_assign_range/env.lst create mode 100644 tests/std/tests/P1206R7_list_assign_range/test.cpp create mode 100644 tests/std/tests/P1206R7_list_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_list_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_list_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_list_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_list_prepend_range/env.lst create mode 100644 tests/std/tests/P1206R7_list_prepend_range/test.cpp create mode 100644 tests/std/tests/P1206R7_map_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_map_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_map_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_map_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_multimap_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_multimap_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_multimap_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_multimap_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_multiset_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_multiset_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_multiset_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_multiset_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_priority_queue_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_priority_queue_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_priority_queue_push_range/env.lst create mode 100644 tests/std/tests/P1206R7_priority_queue_push_range/test.cpp create mode 100644 tests/std/tests/P1206R7_queue_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_queue_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_queue_push_range/env.lst create mode 100644 tests/std/tests/P1206R7_queue_push_range/test.cpp create mode 100644 tests/std/tests/P1206R7_ranges_to/env.lst create mode 100644 tests/std/tests/P1206R7_ranges_to/test.cpp create mode 100644 tests/std/tests/P1206R7_set_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_set_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_set_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_set_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_stack_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_stack_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_stack_push_range/env.lst create mode 100644 tests/std/tests/P1206R7_stack_push_range/test.cpp create mode 100644 tests/std/tests/P1206R7_string_append_range/env.lst create mode 100644 tests/std/tests/P1206R7_string_append_range/test.cpp create mode 100644 tests/std/tests/P1206R7_string_assign_range/env.lst create mode 100644 tests/std/tests/P1206R7_string_assign_range/test.cpp create mode 100644 tests/std/tests/P1206R7_string_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_string_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_string_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_string_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_string_replace_with_range/env.lst create mode 100644 tests/std/tests/P1206R7_string_replace_with_range/test.cpp create mode 100644 tests/std/tests/P1206R7_unordered_map_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_unordered_map_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_unordered_map_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_unordered_map_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_unordered_multimap_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_unordered_multimap_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_unordered_multimap_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_unordered_multimap_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_unordered_multiset_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_unordered_multiset_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_unordered_multiset_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_unordered_multiset_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_unordered_set_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_unordered_set_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_unordered_set_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_unordered_set_insert_range/test.cpp create mode 100644 tests/std/tests/P1206R7_vector_append_range/env.lst create mode 100644 tests/std/tests/P1206R7_vector_append_range/test.cpp create mode 100644 tests/std/tests/P1206R7_vector_assign_range/env.lst create mode 100644 tests/std/tests/P1206R7_vector_assign_range/test.cpp create mode 100644 tests/std/tests/P1206R7_vector_from_range/env.lst create mode 100644 tests/std/tests/P1206R7_vector_from_range/test.cpp create mode 100644 tests/std/tests/P1206R7_vector_insert_range/env.lst create mode 100644 tests/std/tests/P1206R7_vector_insert_range/test.cpp diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 1c087211a7..41b1ffea98 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 @@ -1377,9 +1327,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..c2888863e8 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,66 @@ 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(); + _TRY_BEGIN + if constexpr (_RANGES bidirectional_range<_Rng>) { + auto _ULast = _RANGES _Get_final_iterator_unwrapped(_Range); + const auto _UFirst = _RANGES _Ubegin(_Range); + while (_UFirst != _ULast) { + _Emplace_front_internal(*--_ULast); + } + } else { + auto _UFirst = _RANGES _Ubegin(_Range); + const auto _ULast = _RANGES _Uend(_Range); + for (; _UFirst != _ULast; ++_UFirst) { + _Emplace_front_internal(*_UFirst); // prepend flipped + } + } + _CATCH_ALL + while (_Oldsize < _Mysize()) { + pop_front(); // restore old size, at least + } + _RERAISE; + _CATCH_END + + if constexpr (!_RANGES bidirectional_range<_Rng>) { + const auto _Num = static_cast(_Mysize() - _Oldsize); + _STD reverse(begin(), begin() + _Num); // flip new stuff in place + } + } +#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); + _TRY_BEGIN + for (; _UFirst != _ULast; ++_UFirst) { + _Emplace_back_internal(*_UFirst); + } + _CATCH_ALL + while (_Oldsize < _Mysize()) { + pop_back(); // restore old size, at least + } + _RERAISE; + _CATCH_END + } +#endif // __cpp_lib_containers_ranges + iterator insert(const_iterator _Where, _Ty&& _Val) { return emplace(_Where, _STD move(_Val)); } @@ -784,23 +857,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 +1022,9 @@ public: } void resize(_CRT_GUARDOVERFLOW size_type _Newsize) { + _Orphan_all(); while (_Mysize() < _Newsize) { - emplace_back(); + _Emplace_back_internal(); } while (_Mysize() > _Newsize) { @@ -1115,6 +1173,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; + 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 +1222,48 @@ 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); + for (;;) { // try to assign over an element in the container + if (_First == _Last) { + _Erase_last_n(static_cast(_Mylast - _Myfirst)); return; } - *_Myfirst = *_UFirst; + if (_Myfirst == _Mylast) { + break; + } + + *_Myfirst = *_First; ++_Myfirst; + ++_First; } - _Erase_last_n(static_cast(_Mylast - _Myfirst)); + // container wasn't big enough, insert what's left at end + do { + _Emplace_back_internal(*_First); + ++_First; + } while (_First != _Last); } +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(); @@ -1247,24 +1342,26 @@ public: #endif // _ITERATOR_DEBUG_LEVEL == 2 _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); + auto _UFirst = _Get_unwrapped(_First); + auto _ULast = _Get_unwrapped(_Last); size_type _Oldsize = _Mysize(); if (_UFirst != _ULast) { + _Orphan_all(); 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 + _Emplace_front_internal(*_UFirst); // prepend flipped } _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)); + const auto _Num = static_cast(_Mysize() - _Oldsize); + if (!_Is_bidi_iter_v<_Iter>) { + _STD reverse(begin(), begin() + _Num); // flip new stuff in place + } + _STD rotate(begin(), begin() + _Num, begin() + _Num + static_cast(_Off)); } else { // closer to back _Orphan_all(); _Restore_old_size_guard<_Pop_direction::_Back> _Guard{this, _Oldsize}; @@ -1282,6 +1379,71 @@ public: return begin() + static_cast(_Off); } +#ifdef __cpp_lib_containers_ranges + template <_Container_compatible_range<_Ty> _Rng> + iterator insert_range(const_iterator _Where, _Rng&& _Range) { + size_type _Off = static_cast(_Where - begin()); + +#if _ITERATOR_DEBUG_LEVEL == 2 + _STL_VERIFY(_Mysize() >= _Off, "deque insert iterator outside range"); +#endif // _ITERATOR_DEBUG_LEVEL == 2 + + size_type _Oldsize = _Mysize(); + + auto _UFirst = _RANGES _Ubegin(_Range); + auto _ULast = [&] { + if constexpr (_RANGES bidirectional_range<_Rng>) { + return _RANGES _Get_final_iterator_unwrapped(_Range); + } else { + return _RANGES _Uend(_Range); + } + }(); + if (_UFirst != _ULast) { + _Orphan_all(); + if (_Off <= _Mysize() / 2) { // closer to front, push to front then rotate + _TRY_BEGIN + if constexpr (_RANGES bidirectional_range<_Rng>) { + while (_UFirst != _ULast) { + _Emplace_front_internal(*--_ULast); + } + } else { + for (; _UFirst != _ULast; ++_UFirst) { + _Emplace_front_internal(*_UFirst); // prepend flipped + } + } + _CATCH_ALL + while (_Oldsize < _Mysize()) { + pop_front(); // restore old size, at least + } + _RERAISE; + _CATCH_END + + const auto _Num = static_cast(_Mysize() - _Oldsize); + if constexpr (!_RANGES bidirectional_range<_Rng>) { + _STD reverse(begin(), begin() + _Num); // flip new stuff in place + } + _STD rotate(begin(), begin() + _Num, begin() + _Num + static_cast(_Off)); + } else { // closer to back + _TRY_BEGIN + for (; _UFirst != _ULast; ++_UFirst) { + _Emplace_back_internal(*_UFirst); + } + _CATCH_ALL + while (_Oldsize < _Mysize()) { + pop_back(); // restore old size, at least + } + _RERAISE; + _CATCH_END + + _STD rotate(begin() + static_cast(_Off), + begin() + static_cast(_Oldsize), end()); + } + } + + return begin() + static_cast(_Off); + } +#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 +1739,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 e334451202..ce143ad6ee 100644 --- a/stl/inc/forward_list +++ b/stl/inc/forward_list @@ -463,7 +463,7 @@ struct _Flist_insert_after_op2 { ++_First; // throws } - while (_First != _Last) { // throws + while (_First != _Last) { _Newnode._Allocate(); // throws _Alnode_traits::construct(_Al, _STD addressof(_Newnode._Ptr->_Myval), *_First); // throws const auto _Newtail = _Newnode._Release(); @@ -606,6 +606,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(); @@ -898,19 +916,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(before_begin(), _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; } @@ -920,7 +945,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 @@ -936,6 +961,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); @@ -985,6 +1017,26 @@ public: 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_after location incompatible"); +#endif // _ITERATOR_DEBUG_LEVEL == 2 + + auto _UFirst = _RANGES _Ubegin(_Range); + const auto _ULast = _RANGES _Uend(_Range); + if (_UFirst == _ULast) { + return _Make_iter(_Where._Ptr); + } + + _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); + _Insert_op._Append_range_unchecked(_STD move(_UFirst), _ULast); + return _Make_iter(_Insert_op._Attach_after(_Where._Ptr)); + } +#endif // __cpp_lib_containers_ranges + private: void _Erase_after(_Nodeptr _Pnode) noexcept { // erase element after _Pnode auto _Subject = _Pnode->_Next; @@ -1507,6 +1559,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 e5d0956d72..3019a625f2 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -848,12 +848,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(); } @@ -880,6 +880,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); @@ -1022,8 +1034,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()); } @@ -1223,6 +1234,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"); @@ -1235,6 +1255,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"); @@ -1270,12 +1299,45 @@ 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)); + _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; @@ -1307,8 +1369,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 @@ -1328,6 +1390,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 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 @@ -1783,6 +1857,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 72140847c5..f3a6f925ae 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..81ee00bf4b 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) { // LWG issue submitted but unnumbered as of 2022-06-20 + 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 _Container& _CCont, const range_size_t<_Container> _Count) { + _Cont.reserve(_Count); + { _CCont.capacity() } -> same_as>; + { _CCont.max_size() } -> same_as>; + }; + + template + concept _Common_constructible = common_range<_Rng> && _Cpp17_input_iterator> + && constructible_from<_Container, iterator_t<_Rng>, iterator_t<_Rng>, _Types...>; + + template + concept _Constructible_and_insertable = constructible_from<_Container, _Types...> + && requires(_Container& _Cont) { + requires ( + requires { _Cont.push_back(_STD declval>()); } + || requires { _Cont.insert(_Cont.end(), _STD declval>()); }); + }; + + template + _NODISCARD constexpr auto _Container_inserter(_Container& _Cont) { + if constexpr (requires { _Cont.push_back(_STD declval<_Reference>()); }) { + return back_insert_iterator{_Cont}; + } else { + return insert_iterator{_Cont, _Cont.end()}; + } + } + + template + requires (!view<_Container>) + _NODISCARD constexpr _Container to(_Rng&& _Range, _Types&&... _Args) { + // clang-format on + constexpr bool _Ref_converts = convertible_to, range_value_t<_Container>>; + if constexpr (_Ref_converts && constructible_from<_Container, _Rng, _Types...>) { + return _Container(_STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); + } else if constexpr (_Ref_converts && constructible_from<_Container, from_range_t, _Rng, _Types...>) { + return _Container(from_range, _STD forward<_Rng>(_Range), _STD forward<_Types>(_Args)...); + } else if constexpr (_Ref_converts && _Common_constructible<_Rng, _Container, _Types...>) { + return _Container(_RANGES begin(_Range), _RANGES end(_Range), _STD forward<_Types...>(_Args)...); + } else if constexpr (_Ref_converts && _Constructible_and_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