diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index ff6c3ad1651..04e942926d7 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -111,6 +111,7 @@ add_benchmark(filesystem src/filesystem.cpp) add_benchmark(fill src/fill.cpp) add_benchmark(find_and_count src/find_and_count.cpp) add_benchmark(find_first_of src/find_first_of.cpp) +add_benchmark(flat_meow_assign src/flat_meow_assign.cpp) add_benchmark(has_single_bit src/has_single_bit.cpp) add_benchmark(includes src/includes.cpp) add_benchmark(integer_to_string src/integer_to_string.cpp) diff --git a/benchmarks/src/flat_meow_assign.cpp b/benchmarks/src/flat_meow_assign.cpp new file mode 100644 index 00000000000..980da7521ed --- /dev/null +++ b/benchmarks/src/flat_meow_assign.cpp @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; + +void flat_map_strings_impl(benchmark::State& state, initializer_list> il) { + flat_map pieces; + for (auto _ : state) { + pieces = il; + benchmark::DoNotOptimize(pieces); + } +} + +void flat_map_strings(benchmark::State& state) { + flat_map_strings_impl( + state, {{"soldier"s, 1}, {"soldier"s, 2}, {"soldier"s, 3}, {"soldier"s, 4}, {"soldier"s, 5}, {"soldier"s, 6}, + {"soldier"s, 7}, {"soldier"s, 8}, {"tower"s, 9}, {"horse"s, 10}, {"elephant"s, 11}, {"vizier"s, 12}, + {"king"s, 13}, {"elephant"s, 14}, {"horse"s, 15}, {"tower"s, 16}}); +} + +void flat_set_strings_impl(benchmark::State& state, initializer_list il) { + flat_set pieces; + for (auto _ : state) { + pieces = il; + benchmark::DoNotOptimize(pieces); + } +} + +void flat_set_strings(benchmark::State& state) { + flat_set_strings_impl( + state, {"soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, + "tower"s, "horse"s, "elephant"s, "vizier"s, "king"s, "elephant"s, "horse"s, "tower"s}); +} + +void flat_map_integers(benchmark::State& state) { + flat_map pieces; + for (auto _ : state) { + pieces = {{'s', 1}, {'s', 2}, {'s', 3}, {'s', 4}, {'s', 5}, {'s', 6}, {'s', 7}, {'s', 8}, {'T', 9}, {'H', 10}, + {'E', 11}, {'V', 12}, {'K', 13}, {'E', 14}, {'H', 15}, {'T', 16}}; + benchmark::DoNotOptimize(pieces); + } +} + +void flat_set_integers(benchmark::State& state) { + flat_set pieces; + for (auto _ : state) { + pieces = {'s', 's', 's', 's', 's', 's', 's', 's', 'T', 'H', 'E', 'V', 'K', 'E', 'H', 'T'}; + benchmark::DoNotOptimize(pieces); + } +} + +BENCHMARK(flat_map_strings); +BENCHMARK(flat_set_strings); +BENCHMARK(flat_map_integers); +BENCHMARK(flat_set_integers); + +BENCHMARK_MAIN(); diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index f15d7ecbbfb..a6428797c01 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -76,6 +76,8 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/generator ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/resumable ${CMAKE_CURRENT_LIST_DIR}/inc/filesystem + ${CMAKE_CURRENT_LIST_DIR}/inc/flat_map + ${CMAKE_CURRENT_LIST_DIR}/inc/flat_set ${CMAKE_CURRENT_LIST_DIR}/inc/format ${CMAKE_CURRENT_LIST_DIR}/inc/forward_list ${CMAKE_CURRENT_LIST_DIR}/inc/fstream diff --git a/stl/debugger/STL.natvis b/stl/debugger/STL.natvis index c9cf67abb1f..48c6326a0ea 100644 --- a/stl/debugger/STL.natvis +++ b/stl/debugger/STL.natvis @@ -1035,13 +1035,13 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - - {{ size={_Mypair._Myval2._Mysize} }} + + {{ size={size()} }} _Mypair - _Mypair._Myval2._Mysize + size() _Mypair._Myval2._Map[(($i + _Mypair._Myval2._Myoff) / _EEN_DS) % _Mypair._Myval2._Mapsize][($i + _Mypair._Myval2._Myoff) % _EEN_DS] @@ -2298,4 +2298,60 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + + + + + + + + + + + + {{ size={size()} }} + + + size() + _Key_compare + + + size() + + *value_at(i) + ++i + + + + + + + + + + {{ size={size()} }} + + _Key_compare + _Data.keys + _Data.values + + + + + ({_Key_it}, {_Mapped_it}) + + _Key_it + _Mapped_it + + + + + + {_Data} + + _Key_compare + _Data + + + diff --git a/stl/inc/__msvc_all_public_headers.hpp b/stl/inc/__msvc_all_public_headers.hpp index 106967a54f6..da0e1103797 100644 --- a/stl/inc/__msvc_all_public_headers.hpp +++ b/stl/inc/__msvc_all_public_headers.hpp @@ -83,6 +83,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 587f09a142c..303653318e3 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -2148,6 +2148,12 @@ inline namespace literals { } // namespace string_view_literals } // namespace literals #endif // _HAS_CXX17 + +#if _HAS_CXX23 +template +constexpr bool _Equivalence_is_equality_impl> = + _Is_implementation_handled_char_traits<_Traits>; +#endif // _HAS_CXX23 _STD_END #pragma pop_macro("new") diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 4920137874e..bf330855b06 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -8564,14 +8564,13 @@ void inplace_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Pr _Pred) { ++_ULast; - using _Diff = _Iter_diff_t<_BidIt>; - const _Diff _Count1 = _STD distance(_UFirst, _UMid); + const auto _Count1 = _STD distance(_UFirst, _UMid); if (_Count1 == 1) { // rotate only element remaining in left partition to the end, without allocating _STD _Rotate_one_left(_UFirst, _UMid, _ULast); return; } - const _Diff _Count2 = _STD distance(_UMid, _ULast); + const auto _Count2 = _STD distance(_UMid, _ULast); _Optimistic_temporary_buffer2<_Iter_value_t<_BidIt>> _Temp_buf{(_STD min) (_Count1, _Count2)}; _STD _Buffered_inplace_merge_unchecked_impl( _UFirst, _UMid, _ULast, _Count1, _Count2, _Temp_buf._Data, _Temp_buf._Capacity, _STD _Pass_fn(_Pred)); diff --git a/stl/inc/deque b/stl/inc/deque index 33fd9e6d815..82551c1b627 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -1848,6 +1848,14 @@ namespace pmr { using deque = _STD deque<_Ty, polymorphic_allocator<_Ty>>; } // namespace pmr #endif // _HAS_CXX17 + +#if _HAS_CXX23 +template +constexpr bool _Has_guaranteed_push_back> = true; + +template +constexpr bool _Has_guaranteed_append_range> = true; +#endif // _HAS_CXX23 _STD_END #pragma pop_macro("new") diff --git a/stl/inc/flat_map b/stl/inc/flat_map new file mode 100644 index 00000000000..79581d333b3 --- /dev/null +++ b/stl/inc/flat_map @@ -0,0 +1,1613 @@ +// flat_map standard header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef _FLAT_MAP_ +#define _FLAT_MAP_ +#include +#if _STL_COMPILER_PREPROCESSOR +#if !_HAS_CXX23 +_EMIT_STL_WARNING(STL4038, "The contents of are available only with C++23 or later."); +#else // ^^^ !_HAS_CXX23 / _HAS_CXX23 vvv + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + +// TRANSITION, non-_Ugly attribute tokens +#pragma push_macro("msvc") +#undef msvc + +_STD_BEGIN +template +class _Flat_map_base; + +template +struct _Pairing_iterator_provider; + +template +concept _Can_unwrap_pairing_iterator = + !conjunction_v, _KeyIter>, is_same<_Unwrapped_t<_MappedIter>, _MappedIter>>; + +template +struct _Pairing_iterator_provider { + class _Iterator { + public: + using iterator_category = input_iterator_tag; + using iterator_concept = random_access_iterator_tag; + using difference_type = ptrdiff_t; + using value_type = pair, iter_value_t<_MappedIter>>; + using reference = pair, iter_reference_t<_MappedIter>>; + + _Iterator() = default; + + private: + template + friend class _Flat_map_base; + template + friend struct _Pairing_iterator_provider; + + explicit _Iterator(_KeyIter _Key_iter, _MappedIter _Mapped_iter) + noexcept(is_nothrow_move_constructible_v<_KeyIter> && is_nothrow_move_constructible_v<_MappedIter>) + : _Key_it(_STD move(_Key_iter)), _Mapped_it(_STD move(_Mapped_iter)) {} + + using _Const_iterator = _Pairing_iterator_provider<_KeyIter, _MappedConvIter, _MappedConvIter>::_Iterator; + using _Unwrapped_iterator = _Pairing_iterator_provider<_Unwrapped_t<_KeyIter>, _Unwrapped_t<_MappedIter>, + _Unwrapped_t<_MappedConvIter>>::_Iterator; + + class _Arrow_proxy { + public: + _NODISCARD const reference* operator->() const noexcept { + return _STD addressof(_Ref); + } + + private: + friend _Iterator; + + explicit _Arrow_proxy(const _Iterator& _Iter) : _Ref{*_Iter} {} + + reference _Ref; + }; + + public: + using pointer = _Arrow_proxy; + + _NODISCARD reference operator*() const { + return reference{*_Key_it, *_Mapped_it}; + } + + _NODISCARD friend pair, iter_rvalue_reference_t<_MappedIter>> iter_move( + const _Iterator& _It) { + return {_RANGES iter_move(_It._Key_it), _RANGES iter_move(_It._Mapped_it)}; + } + + _NODISCARD pointer operator->() const { + return pointer{*this}; + } + + _Iterator& operator++() { + ++_Key_it; + ++_Mapped_it; + return *this; + } + + _Iterator operator++(int) { + auto _Old = *this; + ++*this; + return _Old; + } + + _NODISCARD bool operator==(const _Iterator& _Right) const { + _Compat(_Right); + return _Key_it == _Right._Key_it; + } + + _NODISCARD auto operator<=>(const _Iterator& _Right) const { + _Compat(_Right); + return _Synth_three_way{}(_Key_it, _Right._Key_it); + } + + _Iterator& operator--() { + --_Key_it; + --_Mapped_it; + return *this; + } + + _Iterator operator--(int) { + auto _Old = *this; + --*this; + return _Old; + } + + _Iterator& operator+=(const difference_type _Off) { + _Key_it += static_cast>(_Off); + _Mapped_it += static_cast>(_Off); + return *this; + } + + _Iterator& operator-=(const difference_type _Off) { + _Key_it -= static_cast>(_Off); + _Mapped_it -= static_cast>(_Off); + return *this; + } + + _NODISCARD _Iterator operator+(const difference_type _Off) const { + auto _Tmp = *this; + _Tmp += _Off; + return _Tmp; + } + + _NODISCARD _Iterator operator-(const difference_type _Off) const { + auto _Tmp = *this; + _Tmp -= _Off; + return _Tmp; + } + + _NODISCARD reference operator[](const difference_type _Off) const { + return *(*this + _Off); + } + + _NODISCARD difference_type operator-(const _Iterator& _Right) const { + _Compat(_Right); + return _Key_it - _Right._Key_it; + } + + _NODISCARD friend _Iterator operator+(const difference_type _Off, const _Iterator& _Right) { + return _Right + _Off; + } + + _NODISCARD operator _Const_iterator() const + requires (!is_same_v<_MappedIter, _MappedConvIter>) + { + return _Const_iterator{_Key_it, _Mapped_it}; + } + + void _Compat([[maybe_unused]] const _Iterator& _Right) const noexcept { // test for compatible iterator pair +#if _ITERATOR_DEBUG_LEVEL != 0 + _STL_VERIFY( + _Key_it - _Right._Key_it == _Mapped_it - _Right._Mapped_it, "iterators from inconsistent ranges"); +#endif // _ITERATOR_DEBUG_LEVEL != 0 + } + + using _Prevent_inheriting_unwrap = _Iterator; + +#if _ITERATOR_DEBUG_LEVEL != 0 + friend void _Verify_range(const _Iterator& _First, const _Iterator& _Last) noexcept { + if constexpr (_Range_verifiable_v<_KeyIter>) { + _Verify_range(_First._Key_it, _Last._Key_it); // intentional ADL + } + + if constexpr (_Range_verifiable_v<_MappedIter>) { + _Verify_range(_First._Mapped_it, _Last._Mapped_it); // intentional ADL + } + + _First._Compat(_Last); + } +#endif // _ITERATOR_DEBUG_LEVEL != 0 + + void _Verify_offset(const difference_type _Off) const noexcept { + if constexpr (_Offset_verifiable_v<_KeyIter>) { + _Key_it._Verify_offset(_Off); + } + + if constexpr (_Offset_verifiable_v<_MappedIter>) { + _Mapped_it._Verify_offset(_Off); + } + } + + _NODISCARD auto _Unwrapped() const + requires _Can_unwrap_pairing_iterator<_KeyIter, _MappedIter, _MappedConvIter> + { + return _Unwrapped_iterator{_STD _Get_unwrapped(_Key_it), _STD _Get_unwrapped(_Mapped_it)}; + } + + static constexpr bool _Unwrap_when_unverified = _Do_unwrap_when_unverified_v<_KeyIter> + && _Do_unwrap_when_unverified_v<_MappedIter> + && _Do_unwrap_when_unverified_v<_MappedConvIter>; + + void _Seek_to(const _Unwrapped_iterator& _Dst) + requires _Can_unwrap_pairing_iterator<_KeyIter, _MappedIter, _MappedConvIter> + { + _STD _Seek_wrapped(_Key_it, _Dst._Key_it); + _STD _Seek_wrapped(_Mapped_it, _Dst._Mapped_it); + } + +#ifdef _ENABLE_STL_INTERNAL_CHECK + public: +#else + private: +#endif + _KeyIter _Key_it; + _MappedIter _Mapped_it; + }; +}; + +template +struct _NODISCARD _Flat_map_swap_clear_guard { + // Invariant: (_Target1 == nullptr) == (_Target2 == nullptr) + _Containers* _Target1; + _Containers* _Target2; + + _Flat_map_swap_clear_guard& operator=(const _Flat_map_swap_clear_guard&) = delete; + + void _Dismiss() noexcept { + _Target1 = nullptr; + _Target2 = nullptr; + } + + ~_Flat_map_swap_clear_guard() { + if (_Target1) { + _Target1->keys.clear(); + _Target1->values.clear(); + _Target2->keys.clear(); + _Target2->values.clear(); + } + } +}; +template +struct _NODISCARD _Flat_map_swap_clear_guard { + constexpr explicit _Flat_map_swap_clear_guard(_Containers*, _Containers*) noexcept {} + + _Flat_map_swap_clear_guard& operator=(const _Flat_map_swap_clear_guard&) = delete; + + void _Dismiss() noexcept {} +}; + +_EXPORT_STD template , class _KeyContainer = vector<_Key>, + class _MappedContainer = vector<_Mapped>> +class flat_map; + +_EXPORT_STD template , class _KeyContainer = vector<_Key>, + class _MappedContainer = vector<_Mapped>> +class flat_multimap; + +template +class _Flat_map_base { +private: + using _Sorted_t = conditional_t<_IsUnique, sorted_unique_t, sorted_equivalent_t>; + using _Derived = conditional_t<_IsUnique, flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>, + flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>>; + + static constexpr const char* _Msg_not_sorted_maybe_unique = + _IsUnique ? "Keys were not sorted-unique! (N5032 [flat.map.overview]/10)" + : "Keys were not sorted! (N5032 [flat.multimap.overview]/10)"; + static constexpr const char* _Msg_replace_not_sorted_maybe_unique = + _IsUnique ? "Keys were not sorted-unique! (N5032 [flat.map.modifiers]/37)" + : "Keys were not sorted! (N5032 [flat.map.modifiers]/37, [flat.multimap.overview]/4)"; + static constexpr const char* _Msg_different_sizes = + _IsUnique ? "Containers were different sizes! (N5032 [flat.map.overview]/9)" + : "Containers were different sizes! (N5032 [flat.multimap.overview]/9)"; + static constexpr const char* _Msg_replace_different_sizes = + _IsUnique ? "Containers were different sizes! (N5032 [flat.map.modifiers]/37)" + : "Containers were different sizes! (N5032 [flat.map.modifiers]/37, [flat.multimap.overview]/4)"; + +public: + // [flat.map.defn] Types + using key_type = _Key; + using mapped_type = _Mapped; + using value_type = pair; + using key_compare = _Compare; + using reference = pair; + using const_reference = pair; + using size_type = size_t; + using difference_type = ptrdiff_t; + using key_container_type = _KeyContainer; + using mapped_container_type = _MappedContainer; + + using iterator = _Pairing_iterator_provider::_Iterator; + + using const_iterator = _Pairing_iterator_provider::_Iterator; + + using reverse_iterator = _STD reverse_iterator; + using const_reverse_iterator = _STD reverse_iterator; + + static_assert(is_same_v, + "key_type and key_container_type::value_type must be the same. " + "(N5032 [flat.map.overview]/8, [flat.multimap.overview]/8)"); + static_assert(is_same_v, + "mapped_type and mapped_container_type::value_type must be the same. " + "(N5032 [flat.map.overview]/8, [flat.multimap.overview]/8)"); + static_assert(!_Is_vector_bool, + "key_container_type cannot be vector because it is not a sequence container. " + "(N5032 [flat.map.overview]/7, [flat.multimap.overview]/7)"); + static_assert(!_Is_vector_bool, + "mapped_container_type cannot be vector because it is not a sequence container. " + "(N5032 [flat.map.overview]/7, [flat.multimap.overview]/7)"); + static_assert(random_access_iterator, + "key_container_type must support random-access iterators in order to be adapted. " + "(N5032 [flat.map.overview]/7, [flat.multimap.overview]/7)"); + static_assert(random_access_iterator, + "mapped_container_type must support random-access iterators in order to be adapted. " + "(N5032 [flat.map.overview]/7, [flat.multimap.overview]/7)"); + + class value_compare { + public: + _NODISCARD bool operator()(const_reference _Lhs, const_reference _Rhs) const { + return _Key_comparator(_Lhs.first, _Rhs.first); + } + + private: + friend _Flat_map_base; + + explicit value_compare(const key_compare& _Comp) : _Key_comparator(_Comp) {} + + key_compare _Key_comparator; + }; + + struct containers { + key_container_type keys; + mapped_container_type values; + }; + + // [flat.map.cons] Constructors + _Flat_map_base() : _Data(), _Key_compare() {} + + _Flat_map_base(const _Flat_map_base&) = default; + + _Flat_map_base(_Flat_map_base&& _Other) noexcept(is_nothrow_move_constructible_v + && is_nothrow_move_constructible_v + && is_nothrow_copy_constructible_v) // strengthened + : _Data(_STD move(_Other).extract()), + _Key_compare(_Other._Key_compare) // intentionally copy comparator, see LWG-2227 + {} + + explicit _Flat_map_base(const key_compare& _Comp) : _Data(), _Key_compare(_Comp) {} + + _Flat_map_base( + key_container_type _Key_cont, mapped_container_type _Mapped_cont, const key_compare& _Comp = key_compare()) + : _Data{.keys = _STD move(_Key_cont), .values = _STD move(_Mapped_cont)}, _Key_compare(_Comp) { + _STL_ASSERT(_Data.keys.size() == _Data.values.size(), _Msg_different_sizes); + _Establish_invariants(); + } + + _Flat_map_base(_Sorted_t, key_container_type _Key_cont, mapped_container_type _Mapped_cont, + const key_compare& _Comp = key_compare()) + : _Data{.keys = _STD move(_Key_cont), .values = _STD move(_Mapped_cont)}, _Key_compare(_Comp) { + _STL_ASSERT(_Data.keys.size() == _Data.values.size(), _Msg_different_sizes); + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + template <_Iterator_for_container _InIt> + _Flat_map_base(const _InIt _First, const _InIt _Last, const key_compare& _Comp = key_compare()) + : _Data(), _Key_compare(_Comp) { + insert(_First, _Last); + } + + template <_Iterator_for_container _InIt> + _Flat_map_base(_Sorted_t _Tag, const _InIt _First, const _InIt _Last, const key_compare& _Comp = key_compare()) + : _Data(), _Key_compare(_Comp) { + insert(_Tag, _First, _Last); + } + + template <_Container_compatible_range _Rng> + _Flat_map_base(from_range_t, _Rng&& _Range) : _Data(), _Key_compare() { + insert_range(_STD forward<_Rng>(_Range)); + } + + template <_Container_compatible_range _Rng> + _Flat_map_base(from_range_t, _Rng&& _Range, const key_compare& _Comp) : _Data(), _Key_compare(_Comp) { + insert_range(_STD forward<_Rng>(_Range)); + } + + _Flat_map_base(const initializer_list _Ilist, const key_compare& _Comp = key_compare()) + : _Data(), _Key_compare(_Comp) { + insert(_Ilist); + } + + _Flat_map_base(_Sorted_t _Tag, const initializer_list _Ilist, const key_compare& _Comp = key_compare()) + : _Data(), _Key_compare(_Comp) { + insert(_Tag, _Ilist); + } + + // [flat.map.cons.alloc] Constructors with allocators + template <_Usable_allocator_for _Alloc> + explicit _Flat_map_base(const _Alloc& _Al) + : _Data{.keys = _STD make_obj_using_allocator(_Al), + .values = _STD make_obj_using_allocator(_Al)}, + _Key_compare() {} + + template <_Usable_allocator_for _Alloc> + _Flat_map_base(const key_compare& _Comp, const _Alloc& _Al) + : _Data{.keys = _STD make_obj_using_allocator(_Al), + .values = _STD make_obj_using_allocator(_Al)}, + _Key_compare(_Comp) {} + + template <_Usable_allocator_for _Alloc> + _Flat_map_base(const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, const _Alloc& _Al) + : _Flat_map_base(_Key_cont, _Mapped_cont, key_compare(), _Al) {} + + template <_Usable_allocator_for _Alloc> + _Flat_map_base(const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, + const key_compare& _Comp, const _Alloc& _Al) + : _Data{.keys = _STD make_obj_using_allocator(_Al, _Key_cont), + .values = _STD make_obj_using_allocator(_Al, _Mapped_cont)}, + _Key_compare(_Comp) { + _STL_ASSERT(_Data.keys.size() == _Data.values.size(), _Msg_different_sizes); + _Establish_invariants(); + } + + template <_Usable_allocator_for _Alloc> + _Flat_map_base(_Sorted_t _Tag, const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, + const _Alloc& _Al) + : _Flat_map_base(_Tag, _Key_cont, _Mapped_cont, key_compare(), _Al) {} + + template <_Usable_allocator_for _Alloc> + _Flat_map_base(_Sorted_t, const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, + const key_compare& _Comp, const _Alloc& _Al) + : _Data{.keys = _STD make_obj_using_allocator(_Al, _Key_cont), + .values = _STD make_obj_using_allocator(_Al, _Mapped_cont)}, + _Key_compare(_Comp) { + _STL_ASSERT(_Data.keys.size() == _Data.values.size(), _Msg_different_sizes); + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + template <_Usable_allocator_for _Alloc> + _Flat_map_base(const _Flat_map_base& _Other, const _Alloc& _Al) + : _Data{.keys = _STD make_obj_using_allocator(_Al, _Other._Data.keys), + .values = _STD make_obj_using_allocator(_Al, _Other._Data.values)}, + _Key_compare(_Other._Key_compare) {} + +private: + template + _NODISCARD containers _Extract_using_allocator(const _Alloc& _Al) && { + _Clear_guard _Always_clear{this}; + return containers{.keys = _STD make_obj_using_allocator(_Al, _STD move(_Data.keys)), + .values = _STD make_obj_using_allocator(_Al, _STD move(_Data.values))}; + } + +public: + template <_Usable_allocator_for _Alloc> + _Flat_map_base(_Flat_map_base&& _Other, const _Alloc& _Al) + : _Data{_STD move(_Other)._Extract_using_allocator(_Al)}, + _Key_compare(_Other._Key_compare) // intentionally copy comparator, see LWG-2227 + {} + + template <_Iterator_for_container _InIt, _Usable_allocator_for _Alloc> + _Flat_map_base(const _InIt _First, const _InIt _Last, const _Alloc& _Al) : _Flat_map_base(_Al) { + insert(_First, _Last); + } + + template <_Iterator_for_container _InIt, _Usable_allocator_for _Alloc> + _Flat_map_base(const _InIt _First, const _InIt _Last, const key_compare& _Comp, const _Alloc& _Al) + : _Flat_map_base(_Comp, _Al) { + insert(_First, _Last); + } + + template <_Iterator_for_container _InIt, _Usable_allocator_for _Alloc> + _Flat_map_base(_Sorted_t _Tag, const _InIt _First, const _InIt _Last, const _Alloc& _Al) : _Flat_map_base(_Al) { + insert(_Tag, _First, _Last); + } + + template <_Iterator_for_container _InIt, _Usable_allocator_for _Alloc> + _Flat_map_base(_Sorted_t _Tag, const _InIt _First, const _InIt _Last, const key_compare& _Comp, const _Alloc& _Al) + : _Flat_map_base(_Comp, _Al) { + insert(_Tag, _First, _Last); + } + + template <_Container_compatible_range _Rng, + _Usable_allocator_for _Alloc> + _Flat_map_base(from_range_t, _Rng&& _Range, const _Alloc& _Al) : _Flat_map_base(_Al) { + insert_range(_STD forward<_Rng>(_Range)); + } + + template <_Container_compatible_range _Rng, + _Usable_allocator_for _Alloc> + _Flat_map_base(from_range_t, _Rng&& _Range, const key_compare& _Comp, const _Alloc& _Al) + : _Flat_map_base(_Comp, _Al) { + insert_range(_STD forward<_Rng>(_Range)); + } + + template <_Usable_allocator_for _Alloc> + _Flat_map_base(const initializer_list _Ilist, const _Alloc& _Al) : _Flat_map_base(_Al) { + insert(_Ilist); + } + + template <_Usable_allocator_for _Alloc> + _Flat_map_base(const initializer_list _Ilist, const key_compare& _Comp, const _Alloc& _Al) + : _Flat_map_base(_Comp, _Al) { + insert(_Ilist); + } + + template <_Usable_allocator_for _Alloc> + _Flat_map_base(_Sorted_t _Tag, const initializer_list _Ilist, const _Alloc& _Al) : _Flat_map_base(_Al) { + insert(_Tag, _Ilist); + } + + template <_Usable_allocator_for _Alloc> + _Flat_map_base( + _Sorted_t _Tag, const initializer_list _Ilist, const key_compare& _Comp, const _Alloc& _Al) + : _Flat_map_base(_Comp, _Al) { + insert(_Tag, _Ilist); + } + + // Assignment operators + _Flat_map_base& operator=(const _Flat_map_base& _Other) { + _Clear_guard _Guard{this}; + _Data = _Other._Data; + _Key_compare = _Other._Key_compare; + _Guard._Target = nullptr; + return *this; + } + + _Flat_map_base& operator=(_Flat_map_base&& _Other) + noexcept(is_nothrow_move_assignable_v && is_nothrow_move_assignable_v + && is_nothrow_copy_assignable_v) /* strengthened */ { + if (this != _STD addressof(_Other)) { + _Clear_guard _Guard{this}; + _Clear_guard _Always_clear{_STD addressof(_Other)}; + _Data = _STD move(_Other._Data); + _Key_compare = _Other._Key_compare; // intentionally copy comparator, see LWG-2227 + _Guard._Target = nullptr; + } + return *this; + } + + // Iterators + _NODISCARD iterator begin() noexcept { + _STL_INTERNAL_STATIC_ASSERT(random_access_iterator); + return iterator{_Data.keys.cbegin(), _Data.values.begin()}; + } + _NODISCARD const_iterator begin() const noexcept { + _STL_INTERNAL_STATIC_ASSERT(random_access_iterator); + _STL_INTERNAL_STATIC_ASSERT(convertible_to); + return const_iterator{_Data.keys.cbegin(), _Data.values.cbegin()}; + } + _NODISCARD iterator end() noexcept { + return iterator{_Data.keys.cend(), _Data.values.end()}; + } + _NODISCARD const_iterator end() const noexcept { + return const_iterator{_Data.keys.cend(), _Data.values.cend()}; + } + + _NODISCARD reverse_iterator rbegin() noexcept { + return reverse_iterator{end()}; + } + _NODISCARD const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator{end()}; + } + _NODISCARD reverse_iterator rend() noexcept { + return reverse_iterator{begin()}; + } + _NODISCARD const_reverse_iterator rend() const noexcept { + return const_reverse_iterator{begin()}; + } + + _NODISCARD const_iterator cbegin() const noexcept { + return const_iterator{_Data.keys.cbegin(), _Data.values.cbegin()}; + } + _NODISCARD const_iterator cend() const noexcept { + return const_iterator{_Data.keys.cend(), _Data.values.cend()}; + } + + _NODISCARD const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator{cend()}; + } + _NODISCARD const_reverse_iterator crend() const noexcept { + return const_reverse_iterator{cbegin()}; + } + + // [flat.map.capacity] Capacity + _NODISCARD_EMPTY_MEMBER bool empty() const noexcept { + return _Data.keys.empty(); + } + + _NODISCARD size_type size() const noexcept { + return _Data.keys.size(); + } + + _NODISCARD size_type max_size() const noexcept { + return (_STD min) (_Data.keys.max_size(), _Data.values.max_size()); + } + + // [flat.map.modifiers] Modifiers + template + auto emplace(_ArgTypes&&... _Args) + requires is_constructible_v + { + value_type _Val(_STD forward<_ArgTypes>(_Args)...); + return _Try_emplace(_STD move(_Val.first), _STD move(_Val.second)); + } + + template + iterator emplace_hint(const const_iterator _Position, _ArgTypes&&... _Args) + requires is_constructible_v + { + value_type _Val(_STD forward<_ArgTypes>(_Args)...); + return _Emplace_hint(_Position, _STD move(_Val.first), _STD move(_Val.second)); + } + + auto insert(const value_type& _Val) { + return _Try_emplace(_Val.first, _Val.second); + } + auto insert(value_type&& _Val) { + return _Try_emplace(_STD move(_Val.first), _STD move(_Val.second)); + } + + iterator insert(const const_iterator _Position, const value_type& _Val) { + return _Emplace_hint(_Position, _Val.first, _Val.second); + } + iterator insert(const const_iterator _Position, value_type&& _Val) { + return _Emplace_hint(_Position, _STD move(_Val.first), _STD move(_Val.second)); + } + + template + auto insert(_OtherPair&& _Val) + requires is_constructible_v + { + return emplace(_STD forward<_OtherPair>(_Val)); + } + + template + iterator insert(const const_iterator _Position, _OtherPair&& _Val) + requires is_constructible_v + { + return emplace_hint(_Position, _STD forward<_OtherPair>(_Val)); + } + + template <_Iterator_for_container _InIt> + void insert(const _InIt _First, const _InIt _Last) { + _Insert_range(_First, _Last); + } + template <_Iterator_for_container _InIt> + void insert(_Sorted_t, const _InIt _First, const _InIt _Last) { + _Insert_range(_First, _Last); + } + + template <_Container_compatible_range _Rng> + void insert_range(_Rng&& _Range) { + _Insert_range(_RANGES begin(_Range), _RANGES end(_Range)); + } + template <_Container_compatible_range _Rng> + void insert_range(_Sorted_t, _Rng&& _Range) { + _Insert_range(_RANGES begin(_Range), _RANGES end(_Range)); + } + + void insert(const initializer_list _Ilist) { + _Insert_range(_Ilist.begin(), _Ilist.end()); + } + void insert(_Sorted_t, const initializer_list _Ilist) { + _Insert_range(_Ilist.begin(), _Ilist.end()); + } + + _NODISCARD containers extract() && noexcept( + is_nothrow_move_constructible_v + && is_nothrow_move_constructible_v) /* strengthened */ { + // always clears the container (N5032 [flat.map.modifiers]/35 and [flat.multimap.overview]/4) + _Clear_guard _Always_clear{this}; + return _STD move(_Data); + } + + void replace(key_container_type&& _Key_cont, mapped_container_type&& _Mapped_cont) { + _STL_ASSERT(_Key_cont.size() == _Mapped_cont.size(), _Msg_replace_different_sizes); + _STL_ASSERT(_Is_sorted_maybe_unique(_Key_cont.begin(), _Key_cont.end()), _Msg_replace_not_sorted_maybe_unique); + _Clear_guard _Guard{this}; + _Data.keys = _STD move(_Key_cont); + _Data.values = _STD move(_Mapped_cont); + _Guard._Target = nullptr; + } + + iterator erase(const iterator _Position) { + return erase(static_cast(_Position)); + } + + iterator erase(const const_iterator _Position) { + _Clear_guard _Guard{this}; + auto _Key_it = _Data.keys.erase(_Position._Key_it); + auto _Val_it = _Data.values.erase(_Position._Mapped_it); + _Guard._Target = nullptr; + return iterator{_STD move(_Key_it), _STD move(_Val_it)}; + } + + size_type erase(const key_type& _Key_val) { + return _Erase_key(_Key_val); + } + + template + requires _Transparent && (!is_convertible_v<_OtherKey, iterator>) + && (!is_convertible_v<_OtherKey, const_iterator>) + size_type erase(_OtherKey&& _Key_val) { + return _Erase_key(_STD forward<_OtherKey>(_Key_val)); + } + + iterator erase(const const_iterator _First, const const_iterator _Last) { + _Clear_guard _Guard{this}; + auto _Key_it = _Data.keys.erase(_First._Key_it, _Last._Key_it); + auto _Val_it = _Data.values.erase(_First._Mapped_it, _Last._Mapped_it); + _Guard._Target = nullptr; + return iterator{_STD move(_Key_it), _STD move(_Val_it)}; + } + + void swap(_Derived& _Other) + noexcept(is_nothrow_swappable_v && is_nothrow_swappable_v + && is_nothrow_swappable_v) { + constexpr bool _Is_noexcept = is_nothrow_swappable_v + && is_nothrow_swappable_v + && is_nothrow_swappable_v; + _Flat_map_swap_clear_guard<_Is_noexcept, containers> _Guard{ + _STD addressof(_Data), _STD addressof(_Other._Data)}; + _RANGES swap(_Data.keys, _Other._Data.keys); + _RANGES swap(_Data.values, _Other._Data.values); + _RANGES swap(_Key_compare, _Other._Key_compare); + _Guard._Dismiss(); + } + + void clear() noexcept { + _Data.keys.clear(); + _Data.values.clear(); + } + + // Observers + _NODISCARD key_compare key_comp() const { + return _Key_compare; + } + + _NODISCARD value_compare value_comp() const { + return value_compare{_Key_compare}; + } + + _NODISCARD const key_container_type& keys() const noexcept { + return _Data.keys; + } + + _NODISCARD const mapped_container_type& values() const noexcept { + return _Data.values; + } + + // map operations + _NODISCARD iterator find(const key_type& _Key_val) { + return _Find(_Key_val); + } + _NODISCARD const_iterator find(const key_type& _Key_val) const { + return _Find(_Key_val); + } + template + _NODISCARD iterator find(const _OtherKey& _Key_val) + requires _Transparent + { + return _Find(_Key_val); + } + template + _NODISCARD const_iterator find(const _OtherKey& _Key_val) const + requires _Transparent + { + return _Find(_Key_val); + } + + _NODISCARD size_type count(const key_type& _Key_val) const { + return _Count(_Key_val); + } + template + _NODISCARD size_type count(const _OtherKey& _Key_val) const + requires _Transparent + { + return _Count(_Key_val); + } + + _NODISCARD bool contains(const key_type& _Key_val) const { + return _Contains(_Key_val); + } + template + _NODISCARD bool contains(const _OtherKey& _Key_val) const + requires _Transparent + { + return _Contains(_Key_val); + } + + _NODISCARD iterator lower_bound(const key_type& _Key_val) { + return _Lower_bound(_Key_val); + } + _NODISCARD const_iterator lower_bound(const key_type& _Key_val) const { + return _Lower_bound(_Key_val); + } + template + _NODISCARD iterator lower_bound(const _OtherKey& _Key_val) + requires _Transparent + { + return _Lower_bound(_Key_val); + } + template + _NODISCARD const_iterator lower_bound(const _OtherKey& _Key_val) const + requires _Transparent + { + return _Lower_bound(_Key_val); + } + + _NODISCARD iterator upper_bound(const key_type& _Key_val) { + return _Upper_bound(_Key_val); + } + _NODISCARD const_iterator upper_bound(const key_type& _Key_val) const { + return _Upper_bound(_Key_val); + } + template + _NODISCARD iterator upper_bound(const _OtherKey& _Key_val) + requires _Transparent + { + return _Upper_bound(_Key_val); + } + template + _NODISCARD const_iterator upper_bound(const _OtherKey& _Key_val) const + requires _Transparent + { + return _Upper_bound(_Key_val); + } + + _NODISCARD pair equal_range(const key_type& _Key_val) { + return _Equal_range(_Key_val); + } + _NODISCARD pair equal_range(const key_type& _Key_val) const { + return _Equal_range(_Key_val); + } + template + _NODISCARD pair equal_range(const _OtherKey& _Key_val) + requires _Transparent + { + return _Equal_range(_Key_val); + } + template + _NODISCARD pair equal_range(const _OtherKey& _Key_val) const + requires _Transparent + { + return _Equal_range(_Key_val); + } + + _NODISCARD friend bool operator==(const _Derived& _Lhs, const _Derived& _Rhs) { + return _STD equal(_Lhs.cbegin(), _Lhs.cend(), _Rhs.cbegin(), _Rhs.cend()); + } + + _NODISCARD friend auto operator<=>(const _Derived& _Lhs, const _Derived& _Rhs) { + return _STD lexicographical_compare_three_way( + _Lhs.cbegin(), _Lhs.cend(), _Rhs.cbegin(), _Rhs.cend(), _Synth_three_way{}); + } + + friend void swap(_Derived& _Lhs, _Derived& _Rhs) noexcept(noexcept(_Lhs.swap(_Rhs))) { + _Lhs.swap(_Rhs); + } + +protected: + template + _NODISCARD conditional_t<_IsUnique, pair, iterator> _Try_emplace( + _OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) { + _STL_INTERNAL_STATIC_ASSERT(is_constructible_v); + _STL_INTERNAL_STATIC_ASSERT(is_same_v, key_type> + || (is_constructible_v && _Transparent) ); + + const auto _Key_it = _STD upper_bound(_Data.keys.begin(), _Data.keys.end(), _Key_val, _Pass_key_comp()); + const auto _Index = _Key_it - _Data.keys.begin(); + if constexpr (_IsUnique) { + if (_Key_it != _Data.keys.begin() && !_Compare_keys(*(_Key_it - 1), _Key_val)) { + // Previous element is equivalent to key, no insert needed + return {begin() + (_Index - 1), false}; + } + } + + // Need to insert + _Emplace_exact( + cbegin() + _Index, _STD forward<_OtherKey>(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); + + if constexpr (_IsUnique) { + return {begin() + _Index, true}; + } else { + return begin() + _Index; + } + } + + template + _NODISCARD iterator _Emplace_hint( + const const_iterator _Position, _OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) { + _STL_INTERNAL_STATIC_ASSERT(is_constructible_v); + _STL_INTERNAL_STATIC_ASSERT(is_same_v, key_type> + || (is_constructible_v && _Transparent) ); + + // Overwriting is not supported when the container allows multiple copies of a key. + _STL_INTERNAL_STATIC_ASSERT(_IsUnique || !_OverwriteIfExists); + + const const_iterator _Begin = cbegin(); + const const_iterator _End = cend(); + + const weak_ordering _Hint_order = [&] { + if constexpr (_IsUnique) { + if (_Position == _End || _Compare_keys(_Key_val, *_Position._Key_it)) { + if (_Position == _Begin || _Compare_keys(*(_Position._Key_it - 1), _Key_val)) { + return weak_ordering::equivalent; + } else { + return weak_ordering::greater; + } + } + } else { + if (_Position == _End || !_Compare_keys(*_Position._Key_it, _Key_val)) { + if (_Position == _Begin || !_Compare_keys(_Key_val, *(_Position._Key_it - 1))) { + return weak_ordering::equivalent; + } else { + return weak_ordering::greater; + } + } + } + return weak_ordering::less; + }(); + + const auto _New_position = _Iterator_from_key_iterator( + _Hint_order == weak_ordering::equivalent ? _Position._Key_it + : _Hint_order == weak_ordering::less + ? _STD lower_bound(_Position._Key_it, _Data.keys.cend(), _Key_val, _Pass_key_comp()) + : _STD upper_bound(_Data.keys.cbegin(), _Position._Key_it, _Key_val, _Pass_key_comp())); + + if constexpr (_IsUnique) { + if (_Hint_order == weak_ordering::less) { + if (_New_position != _End && !_Compare_keys(_Key_val, *_New_position._Key_it)) { + if constexpr (_OverwriteIfExists) { + *_New_position._Mapped_it = mapped_type(_STD forward<_MappedArgTypes>(_Mapped_args)...); + } + return _New_position; + } + } else if (_Hint_order == weak_ordering::greater) { + if (_New_position != _Begin && !_Compare_keys(*(_New_position._Key_it - 1), _Key_val)) { + const auto _It = _New_position - 1; + if constexpr (_OverwriteIfExists) { + *_It._Mapped_it = mapped_type(_STD forward<_MappedArgTypes>(_Mapped_args)...); + } + return _It; + } + } + } + + const auto _Dist = _New_position - begin(); + _Emplace_exact( + _New_position, _STD forward<_OtherKey>(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); + return begin() + _Dist; + } + +#ifdef _ENABLE_STL_INTERNAL_CHECK +public: +#else +private: +#endif + _NODISCARD bool _Is_sorted_maybe_unique() const { + return _Is_sorted_maybe_unique(_Data.keys.begin(), _Data.keys.end()); + } + +private: + _NODISCARD bool _Is_sorted_maybe_unique( + const key_container_type::const_iterator _It, const key_container_type::const_iterator _End) const { + if constexpr (_IsUnique) { + // sorted-unique + auto _Negated = [this](const key_type& _Lhs, const key_type& _Rhs) { return !_Compare_keys(_Lhs, _Rhs); }; + return _STD adjacent_find(_It, _End, _Negated) == _End; + } else { + return _STD is_sorted(_It, _End, _Pass_key_comp()); + } + } + + _NODISCARD auto _View_to_mutate() { + using _Mutating_iterator = _Pairing_iterator_provider::_Iterator; + return _RANGES subrange<_Mutating_iterator>{_Mutating_iterator{_Data.keys.begin(), _Data.values.begin()}, + _Mutating_iterator{_Data.keys.end(), _Data.values.end()}}; + } + + struct _Value_compare_to_pass { + static constexpr bool _Efficiently_copyable = conjunction_v, + is_trivially_copy_constructible, is_trivially_destructible>; + + using _Copy_or_ref = conditional_t<_Efficiently_copyable, key_compare, const key_compare&>; + + _Copy_or_ref _Key_comparator; + + template + _NODISCARD bool operator()(const _Pair1& _Lhs, const _Pair2& _Rhs) const { + return _Key_comparator(_Lhs.first, _Rhs.first); + } + }; + + _NODISCARD auto _Erase_dupes_if_not_multi_pred() { + _STL_INTERNAL_STATIC_ASSERT(_IsUnique); + if constexpr (_Equivalence_is_equality) { + return [](const auto& _Lhs, const auto& _Rhs) _STATIC_CALL_OPERATOR { return _Lhs.first == _Rhs.first; }; + } else { + return [this](const auto& _Lhs, const auto& _Rhs) { +#ifdef __clang__ // TRANSITION, LLVM-81243 + return !this->_Compare_keys(_Lhs.first, _Rhs.first); +#else // ^^^ workaround / no workaround vvv + return !_Compare_keys(_Lhs.first, _Rhs.first); +#endif // ^^^ no workaround ^^^ + }; + } + } + + template + void _Restore_invariants(const size_type _Old_size) { + // No _Clear_guard needed. This is called only by _Insert_range() (which has a _Clear_guard) + // and _Establish_invariants() (which is called only by constructors which don't need guards). + + auto _View = _View_to_mutate(); + const auto _Begin = _View.begin(); + const auto _Old_end = _Begin + static_cast(_Old_size); + const auto _End = _View.end(); + + if constexpr (_NeedSorting) { + _RANGES sort(_Old_end, _End, _Value_compare_to_pass{_Key_compare}); + } else { + [[maybe_unused]] const auto _Diff = static_cast(_Old_size); + _STL_ASSERT( + _Is_sorted_maybe_unique(_Data.keys.begin() + _Diff, _Data.keys.end()), _Msg_not_sorted_maybe_unique); + } + + _RANGES inplace_merge(_View, _Old_end, _Value_compare_to_pass{_Key_compare}); + + if constexpr (_IsUnique) { + const auto _New_last = _RANGES unique(_View, _Erase_dupes_if_not_multi_pred()).begin(); + _Data.keys.erase(_New_last._Key_it, _Data.keys.end()); + _Data.values.erase(_New_last._Mapped_it, _Data.values.end()); + } + + _STL_INTERNAL_CHECK(_Is_sorted_maybe_unique()); + } + + void _Establish_invariants() { + if (_Data.keys.empty()) { + return; + } + + const auto _Begin = _Data.keys.begin(); + const auto _End = _Data.keys.end(); + const auto _Sorted_until = _STD is_sorted_until(_Begin, _End, _Pass_key_comp()); // O(N) if already sorted. + const auto _Sorted_size = static_cast(_Sorted_until - _Begin); + _Restore_invariants(_Sorted_size); + } + + template + void _Emplace_exact(const const_iterator _Position, _OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) { + _Clear_guard _Guard{this}; + _Data.keys.emplace(_Position._Key_it, _STD forward<_OtherKey>(_Key_val)); + _Data.values.emplace(_Position._Mapped_it, _STD forward<_MappedArgTypes>(_Mapped_args)...); + _Guard._Target = nullptr; + } + + template + void _Insert_range(_InIt _First, const _Sentinel _Last) { + _Clear_guard _Guard{this}; + + const size_type _Old_size = size(); + + // Insert the new elements at the end + for (; _First != _Last; ++_First) { + value_type _Val = *_First; + if constexpr (_Has_guaranteed_push_back) { + _Data.keys.push_back(_STD move(_Val.first)); + } else { + _Data.keys.insert(_Data.keys.end(), _STD move(_Val.first)); + } + + if constexpr (_Has_guaranteed_push_back) { + _Data.values.push_back(_STD move(_Val.second)); + } else { + _Data.values.insert(_Data.values.end(), _STD move(_Val.second)); + } + } + + _Restore_invariants<_NeedSorting>(_Old_size); + + _Guard._Target = nullptr; + } + + template + _NODISCARD size_type _Erase_key(const _KeyTy& _Key_val) { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_KeyTy, key_type> || _Transparent); + const auto _Equal_pos = _Equal_range(_Key_val); + const auto _Count = static_cast(_Equal_pos.second - _Equal_pos.first); + erase(_Equal_pos.first, _Equal_pos.second); + return _Count; + } + + // size_type is always size_t + template + friend size_t erase_if(flat_map<_Key2, _Mapped2, _Compare2, _KeyContainer2, _MappedContainer2>&, _Predicate2); + template + friend size_t erase_if(flat_multimap<_Key2, _Mapped2, _Compare2, _KeyContainer2, _MappedContainer2>&, _Predicate2); + + template + _NODISCARD size_t _Erase_if(_Predicate _Pred) { + _Clear_guard _Guard{this}; + + // N5032 [flat.map.erasure]/2 and [flat.multimap.erasure]/2 + const auto _Proj = [](const auto& _Element) _STATIC_CALL_OPERATOR { return const_reference{_Element}; }; + const auto _New_last = _RANGES remove_if(_View_to_mutate(), _Pred, _Proj).begin(); + const auto _Old_size = size(); + + _Data.keys.erase(_New_last._Key_it, _Data.keys.end()); + _Data.values.erase(_New_last._Mapped_it, _Data.values.end()); + + _Guard._Target = nullptr; + return _Old_size - size(); + } + + template + _NODISCARD auto _Find(this _SelfTy& _Self, const _KeyTy& _Key_val) { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_KeyTy, key_type> || _Transparent); + const auto _Position = + _STD lower_bound(_Self._Data.keys.begin(), _Self._Data.keys.end(), _Key_val, _Self._Pass_key_comp()); + if (_Position != _Self._Data.keys.end() && !_Self._Compare_keys(_Key_val, *_Position)) { + return _Self._Iterator_from_key_iterator(_Position); + } else { + return _Self.end(); + } + } + + template + _NODISCARD size_type _Count(const _KeyTy& _Key_val) const { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_KeyTy, key_type> || _Transparent); + if constexpr (_IsUnique && is_same_v<_KeyTy, key_type>) { // Optimization restricted due to GH-5992 + return _Contains(_Key_val); + } else { + const auto [_First, _Last] = + _STD equal_range(_Data.keys.begin(), _Data.keys.end(), _Key_val, _Pass_key_comp()); + return static_cast(_Last - _First); + } + } + + template + _NODISCARD bool _Contains(const _KeyTy& _Key_val) const { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_KeyTy, key_type> || _Transparent); + return _STD binary_search(_Data.keys.begin(), _Data.keys.end(), _Key_val, _Pass_key_comp()); + } + + template + _NODISCARD auto _Lower_bound(this _SelfTy& _Self, const _KeyTy& _Key_val) { + return _Self._Iterator_from_key_iterator( + _STD lower_bound(_Self._Data.keys.begin(), _Self._Data.keys.end(), _Key_val, _Self._Pass_key_comp())); + } + + template + _NODISCARD auto _Upper_bound(this _SelfTy& _Self, const _KeyTy& _Key_val) { + return _Self._Iterator_from_key_iterator( + _STD upper_bound(_Self._Data.keys.begin(), _Self._Data.keys.end(), _Key_val, _Self._Pass_key_comp())); + } + + template + _NODISCARD auto _Equal_range(this _SelfTy& _Self, const _KeyTy& _Key_val) { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_KeyTy, key_type> || _Transparent); + if constexpr (_IsUnique && is_same_v<_KeyTy, key_type>) { // Optimization restricted due to GH-5992 + // In a non-multi container, equal_range can have size at most 1 + const auto _First = + _STD lower_bound(_Self._Data.keys.begin(), _Self._Data.keys.end(), _Key_val, _Self._Pass_key_comp()); + const bool _Missing = _First == _Self._Data.keys.end() || _Self._Compare_keys(_Key_val, *_First); + return pair{_Self._Iterator_from_key_iterator(_First), + _Self._Iterator_from_key_iterator(_Missing ? _First : _First + 1)}; + } else { + const auto [_First, _Last] = + _STD equal_range(_Self._Data.keys.begin(), _Self._Data.keys.end(), _Key_val, _Self._Pass_key_comp()); + return pair{_Self._Iterator_from_key_iterator(_First), _Self._Iterator_from_key_iterator(_Last)}; + } + } + + template + _NODISCARD conditional_t, const_iterator, iterator> _Iterator_from_key_iterator( + this _SelfTy& _Self, const key_container_type::const_iterator& _Iter) { + const difference_type _Offset = _Iter - _Self._Data.keys.cbegin(); + return _Self.begin() + _Offset; + } + + template + _NODISCARD bool _Compare_keys(const _Lty& _Lhs, const _Rty& _Rhs) const + noexcept(noexcept(_DEBUG_LT_PRED(_Key_compare, _Lhs, _Rhs))) { + _STL_INTERNAL_STATIC_ASSERT( + (is_same_v<_Lty, key_type> && is_same_v<_Rty, key_type>) || _Transparent); + + return _DEBUG_LT_PRED(_Key_compare, _Lhs, _Rhs); + } + + _NODISCARD auto _Pass_key_comp() const noexcept { + return _STD _Pass_fn(_Key_compare); + } + + containers _Data; + _MSVC_NO_UNIQUE_ADDRESS key_compare _Key_compare; +}; + +_EXPORT_STD template +class flat_map : public _Flat_map_base { +private: + using _Mybase = _Flat_map_base; + +public: + using _Mybase::_Mybase; + flat_map(const flat_map&) = default; + flat_map(flat_map&&) = default; + + using typename _Mybase::const_iterator; + using typename _Mybase::iterator; + using typename _Mybase::key_compare; + using typename _Mybase::key_type; + using typename _Mybase::mapped_type; + using typename _Mybase::value_type; + + flat_map& operator=(const flat_map&) = default; + flat_map& operator=(flat_map&&) = default; + + flat_map& operator=(const initializer_list _Ilist) { + this->clear(); + this->insert(_Ilist.begin(), _Ilist.end()); + return *this; + } + + // [flat.map.access] Access + mapped_type& operator[](const key_type& _Key_val) + requires is_default_constructible_v + { + return try_emplace(_Key_val).first->second; + } + mapped_type& operator[](key_type&& _Key_val) + requires is_default_constructible_v + { + return try_emplace(_STD move(_Key_val)).first->second; + } + template + mapped_type& operator[](_OtherKey&& _Key_val) + requires _Transparent && is_constructible_v + && is_default_constructible_v + { + return try_emplace(_STD forward<_OtherKey>(_Key_val)).first->second; + } + + _NODISCARD mapped_type& at(const key_type& _Key_val) { + return _At(_Key_val); + } + _NODISCARD const mapped_type& at(const key_type& _Key_val) const { + return _At(_Key_val); + } + template + _NODISCARD mapped_type& at(const _OtherKey& _Key_val) + requires _Transparent + { + return _At(_Key_val); + } + template + _NODISCARD const mapped_type& at(const _OtherKey& _Key_val) const + requires _Transparent + { + return _At(_Key_val); + } + + // [flat.map.modifiers] Modifiers + template + requires is_constructible_v + pair try_emplace(const key_type& _Key_val, _MappedArgTypes&&... _Mapped_args) { + return this->_Try_emplace(_Key_val, _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + requires is_constructible_v + pair try_emplace(key_type&& _Key_val, _MappedArgTypes&&... _Mapped_args) { + return this->_Try_emplace(_STD move(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + requires _Transparent && is_constructible_v + && is_constructible_v && (!is_convertible_v<_OtherKey, const_iterator>) + && (!is_convertible_v<_OtherKey, iterator>) + pair try_emplace(_OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) { + return this->_Try_emplace(_STD forward<_OtherKey>(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + iterator try_emplace(const const_iterator _Position, const key_type& _Key_val, _MappedArgTypes&&... _Mapped_args) + requires is_constructible_v + { + return this->template _Emplace_hint(_Position, _Key_val, _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + iterator try_emplace(const const_iterator _Position, key_type&& _Key_val, _MappedArgTypes&&... _Mapped_args) + requires is_constructible_v + { + return this->template _Emplace_hint( + _Position, _STD move(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + iterator try_emplace(const const_iterator _Position, _OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) + requires _Transparent && is_constructible_v + && is_constructible_v + { + return this->template _Emplace_hint( + _Position, _STD forward<_OtherKey>(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + pair insert_or_assign(const key_type& _Key_val, _OtherMapped&& _Mapped_val) + requires is_assignable_v && is_constructible_v + { + return _Insert_or_assign(_Key_val, _STD forward<_OtherMapped>(_Mapped_val)); + } + + template + pair insert_or_assign(key_type&& _Key_val, _OtherMapped&& _Mapped_val) + requires is_assignable_v && is_constructible_v + { + return _Insert_or_assign(_STD move(_Key_val), _STD forward<_OtherMapped>(_Mapped_val)); + } + + template + pair insert_or_assign(_OtherKey&& _Key_val, _OtherMapped&& _Mapped_val) + requires _Transparent && is_constructible_v + && is_assignable_v && is_constructible_v + { + return _Insert_or_assign(_STD forward<_OtherKey>(_Key_val), _STD forward<_OtherMapped>(_Mapped_val)); + } + + template + iterator insert_or_assign(const const_iterator _Position, const key_type& _Key_val, _OtherMapped&& _Mapped_val) + requires is_assignable_v && is_constructible_v + { + return this->template _Emplace_hint(_Position, _Key_val, _STD forward<_OtherMapped>(_Mapped_val)); + } + + template + iterator insert_or_assign(const const_iterator _Position, key_type&& _Key_val, _OtherMapped&& _Mapped_val) + requires is_assignable_v && is_constructible_v + { + return this->template _Emplace_hint( + _Position, _STD move(_Key_val), _STD forward<_OtherMapped>(_Mapped_val)); + } + + template + iterator insert_or_assign(const const_iterator _Position, _OtherKey&& _Key_val, _OtherMapped&& _Mapped_val) + requires _Transparent && is_constructible_v + && is_assignable_v && is_constructible_v + { + return this->template _Emplace_hint( + _Position, _STD forward<_OtherKey>(_Key_val), _STD forward<_OtherMapped>(_Mapped_val)); + } + +private: + template + _NODISCARD auto& _At(this _SelfTy& _Self, const _KeyTy& _Key_val) { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_KeyTy, key_type> || _Transparent); + const auto _Position = _Self.find(_Key_val); + if (_Position == _Self.end()) { + _Xout_of_range("invalid flat_map key"); + } + + return _Position->second; + } + + template + _NODISCARD pair _Insert_or_assign(_KeyTy&& _Key_val, _OtherMapped&& _Mapped_val) { + auto _Res = this->_Try_emplace(_STD forward<_KeyTy>(_Key_val), _STD forward<_OtherMapped>(_Mapped_val)); + if (!_Res.second) { // Already exists + _Res.first->second = _STD forward<_OtherMapped>(_Mapped_val); + } + return _Res; + } +}; + +_EXPORT_STD template +class flat_multimap : public _Flat_map_base { +private: + using _Mybase = _Flat_map_base; + +public: + using typename _Mybase::value_type; + + using _Mybase::_Mybase; + flat_multimap(const flat_multimap&) = default; + flat_multimap(flat_multimap&&) = default; + + flat_multimap& operator=(const flat_multimap&) = default; + flat_multimap& operator=(flat_multimap&&) = default; + + flat_multimap& operator=(const initializer_list _Ilist) { + this->clear(); + this->insert(_Ilist.begin(), _Ilist.end()); + return *this; + } +}; + +_EXPORT_STD template +size_t erase_if(flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>& _Cont, _Predicate _Pred) { + return _Cont._Erase_if(_STD _Pass_fn(_Pred)); +} +_EXPORT_STD template +size_t erase_if(flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>& _Cont, _Predicate _Pred) { + return _Cont._Erase_if(_STD _Pass_fn(_Pred)); +} + +template +struct uses_allocator, _Alloc> + : bool_constant && uses_allocator_v<_MappedContainer, _Alloc>> {}; + +template +struct uses_allocator, _Alloc> + : bool_constant && uses_allocator_v<_MappedContainer, _Alloc>> {}; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Valid_compare_for_container<_KeyContainer> _Compare = less> +flat_map(_KeyContainer, _MappedContainer, _Compare = _Compare()) -> flat_map; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Usable_allocator_for<_KeyContainer, _MappedContainer> _Alloc> +flat_map(_KeyContainer, _MappedContainer, _Alloc) -> flat_map, _KeyContainer, _MappedContainer>; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Valid_compare_for_container<_KeyContainer> _Compare, _Usable_allocator_for<_KeyContainer, _MappedContainer> _Alloc> +flat_map(_KeyContainer, _MappedContainer, _Compare, _Alloc) -> flat_map; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Valid_compare_for_container<_KeyContainer> _Compare = less> +flat_map(sorted_unique_t, _KeyContainer, _MappedContainer, _Compare = _Compare()) + -> flat_map; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Usable_allocator_for<_KeyContainer, _MappedContainer> _Alloc> +flat_map(sorted_unique_t, _KeyContainer, _MappedContainer, _Alloc) -> flat_map, _KeyContainer, _MappedContainer>; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Valid_compare_for_container<_KeyContainer> _Compare, _Usable_allocator_for<_KeyContainer, _MappedContainer> _Alloc> +flat_map(sorted_unique_t, _KeyContainer, _MappedContainer, _Compare, _Alloc) + -> flat_map; + +#if 1 // TRANSITION, P2582R1 (MSVC, Clang, EDG) +template _Alloc> +flat_map(flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>, _Alloc) + -> flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>; +#endif // ^^^ workaround ^^^ + +template <_Iterator_for_container _InIt, _Not_allocator_for_container _Compare = less<_Guide_key_t<_InIt>>> +flat_map(_InIt, _InIt, _Compare = _Compare()) -> flat_map<_Guide_key_t<_InIt>, _Guide_val_t<_InIt>, _Compare>; + +template <_Iterator_for_container _InIt, _Not_allocator_for_container _Compare = less<_Guide_key_t<_InIt>>> +flat_map(sorted_unique_t, _InIt, _InIt, _Compare = _Compare()) + -> flat_map<_Guide_key_t<_InIt>, _Guide_val_t<_InIt>, _Compare>; + +#ifdef __cpp_lib_byte +// TRANSITION, CWG-2369, should just use constrained template parameters. +template <_RANGES input_range _Rng, _Not_allocator_for_container _Compare = less<_Range_key_type<_Rng>>, + class _Alloc = allocator, enable_if_t<_Allocator_for_container<_Alloc>, int> = 0> +flat_map(from_range_t, _Rng&&, _Compare = _Compare(), _Alloc = _Alloc()) -> flat_map<_Range_key_type<_Rng>, + _Range_mapped_type<_Rng>, _Compare, vector<_Range_key_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_key_type<_Rng>>>, + vector<_Range_mapped_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_mapped_type<_Rng>>>>; +#else // ^^^ defined(__cpp_lib_byte) / !defined(__cpp_lib_byte) vvv +template <_RANGES input_range _Rng, _Not_allocator_for_container _Compare = less<_Range_key_type<_Rng>>> +flat_map(from_range_t, _Rng&&, _Compare = _Compare()) -> flat_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, + _Compare, vector<_Range_key_type<_Rng>>, vector<_Range_mapped_type<_Rng>>>; + +// TRANSITION, CWG-2369, should just use constrained template parameters. +template <_RANGES input_range _Rng, _Not_allocator_for_container _Compare, class _Alloc, + enable_if_t<_Allocator_for_container<_Alloc>, int> = 0> +flat_map(from_range_t, _Rng&&, _Compare, _Alloc) -> flat_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Compare, + vector<_Range_key_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_key_type<_Rng>>>, + vector<_Range_mapped_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_mapped_type<_Rng>>>>; +#endif // ^^^ !defined(__cpp_lib_byte) ^^^ + +// TRANSITION, CWG-2369, should just use constrained template parameters. +template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Allocator_for_container<_Alloc>, int> = 0> +flat_map(from_range_t, _Rng&&, _Alloc) -> flat_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, + less<_Range_key_type<_Rng>>, vector<_Range_key_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_key_type<_Rng>>>, + vector<_Range_mapped_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_mapped_type<_Rng>>>>; + +template > +flat_map(initializer_list>, _Compare = _Compare()) -> flat_map<_Key, _Mapped, _Compare>; + +template > +flat_map(sorted_unique_t, initializer_list>, _Compare = _Compare()) + -> flat_map<_Key, _Mapped, _Compare>; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Valid_compare_for_container<_KeyContainer> _Compare = less> +flat_multimap(_KeyContainer, _MappedContainer, _Compare = _Compare()) + -> flat_multimap; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Usable_allocator_for<_KeyContainer, _MappedContainer> _Alloc> +flat_multimap(_KeyContainer, _MappedContainer, _Alloc) -> flat_multimap, _KeyContainer, _MappedContainer>; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Valid_compare_for_container<_KeyContainer> _Compare, _Usable_allocator_for<_KeyContainer, _MappedContainer> _Alloc> +flat_multimap(_KeyContainer, _MappedContainer, _Compare, _Alloc) -> flat_multimap; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Valid_compare_for_container<_KeyContainer> _Compare = less> +flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Compare = _Compare()) + -> flat_multimap; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Usable_allocator_for<_KeyContainer, _MappedContainer> _Alloc> +flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Alloc) + -> flat_multimap, _KeyContainer, _MappedContainer>; + +template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, + _Valid_compare_for_container<_KeyContainer> _Compare, _Usable_allocator_for<_KeyContainer, _MappedContainer> _Alloc> +flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Compare, _Alloc) + -> flat_multimap; + +#if 1 // TRANSITION, P2582R1 (MSVC, Clang, EDG) +template _Alloc> +flat_multimap(flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>, _Alloc) + -> flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>; +#endif // ^^^ workaround ^^^ + +template <_Iterator_for_container _InIt, _Not_allocator_for_container _Compare = less<_Guide_key_t<_InIt>>> +flat_multimap(_InIt, _InIt, _Compare = _Compare()) -> flat_multimap<_Guide_key_t<_InIt>, _Guide_val_t<_InIt>, _Compare>; + +template <_Iterator_for_container _InIt, _Not_allocator_for_container _Compare = less<_Guide_key_t<_InIt>>> +flat_multimap(sorted_equivalent_t, _InIt, _InIt, _Compare = _Compare()) + -> flat_multimap<_Guide_key_t<_InIt>, _Guide_val_t<_InIt>, _Compare>; + +#ifdef __cpp_lib_byte +// TRANSITION, CWG-2369, should just use constrained template parameters. +template <_RANGES input_range _Rng, _Not_allocator_for_container _Compare = less<_Range_key_type<_Rng>>, + class _Alloc = allocator, enable_if_t<_Allocator_for_container<_Alloc>, int> = 0> +flat_multimap(from_range_t, _Rng&&, _Compare = _Compare(), _Alloc = _Alloc()) -> flat_multimap<_Range_key_type<_Rng>, + _Range_mapped_type<_Rng>, _Compare, vector<_Range_key_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_key_type<_Rng>>>, + vector<_Range_mapped_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_mapped_type<_Rng>>>>; +#else // ^^^ defined(__cpp_lib_byte) / !defined(__cpp_lib_byte) vvv +template <_RANGES input_range _Rng, _Not_allocator_for_container _Compare = less<_Range_key_type<_Rng>>> +flat_multimap(from_range_t, _Rng&&, _Compare = _Compare()) -> flat_multimap<_Range_key_type<_Rng>, + _Range_mapped_type<_Rng>, _Compare, vector<_Range_key_type<_Rng>>, vector<_Range_mapped_type<_Rng>>>; + +// TRANSITION, CWG-2369, should just use constrained template parameters. +template <_RANGES input_range _Rng, _Not_allocator_for_container _Compare, class _Alloc, + enable_if_t<_Allocator_for_container<_Alloc>, int> = 0> +flat_multimap(from_range_t, _Rng&&, _Compare, _Alloc) -> flat_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, + _Compare, vector<_Range_key_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_key_type<_Rng>>>, + vector<_Range_mapped_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_mapped_type<_Rng>>>>; +#endif // ^^^ !defined(__cpp_lib_byte) ^^^ + +// TRANSITION, CWG-2369, should just use constrained template parameters. +template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Allocator_for_container<_Alloc>, int> = 0> +flat_multimap(from_range_t, _Rng&&, _Alloc) -> flat_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, + less<_Range_key_type<_Rng>>, vector<_Range_key_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_key_type<_Rng>>>, + vector<_Range_mapped_type<_Rng>, _Rebind_alloc_t<_Alloc, _Range_mapped_type<_Rng>>>>; + +template > +flat_multimap(initializer_list>, _Compare = _Compare()) -> flat_multimap<_Key, _Mapped, _Compare>; + +template > +flat_multimap(sorted_equivalent_t, initializer_list>, _Compare = _Compare()) + -> flat_multimap<_Key, _Mapped, _Compare>; +_STD_END + +// TRANSITION, non-_Ugly attribute tokens +#pragma pop_macro("msvc") + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // ^^^ _HAS_CXX23 ^^^ +#endif // _STL_COMPILER_PREPROCESSOR +#endif // _FLAT_MAP_ diff --git a/stl/inc/flat_set b/stl/inc/flat_set new file mode 100644 index 00000000000..52494d36d52 --- /dev/null +++ b/stl/inc/flat_set @@ -0,0 +1,993 @@ +// flat_set standard header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef _FLAT_SET_ +#define _FLAT_SET_ +#include +#if _STL_COMPILER_PREPROCESSOR +#if !_HAS_CXX23 +_EMIT_STL_WARNING(STL4038, "The contents of are available only with C++23 or later."); +#else // ^^^ !_HAS_CXX23 / _HAS_CXX23 vvv +#include +#include +#include +#include +#include + +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + +// TRANSITION, non-_Ugly attribute tokens +#pragma push_macro("msvc") +#undef msvc + +_STD_BEGIN +template +struct _NODISCARD _Flat_set_swap_clear_guard { + // Invariant: (_Target1 == nullptr) == (_Target2 == nullptr) + _Container* _Target1; + _Container* _Target2; + + _Flat_set_swap_clear_guard& operator=(const _Flat_set_swap_clear_guard&) = delete; + + void _Dismiss() noexcept { + _Target1 = nullptr; + _Target2 = nullptr; + } + + ~_Flat_set_swap_clear_guard() { + if (_Target1) { + _Target1->clear(); + _Target2->clear(); + } + } +}; +template +struct _NODISCARD _Flat_set_swap_clear_guard { + constexpr explicit _Flat_set_swap_clear_guard(_Container*, _Container*) noexcept {} + + _Flat_set_swap_clear_guard& operator=(const _Flat_set_swap_clear_guard&) = delete; + + void _Dismiss() noexcept {} +}; + +_EXPORT_STD template , class _Container = vector<_Key>> +class flat_set; + +_EXPORT_STD template , class _Container = vector<_Key>> +class flat_multiset; + +template +class _Flat_set_base { +private: + using _Sorted_t = conditional_t<_IsUnique, sorted_unique_t, sorted_equivalent_t>; + using _Derived = + conditional_t<_IsUnique, flat_set<_Key, _Compare, _Container>, flat_multiset<_Key, _Compare, _Container>>; + + static constexpr const char* _Msg_not_sorted_maybe_unique = + _IsUnique ? "Input was not sorted-unique! (N5032 [flat.set.overview]/9)" + : "Input was not sorted! (N5032 [flat.multiset.overview]/9)"; + static constexpr const char* _Msg_replace_not_sorted_maybe_unique = + _IsUnique ? "Input was not sorted-unique! (N5032 [flat.set.modifiers]/18)" + : "Input was not sorted! (N5032 [flat.multiset.modifiers]/17)"; + static constexpr const char* _Msg_heterogeneous_insertion_inconsistent_with_lookup = + "The conversion from the heterogeneous key to key_type should be consistent with the heterogeneous lookup!"; + +public: + // [flat.set.defn] Types + using key_type = _Key; + using value_type = _Key; + using key_compare = _Compare; + using value_compare = _Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = _Container::size_type; + using difference_type = _Container::difference_type; + using const_iterator = _Container::const_iterator; + using iterator = const_iterator; + using const_reverse_iterator = _STD reverse_iterator; + using reverse_iterator = const_reverse_iterator; + using container_type = _Container; + + static_assert(same_as, + "key_type and container_type::value_type must be the same. " + "(N5032 [flat.set.overview]/8, [flat.multiset.overview]/8)"); + static_assert(!_Is_vector_bool, + "vector cannot be adapted because it is not a sequence container. " + "(N5032 [flat.set.overview]/7, [flat.multiset.overview]/7)"); + static_assert(random_access_iterator, + "Sequence containers must support random-access iterators in order to be adapted. " + "(N5032 [flat.set.overview]/7, [flat.multiset.overview]/7)"); + + // [flat.set.cons] Constructors + _Flat_set_base() : _Data(), _Key_compare() {} + + _Flat_set_base(const _Flat_set_base&) = default; + + _Flat_set_base(_Flat_set_base&& _Other) noexcept( + is_nothrow_move_constructible_v && is_nothrow_copy_constructible_v) // strengthened + : _Data(_STD move(_Other).extract()), + _Key_compare(_Other._Key_compare) // intentionally copy comparator, see LWG-2227 + {} + + explicit _Flat_set_base(const key_compare& _Comp) : _Data(), _Key_compare(_Comp) {} + + explicit _Flat_set_base(container_type _Cont, const key_compare& _Comp = key_compare()) + : _Data(_STD move(_Cont)), _Key_compare(_Comp) { + _Establish_invariants(); + } + + _Flat_set_base(_Sorted_t, container_type _Cont, const key_compare& _Comp = key_compare()) + : _Data(_STD move(_Cont)), _Key_compare(_Comp) { + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + template <_Iterator_for_container _InIt> + _Flat_set_base(const _InIt _First, const _InIt _Last, const key_compare& _Comp = key_compare()) + : _Data(_First, _Last), _Key_compare(_Comp) { + _Establish_invariants(); + } + + template <_Iterator_for_container _InIt> + _Flat_set_base(_Sorted_t, const _InIt _First, const _InIt _Last, const key_compare& _Comp = key_compare()) + : _Data(_First, _Last), _Key_compare(_Comp) { + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + template <_Container_compatible_range _Rng> + _Flat_set_base(from_range_t, _Rng&& _Range) : _Data(from_range, _STD forward<_Rng>(_Range)), _Key_compare() { + _Establish_invariants(); + } + + template <_Container_compatible_range _Rng> + _Flat_set_base(from_range_t, _Rng&& _Range, const key_compare& _Comp) + : _Data(from_range, _STD forward<_Rng>(_Range)), _Key_compare(_Comp) { + _Establish_invariants(); + } + + _Flat_set_base(const initializer_list _Ilist, const key_compare& _Comp = key_compare()) + : _Data(_Ilist.begin(), _Ilist.end()), _Key_compare(_Comp) { + _Establish_invariants(); + } + + _Flat_set_base(_Sorted_t, const initializer_list _Ilist, const key_compare& _Comp = key_compare()) + : _Data(_Ilist.begin(), _Ilist.end()), _Key_compare(_Comp) { + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + // [flat.set.cons.alloc] Constructors with allocators + template <_Usable_allocator_for _Alloc> + explicit _Flat_set_base(const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al)), _Key_compare() {} + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(const key_compare& _Comp, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al)), _Key_compare(_Comp) {} + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(const container_type& _Cont, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _Cont)), _Key_compare() { + _Establish_invariants(); + } + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(const container_type& _Cont, const key_compare& _Comp, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _Cont)), _Key_compare(_Comp) { + _Establish_invariants(); + } + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(_Sorted_t, const container_type& _Cont, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _Cont)), _Key_compare() { + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(_Sorted_t, const container_type& _Cont, const key_compare& _Comp, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _Cont)), _Key_compare(_Comp) { + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(const _Flat_set_base& _Other, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _Other._Data)), _Key_compare(_Other._Key_compare) {} + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(_Flat_set_base&& _Other, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _STD move(_Other).extract())), + _Key_compare(_Other._Key_compare) // intentionally copy comparator, see LWG-2227 + {} + + template <_Iterator_for_container _InIt, _Usable_allocator_for _Alloc> + _Flat_set_base(const _InIt _First, const _InIt _Last, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _First, _Last)), _Key_compare() { + _Establish_invariants(); + } + + template <_Iterator_for_container _InIt, _Usable_allocator_for _Alloc> + _Flat_set_base(const _InIt _First, const _InIt _Last, const key_compare& _Comp, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _First, _Last)), _Key_compare(_Comp) { + _Establish_invariants(); + } + + template <_Iterator_for_container _InIt, _Usable_allocator_for _Alloc> + _Flat_set_base(_Sorted_t, const _InIt _First, const _InIt _Last, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _First, _Last)), _Key_compare() { + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + template <_Iterator_for_container _InIt, _Usable_allocator_for _Alloc> + _Flat_set_base(_Sorted_t, const _InIt _First, const _InIt _Last, const key_compare& _Comp, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _First, _Last)), _Key_compare(_Comp) { + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + template <_Container_compatible_range _Rng, _Usable_allocator_for _Alloc> + _Flat_set_base(from_range_t, _Rng&& _Range, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, from_range, _STD forward<_Rng>(_Range))), + _Key_compare() { + _Establish_invariants(); + } + + template <_Container_compatible_range _Rng, _Usable_allocator_for _Alloc> + _Flat_set_base(from_range_t, _Rng&& _Range, const key_compare& _Comp, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, from_range, _STD forward<_Rng>(_Range))), + _Key_compare(_Comp) { + _Establish_invariants(); + } + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(const initializer_list _Ilist, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _Ilist.begin(), _Ilist.end())), _Key_compare() { + _Establish_invariants(); + } + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(const initializer_list _Ilist, const key_compare& _Comp, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _Ilist.begin(), _Ilist.end())), _Key_compare(_Comp) { + _Establish_invariants(); + } + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(_Sorted_t, const initializer_list _Ilist, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _Ilist.begin(), _Ilist.end())), _Key_compare() { + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(_Sorted_t, const initializer_list _Ilist, const key_compare& _Comp, const _Alloc& _Al) + : _Data(_STD make_obj_using_allocator(_Al, _Ilist.begin(), _Ilist.end())), _Key_compare(_Comp) { + _STL_ASSERT(_Is_sorted_maybe_unique(), _Msg_not_sorted_maybe_unique); + } + + // Assignment operators + _Flat_set_base& operator=(const _Flat_set_base& _Other) { + _Clear_guard _Guard{this}; + _Data = _Other._Data; + _Key_compare = _Other._Key_compare; + _Guard._Target = nullptr; + return *this; + } + + _Flat_set_base& operator=(_Flat_set_base&& _Other) noexcept( + is_nothrow_move_assignable_v && is_nothrow_copy_assignable_v) /* strengthened */ { + if (this != _STD addressof(_Other)) { + _Clear_guard _Guard{this}; + _Clear_guard _Always_clear{_STD addressof(_Other)}; + _Data = _STD move(_Other._Data); + _Key_compare = _Other._Key_compare; // intentionally copy comparator, see LWG-2227 + _Guard._Target = nullptr; + } + return *this; + } + + // Iterators + // NB: The non-const overloads are intentionally removed for brevity. This will not result in behavioral changes. + _NODISCARD const_iterator begin() const noexcept { + return _Data.begin(); + } + _NODISCARD const_iterator end() const noexcept { + return _Data.end(); + } + + _NODISCARD const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator{_Data.end()}; + } + _NODISCARD const_reverse_iterator rend() const noexcept { + return const_reverse_iterator{_Data.begin()}; + } + + _NODISCARD const_iterator cbegin() const noexcept { + return _Data.begin(); + } + _NODISCARD const_iterator cend() const noexcept { + return _Data.end(); + } + + _NODISCARD const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator{_Data.end()}; + } + _NODISCARD const_reverse_iterator crend() const noexcept { + return const_reverse_iterator{_Data.begin()}; + } + + // Capacity + _NODISCARD_EMPTY_MEMBER bool empty() const noexcept { + return _Data.empty(); + } + _NODISCARD size_type size() const noexcept { + return _Data.size(); + } + _NODISCARD size_type max_size() const noexcept { + return _Data.max_size(); + } + + // [flat.set.modifiers] Modifiers + template + auto emplace(_ArgTypes&&... _Args) + requires is_constructible_v + { + constexpr bool _Is_key_type = _In_place_key_extract_set::_Extractable; + if constexpr (_Is_key_type) { + return _Emplace(_STD forward<_ArgTypes>(_Args)...); + } else { + return _Emplace(key_type(_STD forward<_ArgTypes>(_Args)...)); + } + } + + template + iterator emplace_hint(const const_iterator _Position, _ArgTypes&&... _Args) + requires is_constructible_v + { + constexpr bool _Is_key_type = _In_place_key_extract_set::_Extractable; + if constexpr (_Is_key_type) { + return _Emplace_hint(_Position, _STD forward<_ArgTypes>(_Args)...); + } else { + return _Emplace_hint(_Position, key_type(_STD forward<_ArgTypes>(_Args)...)); + } + } + + auto insert(const value_type& _Val) { + return _Emplace(_Val); + } + auto insert(value_type&& _Val) { + return _Emplace(_STD move(_Val)); + } + template <_Different_from _Other> + requires _IsUnique && _Transparent && is_constructible_v + auto insert(_Other&& _Val) { + return _Emplace(_STD forward<_Other>(_Val)); + } + + iterator insert(const const_iterator _Position, const value_type& _Val) { + return _Emplace_hint(_Position, _Val); + } + iterator insert(const const_iterator _Position, value_type&& _Val) { + return _Emplace_hint(_Position, _STD move(_Val)); + } + template <_Different_from _Other> + requires _IsUnique && _Transparent && is_constructible_v + iterator insert(const const_iterator _Position, _Other&& _Val) { + return _Emplace_hint(_Position, _STD forward<_Other>(_Val)); + } + + template <_Iterator_for_container _InIt> + void insert(const _InIt _First, const _InIt _Last) { + _Insert_range(_First, _Last); + } + template <_Iterator_for_container _InIt> + void insert(_Sorted_t, const _InIt _First, const _InIt _Last) { + _Insert_range(_First, _Last); + } + + template <_Container_compatible_range _Rng> + void insert_range(_Rng&& _Range) { + _Insert_range(_STD forward<_Rng>(_Range)); + } + template <_Container_compatible_range _Rng> + void insert_range(_Sorted_t, _Rng&& _Range) { + _Insert_range(_STD forward<_Rng>(_Range)); + } + + void insert(const initializer_list _Ilist) { + _Insert_range(_Ilist.begin(), _Ilist.end()); + } + void insert(_Sorted_t, const initializer_list _Ilist) { + _Insert_range(_Ilist.begin(), _Ilist.end()); + } + + _NODISCARD container_type extract() && noexcept( + is_nothrow_move_constructible_v) /* strengthened */ { + // always clears the container (N5032 [flat.set.modifiers]/16 and [flat.multiset.modifiers]/15) + _Clear_guard _Always_clear{this}; + return _STD move(_Data); + } + + void replace(container_type&& _Cont) { + _STL_ASSERT(_Is_sorted_maybe_unique(_Cont.begin(), _Cont.end()), _Msg_replace_not_sorted_maybe_unique); + _Clear_guard _Guard{this}; + _Data = _STD move(_Cont); + _Guard._Target = nullptr; + } + + // NB: `erase(iterator)` is identical to `erase(const_iterator)` + iterator erase(const const_iterator _Position) { + _Clear_guard _Guard{this}; + const auto _Ret = _Data.erase(_Position); + _Guard._Target = nullptr; + return _Ret; + } + + size_type erase(const key_type& _Val) { + return _Erase_key(_Val); + } + template <_Different_from _Other> + requires _Transparent && (!is_convertible_v<_Other, const_iterator>) + size_type erase(_Other&& _Val) { + return _Erase_key(_Val); + } + + iterator erase(const const_iterator _First, const const_iterator _Last) { + _Clear_guard _Guard{this}; + const auto _Ret = _Data.erase(_First, _Last); + _Guard._Target = nullptr; + return _Ret; + } + + void swap(_Derived& _Other) + noexcept(is_nothrow_swappable_v && is_nothrow_swappable_v) { + constexpr bool _Is_noexcept = is_nothrow_swappable_v && is_nothrow_swappable_v; + _Flat_set_swap_clear_guard<_Is_noexcept, container_type> _Guard{ + _STD addressof(_Data), _STD addressof(_Other._Data)}; + _RANGES swap(_Data, _Other._Data); + _RANGES swap(_Key_compare, _Other._Key_compare); + _Guard._Dismiss(); + } + + void clear() noexcept { + _Data.clear(); + } + + // Observers + _NODISCARD key_compare key_comp() const { + return _Key_compare; + } + _NODISCARD value_compare value_comp() const { + return _Key_compare; + } + + // Set operations + // NB: The non-const overloads are intentionally removed for brevity. This will not result in behavioral changes. + _NODISCARD const_iterator find(const key_type& _Val) const { + return _Find(_Val); + } + template + requires _Transparent + _NODISCARD const_iterator find(const _Other& _Val) const { + return _Find(_Val); + } + + _NODISCARD size_type count(const key_type& _Val) const { + return _Count(_Val); + } + template + requires _Transparent + _NODISCARD size_type count(const _Other& _Val) const { + return _Count(_Val); + } + + _NODISCARD bool contains(const key_type& _Val) const { + return _STD binary_search(cbegin(), cend(), _Val, _Pass_comp()); + } + template + requires _Transparent + _NODISCARD bool contains(const _Other& _Val) const { + return _STD binary_search(cbegin(), cend(), _Val, _Pass_comp()); + } + + _NODISCARD const_iterator lower_bound(const key_type& _Val) const { + return _STD lower_bound(cbegin(), cend(), _Val, _Pass_comp()); + } + template + requires _Transparent + _NODISCARD const_iterator lower_bound(const _Other& _Val) const { + return _STD lower_bound(cbegin(), cend(), _Val, _Pass_comp()); + } + + _NODISCARD const_iterator upper_bound(const key_type& _Val) const { + return _STD upper_bound(cbegin(), cend(), _Val, _Pass_comp()); + } + template + requires _Transparent + _NODISCARD const_iterator upper_bound(const _Other& _Val) const { + return _STD upper_bound(cbegin(), cend(), _Val, _Pass_comp()); + } + + _NODISCARD pair equal_range(const key_type& _Val) const { + return _Equal_range(_Val); + } + template + requires _Transparent + _NODISCARD pair equal_range(const _Other& _Val) const { + return _Equal_range(_Val); + } + + _NODISCARD friend bool operator==(const _Derived& _Lhs, const _Derived& _Rhs) { + return _STD equal(_Lhs._Data.begin(), _Lhs._Data.end(), _Rhs._Data.begin(), _Rhs._Data.end()); + } + + _NODISCARD friend auto operator<=>(const _Derived& _Lhs, const _Derived& _Rhs) { + return _STD lexicographical_compare_three_way( + _Lhs._Data.begin(), _Lhs._Data.end(), _Rhs._Data.begin(), _Rhs._Data.end(), _Synth_three_way{}); + } + + friend void swap(_Derived& _Lhs, _Derived& _Rhs) noexcept(noexcept(_Lhs.swap(_Rhs))) { + _Lhs.swap(_Rhs); + } + +#ifdef _ENABLE_STL_INTERNAL_CHECK +public: +#else +private: +#endif + _NODISCARD bool _Is_sorted_maybe_unique() const { + return _Is_sorted_maybe_unique(_Data.begin(), _Data.end()); + } + +private: + _NODISCARD bool _Is_sorted_maybe_unique(const const_iterator _It, const const_iterator _End) const { + if constexpr (_IsUnique) { + // sorted-unique + auto _Negated = [this](const key_type& _Lhs, const key_type& _Rhs) { return !_Compare_keys(_Lhs, _Rhs); }; + return _STD adjacent_find(_It, _End, _Negated) == _End; + } else { + return _STD is_sorted(_It, _End, _Pass_comp()); + } + } + + _NODISCARD auto _Erase_dupes_if_not_multi_pred() { + _STL_INTERNAL_STATIC_ASSERT(_IsUnique); + if constexpr (_Equivalence_is_equality) { + return equal_to<>{}; + } else { + return [this](const key_type& _Lhs, const key_type& _Rhs) { return !_Compare_keys(_Lhs, _Rhs); }; + } + } + + template + void _Restore_invariants(const size_type _Old_size) { + // No _Clear_guard needed. This is called only by _Insert_range() (which has a _Clear_guard) + // and _Establish_invariants() (which is called only by constructors which don't need guards). + + const auto _Begin = _Data.begin(); + const auto _Old_end = _Begin + static_cast(_Old_size); + const auto _End = _Data.end(); + + if constexpr (_NeedSorting) { + _STD sort(_Old_end, _End, _Pass_comp()); + } else { + _STL_ASSERT(_Is_sorted_maybe_unique(_Old_end, _End), _Msg_not_sorted_maybe_unique); + } + + _STD inplace_merge(_Begin, _Old_end, _End, _Pass_comp()); + + if constexpr (_IsUnique) { + _Data.erase(_STD unique(_Begin, _End, _Erase_dupes_if_not_multi_pred()), _End); + } + + _STL_INTERNAL_CHECK(_Is_sorted_maybe_unique()); + } + + void _Establish_invariants() { + if (_Data.empty()) { + return; + } + + const auto _Begin = _Data.begin(); + const auto _End = _Data.end(); + const auto _Sorted_until = _STD is_sorted_until(_Begin, _End, _Pass_comp()); // O(N) if already sorted. + const auto _Sorted_size = static_cast(_Sorted_until - _Begin); + _Restore_invariants(_Sorted_size); + } + + template + _NODISCARD bool _Can_insert(const const_iterator _Where, const _Ty& _Val) const { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_Ty, key_type>); // only accepts key_type + + // check that _Val can be inserted before _Where + if constexpr (_IsUnique) { + // check that _Where is the lower_bound for _Val, and *_Where is not equivalent to _Val + // equivalent to checking *(_Where-1) < _Val < *_Where + return (_Where == cend() || _Compare_keys(_Val, *_Where)) + && (_Where == cbegin() || _Compare_keys(*(_Where - 1), _Val)); + } else { + // check that _Where is the upper_bound for _Val + // equivalent to checking *(_Where-1) <= _Val < *_Where + return (_Where == cend() || _Compare_keys(_Val, *_Where)) + && (_Where == cbegin() || !_Compare_keys(_Val, *(_Where - 1))); + } + } + + template + _NODISCARD iterator _Emplace_with_clear_guard(const const_iterator _Where, _Ty&& _Val) { + if constexpr (_Has_guaranteed_single_insertion) { + return _Data.emplace(_Where, _STD forward<_Ty>(_Val)); + } else { + _Clear_guard _Guard{this}; + auto _Iter = _Data.emplace(_Where, _STD forward<_Ty>(_Val)); + _Guard._Target = nullptr; + return _Iter; + } + } + + template + _NODISCARD conditional_t<_IsUnique, pair, iterator> _Emplace(_Ty&& _Val) { + if constexpr (_IsUnique) { + const const_iterator _Where = lower_bound(_Val); + if (_Where != cend() && !_Compare_keys(_Val, *_Where)) { + return pair{_Where, false}; + } + + if constexpr (is_same_v, key_type>) { + _STL_INTERNAL_CHECK(_Can_insert(_Where, _Val)); + return pair{_Emplace_with_clear_guard(_Where, _STD forward<_Ty>(_Val)), true}; + } else { + // heterogeneous insertion + _STL_INTERNAL_STATIC_ASSERT(_Transparent && is_constructible_v); + key_type _Keyval(_STD forward<_Ty>(_Val)); + _STL_ASSERT(_Can_insert(_Where, _Keyval), _Msg_heterogeneous_insertion_inconsistent_with_lookup); + return pair{_Emplace_with_clear_guard(_Where, _STD move(_Keyval)), true}; + } + } else { + _STL_INTERNAL_STATIC_ASSERT(is_same_v, key_type>); + return _Emplace_with_clear_guard(upper_bound(_Val), _STD forward<_Ty>(_Val)); + } + } + + template + _NODISCARD iterator _Emplace_hint(const_iterator _Where, _Ty&& _Val) { + const const_iterator _Begin = cbegin(); + const const_iterator _End = cend(); + + if constexpr (_IsUnique) { + // look for lower_bound(_Val) + if (_Where == _End || !_Compare_keys(*_Where, _Val)) { + // _Val <= *_Where + if (_Where == _Begin || _Compare_keys(*(_Where - 1), _Val)) { + // _Val > *(_Where-1) ~ lower_bound is _Where + } else { + // _Val <= *(_Where-1) ~ lower_bound is in [_Begin,_Where-1] + _Where = _STD lower_bound(_Begin, _Where - 1, _Val, _Pass_comp()); + } + } else { + // _Val > *_Where ~ lower_bound is in [_Where+1,_End] + _Where = _STD lower_bound(_Where + 1, _End, _Val, _Pass_comp()); + } + + if (_Where != _End && !_Compare_keys(_Val, *_Where)) { + return _Where; + } + + if constexpr (is_same_v, key_type>) { + _STL_INTERNAL_CHECK(_Can_insert(_Where, _Val)); + return _Emplace_with_clear_guard(_Where, _STD forward<_Ty>(_Val)); + } else { + // heterogeneous insertion + _STL_INTERNAL_STATIC_ASSERT(_Transparent && is_constructible_v); + key_type _Keyval(_STD forward<_Ty>(_Val)); + _STL_ASSERT(_Can_insert(_Where, _Keyval), _Msg_heterogeneous_insertion_inconsistent_with_lookup); + return _Emplace_with_clear_guard(_Where, _STD move(_Keyval)); + } + } else { + _STL_INTERNAL_STATIC_ASSERT(is_same_v, key_type>); + + // look for closest position just prior to _Where, respecting ordering + if (_Where == _End || _Compare_keys(_Val, *_Where)) { + // _Val < *_Where + if (_Where == _Begin || !_Compare_keys(_Val, *(_Where - 1))) { + // _Val >= *(_Where-1) ~ closest valid position is _Where + } else { + // _Val < *(_Where-1) ~ closest valid position is upper_bound(_Val) located in [_Begin,_Where-1] + _Where = _STD upper_bound(_Begin, _Where - 1, _Val, _Pass_comp()); + } + // _Val < *_Where, so upper_bound is indeed "as close as possible" + _STL_INTERNAL_CHECK(_Can_insert(_Where, _Val)); + } else { + // _Val >= *_Where ~ search for lower_bound in [_Where,_End] to place _Val "as close as possible" + _Where = _STD lower_bound(_Where, _End, _Val, _Pass_comp()); + } + + return _Emplace_with_clear_guard(_Where, _STD forward<_Ty>(_Val)); + } + } + + template + void _Insert_range(const _InIt _First, const _InIt _Last) { + _Clear_guard _Guard{this}; + const size_type _Old_size = size(); + _Data.insert(_Data.end(), _First, _Last); + _Restore_invariants<_NeedSorting>(_Old_size); + _Guard._Target = nullptr; + } + + template _Rng> + void _Insert_range(_Rng&& _Range) { + _Clear_guard _Guard{this}; + const size_type _Old_size = size(); + if constexpr (_Has_guaranteed_append_range) { + _Data.append_range(_STD forward<_Rng>(_Range)); + } else { + _Data.insert_range(_Data.end(), _STD forward<_Rng>(_Range)); + } + _Restore_invariants<_NeedSorting>(_Old_size); + _Guard._Target = nullptr; + } + + template + _NODISCARD size_type _Erase_key(const _KeyTy& _Key_val) { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_KeyTy, key_type> || _Transparent); + + if constexpr (_IsUnique && is_same_v<_KeyTy, key_type>) { // Optimization restricted due to GH-5992 + const const_iterator _Where = lower_bound(_Key_val); + if (_Where != cend() && !_Compare_keys(_Key_val, *_Where)) { + _Clear_guard _Guard{this}; + _Data.erase(_Where); + _Guard._Target = nullptr; + return 1; + } + return 0; + } else { + const auto [_First, _Last] = equal_range(_Key_val); + + const auto _Removed = static_cast(_Last - _First); + _Clear_guard _Guard{this}; + _Data.erase(_First, _Last); + _Guard._Target = nullptr; + return _Removed; + } + } + + // typename is a workaround for VSO-2680018 (EDG) + template + friend typename _Container2::size_type erase_if(flat_set<_Key2, _Compare2, _Container2>&, _Predicate2); + template + friend typename _Container2::size_type erase_if(flat_multiset<_Key2, _Compare2, _Container2>&, _Predicate2); + + template + _NODISCARD size_type _Erase_if(_Predicate _Pred) { + // Maintain invariants when an exception is thrown (N5032 [flat.set.erasure]/5, [flat.multiset.erasure]/5) + _Clear_guard _Guard{this}; + const auto _Erased_count = _STD _Erase_remove_if(_Data, _Pred); + _Guard._Target = nullptr; + return _Erased_count; + } + + template + _NODISCARD const_iterator _Find(const _KeyTy& _Key_val) const { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_KeyTy, key_type> || _Transparent); + + const const_iterator _End = cend(); + const const_iterator _Where = lower_bound(_Key_val); + if (_Where != _End && !_Compare_keys(_Key_val, *_Where)) { + return _Where; + } else { + return _End; + } + } + + template + _NODISCARD size_type _Count(const _KeyTy& _Key_val) const { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_KeyTy, key_type> || _Transparent); + if constexpr (_IsUnique && is_same_v<_KeyTy, key_type>) { // Optimization restricted due to GH-5992 + return contains(_Key_val); + } else { + const auto [_First, _Last] = _Equal_range(_Key_val); + return static_cast(_Last - _First); + } + } + + template + _NODISCARD pair _Equal_range(const _KeyTy& _Key_val) const { + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_KeyTy, key_type> || _Transparent); + if constexpr (_IsUnique && is_same_v<_KeyTy, key_type>) { // Optimization restricted due to GH-5992 + // In a non-multi container, equal_range can have size at most 1 + const auto _First = _STD lower_bound(_Data.begin(), _Data.end(), _Key_val, _Pass_comp()); + const bool _Missing = _First == _Data.end() || _Compare_keys(_Key_val, *_First); + return pair{_First, _Missing ? _First : _First + 1}; + } else { + return _STD equal_range(begin(), end(), _Key_val, _Pass_comp()); + } + } + + template + _NODISCARD bool _Compare_keys(const _Lty& _Lhs, const _Rty& _Rhs) const + noexcept(noexcept(_DEBUG_LT_PRED(_Key_compare, _Lhs, _Rhs))) { + _STL_INTERNAL_STATIC_ASSERT( + (is_same_v<_Lty, key_type> && is_same_v<_Rty, key_type>) || _Transparent); + + return _DEBUG_LT_PRED(_Key_compare, _Lhs, _Rhs); + } + + _NODISCARD auto _Pass_comp() const noexcept { + return _STD _Pass_fn(_Key_compare); + } + + container_type _Data; + _MSVC_NO_UNIQUE_ADDRESS key_compare _Key_compare; +}; + +_EXPORT_STD template +class flat_set : public _Flat_set_base { +private: + using _Mybase = _Flat_set_base; + +public: + using _Mybase::_Mybase; + flat_set(const flat_set&) = default; + flat_set(flat_set&&) = default; + + flat_set& operator=(const flat_set&) = default; + flat_set& operator=(flat_set&&) = default; + + flat_set& operator=(const initializer_list<_Key> _Ilist) { + this->clear(); + this->insert(_Ilist.begin(), _Ilist.end()); + return *this; + } +}; + +_EXPORT_STD template +class flat_multiset : public _Flat_set_base { +private: + using _Mybase = _Flat_set_base; + +public: + using _Mybase::_Mybase; + flat_multiset(const flat_multiset&) = default; + flat_multiset(flat_multiset&&) = default; + + flat_multiset& operator=(const flat_multiset&) = default; + flat_multiset& operator=(flat_multiset&&) = default; + + flat_multiset& operator=(const initializer_list<_Key> _Ilist) { + this->clear(); + this->insert(_Ilist.begin(), _Ilist.end()); + return *this; + } +}; + +_EXPORT_STD template +_Container::size_type erase_if(flat_set<_Key, _Compare, _Container>& _Cont, _Predicate _Pred) { + return _Cont._Erase_if(_STD _Pass_fn(_Pred)); +} +_EXPORT_STD template +_Container::size_type erase_if(flat_multiset<_Key, _Compare, _Container>& _Cont, _Predicate _Pred) { + return _Cont._Erase_if(_STD _Pass_fn(_Pred)); +} + +template +struct uses_allocator, _Alloc> + : bool_constant> {}; + +template +struct uses_allocator, _Alloc> + : bool_constant> {}; + +template <_Not_allocator_for_container _Container, + _Valid_compare_for_container<_Container> _Compare = less> +flat_set(_Container, _Compare = _Compare()) -> flat_set; +template <_Not_allocator_for_container _Container, _Usable_allocator_for<_Container> _Alloc> +flat_set(_Container, _Alloc) + -> flat_set, _Container>; +template <_Not_allocator_for_container _Container, _Valid_compare_for_container<_Container> _Compare, + _Usable_allocator_for<_Container> _Alloc> +flat_set(_Container, _Compare, _Alloc) -> flat_set; + +template <_Not_allocator_for_container _Container, + _Valid_compare_for_container<_Container> _Compare = less> +flat_set(sorted_unique_t, _Container, _Compare = _Compare()) + -> flat_set; +template <_Not_allocator_for_container _Container, _Usable_allocator_for<_Container> _Alloc> +flat_set(sorted_unique_t, _Container, _Alloc) + -> flat_set, _Container>; +template <_Not_allocator_for_container _Container, _Valid_compare_for_container<_Container> _Compare, + _Usable_allocator_for<_Container> _Alloc> +flat_set(sorted_unique_t, _Container, _Compare, _Alloc) + -> flat_set; + +#if 1 // TRANSITION, P2582R1 (MSVC, Clang, EDG) +template _Alloc> +flat_set(flat_set<_Key, _Compare, _Container>, _Alloc) -> flat_set<_Key, _Compare, _Container>; +#endif // ^^^ workaround ^^^ + +template <_Iterator_for_container _InIt, _Not_allocator_for_container _Compare = less>> +flat_set(_InIt, _InIt, _Compare = _Compare()) -> flat_set, _Compare>; +template <_Iterator_for_container _InIt, _Not_allocator_for_container _Compare = less>> +flat_set(sorted_unique_t, _InIt, _InIt, _Compare = _Compare()) -> flat_set, _Compare>; + +// TRANSITION, CWG-2369, should just use constrained template parameters. +template <_RANGES input_range _Range, _Not_allocator_for_container _Compare = less<_RANGES range_value_t<_Range>>, + class _Alloc = allocator<_RANGES range_value_t<_Range>>, enable_if_t<_Allocator_for_container<_Alloc>, int> = 0> +flat_set(from_range_t, _Range&&, _Compare = _Compare(), _Alloc = _Alloc()) -> flat_set<_RANGES range_value_t<_Range>, + _Compare, vector<_RANGES range_value_t<_Range>, _Rebind_alloc_t<_Alloc, _RANGES range_value_t<_Range>>>>; + +// TRANSITION, CWG-2369, should just use constrained template parameters. +template <_RANGES input_range _Range, class _Alloc, enable_if_t<_Allocator_for_container<_Alloc>, int> = 0> +flat_set(from_range_t, _Range&&, _Alloc) -> flat_set<_RANGES range_value_t<_Range>, less<_RANGES range_value_t<_Range>>, + vector<_RANGES range_value_t<_Range>, _Rebind_alloc_t<_Alloc, _RANGES range_value_t<_Range>>>>; + +template > +flat_set(initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; +template > +flat_set(sorted_unique_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; + +template <_Not_allocator_for_container _Container, + _Valid_compare_for_container<_Container> _Compare = less> +flat_multiset(_Container, _Compare = _Compare()) + -> flat_multiset; +template <_Not_allocator_for_container _Container, _Usable_allocator_for<_Container> _Alloc> +flat_multiset(_Container, _Alloc) + -> flat_multiset, _Container>; +template <_Not_allocator_for_container _Container, _Valid_compare_for_container<_Container> _Compare, + _Usable_allocator_for<_Container> _Alloc> +flat_multiset(_Container, _Compare, _Alloc) -> flat_multiset; + +template <_Not_allocator_for_container _Container, + _Valid_compare_for_container<_Container> _Compare = less> +flat_multiset(sorted_equivalent_t, _Container, _Compare = _Compare()) + -> flat_multiset; +template <_Not_allocator_for_container _Container, _Usable_allocator_for<_Container> _Alloc> +flat_multiset(sorted_equivalent_t, _Container, _Alloc) + -> flat_multiset, _Container>; +template <_Not_allocator_for_container _Container, _Valid_compare_for_container<_Container> _Compare, + _Usable_allocator_for<_Container> _Alloc> +flat_multiset(sorted_equivalent_t, _Container, _Compare, _Alloc) + -> flat_multiset; + +#if 1 // TRANSITION, P2582R1 (MSVC, Clang, EDG) +template _Alloc> +flat_multiset(flat_multiset<_Key, _Compare, _Container>, _Alloc) -> flat_multiset<_Key, _Compare, _Container>; +#endif // ^^^ workaround ^^^ + +template <_Iterator_for_container _InIt, _Not_allocator_for_container _Compare = less>> +flat_multiset(_InIt, _InIt, _Compare = _Compare()) -> flat_multiset, _Compare>; +template <_Iterator_for_container _InIt, _Not_allocator_for_container _Compare = less>> +flat_multiset(sorted_equivalent_t, _InIt, _InIt, _Compare = _Compare()) -> flat_multiset, _Compare>; + +// TRANSITION, CWG-2369, should just use constrained template parameters. +template <_RANGES input_range _Range, _Not_allocator_for_container _Compare = less<_RANGES range_value_t<_Range>>, + class _Alloc = allocator<_RANGES range_value_t<_Range>>, enable_if_t<_Allocator_for_container<_Alloc>, int> = 0> +flat_multiset(from_range_t, _Range&&, _Compare = _Compare(), _Alloc = _Alloc()) + -> flat_multiset<_RANGES range_value_t<_Range>, _Compare, + vector<_RANGES range_value_t<_Range>, _Rebind_alloc_t<_Alloc, _RANGES range_value_t<_Range>>>>; + +// TRANSITION, CWG-2369, should just use constrained template parameters. +template <_RANGES input_range _Range, class _Alloc, enable_if_t<_Allocator_for_container<_Alloc>, int> = 0> +flat_multiset(from_range_t, _Range&&, _Alloc) + -> flat_multiset<_RANGES range_value_t<_Range>, less<_RANGES range_value_t<_Range>>, + vector<_RANGES range_value_t<_Range>, _Rebind_alloc_t<_Alloc, _RANGES range_value_t<_Range>>>>; + +template > +flat_multiset(initializer_list<_Key>, _Compare = _Compare()) -> flat_multiset<_Key, _Compare>; +template > +flat_multiset(sorted_equivalent_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_multiset<_Key, _Compare>; + +_STD_END + +// TRANSITION, non-_Ugly attribute tokens +#pragma pop_macro("msvc") + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) + +#endif // ^^^ _HAS_CXX23 ^^^ +#endif // _STL_COMPILER_PREPROCESSOR +#endif // _FLAT_SET_ diff --git a/stl/inc/header-units.json b/stl/inc/header-units.json index 41d0c163b53..536c2fb4990 100644 --- a/stl/inc/header-units.json +++ b/stl/inc/header-units.json @@ -71,6 +71,8 @@ "execution", "expected", "filesystem", + "flat_map", + "flat_set", "format", "forward_list", "fstream", diff --git a/stl/inc/map b/stl/inc/map index 1e7c30bc404..860d463ded8 100644 --- a/stl/inc/map +++ b/stl/inc/map @@ -384,9 +384,8 @@ template map(initializer_list>, _Alloc) -> map<_Kty, _Ty, less<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Pr = less<_Range_key_type<_Rng>>, +template <_RANGES input_range _Rng, _Not_allocator_for_container _Pr = less<_Range_key_type<_Rng>>, _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> - requires (!_Allocator_for_container<_Pr>) map(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Pr, _Alloc>; @@ -615,9 +614,8 @@ template multimap(initializer_list>, _Alloc) -> multimap<_Kty, _Ty, less<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Pr = less<_Range_key_type<_Rng>>, +template <_RANGES input_range _Rng, _Not_allocator_for_container _Pr = less<_Range_key_type<_Rng>>, _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> - requires (!_Allocator_for_container<_Pr>) multimap(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Pr, _Alloc>; diff --git a/stl/inc/set b/stl/inc/set index d78a0b88cfb..9d69548a259 100644 --- a/stl/inc/set +++ b/stl/inc/set @@ -195,9 +195,8 @@ template ::value, in set(initializer_list<_Kty>, _Alloc) -> set<_Kty, less<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Pr = less<_RANGES range_value_t<_Rng>>, +template <_RANGES input_range _Rng, _Not_allocator_for_container _Pr = less<_RANGES range_value_t<_Rng>>, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> - requires (!_Allocator_for_container<_Pr>) set(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> set<_RANGES range_value_t<_Rng>, _Pr, _Alloc>; template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> @@ -409,9 +408,8 @@ template ::value, in multiset(initializer_list<_Kty>, _Alloc) -> multiset<_Kty, less<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Pr = less<_RANGES range_value_t<_Rng>>, +template <_RANGES input_range _Rng, _Not_allocator_for_container _Pr = less<_RANGES range_value_t<_Rng>>, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> - requires (!_Allocator_for_container<_Pr>) multiset(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> multiset<_RANGES range_value_t<_Rng>, _Pr, _Alloc>; template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> diff --git a/stl/inc/unordered_map b/stl/inc/unordered_map index 2292fb3dc64..3bc38508676 100644 --- a/stl/inc/unordered_map +++ b/stl/inc/unordered_map @@ -495,9 +495,8 @@ unordered_map(initializer_list>, _Guide_size_type_t<_Alloc>, _Ha #if _HAS_CXX23 template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_Range_key_type<_Rng>>, - class _Keyeq = equal_to<_Range_key_type<_Rng>>, - _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> - requires (!_Allocator_for_container<_Keyeq>) + _Not_allocator_for_container _Keyeq = equal_to<_Range_key_type<_Rng>>, + _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> unordered_map(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Hasher, _Keyeq, _Alloc>; @@ -865,9 +864,8 @@ unordered_multimap(initializer_list>, _Guide_size_type_t<_Alloc> #if _HAS_CXX23 template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_Range_key_type<_Rng>>, - class _Keyeq = equal_to<_Range_key_type<_Rng>>, - _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> - requires (!_Allocator_for_container<_Keyeq>) + _Not_allocator_for_container _Keyeq = equal_to<_Range_key_type<_Rng>>, + _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> unordered_multimap(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Hasher, _Keyeq, _Alloc>; diff --git a/stl/inc/unordered_set b/stl/inc/unordered_set index 8b33a274f02..89c33f977cb 100644 --- a/stl/inc/unordered_set +++ b/stl/inc/unordered_set @@ -351,9 +351,8 @@ unordered_set(initializer_list<_Kty>, _Guide_size_type_t<_Alloc>, _Hasher, _Allo #if _HAS_CXX23 template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_RANGES range_value_t<_Rng>>, - class _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, - _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> - requires (!_Allocator_for_container<_Keyeq>) + _Not_allocator_for_container _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, + _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> unordered_set(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_set<_RANGES range_value_t<_Rng>, _Hasher, _Keyeq, _Alloc>; @@ -694,9 +693,8 @@ unordered_multiset(initializer_list<_Kty>, _Guide_size_type_t<_Alloc>, _Hasher, #if _HAS_CXX23 template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_RANGES range_value_t<_Rng>>, - class _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, - _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> - requires (!_Allocator_for_container<_Keyeq>) + _Not_allocator_for_container _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, + _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> unordered_multiset(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_multiset<_RANGES range_value_t<_Rng>, _Hasher, _Keyeq, _Alloc>; diff --git a/stl/inc/vector b/stl/inc/vector index 193eae34ace..5ada42b06b7 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -882,7 +882,7 @@ private: _STL_INTERNAL_CHECK(_Mylast == _My_data._Myend); // check that we have no unused capacity - const auto _Whereoff = static_cast(_Whereptr - _Myfirst); + const auto _Whereoff = _Whereptr - _Myfirst; const auto _Oldsize = static_cast(_Mylast - _Myfirst); if (_Oldsize == max_size()) { @@ -893,7 +893,7 @@ private: size_type _Newcapacity = _Calculate_growth(_Newsize); const pointer _Newvec = _STD _Allocate_at_least_helper(_Al, _Newcapacity); - const pointer _Constructed_last = _Newvec + _Whereoff + 1; + const pointer _Constructed_last = _Newvec + static_cast<_Iter_diff_t>(_Whereoff + 1); _Reallocation_guard2 _Guard{_Al, _Newvec, _Newcapacity, _Constructed_last, _Constructed_last}; auto& _Constructed_first = _Guard._Constructed_first; @@ -910,7 +910,8 @@ private: } else { // provide basic guarantee _STD _Uninitialized_move(_Myfirst, _Whereptr, _Newvec, _Al); _Constructed_first = _Newvec; - _STD _Uninitialized_move(_Whereptr, _Mylast, _Newvec + _Whereoff + 1, _Al); + _STD _Uninitialized_move( + _Whereptr, _Mylast, _Newvec + static_cast<_Iter_diff_t>(_Whereoff + 1), _Al); } _Guard._New_begin = nullptr; @@ -2075,8 +2076,8 @@ private: } _Myfirst = _Newvec; - _Mylast = _Newvec + _Newsize; - _Myend = _Newvec + _Newcapacity; + _Mylast = _Newvec + static_cast<_Iter_diff_t>(_Newsize); + _Myend = _Newvec + static_cast<_Iter_diff_t>(_Newcapacity); _ASAN_VECTOR_CREATE; } @@ -4057,6 +4058,53 @@ _CONSTEXPR20 _OutIt _Transform_vbool_aligned( #undef _ASAN_VECTOR_EXTEND_GUARD #undef _ASAN_VECTOR_RELEASE_GUARD #undef _INSERT_VECTOR_ANNOTATION + +#if _HAS_CXX23 +// This and machinery is here because is the leaf-most header included by both of them. + +_EXPORT_STD struct sorted_unique_t { + explicit sorted_unique_t() = default; +}; +_EXPORT_STD inline constexpr sorted_unique_t sorted_unique{}; + +_EXPORT_STD struct sorted_equivalent_t { + explicit sorted_equivalent_t() = default; +}; +_EXPORT_STD inline constexpr sorted_equivalent_t sorted_equivalent{}; + +template +constexpr bool _Is_vector_bool = false; +template +constexpr bool _Is_vector_bool> = true; + +template +constexpr bool _Has_guaranteed_push_back> = !is_same_v<_Ty, bool>; + +template +constexpr bool _Has_guaranteed_append_range> = !is_same_v<_Ty, bool>; + +template +concept _Usable_allocator_for = (uses_allocator_v<_Containers, _Alloc> && ...); + +template +concept _Valid_compare_for_container = _Not_allocator_for_container<_Compare> + && is_invocable_v; +#endif // ^^^ _HAS_CXX23 ^^^ + +template +struct _NODISCARD _Clear_guard { + _Ty* _Target; + + _Clear_guard& operator=(const _Clear_guard&) = delete; + _Clear_guard& operator=(_Clear_guard&&) = delete; + + ~_Clear_guard() { + if (_Target) { + _Target->clear(); + } + } +}; _STD_END #pragma pop_macro("new") diff --git a/stl/inc/xhash b/stl/inc/xhash index ef3ed86bb53..1cfd0d21afb 100644 --- a/stl/inc/xhash +++ b/stl/inc/xhash @@ -413,21 +413,6 @@ private: _Pocma(_Vec._Mypair._Get_first(), _Right._Vec._Mypair._Get_first()); } - struct _NODISCARD _Clear_guard { - _Hash* _Target; - - explicit _Clear_guard(_Hash* const _Target_) : _Target(_Target_) {} - - _Clear_guard(const _Clear_guard&) = delete; - _Clear_guard& operator=(const _Clear_guard&) = delete; - - ~_Clear_guard() { - if (_Target) { - _Target->clear(); - } - } - }; - #ifdef _ENABLE_STL_INTERNAL_CHECK struct _NODISCARD _Check_container_invariants_guard { const _Hash& _Target; @@ -507,7 +492,7 @@ public: } } else if constexpr (_Pocma_val == _Pocma_values::_No_propagate_allocators) { if (_Al != _Right_al) { - _Clear_guard _Guard{this}; + _Clear_guard<_Hash> _Guard{this}; _Traitsobj = _Right._Traitsobj; using _Adapter = _Reinterpret_move_iter; _List.template _Assign_cast<_Mutable_value_type&>( @@ -703,7 +688,7 @@ public: _Pocca_both(_Right); _Vec_proxy._Bind(_Alproxy, _STD addressof(_Vec._Mypair._Myval2)); - _Clear_guard _Guard{this}; + _Clear_guard<_Hash> _Guard{this}; _Traitsobj = _Right._Traitsobj; _List.template _Assign_cast<_Mutable_value_type&>( _Right._List._Unchecked_begin(), _Right._List._Unchecked_end()); @@ -714,7 +699,7 @@ public: } } - _Clear_guard _Guard{this}; + _Clear_guard<_Hash> _Guard{this}; _Traitsobj = _Right._Traitsobj; _Pocca_both(_Right); _List.template _Assign_cast<_Mutable_value_type&>( @@ -1661,7 +1646,7 @@ protected: _Mask = _Buckets - 1; _Maxidx = _Buckets; - _Clear_guard _Guard{this}; + _Clear_guard<_Hash> _Guard{this}; _Unchecked_iterator _Inserted = _Unchecked_begin(); @@ -1898,7 +1883,7 @@ protected: // For constraining deduction guides (N4981 [unord.req.general]/248.3) #if _HAS_CXX23 template -concept _Hasher_for_container = !integral<_Hasher> && !_Allocator_for_container<_Hasher>; +concept _Hasher_for_container = !integral<_Hasher> && _Not_allocator_for_container<_Hasher>; template using _Is_hasher = bool_constant<_Hasher_for_container<_Hasher>>; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 2e86091d9d0..4bdb8fed77a 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -792,6 +792,9 @@ constexpr bool _Is_simple_alloc_v = && is_same_v::pointer, typename _Alloc::value_type*> && is_same_v::const_pointer, const typename _Alloc::value_type*>; +// SCARY iterators are permitted but not required by the Standard. See: +// N2911 Minimizing Dependencies Within Generic Classes For Faster And Smaller Programs +// N2980 SCARY Iterator Assignment And Initialization template struct _Simple_types { // wraps types from allocators with simple addressing for use in iterators // and other SCARY machinery @@ -2760,6 +2763,16 @@ namespace ranges { elements_of(_Rng&&, _Alloc) -> elements_of<_Rng&&, _Alloc>; #endif // ^^^ !defined(__cpp_lib_byte) ^^^ } // namespace ranges + +template +constexpr bool _Has_guaranteed_push_back = false; // N5032 [sequence.reqmts]/104, /108; used by flat_(multi)map::insert. + +// N5032 [container.reqmts]/66.1; used by various flat_(multi)set inserting functions. +template +constexpr bool _Has_guaranteed_single_insertion = _Has_guaranteed_push_back<_Ty>; + +template +constexpr bool _Has_guaranteed_append_range = false; // N5032 [sequence.reqmts]/112; used by flat_(multi)set::insert. #endif // _HAS_CXX23 template diff --git a/stl/inc/xstring b/stl/inc/xstring index 5952e6c47d7..1617a4aa381 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -3236,6 +3236,12 @@ private: #pragma warning(pop) +#if _HAS_CXX23 +template +constexpr bool _Equivalence_is_equality_impl> = + _Is_implementation_handled_char_traits<_Traits>; +#endif // _HAS_CXX23 + #if _HAS_CXX17 template >, enable_if_t, _Is_allocator<_Alloc>>, int> = 0> @@ -3622,6 +3628,11 @@ namespace pmr { _EXPORT_STD using wstring = basic_string; } // namespace pmr #endif // _HAS_CXX17 + +#if _HAS_CXX23 +template +constexpr bool _Has_guaranteed_push_back> = true; +#endif // _HAS_CXX23 _STD_END #undef _ASAN_STRING_REMOVE diff --git a/stl/inc/xutility b/stl/inc/xutility index afa828543e4..4394169e352 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1677,6 +1677,9 @@ concept _Allocator_for_container = requires(_Ty& _Alloc) { _Alloc.deallocate(_Alloc.allocate(size_t{1}), size_t{1}); }; +template +concept _Not_allocator_for_container = !_Allocator_for_container<_Ty>; + template struct _Is_allocator : bool_constant<_Allocator_for_container<_Ty>> {}; #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv @@ -7776,12 +7779,12 @@ _EXPORT_STD template _NODISCARD _CONSTEXPR20 _FwdIt lower_bound(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val, _Pr _Pred) { // find first element not before _Val _STD _Adl_verify_range(_First, _Last); - auto _UFirst = _STD _Get_unwrapped(_First); - _Iter_diff_t<_FwdIt> _Count = _STD distance(_UFirst, _STD _Get_unwrapped(_Last)); + auto _UFirst = _STD _Get_unwrapped(_First); + auto _Count = _STD distance(_UFirst, _STD _Get_unwrapped(_Last)); while (0 < _Count) { // divide and conquer, find half that contains answer - const _Iter_diff_t<_FwdIt> _Count2 = _Count / 2; - const auto _UMid = _STD next(_UFirst, _Count2); + const auto _Count2 = static_cast(_Count / 2); + const auto _UMid = _STD next(_UFirst, _Count2); if (_Pred(*_UMid, _Val)) { // try top half _UFirst = _STD _Next_iter(_UMid); _Count -= _Count2 + 1; @@ -7804,12 +7807,12 @@ _EXPORT_STD template _NODISCARD _CONSTEXPR20 _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr _Pred) { // find first element that _Val is before _STD _Adl_verify_range(_First, _Last); - auto _UFirst = _STD _Get_unwrapped(_First); - _Iter_diff_t<_FwdIt> _Count = _STD distance(_UFirst, _STD _Get_unwrapped(_Last)); + auto _UFirst = _STD _Get_unwrapped(_First); + auto _Count = _STD distance(_UFirst, _STD _Get_unwrapped(_Last)); while (0 < _Count) { // divide and conquer, find half that contains answer - _Iter_diff_t<_FwdIt> _Count2 = _Count / 2; - const auto _UMid = _STD next(_UFirst, _Count2); + const auto _Count2 = static_cast(_Count / 2); + const auto _UMid = _STD next(_UFirst, _Count2); if (_Pred(_Val, *_UMid)) { _Count = _Count2; } else { // try top half @@ -7955,6 +7958,16 @@ _NODISCARD constexpr bool _Mul_overflow(const _Int _Left, const _Int _Right, _In } #endif // _HAS_CXX17 +#if _HAS_CXX23 +template +constexpr bool _Equivalence_is_equality_impl = is_integral_v<_Ty> || is_pointer_v<_Ty>; + +// For ranges::less and ranges::greater, see N5032 [range.cmp]/9, [concept.totallyordered]/1.1, [cmp.concept]/1.2. +template +constexpr bool _Equivalence_is_equality = + _Is_any_of_v<_Compare, _RANGES less, _RANGES greater> + || (_Is_any_of_v<_Compare, less<>, less<_Key>, greater<>, greater<_Key>> && _Equivalence_is_equality_impl<_Key>); +#endif // _HAS_CXX23 _STD_END // TRANSITION, non-_Ugly attribute tokens diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 705a144947d..7550a613043 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -326,6 +326,7 @@ // P0288R9 move_only_function // P0323R12 // P0401R6 Providing Size Feedback In The Allocator Interface +// P0429R9 // P0448R4 // P0627R6 unreachable() // P0798R8 Monadic Operations For optional @@ -336,6 +337,7 @@ // P1132R7 out_ptr(), inout_ptr() // P1147R1 Printing volatile Pointers // P1206R7 Conversions From Ranges To Containers +// P1222R4 // P1223R5 ranges::find_last, ranges::find_last_if, ranges::find_last_if_not // P1272R4 byteswap() // P1328R1 constexpr type_info::operator==() @@ -402,6 +404,7 @@ // P3142R0 Printing Blank Lines With println() // P3235R3 std::print More Types Faster With Less Memory // (partial implementation; see GH-4924) +// P3567R2 flat_meow Fixes // Parallel Algorithms Notes // C++ allows an implementation to implement parallel algorithms as calls to the serial algorithms. @@ -1756,6 +1759,8 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_constexpr_typeinfo 202106L #define __cpp_lib_containers_ranges 202202L #define __cpp_lib_expected 202211L +#define __cpp_lib_flat_map 202511L +#define __cpp_lib_flat_set 202511L #define __cpp_lib_format_ranges 202207L #define __cpp_lib_formatters 202302L #define __cpp_lib_forward_like 202207L diff --git a/stl/modules/std.ixx b/stl/modules/std.ixx index d582fc80db7..00b289b5c3c 100644 --- a/stl/modules/std.ixx +++ b/stl/modules/std.ixx @@ -123,6 +123,8 @@ export module std; #if _HAS_CXX23 #include +#include +#include #include #include #include diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index a86a113444f..fdc601ae792 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -247,181 +247,6 @@ std/input.output/syncstream/osyncstream/thread/several_threads.pass.cpp:1 SKIPPE std/depr/depr.c.headers/uchar_h.compile.pass.cpp FAIL std/strings/c.strings/cuchar.compile.pass.cpp FAIL -# P0429R9 -std/containers/container.adaptors/flat.map.syn/sorted_equivalent.pass.cpp FAIL -std/containers/container.adaptors/flat.map.syn/sorted_unique.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.access/at_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.access/at.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.access/index_key.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.access/index_rv_key.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.access/index_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.capacity/empty.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.capacity/max_size.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.capacity/size.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/assign_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/compare.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/containers.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/copy_alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/copy_assign.addressof.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/copy_assign.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/copy.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/deduct_pmr.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/deduct.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/deduct.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/default_noexcept.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/default.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/dtor_noexcept.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/move_alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/move_assign_clears.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/move_assign_noexcept.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/move_assign.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/move_exceptions.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/move_noexcept.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/move.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/pmr.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/range.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/sorted_container.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/sorted_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.cons/sorted_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.erasure/erase_if_exceptions.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.erasure/erase_if.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.iterators/iterator_comparison.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.iterators/iterator_concept_conformance.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.iterators/iterator.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.iterators/range_concept_conformance.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.iterators/reverse_iterator.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/clear.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/emplace_hint.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/emplace.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/erase_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/erase_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/erase_key_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/erase_key.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/extract.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_cv.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_iter_cv.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_iter_rv.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_or_assign_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_or_assign.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_rv.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_sorted_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_sorted_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/replace.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_free.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_member.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/try_emplace_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.modifiers/try_emplace.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.observers/keys_values.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/contains_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/contains.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/count_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/count.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/equal_range_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/equal_range.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/find_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/find.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/lower_bound_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/lower_bound.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/upper_bound_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.map/flat.map.operations/upper_bound.pass.cpp FAIL -std/containers/container.adaptors/flat.map/incomplete_type.pass.cpp FAIL -std/containers/container.adaptors/flat.map/op_compare.pass.cpp FAIL -std/containers/container.adaptors/flat.map/robust_against_nonbool.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.map/types.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/empty.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/max_size.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/size.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/assign_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/compare.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/containers.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_assign.addressof.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy_assign.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/copy.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct_pmr.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default_noexcept.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/default.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/dtor_noexcept.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_clears.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign_noexcept.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_assign.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_exceptions.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_noexcept.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/pmr.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/range.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_container.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.cons/sorted_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.erasure/erase_if_exceptions.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.erasure/erase_if.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_concept_conformance.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/range_concept_conformance.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/reverse_iterator.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/clear.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace_hint.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/emplace.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/extract.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_cv.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_cv.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_rv.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_rv.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_sorted_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/replace.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.observers/keys_values.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/incomplete_type.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/op_compare.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/robust_against_nonbool.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multimap/types.compile.pass.cpp FAIL -std/language.support/support.limits/support.limits.general/flat_map.version.compile.pass.cpp FAIL -std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtmap/format.functions.format.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtmap/format.functions.vformat.pass.cpp FAIL - # P0533R9 constexpr For And std/language.support/support.limits/support.limits.general/cmath.version.compile.pass.cpp FAIL std/language.support/support.limits/support.limits.general/cstdlib.version.compile.pass.cpp FAIL @@ -439,152 +264,6 @@ std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp FAIL std/numerics/numeric.ops/numeric.ops.sat/sub_sat.compile.pass.cpp FAIL std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp FAIL -# P1222R4 -std/containers/container.adaptors/flat.multiset/flat.multiset.capacity/empty.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.capacity/max_size.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.capacity/size.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/assign_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/compare.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/containers.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/copy_alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/copy_assign.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/copy.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/deduct_pmr.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/deduct.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/deduct.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/default.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/dtor_noexcept.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/move_alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/move_assign.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/move.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/pmr.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/range.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/sorted_container.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/sorted_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.cons/sorted_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.erasure/erase_if_exceptions.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.erasure/erase_if.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.iterators/iterator_comparison.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.iterators/iterator_concept_conformance.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.iterators/iterator.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.iterators/range_concept_conformance.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.iterators/reverse_iterator.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/clear.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/emplace_hint.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/emplace.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/erase_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/erase_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/erase_key_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/erase_key.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/extract.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_cv.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_iter_cv.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_iter_rv.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_rv.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_sorted_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_sorted_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/replace.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_free.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_member.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.observers/comp.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/contains_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/contains.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/count_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/count.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/equal_range_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/equal_range.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/find_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/find.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/lower_bound_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/lower_bound.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/upper_bound_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/flat.multiset.operations/upper_bound.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/incomplete_type.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/op_compare.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/robust_against_nonbool.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.multiset/types.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.capacity/empty.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.capacity/size.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/assign_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/compare.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/containers.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/copy_alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/copy_assign.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/copy.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/deduct_pmr.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/deduct.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/deduct.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/default.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/dtor_noexcept.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/move_alloc.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/move_assign.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/pmr.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/range.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/sorted_container.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/sorted_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.cons/sorted_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if_exceptions.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.erasure/erase_if.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_concept_conformance.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.iterators/iterator.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.iterators/range_concept_conformance.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.iterators/reverse_iterator.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/clear.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace_hint.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/emplace.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_cv.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_cv.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_rv.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_rv.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_initializer_list.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_sorted_iter_iter.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/replace.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/contains.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/count.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/equal_range.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/find.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp FAIL -std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound.pass.cpp FAIL -std/containers/container.adaptors/flat.set/incomplete_type.pass.cpp FAIL -std/containers/container.adaptors/flat.set/op_compare.pass.cpp FAIL -std/containers/container.adaptors/flat.set/robust_against_nonbool.compile.pass.cpp FAIL -std/containers/container.adaptors/flat.set/types.compile.pass.cpp FAIL -std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp FAIL - # P1789R3 Library Support For Expansion Statements # Add 'std-at-least-c++26' to tests/utils/stl/test/tests.py when beginning work on C++26. std/utilities/intseq/intseq.binding/structured_binding.pass.cpp FAIL @@ -639,6 +318,140 @@ std/utilities/optional/optional.iterator/iterator.pass.cpp FAIL std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp:0 FAIL std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp:1 FAIL +# MSVC has not implemented P2448R2 "Relaxing some constexpr restrictions" +std/containers/container.adaptors/flat.map/flat.map.access/at_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.access/at_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.access/index_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.access/index_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.capacity/max_size.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.capacity/max_size.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.iterators/iterator.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.iterators/iterator.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/erase_key_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/erase_key_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/extract.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/extract.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_iter_iter.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_iter_iter.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_or_assign_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_or_assign_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_rv.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_rv.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/try_emplace_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.modifiers/try_emplace_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/contains_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/contains_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/count_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/count_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/equal_range_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/equal_range_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/find_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/find_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/lower_bound_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/lower_bound_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/upper_bound_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/flat.map.operations/upper_bound_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.map/op_compare.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.map/op_compare.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/max_size.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.capacity/max_size.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/erase_key_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/extract.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/extract.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_iter.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_iter_iter.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_rv.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_rv.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/contains_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/count_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/equal_range_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/find_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/lower_bound_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.operations/upper_bound_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.capacity/max_size.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.capacity/max_size.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/erase_key_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/erase_key_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/extract.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/extract.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_iter_iter.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_iter_iter.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.observers/comp.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.observers/comp.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/contains_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/contains_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/count_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/count_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/equal_range_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/equal_range_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/find_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/find_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/lower_bound_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/lower_bound_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/upper_bound_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/flat.multiset.operations/upper_bound_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.multiset/op_compare.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.multiset/op_compare.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.capacity/max_size.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/extract.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_iter_iter.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.observers/comp.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/contains_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/count_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/equal_range_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/find_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/lower_bound_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/flat.set.operations/upper_bound_transparent.pass.cpp:1 FAIL +std/containers/container.adaptors/flat.set/op_compare.pass.cpp:0 FAIL +std/containers/container.adaptors/flat.set/op_compare.pass.cpp:1 FAIL + # *** MISSING LWG ISSUE RESOLUTIONS *** # LWG-2532 "Satisfying a promise at thread exit" (Open) @@ -984,6 +797,11 @@ std/time/time.clock/time.clock.file/to_from_sys.pass.cpp FAIL # libc++'s filesystem::path::iterator models bidirectional_iterator, which is not guaranteed by the Standard std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp FAIL +# MSVC's STL and libc++ speculatively implement LWG-2227 (not yet resolved) in different ways. +# static_assert(!std::is_nothrow_move_constructible_v) with C = std::flat_(multi)map +std/containers/container.adaptors/flat.map/flat.map.cons/move_noexcept.pass.cpp FAIL +std/containers/container.adaptors/flat.multimap/flat.multimap.cons/move_noexcept.pass.cpp FAIL + # libc++ speculatively implemented an old proposed resolution for LWG-3645. # This test is bogus according to the wording that was ultimately accepted for C++23. std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp FAIL diff --git a/tests/std/include/test_container_requirements.hpp b/tests/std/include/test_container_requirements.hpp new file mode 100644 index 00000000000..43f18fc1eb3 --- /dev/null +++ b/tests/std/include/test_container_requirements.hpp @@ -0,0 +1,207 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +// Extracted common functionality from flat_map and flat_set tests. +// May be extended for other containers if needed. + +template +void assert_container_requirements(const T& s) { + T m = s; + assert(m == s); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_convertible_v); + static_assert(std::is_same_v m.end()), std::strong_ordering>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v + || std::is_same_v); + static_assert(std::is_same_v); + + T my_moved = std::move(m); + assert(!(my_moved != s)); + + T my_empty{}; + assert(my_empty.empty()); + + T non_empty = s; + my_empty.swap(non_empty); + assert(non_empty.empty()); + assert(my_empty == s); + + std::swap(my_empty, non_empty); + assert(my_empty.empty()); + assert(non_empty == s); + + assert(s.cbegin() <= s.cend()); + assert((s.cbegin() < s.cend()) == !s.empty()); + + assert(m.begin() <= m.end()); + assert((m.begin() < m.end()) == !m.empty()); + + assert(static_cast(s.cend() - s.cbegin()) == s.size()); +} + +template +void assert_reversible_container_requirements(const T& s) { + static_assert(std::is_same_v, typename T::reverse_iterator>); + static_assert( + std::is_same_v, typename T::const_reverse_iterator>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_convertible_v); +} + +template +concept map_has_nothrow_swappable_containers = requires { + typename T::key_container_type; + typename T::mapped_container_type; + requires std::is_nothrow_swappable_v; + requires std::is_nothrow_swappable_v; +}; + +template +concept set_has_nothrow_swappable_containers = requires { + typename T::container_type; + requires std::is_nothrow_swappable_v; +}; + +template +concept has_nothrow_swappable_containers = + set_has_nothrow_swappable_containers || map_has_nothrow_swappable_containers; + +template +void assert_noexcept_requirements(T& s) { + static_assert(noexcept(s.begin())); + static_assert(noexcept(s.end())); + static_assert(noexcept(s.cbegin())); + static_assert(noexcept(s.cend())); + static_assert(noexcept(s.rbegin())); + static_assert(noexcept(s.rend())); + static_assert(noexcept(s.crbegin())); + static_assert(noexcept(s.crend())); + + static_assert(noexcept(s.empty())); + static_assert(noexcept(s.size())); + static_assert(noexcept(s.max_size())); + + if constexpr (!std::is_const_v) { + constexpr bool is_noexcept = + has_nothrow_swappable_containers && std::is_nothrow_swappable_v; + static_assert(noexcept(s.swap(s)) == is_noexcept); + static_assert(noexcept(std::ranges::swap(s, s)) == is_noexcept); // using ADL-swap + static_assert(noexcept(s.clear())); + } +} + +template +void assert_is_sorted_maybe_unique(const T& s) { + const auto val_comp = s.value_comp(); + const auto begin_it = s.cbegin(); + const auto end_it = s.cend(); + + // internal check by the container itself + assert(s._Is_sorted_maybe_unique()); + + // external check observable by the user + assert(std::is_sorted(begin_it, end_it, val_comp)); + if constexpr (ExpectedUnique) { + const auto not_comp = [&](const auto& left, const auto& right) { return !val_comp(left, right); }; + const bool is_unique = std::adjacent_find(begin_it, end_it, not_comp) == end_it; + + if constexpr (std::formattable) { + if (!is_unique) { + std::println("Container {} is not unique", s); + } + } + assert(is_unique); + } +} + +template +void assert_set_requirements() { + using iterator = T::iterator; + using const_iterator = T::const_iterator; + using key_type = T::key_type; + using value_type = T::value_type; + using reference = T::reference; + using const_reference = T::const_reference; + + static_assert(std::same_as, const_iterator>); + static_assert(std::is_convertible_v); + + // additionally: + static_assert(std::is_same_v); + static_assert(std::same_as, iterator>); + static_assert(std::is_convertible_v); + static_assert(std::is_same_v().begin()), const value_type&>); + static_assert(std::is_same_v, value_type>); + static_assert(std::is_same_v); +} + +template +void assert_map_requirements() { + using iterator = T::iterator; + using const_iterator = T::const_iterator; + using key_type = T::key_type; + using value_type = T::value_type; + using mapped_type = T::mapped_type; + + static_assert(std::same_as, const_iterator>); + static_assert(std::is_convertible_v); + + // additionally: + static_assert(std::is_same_v>); +} + +template +void assert_three_way_comparability() { + using value_type = T::value_type; + if constexpr (std::three_way_comparable) { + static_assert(std::three_way_comparable); + } +} + +class key_comparator { +private: + static const auto& extract_key(const auto& obj) { + if constexpr (requires { obj.key; }) { + return obj.key; + } else { + return obj; + } + } + +public: + bool operator()(const auto& lhs, const auto& rhs) const { + return extract_key(lhs) < extract_key(rhs); + } + + using is_transparent = int; +}; diff --git a/tests/std/include/test_header_units_and_modules.hpp b/tests/std/include/test_header_units_and_modules.hpp index df85f9439e5..71aaf6a6632 100644 --- a/tests/std/include/test_header_units_and_modules.hpp +++ b/tests/std/include/test_header_units_and_modules.hpp @@ -240,6 +240,56 @@ void test_filesystem() { assert(info.capacity != static_cast(-1)); } +#if TEST_STANDARD >= 23 +void test_flat_map() { + using namespace std; + puts("Testing ."); + + [[maybe_unused]] constexpr sorted_unique_t unique_tag = sorted_unique; + [[maybe_unused]] constexpr sorted_equivalent_t equivalent_tag = sorted_equivalent; + + constexpr auto simple_truth = [](const auto&) { return true; }; + + flat_map fm; + fm.emplace(42, 172); + fm.emplace(42, 729); + assert(fm.size() == 1); + assert(erase_if(fm, simple_truth) == 1); + assert(fm.empty()); + + flat_multimap fmm; + fmm.emplace(42, 172); + fmm.emplace(42, 729); + assert(fmm.size() == 2); + assert(erase_if(fmm, simple_truth) == 2); + assert(fmm.empty()); +} + +void test_flat_set() { + using namespace std; + puts("Testing ."); + + [[maybe_unused]] constexpr sorted_unique_t unique_tag = sorted_unique; + [[maybe_unused]] constexpr sorted_equivalent_t equivalent_tag = sorted_equivalent; + + constexpr auto simple_truth = [](const auto&) { return true; }; + + flat_set fs; + fs.emplace(42); + fs.emplace(42); + assert(fs.size() == 1); + assert(erase_if(fs, simple_truth) == 1); + assert(fs.empty()); + + flat_multiset fms; + fms.emplace(42); + fms.emplace(42); + assert(fms.size() == 2); + assert(erase_if(fms, simple_truth) == 2); + assert(fms.empty()); +} +#endif // TEST_STANDARD >= 23 + void test_format() { using namespace std; puts("Testing ."); @@ -1193,6 +1243,10 @@ void all_cpp_header_tests() { test_expected(); #endif // TEST_STANDARD >= 23 test_filesystem(); +#if TEST_STANDARD >= 23 + test_flat_map(); + test_flat_set(); +#endif // TEST_STANDARD >= 23 test_format(); test_forward_list(); test_fstream(); diff --git a/tests/std/test.lst b/tests/std/test.lst index 85d7fde5fe5..5cd8523d0c6 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -381,6 +381,8 @@ tests\P0408R7_efficient_access_to_stringbuf_buffer tests\P0414R2_shared_ptr_for_arrays tests\P0415R1_constexpr_complex tests\P0426R1_constexpr_char_traits +tests\P0429R9_flat_map +tests\P0429R9_flat_map_ms_specific tests\P0433R2_deduction_guides tests\P0448R4_iosfwd tests\P0448R4_spanstream @@ -618,6 +620,7 @@ tests\P1206R7_vector_from_range tests\P1206R7_vector_insert_range tests\P1208R6_source_location tests\P1209R0_erase_if_erase +tests\P1222R4_flat_set tests\P1223R5_ranges_alg_find_last tests\P1223R5_ranges_alg_find_last_if tests\P1223R5_ranges_alg_find_last_if_not diff --git a/tests/std/tests/Dev10_709168_marking_iterators_as_checked/test.compile.pass.cpp b/tests/std/tests/Dev10_709168_marking_iterators_as_checked/test.compile.pass.cpp index 4a4b9435c9a..e137800b970 100644 --- a/tests/std/tests/Dev10_709168_marking_iterators_as_checked/test.compile.pass.cpp +++ b/tests/std/tests/Dev10_709168_marking_iterators_as_checked/test.compile.pass.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -109,6 +111,14 @@ STATIC_ASSERT(stl_checked == _Range_verifiable_v::iterator>); STATIC_ASSERT(stl_checked == _Range_verifiable_v::reverse_iterator>); #endif // _HAS_CXX20 +#if _HAS_CXX23 +// Checks for flat_set should trivially pass since it directly uses the underlying container's iterator +STATIC_ASSERT(stl_checked == _Range_verifiable_v::iterator>); +STATIC_ASSERT(stl_checked == _Range_verifiable_v::reverse_iterator>); +STATIC_ASSERT(stl_checked == _Range_verifiable_v::iterator>); +STATIC_ASSERT(stl_checked == _Range_verifiable_v::reverse_iterator>); +#endif // _HAS_CXX23 + STATIC_ASSERT(!_Range_verifiable_v<::DerivedFrom>); STATIC_ASSERT(!_Range_verifiable_v<::DerivedFrom>); STATIC_ASSERT(!_Range_verifiable_v<::DerivedFrom>); @@ -181,6 +191,13 @@ STATIC_ASSERT(!_Range_verifiable_v<::DerivedFrom::iterator>>); STATIC_ASSERT(!_Range_verifiable_v<::DerivedFrom::reverse_iterator>>); #endif // _HAS_CXX20 +#if _HAS_CXX23 +STATIC_ASSERT(!_Range_verifiable_v<::DerivedFrom::iterator>>); +STATIC_ASSERT(!_Range_verifiable_v<::DerivedFrom::reverse_iterator>>); +STATIC_ASSERT(!_Range_verifiable_v<::DerivedFrom::iterator>>); +STATIC_ASSERT(!_Range_verifiable_v<::DerivedFrom::reverse_iterator>>); +#endif // _HAS_CXX23 + template constexpr bool test_unwrappable() { STATIC_ASSERT(_Unwrappable_v == Expected); @@ -394,6 +411,13 @@ STATIC_ASSERT(test_unwrappable_for_unverified::iterator, !stl_checked> STATIC_ASSERT(test_unwrappable_for_unverified::reverse_iterator, !stl_checked>()); #endif // _HAS_CXX20 +#if _HAS_CXX23 +STATIC_ASSERT(test_unwrappable_for_unverified::iterator, !stl_checked>()); +STATIC_ASSERT(test_unwrappable_for_unverified::reverse_iterator, !stl_checked>()); +STATIC_ASSERT(test_unwrappable_for_unverified::iterator, !stl_checked>()); +STATIC_ASSERT(test_unwrappable_for_unverified::reverse_iterator, !stl_checked>()); +#endif // _HAS_CXX23 + STATIC_ASSERT(test_unwrappable()); STATIC_ASSERT(test_unwrappable()); STATIC_ASSERT(test_unwrappable()); @@ -467,6 +491,13 @@ STATIC_ASSERT(test_unwrappable::iterator, true>()); STATIC_ASSERT(test_unwrappable::reverse_iterator, true>()); #endif // _HAS_CXX20 +#if _HAS_CXX23 +STATIC_ASSERT(test_unwrappable::iterator, true>()); +STATIC_ASSERT(test_unwrappable::reverse_iterator, true>()); +STATIC_ASSERT(test_unwrappable::iterator, true>()); +STATIC_ASSERT(test_unwrappable::reverse_iterator, true>()); +#endif // _HAS_CXX23 + STATIC_ASSERT(test_unwrappable_for_offset()); STATIC_ASSERT(test_unwrappable_for_offset()); STATIC_ASSERT(test_unwrappable_for_offset()); @@ -540,6 +571,13 @@ STATIC_ASSERT(test_unwrappable_for_offset::iterator, true>()); STATIC_ASSERT(test_unwrappable_for_offset::reverse_iterator, true>()); #endif // _HAS_CXX20 +#if _HAS_CXX23 +STATIC_ASSERT(test_unwrappable_for_offset::iterator, true>()); +STATIC_ASSERT(test_unwrappable_for_offset::reverse_iterator, true>()); +STATIC_ASSERT(test_unwrappable_for_offset::iterator, true>()); +STATIC_ASSERT(test_unwrappable_for_offset::reverse_iterator, true>()); +#endif // _HAS_CXX23 + STATIC_ASSERT(test_unwrappable_for_unverified<::DerivedFrom, false>()); STATIC_ASSERT(test_unwrappable_for_unverified<::DerivedFrom, false>()); STATIC_ASSERT(test_unwrappable_for_unverified<::DerivedFrom, false>()); @@ -612,6 +650,13 @@ STATIC_ASSERT(test_unwrappable_for_unverified<::DerivedFrom::iterator> STATIC_ASSERT(test_unwrappable_for_unverified<::DerivedFrom::reverse_iterator>, false>()); #endif // _HAS_CXX20 +#if _HAS_CXX23 +STATIC_ASSERT(test_unwrappable_for_unverified<::DerivedFrom::iterator>, false>()); +STATIC_ASSERT(test_unwrappable_for_unverified<::DerivedFrom::reverse_iterator>, false>()); +STATIC_ASSERT(test_unwrappable_for_unverified<::DerivedFrom::iterator>, false>()); +STATIC_ASSERT(test_unwrappable_for_unverified<::DerivedFrom::reverse_iterator>, false>()); +#endif // _HAS_CXX23 + STATIC_ASSERT(test_unwrappable<::DerivedFrom, false>()); STATIC_ASSERT(test_unwrappable<::DerivedFrom, false>()); STATIC_ASSERT(test_unwrappable<::DerivedFrom, false>()); @@ -684,6 +729,13 @@ STATIC_ASSERT(test_unwrappable<::DerivedFrom::iterator>, false>()); STATIC_ASSERT(test_unwrappable<::DerivedFrom::reverse_iterator>, false>()); #endif // _HAS_CXX20 +#if _HAS_CXX23 +STATIC_ASSERT(test_unwrappable<::DerivedFrom::iterator>, false>()); +STATIC_ASSERT(test_unwrappable<::DerivedFrom::reverse_iterator>, false>()); +STATIC_ASSERT(test_unwrappable<::DerivedFrom::iterator>, false>()); +STATIC_ASSERT(test_unwrappable<::DerivedFrom::reverse_iterator>, false>()); +#endif // _HAS_CXX23 + STATIC_ASSERT(test_unwrappable_for_offset<::DerivedFrom, false>()); STATIC_ASSERT(test_unwrappable_for_offset<::DerivedFrom, false>()); STATIC_ASSERT(test_unwrappable_for_offset<::DerivedFrom, false>()); @@ -755,3 +807,10 @@ STATIC_ASSERT(test_unwrappable_for_offset<::DerivedFrom::iterator>, false>()); STATIC_ASSERT(test_unwrappable_for_offset<::DerivedFrom::reverse_iterator>, false>()); #endif // _HAS_CXX20 + +#if _HAS_CXX23 +STATIC_ASSERT(test_unwrappable_for_offset<::DerivedFrom::iterator>, false>()); +STATIC_ASSERT(test_unwrappable_for_offset<::DerivedFrom::reverse_iterator>, false>()); +STATIC_ASSERT(test_unwrappable_for_offset<::DerivedFrom::iterator>, false>()); +STATIC_ASSERT(test_unwrappable_for_offset<::DerivedFrom::reverse_iterator>, false>()); +#endif // _HAS_CXX23 diff --git a/tests/std/tests/Dev11_0437519_container_requirements/test.compile.pass.cpp b/tests/std/tests/Dev11_0437519_container_requirements/test.compile.pass.cpp index 4cfa84a262e..d391f30b16c 100644 --- a/tests/std/tests/Dev11_0437519_container_requirements/test.compile.pass.cpp +++ b/tests/std/tests/Dev11_0437519_container_requirements/test.compile.pass.cpp @@ -13,7 +13,7 @@ // A brief overview of the contents of this file: // // The first 650 lines or so of this file (everything up to the first use of DEFINE_TEST) are test -// utilities: stub allocators, comparers, and other kinds of types with which we can instantiate +// utilities: stub allocators, comparators, and other kinds of types with which we can instantiate // containers; test types that define a restricted set of operations; and a set of container traits // classes that unify the interfaces for the containers so we can use a common set of tests for // them (these traits also define a few useful properties for each container so we know what to @@ -1678,7 +1678,7 @@ NOT_SUPPORTED_SPECIALIZATION(test_ordered_associative_typedefs_for_maps, tag_mul NOT_SUPPORTED_SPECIALIZATION(test_ordered_associative_typedefs_for_maps, tag_set); -DEFINE_TEST(test_ordered_associative_default_constructor_with_comparer, +DEFINE_TEST(test_ordered_associative_default_constructor_with_comparator, { // X(c) and X a(c); // Requires: key_compare is CopyConstructible @@ -1710,13 +1710,13 @@ DEFINE_TEST(test_ordered_associative_default_constructor_with_comparer, }); -DEFINE_TEST(test_ordered_associative_range_constructor_with_comparer, { +DEFINE_TEST(test_ordered_associative_range_constructor_with_comparator, { // SPEC: These are the only two operations for which traits are specified for key_compare, but // there are many other operations for which key_compare must meet other requirements (e.g. a // call to a.key_comp() necessitates that the key_comp type is move constructible. // - // In the rest of the tests, I have assumed std::less for the comparer, which meets any possible - // requirements, but it should be considered whether the comparer requirements should be more + // In the rest of the tests, I have assumed std::less for the comparator, which meets any possible + // requirements, but it should be considered whether the comparator requirements should be more // thoroughly specified. std::move_iterator> i; @@ -1746,7 +1746,7 @@ DEFINE_TEST(test_ordered_associative_initializer_list_assign, { }); -DEFINE_TEST(test_ordered_associative_comparers, { +DEFINE_TEST(test_ordered_associative_comparators, { // a.key_comp() // [No Requires clause] c_of_erasable const a; @@ -1926,10 +1926,10 @@ struct check_all_ordered_associative_requirements { check_all_ordered_associative_requirements() { test_ordered_associative_typedefs(); test_ordered_associative_typedefs_for_maps(); - test_ordered_associative_default_constructor_with_comparer(); - test_ordered_associative_range_constructor_with_comparer(); + test_ordered_associative_default_constructor_with_comparator(); + test_ordered_associative_range_constructor_with_comparator(); test_ordered_associative_initializer_list_assign(); - test_ordered_associative_comparers(); + test_ordered_associative_comparators(); test_ordered_associative_emplace(); test_ordered_associative_insert(); test_ordered_associative_erase(); diff --git a/tests/std/tests/GH_000545_include_compare/test.cpp b/tests/std/tests/GH_000545_include_compare/test.cpp index 9bba56a9318..021c62debea 100644 --- a/tests/std/tests/GH_000545_include_compare/test.cpp +++ b/tests/std/tests/GH_000545_include_compare/test.cpp @@ -6,6 +6,8 @@ void test_chrono(); void test_coroutine(); void test_deque(); void test_filesystem(); +void test_flat_map(); +void test_flat_set(); void test_forward_list(); void test_iterator(); void test_list(); @@ -36,6 +38,8 @@ int main() { test_coroutine(); test_deque(); test_filesystem(); + test_flat_map(); + test_flat_set(); test_forward_list(); test_iterator(); test_list(); diff --git a/tests/std/tests/GH_000545_include_compare/test_flat_map.cpp b/tests/std/tests/GH_000545_include_compare/test_flat_map.cpp new file mode 100644 index 00000000000..b7a050857aa --- /dev/null +++ b/tests/std/tests/GH_000545_include_compare/test_flat_map.cpp @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#if _HAS_CXX23 + +#include + +// Testing LWG-3330 "Include from most library headers" by intentionally NOT including + +static_assert(std::is_eq(std::partial_ordering::equivalent)); + +#endif // _HAS_CXX23 + +void test_flat_map() {} diff --git a/tests/std/tests/GH_000545_include_compare/test_flat_set.cpp b/tests/std/tests/GH_000545_include_compare/test_flat_set.cpp new file mode 100644 index 00000000000..aa16a42bb97 --- /dev/null +++ b/tests/std/tests/GH_000545_include_compare/test_flat_set.cpp @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#if _HAS_CXX23 + +#include + +// Testing LWG-3330 "Include from most library headers" by intentionally NOT including + +static_assert(std::is_eq(std::partial_ordering::equivalent)); + +#endif // _HAS_CXX23 + +void test_flat_set() {} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_map.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_map.cpp index 76a545f65c4..16dafe71849 100644 --- a/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_map.cpp +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_map.cpp @@ -2,8 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include -#if defined(__cpp_lib_flat_map) -static_assert(false, "When this feature is implemented, update this to a Standard mode check."); +#if _HAS_CXX23 #include @@ -27,8 +26,8 @@ void test_flat_map() { } } -#else // ^^^ defined(__cpp_lib_flat_map) / !defined(__cpp_lib_flat_map) vvv +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv void test_flat_map() {} -#endif // ^^^ !defined(__cpp_lib_flat_map) ^^^ +#endif // ^^^ !_HAS_CXX23 ^^^ diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_set.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_set.cpp index 811f96eeea9..d995b42124a 100644 --- a/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_set.cpp +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_set.cpp @@ -2,8 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include -#if defined(__cpp_lib_flat_set) -static_assert(false, "When this feature is implemented, update this to a Standard mode check."); +#if _HAS_CXX23 #include @@ -21,8 +20,8 @@ void test_flat_set() { } } -#else // ^^^ defined(__cpp_lib_flat_set) / !defined(__cpp_lib_flat_set) vvv +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv void test_flat_set() {} -#endif // ^^^ !defined(__cpp_lib_flat_set) ^^^ +#endif // ^^^ !_HAS_CXX23 ^^^ diff --git a/tests/std/tests/P0429R9_flat_map/env.lst b/tests/std/tests/P0429R9_flat_map/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0429R9_flat_map/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0429R9_flat_map/test.cpp b/tests/std/tests/P0429R9_flat_map/test.cpp new file mode 100644 index 00000000000..b2e8adea29b --- /dev/null +++ b/tests/std/tests/P0429R9_flat_map/test.cpp @@ -0,0 +1,1653 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +using namespace std; + +// See GH-5965: Speculative resolution of LWG-3963 "Different flat_(multi)map specializations +// should be able to share same nested classes" is not likely to be accepted +static_assert(!is_same_v::containers, flat_multimap::containers>); +static_assert(!is_same_v::value_compare, flat_multimap::value_compare>); + +template class Tmpl> +constexpr bool is_specialization_v = false; +template