From dfd4e623f47cdd46142cee97074fd90d1065d270 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 27 Jan 2026 06:46:39 -0800 Subject: [PATCH 01/32] Bugfix: Guard `_STD min` against macroization. --- stl/inc/flat_map | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 9f9c0fd3640..263c28eec38 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -636,7 +636,7 @@ public: } _NODISCARD size_type max_size() const noexcept { - return _STD min(_Data.keys.max_size(), _Data.values.max_size()); + return (_STD min) (_Data.keys.max_size(), _Data.values.max_size()); } // [flat.map.modifiers] Modifiers From 616c953b16a64025463c5ffb2aca10db7da7897c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 27 Jan 2026 06:51:56 -0800 Subject: [PATCH 02/32] flat_map: Avoid `_STD make_reverse_iterator()`. --- stl/inc/flat_map | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 263c28eec38..c781dceb1aa 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -575,19 +575,19 @@ public: } _NODISCARD reverse_iterator rbegin() noexcept { - return _STD make_reverse_iterator(end()); + return reverse_iterator{end()}; } _NODISCARD const_reverse_iterator rbegin() const noexcept { - return _STD make_reverse_iterator(end()); + return const_reverse_iterator{end()}; } _NODISCARD reverse_iterator rend() noexcept { - return _STD make_reverse_iterator(begin()); + return reverse_iterator{begin()}; } _NODISCARD const_reverse_iterator rend() const noexcept { - return _STD make_reverse_iterator(begin()); + return const_reverse_iterator{begin()}; } _NODISCARD const_iterator cbegin() const noexcept { @@ -599,11 +599,11 @@ public: } _NODISCARD const_reverse_iterator crbegin() const noexcept { - return _STD make_reverse_iterator(cend()); + return const_reverse_iterator{cend()}; } _NODISCARD const_reverse_iterator crend() const noexcept { - return _STD make_reverse_iterator(cbegin()); + return const_reverse_iterator{cbegin()}; } void swap(_Derived& _Other) From 4905cc21af73b7cec7d5f86183b807aed0051424 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 27 Jan 2026 06:52:32 -0800 Subject: [PATCH 03/32] flat_set: Reduce layers when calling rbegin(), rend(), crbegin(), crend(). --- stl/inc/flat_set | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 60d723304e9..e33b60c1bd9 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -261,10 +261,10 @@ public: } _NODISCARD const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); + return const_reverse_iterator{_Mycont.end()}; } _NODISCARD const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); + return const_reverse_iterator{_Mycont.begin()}; } _NODISCARD const_iterator cbegin() const noexcept { @@ -275,10 +275,10 @@ public: } _NODISCARD const_reverse_iterator crbegin() const noexcept { - return rbegin(); + return const_reverse_iterator{_Mycont.end()}; } _NODISCARD const_reverse_iterator crend() const noexcept { - return rend(); + return const_reverse_iterator{_Mycont.begin()}; } // capacity From ec7e6473cd7ee76b48348e477a07ad514a4b1cb0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 27 Jan 2026 13:46:40 -0800 Subject: [PATCH 04/32] Add strengthened comments to `_Flat_map_base` move ctor/assign. --- stl/inc/flat_map | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index c781dceb1aa..c5932309be8 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -520,7 +520,7 @@ public: // Move constructors _Flat_map_base(_Flat_map_base&& _Other) noexcept(is_nothrow_copy_constructible_v && is_nothrow_move_constructible_v - && is_nothrow_move_constructible_v) + && is_nothrow_move_constructible_v) // strengthened : _Data(_STD move(_Other).extract()), _Key_compare(_Other._Key_compare) // intentionally copy comparator, see LWG-2227 {} @@ -542,8 +542,7 @@ public: _Flat_map_base& operator=(_Flat_map_base&& _Other) noexcept(is_nothrow_copy_assignable_v && is_nothrow_move_assignable_v - && is_nothrow_move_assignable_v) { - + && is_nothrow_move_assignable_v) /* strengthened */ { if (this != _STD addressof(_Other)) { _Clear_guard _Guard{this}; _Clear_guard _Always_clear{_STD addressof(_Other)}; From c009b6af991f43ee53fff5b53281bfa57ef4c86a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 27 Jan 2026 14:07:54 -0800 Subject: [PATCH 05/32] Use aliases more consistently. --- stl/inc/flat_map | 9 +++++---- stl/inc/flat_set | 29 +++++++++++++++-------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index c5932309be8..34883fd6b10 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -606,9 +606,10 @@ public: } void swap(_Derived& _Other) - noexcept(is_nothrow_swappable_v<_KeyContainer> && is_nothrow_swappable_v<_MappedContainer> + noexcept(is_nothrow_swappable_v && is_nothrow_swappable_v && is_nothrow_swappable_v) { - constexpr bool _Is_noexcept = is_nothrow_swappable_v<_KeyContainer> && is_nothrow_swappable_v<_MappedContainer> + constexpr bool _Is_noexcept = is_nothrow_swappable_v + && is_nothrow_swappable_v && is_nothrow_swappable_v; auto& _Other_base = static_cast<_Flat_map_base&>(_Other); _Flat_map_swap_clear_guard<_Is_noexcept, containers> _Guard{ @@ -1150,13 +1151,13 @@ private: // Insert the new elements at the end for (; _First != _Last; ++_First) { value_type _Val = *_First; - if constexpr (_Has_guaranteed_push_back<_KeyContainer>) { + 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<_MappedContainer>) { + 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)); diff --git a/stl/inc/flat_set b/stl/inc/flat_set index e33b60c1bd9..59c1d57875b 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -85,16 +85,6 @@ private: static constexpr const char* _Msg_not_sorted = _IsUnique ? "Input was not sorted-unique!" : "Input was not sorted!"; public: - static_assert(same_as<_Kty, typename _Container::value_type>, - "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<_Container>, - "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)"); - using key_type = _Kty; using value_type = _Kty; using key_compare = _Keylt; @@ -109,6 +99,16 @@ public: 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() : _Flat_set_base(key_compare()) {} @@ -399,9 +399,10 @@ public: return _Ret; } - void swap(_Derived& _Other) noexcept(is_nothrow_swappable_v<_Container> && is_nothrow_swappable_v<_Keylt>) { - constexpr bool _Is_noexcept = is_nothrow_swappable_v<_Container> && is_nothrow_swappable_v<_Keylt>; - _Flat_set_swap_clear_guard<_Is_noexcept, _Container> _Guard{ + 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(_Mycont), _STD addressof(_Other._Mycont)}; _RANGES swap(_Mycont, _Other._Mycont); _RANGES swap(_Mycomp, _Other._Mycomp); @@ -623,7 +624,7 @@ private: void _Insert_range(_Rng&& _Range) { const size_type _Old_size = size(); _Clear_guard _Guard{this}; - if constexpr (_Has_guaranteed_append_range<_Container>) { + if constexpr (_Has_guaranteed_append_range) { _Mycont.append_range(_STD forward<_Rng>(_Range)); } else { _Mycont.insert_range(_Mycont.end(), _STD forward<_Rng>(_Range)); From ad70d74eed70b3ff8c2982966e3fb886cf644579 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Jan 2026 10:01:32 -0800 Subject: [PATCH 06/32] flat_set: Make `_Emplace_with_clear_guard` a member function. --- stl/inc/flat_set | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 59c1d57875b..9f4b54a7165 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -57,18 +57,6 @@ struct _NODISCARD _Flat_set_swap_clear_guard { void _Dismiss() noexcept {} }; -template -_NODISCARD auto _Emplace_with_clear_guard(_Container& _Cont, typename _Container::const_iterator _Where, _Ty&& _Val) { - if constexpr (_Has_guaranteed_single_insertion<_Container>) { - return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); - } else { - _Clear_guard _Guard{_STD addressof(_Cont)}; - auto _Iter = _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); - _Guard._Target = nullptr; - return _Iter; - } -} - _EXPORT_STD template , class _Container = vector<_Kty>> class flat_set; @@ -527,6 +515,18 @@ private: } } + template + _NODISCARD iterator _Emplace_with_clear_guard(const const_iterator _Where, _Ty&& _Val) { + if constexpr (_Has_guaranteed_single_insertion) { + return _Mycont.emplace(_Where, _STD forward<_Ty>(_Val)); + } else { + _Clear_guard _Guard{this}; + auto _Iter = _Mycont.emplace(_Where, _STD forward<_Ty>(_Val)); + _Guard._Target = nullptr; + return _Iter; + } + } + template _NODISCARD conditional_t<_IsUnique, pair, iterator> _Emplace(_Ty&& _Val) { if constexpr (_IsUnique) { @@ -537,7 +537,7 @@ private: if constexpr (is_same_v, _Kty>) { _STL_INTERNAL_CHECK(_Can_insert(_Where, _Val)); - return pair{_STD _Emplace_with_clear_guard(_Mycont, _Where, _STD forward<_Ty>(_Val)), true}; + return pair{_Emplace_with_clear_guard(_Where, _STD forward<_Ty>(_Val)), true}; } else { // heterogeneous insertion _STL_INTERNAL_STATIC_ASSERT(_Transparent && is_constructible_v<_Kty, _Ty>); @@ -545,11 +545,11 @@ private: _STL_ASSERT(_Can_insert(_Where, _Keyval), "The conversion from the heterogeneous key to key_type should " "be consistent with the heterogeneous lookup!"); - return pair{_STD _Emplace_with_clear_guard(_Mycont, _Where, _STD move(_Keyval)), true}; + return pair{_Emplace_with_clear_guard(_Where, _STD move(_Keyval)), true}; } } else { _STL_INTERNAL_STATIC_ASSERT(is_same_v, _Kty>); - return _STD _Emplace_with_clear_guard(_Mycont, upper_bound(_Val), _STD forward<_Ty>(_Val)); + return _Emplace_with_clear_guard(upper_bound(_Val), _STD forward<_Ty>(_Val)); } } @@ -579,7 +579,7 @@ private: if constexpr (is_same_v, _Kty>) { _STL_INTERNAL_CHECK(_Can_insert(_Where, _Val)); - return _STD _Emplace_with_clear_guard(_Mycont, _Where, _STD forward<_Ty>(_Val)); + return _Emplace_with_clear_guard(_Where, _STD forward<_Ty>(_Val)); } else { // heterogeneous insertion _STL_INTERNAL_STATIC_ASSERT(_Transparent && is_constructible_v<_Kty, _Ty>); @@ -587,7 +587,7 @@ private: _STL_ASSERT(_Can_insert(_Where, _Keyval), "The conversion from the heterogeneous key to key_type should " "be consistent with the heterogeneous lookup!"); - return _STD _Emplace_with_clear_guard(_Mycont, _Where, _STD move(_Keyval)); + return _Emplace_with_clear_guard(_Where, _STD move(_Keyval)); } } else { _STL_INTERNAL_STATIC_ASSERT(is_same_v, _Kty>); @@ -608,7 +608,7 @@ private: _Where = _STD lower_bound(_Where, _End, _Val, _Pass_comp()); } - return _STD _Emplace_with_clear_guard(_Mycont, _Where, _STD forward<_Ty>(_Val)); + return _Emplace_with_clear_guard(_Where, _STD forward<_Ty>(_Val)); } } From cce21185c4f5dc2f2bdb4ad30305fc4de5cbe308 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Jan 2026 12:09:04 -0800 Subject: [PATCH 07/32] Reorder flat_meow members to follow Standard order, adjust comments/whitespace, no other changes. --- stl/inc/flat_map | 354 +++++++++++++++++++++-------------------------- stl/inc/flat_set | 157 ++++++++++++--------- 2 files changed, 255 insertions(+), 256 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 34883fd6b10..5c8c68ebf64 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -33,8 +33,6 @@ _STL_DISABLE_CLANG_WARNINGS #undef msvc _STD_BEGIN -// Implementation - template class _Flat_map_base; @@ -308,6 +306,7 @@ private: static constexpr const char* _Msg_not_sorted = _IsUnique ? "Keys were not sorted-unique!" : "Keys were not sorted!"; public: + // [flat.map.defn] Types using key_type = _Key; using mapped_type = _Mapped; using value_type = pair; @@ -367,17 +366,18 @@ public: }; // [flat.map.cons] Constructors - explicit _Flat_map_base(const key_compare& _Comp) : _Data(), _Key_compare(_Comp) {} _Flat_map_base() : _Flat_map_base(key_compare()) {} - template <_Usable_allocator_for _Allocator> - explicit _Flat_map_base(const _Allocator& _Alloc) : _Flat_map_base(key_compare(), _Alloc) {} + _Flat_map_base(const _Flat_map_base& _Other) : _Data(_Other._Data), _Key_compare(_Other._Key_compare) {} - template <_Usable_allocator_for _Allocator> - _Flat_map_base(const key_compare& _Comp, const _Allocator& _Alloc) - : _Data{.keys = _STD make_obj_using_allocator(_Alloc), - .values = _STD make_obj_using_allocator(_Alloc)}, - _Key_compare(_Comp) {} + _Flat_map_base(_Flat_map_base&& _Other) + noexcept(is_nothrow_copy_constructible_v && is_nothrow_move_constructible_v + && is_nothrow_move_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()) @@ -386,6 +386,51 @@ public: _Make_invariants_fulfilled(); } + _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(), "key_cont.size() != mapped_cont.size()"); + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); + } + + template <_Iterator_for_container _InputIterator> + _Flat_map_base(const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp = key_compare()) + : _Flat_map_base(_Comp) { + insert(_First, _Last); + } + + template <_Iterator_for_container _InputIterator> + _Flat_map_base( + _Sorted_t, const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp = key_compare()) + : _Flat_map_base(_Comp) { + _Insert_range(_First, _Last); + } + + template <_Container_compatible_range _Rng> + _Flat_map_base(from_range_t _From_range, _Rng&& _Range) + : _Flat_map_base(_From_range, _STD forward<_Rng>(_Range), key_compare()) {} + + template <_Container_compatible_range _Rng> + _Flat_map_base(from_range_t, _Rng&& _Range, const key_compare& _Comp) : _Flat_map_base(_Comp) { + insert_range(_STD forward<_Rng>(_Range)); + } + + _Flat_map_base(const initializer_list _Ilist, const key_compare& _Comp = key_compare()) + : _Flat_map_base(_Ilist.begin(), _Ilist.end(), _Comp) {} + + _Flat_map_base(_Sorted_t _Tag, const initializer_list _Ilist, const key_compare& _Comp = key_compare()) + : _Flat_map_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp) {} + + // [flat.map.cons.alloc] Constructors with allocators + template <_Usable_allocator_for _Allocator> + explicit _Flat_map_base(const _Allocator& _Alloc) : _Flat_map_base(key_compare(), _Alloc) {} + + template <_Usable_allocator_for _Allocator> + _Flat_map_base(const key_compare& _Comp, const _Allocator& _Alloc) + : _Data{.keys = _STD make_obj_using_allocator(_Alloc), + .values = _STD make_obj_using_allocator(_Alloc)}, + _Key_compare(_Comp) {} + template <_Usable_allocator_for _Allocator> _Flat_map_base( const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, const _Allocator& _Alloc) @@ -401,13 +446,6 @@ public: _Make_invariants_fulfilled(); } - _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(), "key_cont.size() != mapped_cont.size()"); - _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); - } - template <_Usable_allocator_for _Allocator> _Flat_map_base(_Sorted_t _Tag, const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, const _Allocator& _Alloc) @@ -423,11 +461,17 @@ public: _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); } - template <_Iterator_for_container _InputIterator> - _Flat_map_base(const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp = key_compare()) - : _Flat_map_base(_Comp) { - insert(_First, _Last); - } + template <_Usable_allocator_for _Allocator> + _Flat_map_base(const _Flat_map_base& _Other, const _Allocator& _Alloc) + : _Data{.keys = _STD make_obj_using_allocator(_Alloc, _Other._Data.keys), + .values = _STD make_obj_using_allocator(_Alloc, _Other._Data.values)}, + _Key_compare(_Other._Key_compare) {} + + template <_Usable_allocator_for _Allocator> + _Flat_map_base(_Flat_map_base&& _Other, const _Allocator& _Alloc) + : _Data{_STD move(_Other)._Extract_using_allocator(_Alloc)}, + _Key_compare(_Other._Key_compare) // intentionally copy comparator, see LWG-2227 + {} template <_Iterator_for_container _InputIterator, _Usable_allocator_for _Allocator> @@ -444,33 +488,10 @@ public: insert(_First, _Last); } - template <_Container_compatible_range _Rng> - _Flat_map_base(from_range_t _From_range, _Rng&& _Range) - : _Flat_map_base(_From_range, _STD forward<_Rng>(_Range), key_compare()) {} - - template <_Container_compatible_range _Rng, - _Usable_allocator_for _Allocator> - _Flat_map_base(from_range_t _From_range, _Rng&& _Range, const _Allocator& _Alloc) - : _Flat_map_base(_From_range, _STD forward<_Rng>(_Range), key_compare(), _Alloc) {} - - template <_Container_compatible_range _Rng> - _Flat_map_base(from_range_t, _Rng&& _Range, const key_compare& _Comp) : _Flat_map_base(_Comp) { - insert_range(_STD forward<_Rng>(_Range)); - } - - template <_Container_compatible_range _Rng, + template <_Iterator_for_container _InputIterator, _Usable_allocator_for _Allocator> - _Flat_map_base(from_range_t, _Rng&& _Range, const key_compare& _Comp, const _Allocator& _Alloc) - : _Flat_map_base(_Comp, _Alloc) { - insert_range(_STD forward<_Rng>(_Range)); - } - - template <_Iterator_for_container _InputIterator> - _Flat_map_base( - _Sorted_t, const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp = key_compare()) - : _Flat_map_base(_Comp) { - _Insert_range(_First, _Last); - } + _Flat_map_base(_Sorted_t _Tag, const _InputIterator _First, const _InputIterator _Last, const _Allocator& _Alloc) + : _Flat_map_base(_Tag, _First, _Last, key_compare(), _Alloc) {} template <_Iterator_for_container _InputIterator, _Usable_allocator_for _Allocator> @@ -480,58 +501,36 @@ public: _Insert_range(_First, _Last); } - template <_Iterator_for_container _InputIterator, + template <_Container_compatible_range _Rng, _Usable_allocator_for _Allocator> - _Flat_map_base(_Sorted_t _Tag, const _InputIterator _First, const _InputIterator _Last, const _Allocator& _Alloc) - : _Flat_map_base(_Tag, _First, _Last, key_compare(), _Alloc) {} - - _Flat_map_base(const initializer_list _Ilist, const key_compare& _Comp = key_compare()) - : _Flat_map_base(_Ilist.begin(), _Ilist.end(), _Comp) {} + _Flat_map_base(from_range_t _From_range, _Rng&& _Range, const _Allocator& _Alloc) + : _Flat_map_base(_From_range, _STD forward<_Rng>(_Range), key_compare(), _Alloc) {} - template <_Usable_allocator_for _Allocator> - _Flat_map_base(const initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) - : _Flat_map_base(_Ilist.begin(), _Ilist.end(), _Comp, _Alloc) {} + template <_Container_compatible_range _Rng, + _Usable_allocator_for _Allocator> + _Flat_map_base(from_range_t, _Rng&& _Range, const key_compare& _Comp, const _Allocator& _Alloc) + : _Flat_map_base(_Comp, _Alloc) { + insert_range(_STD forward<_Rng>(_Range)); + } template <_Usable_allocator_for _Allocator> _Flat_map_base(const initializer_list _Ilist, const _Allocator& _Alloc) : _Flat_map_base(_Ilist, key_compare(), _Alloc) {} - _Flat_map_base(_Sorted_t _Tag, const initializer_list _Ilist, const key_compare& _Comp = key_compare()) - : _Flat_map_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp) {} - template <_Usable_allocator_for _Allocator> - _Flat_map_base( - _Sorted_t _Tag, const initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) - : _Flat_map_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp, _Alloc) {} + _Flat_map_base(const initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) + : _Flat_map_base(_Ilist.begin(), _Ilist.end(), _Comp, _Alloc) {} template <_Usable_allocator_for _Allocator> _Flat_map_base(_Sorted_t _Tag, const initializer_list _Ilist, const _Allocator& _Alloc) : _Flat_map_base(_Tag, _Ilist, key_compare(), _Alloc) {} - // Copy constructors - _Flat_map_base(const _Flat_map_base& _Other) : _Data(_Other._Data), _Key_compare(_Other._Key_compare) {} - - template <_Usable_allocator_for _Allocator> - _Flat_map_base(const _Flat_map_base& _Other, const _Allocator& _Alloc) - : _Data{.keys = _STD make_obj_using_allocator(_Alloc, _Other._Data.keys), - .values = _STD make_obj_using_allocator(_Alloc, _Other._Data.values)}, - _Key_compare(_Other._Key_compare) {} - - // Move constructors - _Flat_map_base(_Flat_map_base&& _Other) - noexcept(is_nothrow_copy_constructible_v && is_nothrow_move_constructible_v - && is_nothrow_move_constructible_v) // strengthened - : _Data(_STD move(_Other).extract()), - _Key_compare(_Other._Key_compare) // intentionally copy comparator, see LWG-2227 - {} - template <_Usable_allocator_for _Allocator> - _Flat_map_base(_Flat_map_base&& _Other, const _Allocator& _Alloc) - : _Data{_STD move(_Other)._Extract_using_allocator(_Alloc)}, - _Key_compare(_Other._Key_compare) // intentionally copy comparator, see LWG-2227 - {} + _Flat_map_base( + _Sorted_t _Tag, const initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) + : _Flat_map_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp, _Alloc) {} - // Assignment + // Assignment operators _Flat_map_base& operator=(const _Flat_map_base& _Other) { _Clear_guard _Guard{this}; _Data = _Other._Data; @@ -553,22 +552,19 @@ public: return *this; } - // [container.reqmts] iterators + // 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.begin()}; } - _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.end()}; } @@ -576,15 +572,12 @@ public: _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()}; } @@ -592,7 +585,6 @@ public: _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()}; } @@ -600,32 +592,10 @@ public: _NODISCARD const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; } - _NODISCARD const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; } - 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; - auto& _Other_base = static_cast<_Flat_map_base&>(_Other); - _Flat_map_swap_clear_guard<_Is_noexcept, containers> _Guard{ - _STD addressof(_Data), _STD addressof(_Other_base._Data)}; - _RANGES swap(_Data.keys, _Other_base._Data.keys); - _RANGES swap(_Data.values, _Other_base._Data.values); - _RANGES swap(_Key_compare, _Other_base._Key_compare); - _Guard._Dismiss(); - } - - // [container.reqmts] clear - void clear() noexcept { - _Data.keys.clear(); - _Data.values.clear(); - } - // [flat.map.capacity] Capacity _NODISCARD_EMPTY_MEMBER bool empty() const noexcept { return _Data.keys.empty(); @@ -648,21 +618,6 @@ public: return _Try_emplace(_STD move(_Val.first), _STD move(_Val.second)); } - auto insert(const value_type& _Pair_val) { - return _Try_emplace(_Pair_val.first, _Pair_val.second); - } - - auto insert(value_type&& _Pair_val) { - return _Try_emplace(_STD move(_Pair_val.first), _STD move(_Pair_val.second)); - } - - template - auto insert(_PairValTy&& _Pair_val) - requires is_constructible_v - { - return emplace(_STD forward<_PairValTy>(_Pair_val)); - } - template iterator emplace_hint(const const_iterator _Position, _ArgTypes&&... _Args) requires is_constructible_v @@ -671,14 +626,27 @@ public: return _Emplace_hint(_Position, _STD move(_Val.first), _STD move(_Val.second)); } + auto insert(const value_type& _Pair_val) { + return _Try_emplace(_Pair_val.first, _Pair_val.second); + } + auto insert(value_type&& _Pair_val) { + return _Try_emplace(_STD move(_Pair_val.first), _STD move(_Pair_val.second)); + } + iterator insert(const const_iterator _Position, const value_type& _Pair_val) { return emplace_hint(_Position, _Pair_val); } - iterator insert(const const_iterator _Position, value_type&& _Pair_val) { return emplace_hint(_Position, _STD move(_Pair_val)); } + template + auto insert(_PairValTy&& _Pair_val) + requires is_constructible_v + { + return emplace(_STD forward<_PairValTy>(_Pair_val)); + } + template iterator insert(const const_iterator _Position, _PairValTy&& _Pair_val) requires is_constructible_v @@ -690,7 +658,6 @@ public: void insert(const _InputIterator _First, const _InputIterator _Last) { _Insert_range(_First, _Last); } - template <_Iterator_for_container _InputIterator> void insert(_Sorted_t, const _InputIterator _First, const _InputIterator _Last) { _Insert_range(_First, _Last); @@ -700,7 +667,6 @@ public: 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)); @@ -709,11 +675,34 @@ public: 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); + } + + template + _NODISCARD containers _Extract_using_allocator(const _Allocator& _Alloc) && { + _Clear_guard _Always_clear{this}; + return containers{.keys = _STD make_obj_using_allocator(_Alloc, _STD move(_Data.keys)), + .values = _STD make_obj_using_allocator(_Alloc, _STD move(_Data.values))}; + } + + void replace(key_container_type&& _Key_cont, mapped_container_type&& _Mapped_cont) { + _STL_ASSERT(_Key_cont.size() == _Mapped_cont.size(), "key_cont.size() != mapped_cont.size()"); + _STL_ASSERT(_Is_sorted_and_unique(_Key_cont), _Msg_not_sorted); + _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)); } @@ -726,14 +715,6 @@ public: return iterator{_STD move(_Key_it), _STD move(_Val_it)}; } - 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)}; - } - size_type erase(const key_type& _Key_val) { return _Erase_key(_Key_val); } @@ -745,31 +726,35 @@ public: return _Erase_key(_STD forward<_OtherKey>(_Key_val)); } - _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); + 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)}; } - template - _NODISCARD containers _Extract_using_allocator(const _Allocator& _Alloc) && { - _Clear_guard _Always_clear{this}; - return containers{.keys = _STD make_obj_using_allocator(_Alloc, _STD move(_Data.keys)), - .values = _STD make_obj_using_allocator(_Alloc, _STD move(_Data.values))}; + 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; + auto& _Other_base = static_cast<_Flat_map_base&>(_Other); + _Flat_map_swap_clear_guard<_Is_noexcept, containers> _Guard{ + _STD addressof(_Data), _STD addressof(_Other_base._Data)}; + _RANGES swap(_Data.keys, _Other_base._Data.keys); + _RANGES swap(_Data.values, _Other_base._Data.values); + _RANGES swap(_Key_compare, _Other_base._Key_compare); + _Guard._Dismiss(); } - void replace(key_container_type&& _Key_cont, mapped_container_type&& _Mapped_cont) { - _STL_ASSERT(_Key_cont.size() == _Mapped_cont.size(), "key_cont.size() != mapped_cont.size()"); - _STL_ASSERT(_Is_sorted_and_unique(_Key_cont), _Msg_not_sorted); - _Clear_guard _Guard{this}; - _Data.keys = _STD move(_Key_cont); - _Data.values = _STD move(_Mapped_cont); - _Guard._Target = nullptr; + void clear() noexcept { + _Data.keys.clear(); + _Data.values.clear(); } - // observers + // Observers _NODISCARD key_compare key_comp() const { return _Key_compare; } @@ -790,18 +775,15 @@ public: _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); } - - _NODISCARD const_iterator find(const key_type& _Key_val) const { - return _Find(_Key_val); - } - template _NODISCARD const_iterator find(const _OtherKey& _Key_val) const requires _Transparent @@ -812,7 +794,6 @@ public: _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 @@ -823,7 +804,6 @@ public: _NODISCARD bool contains(const key_type& _Key_val) const { return _Contains(_Key_val); } - template _NODISCARD bool contains(const _OtherKey& _Key_val) const requires _Transparent @@ -834,18 +814,15 @@ public: _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); } - - _NODISCARD const_iterator lower_bound(const key_type& _Key_val) const { - return _Lower_bound(_Key_val); - } - template _NODISCARD const_iterator lower_bound(const _OtherKey& _Key_val) const requires _Transparent @@ -856,18 +833,15 @@ public: _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); } - - _NODISCARD const_iterator upper_bound(const key_type& _Key_val) const { - return _Upper_bound(_Key_val); - } - template _NODISCARD const_iterator upper_bound(const _OtherKey& _Key_val) const requires _Transparent @@ -878,18 +852,15 @@ public: _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); } - - _NODISCARD pair equal_range(const key_type& _Key_val) const { - return _Equal_range(_Key_val); - } - template _NODISCARD pair equal_range(const _OtherKey& _Key_val) const requires _Transparent @@ -912,7 +883,6 @@ public: _Left.swap(_Right); } - protected: containers _Data; _MSVC_NO_UNIQUE_ADDRESS key_compare _Key_compare; @@ -1305,7 +1275,6 @@ public: { return try_emplace(_STD move(_Key_val)).first->second; } - template mapped_type& operator[](_OtherKey&& _Key_val) requires _Transparent && is_constructible_v @@ -1317,18 +1286,15 @@ public: _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 @@ -1526,7 +1492,6 @@ template >, _Compare = _Compare()) -> flat_map<_Key, _Mapped, _Compare>; -// Specialization of uses_allocator template struct uses_allocator, _Allocator> : bool_constant && uses_allocator_v<_MappedContainer, _Allocator>> {}; @@ -1578,6 +1543,7 @@ template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_contain _Usable_allocator_for<_KeyContainer, _MappedContainer> _Allocator> flat_multimap(_KeyContainer, _MappedContainer, _Allocator) -> 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> _Allocator> @@ -1596,6 +1562,7 @@ template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_contain flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Allocator) -> 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> _Allocator> @@ -1648,7 +1615,6 @@ template >, _Compare = _Compare()) -> flat_multimap<_Key, _Mapped, _Compare>; -// Specialization of uses_allocator template struct uses_allocator, _Allocator> : bool_constant && uses_allocator_v<_MappedContainer, _Allocator>> {}; diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 9f4b54a7165..e3f6d31694f 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -73,6 +73,7 @@ private: static constexpr const char* _Msg_not_sorted = _IsUnique ? "Input was not sorted-unique!" : "Input was not sorted!"; public: + // [flat.set.defn] Types using key_type = _Kty; using value_type = _Kty; using key_compare = _Keylt; @@ -100,76 +101,114 @@ public: // [flat.set.cons] Constructors _Flat_set_base() : _Flat_set_base(key_compare()) {} - template <_Usable_allocator_for _Alloc> - _Flat_set_base(const _Flat_set_base& _Other, const _Alloc& _Al) - : _Mycont(_STD make_obj_using_allocator(_Al, _Other._Mycont)), _Mycomp(_Other._Mycomp) {} - template <_Usable_allocator_for _Alloc> - _Flat_set_base(_Flat_set_base&& _Other, const _Alloc& _Al) - : _Mycont(_STD make_obj_using_allocator(_Al, _STD move(_Other).extract())), - _Mycomp(_Other._Mycomp) // intentionally copy comparator, see LWG-2227 + _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 + : _Mycont(_STD move(_Other).extract()), _Mycomp(_Other._Mycomp) // intentionally copy comparator, see LWG-2227 {} + explicit _Flat_set_base(const key_compare& _Comp) : _Mycont(), _Mycomp(_Comp) {} + explicit _Flat_set_base(container_type _Cont, const key_compare& _Comp = key_compare()) : _Mycont(_STD move(_Cont)), _Mycomp(_Comp) { _Make_invariants_fulfilled(); } + + _Flat_set_base(_Sorted_t, container_type _Cont, const key_compare& _Comp = key_compare()) + : _Mycont(_STD move(_Cont)), _Mycomp(_Comp) { + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); + } + + template <_Iterator_for_container _Iter> + _Flat_set_base(const _Iter _First, const _Iter _Last, const key_compare& _Comp = key_compare()) + : _Mycont(), _Mycomp(_Comp) { + _Mycont.assign(_First, _Last); + _Make_invariants_fulfilled(); + } + + template <_Iterator_for_container _Iter> + _Flat_set_base(_Sorted_t _Tag, const _Iter _First, const _Iter _Last, const key_compare& _Comp = key_compare()) + : _Flat_set_base(_Tag, container_type(_First, _Last), _Comp) {} + + template <_Container_compatible_range<_Kty> _Rng> + _Flat_set_base(from_range_t, _Rng&& _Range) + : _Flat_set_base(container_type(from_range, _STD forward<_Rng>(_Range))) {} + + template <_Container_compatible_range<_Kty> _Rng> + _Flat_set_base(from_range_t, _Rng&& _Range, const key_compare& _Comp) + : _Flat_set_base(container_type(from_range, _STD forward<_Rng>(_Range)), _Comp) {} + + _Flat_set_base(const initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) + : _Flat_set_base(_Ilist.begin(), _Ilist.end(), _Comp) {} + + _Flat_set_base(_Sorted_t _Tag, const initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) + : _Flat_set_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp) {} + + // [flat.set.cons.alloc] Constructors with allocators + template <_Usable_allocator_for _Alloc> + explicit _Flat_set_base(const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp() {} + + template <_Usable_allocator_for _Alloc> + _Flat_set_base(const key_compare& _Comp, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp(_Comp) {} + template <_Usable_allocator_for _Alloc> _Flat_set_base(const container_type& _Cont, const _Alloc& _Al) : _Flat_set_base(_STD make_obj_using_allocator(_Al, _Cont)) {} + template <_Usable_allocator_for _Alloc> _Flat_set_base(const container_type& _Cont, const key_compare& _Comp, const _Alloc& _Al) : _Flat_set_base(_STD make_obj_using_allocator(_Al, _Cont), _Comp) {} - _Flat_set_base(_Sorted_t, container_type _Cont, const key_compare& _Comp = key_compare()) - : _Mycont(_STD move(_Cont)), _Mycomp(_Comp) { - _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); - } template <_Usable_allocator_for _Alloc> _Flat_set_base(_Sorted_t _Tag, const container_type& _Cont, const _Alloc& _Al) : _Flat_set_base(_Tag, _STD make_obj_using_allocator(_Al, _Cont)) {} + template <_Usable_allocator_for _Alloc> _Flat_set_base(_Sorted_t _Tag, const container_type& _Cont, const key_compare& _Comp, const _Alloc& _Al) : _Flat_set_base(_Tag, _STD make_obj_using_allocator(_Al, _Cont), _Comp) {} - explicit _Flat_set_base(const key_compare& _Comp) : _Mycont(), _Mycomp(_Comp) {} template <_Usable_allocator_for _Alloc> - _Flat_set_base(const key_compare& _Comp, const _Alloc& _Al) - : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp(_Comp) {} + _Flat_set_base(const _Flat_set_base& _Other, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al, _Other._Mycont)), _Mycomp(_Other._Mycomp) {} + template <_Usable_allocator_for _Alloc> - explicit _Flat_set_base(const _Alloc& _Al) - : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp() {} + _Flat_set_base(_Flat_set_base&& _Other, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al, _STD move(_Other).extract())), + _Mycomp(_Other._Mycomp) // intentionally copy comparator, see LWG-2227 + {} - template <_Iterator_for_container _Iter> - _Flat_set_base(const _Iter _First, const _Iter _Last, const key_compare& _Comp = key_compare()) - : _Mycont(), _Mycomp(_Comp) { + template <_Iterator_for_container _Iter, _Usable_allocator_for _Alloc> + _Flat_set_base(const _Iter _First, const _Iter _Last, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp() { _Mycont.assign(_First, _Last); _Make_invariants_fulfilled(); } + template <_Iterator_for_container _Iter, _Usable_allocator_for _Alloc> _Flat_set_base(const _Iter _First, const _Iter _Last, const key_compare& _Comp, const _Alloc& _Al) : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp(_Comp) { _Mycont.assign(_First, _Last); _Make_invariants_fulfilled(); } + template <_Iterator_for_container _Iter, _Usable_allocator_for _Alloc> - _Flat_set_base(const _Iter _First, const _Iter _Last, const _Alloc& _Al) - : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp() { - _Mycont.assign(_First, _Last); - _Make_invariants_fulfilled(); - } + _Flat_set_base(_Sorted_t _Tag, const _Iter _First, const _Iter _Last, const _Alloc& _Al) + : _Flat_set_base(_Tag, _STD make_obj_using_allocator(_Al, _First, _Last)) {} + + template <_Iterator_for_container _Iter, _Usable_allocator_for _Alloc> + _Flat_set_base(_Sorted_t _Tag, const _Iter _First, const _Iter _Last, const key_compare& _Comp, const _Alloc& _Al) + : _Flat_set_base(_Tag, _STD make_obj_using_allocator(_Al, _First, _Last), _Comp) {} - template <_Container_compatible_range<_Kty> _Rng> - _Flat_set_base(from_range_t, _Rng&& _Range) - : _Flat_set_base(container_type(from_range, _STD forward<_Rng>(_Range))) {} template <_Container_compatible_range<_Kty> _Rng, _Usable_allocator_for _Alloc> _Flat_set_base(from_range_t, _Rng&& _Range, const _Alloc& _Al) : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp() { _Mycont.assign_range(_STD forward<_Rng>(_Range)); _Make_invariants_fulfilled(); } - template <_Container_compatible_range<_Kty> _Rng> - _Flat_set_base(from_range_t, _Rng&& _Range, const key_compare& _Comp) - : _Flat_set_base(container_type(from_range, _STD forward<_Rng>(_Range)), _Comp) {} + template <_Container_compatible_range<_Kty> _Rng, _Usable_allocator_for _Alloc> _Flat_set_base(from_range_t, _Rng&& _Range, const key_compare& _Comp, const _Alloc& _Al) : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp(_Comp) { @@ -177,40 +216,23 @@ public: _Make_invariants_fulfilled(); } - template <_Iterator_for_container _Iter> - _Flat_set_base(_Sorted_t _Tag, const _Iter _First, const _Iter _Last, const key_compare& _Comp = key_compare()) - : _Flat_set_base(_Tag, container_type(_First, _Last), _Comp) {} - template <_Iterator_for_container _Iter, _Usable_allocator_for _Alloc> - _Flat_set_base(_Sorted_t _Tag, const _Iter _First, const _Iter _Last, const key_compare& _Comp, const _Alloc& _Al) - : _Flat_set_base(_Tag, _STD make_obj_using_allocator(_Al, _First, _Last), _Comp) {} - template <_Iterator_for_container _Iter, _Usable_allocator_for _Alloc> - _Flat_set_base(_Sorted_t _Tag, const _Iter _First, const _Iter _Last, const _Alloc& _Al) - : _Flat_set_base(_Tag, _STD make_obj_using_allocator(_Al, _First, _Last)) {} - - _Flat_set_base(const initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) - : _Flat_set_base(_Ilist.begin(), _Ilist.end(), _Comp) {} - template <_Usable_allocator_for _Alloc> - _Flat_set_base(const initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) - : _Flat_set_base(_Ilist.begin(), _Ilist.end(), _Comp, _Al) {} template <_Usable_allocator_for _Alloc> _Flat_set_base(const initializer_list<_Kty> _Ilist, const _Alloc& _Al) : _Flat_set_base(_Ilist.begin(), _Ilist.end(), _Al) {} - _Flat_set_base(_Sorted_t _Tag, const initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) - : _Flat_set_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp) {} template <_Usable_allocator_for _Alloc> - _Flat_set_base(_Sorted_t _Tag, const initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) - : _Flat_set_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp, _Al) {} + _Flat_set_base(const initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) + : _Flat_set_base(_Ilist.begin(), _Ilist.end(), _Comp, _Al) {} + template <_Usable_allocator_for _Alloc> _Flat_set_base(_Sorted_t _Tag, const initializer_list<_Kty> _Ilist, const _Alloc& _Al) : _Flat_set_base(_Tag, _Ilist.begin(), _Ilist.end(), _Al) {} - _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 - : _Mycont(_STD move(_Other).extract()), _Mycomp(_Other._Mycomp) // intentionally copy comparator, see LWG-2227 - {} + template <_Usable_allocator_for _Alloc> + _Flat_set_base(_Sorted_t _Tag, const initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) + : _Flat_set_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp, _Al) {} + // Assignment operators _Flat_set_base& operator=(const _Flat_set_base& _Other) { _Clear_guard _Guard{this}; _Mycont = _Other._Mycont; @@ -218,9 +240,9 @@ public: _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 - { + 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)}; @@ -239,7 +261,7 @@ public: return static_cast<_Derived&>(*this); } - // iterators + // 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 _Mycont.begin(); @@ -269,7 +291,7 @@ public: return const_reverse_iterator{_Mycont.begin()}; } - // capacity + // Capacity _NODISCARD_EMPTY_MEMBER bool empty() const noexcept { return _Mycont.empty(); } @@ -280,7 +302,7 @@ public: return _Mycont.max_size(); } - // modifiers + // [flat.set.modifiers] Modifiers template auto emplace(_Args&&... _Vals) requires is_constructible_v @@ -292,6 +314,7 @@ public: return _Emplace(_Kty(_STD forward<_Args>(_Vals)...)); } } + template iterator emplace_hint(const const_iterator _Hint, _Args&&... _Vals) requires is_constructible_v @@ -336,6 +359,7 @@ public: void insert(_Sorted_t, const _Iter _First, const _Iter _Last) { _Insert_range(_First, _Last); } + template <_Container_compatible_range<_Kty> _Rng> void insert_range(_Rng&& _Range) { _Insert_range(_STD forward<_Rng>(_Range)); @@ -344,6 +368,7 @@ public: void insert_range(_Sorted_t, _Rng&& _Range) { _Insert_range(_STD forward<_Rng>(_Range)); } + void insert(const initializer_list<_Kty> _Ilist) { _Insert_range(_Ilist.begin(), _Ilist.end()); } @@ -372,6 +397,7 @@ public: _Guard._Target = nullptr; return _Ret; } + size_type erase(const _Kty& _Val) { return _Erase(_Val); } @@ -380,6 +406,7 @@ public: size_type erase(_Other&& _Val) { return _Erase(_Val); } + iterator erase(const const_iterator _First, const const_iterator _Last) { _Clear_guard _Guard{this}; const auto _Ret = _Mycont.erase(_First, _Last); @@ -401,7 +428,7 @@ public: _Mycont.clear(); } - // observers + // Observers _NODISCARD key_compare key_comp() const { return _Mycomp; } @@ -409,7 +436,7 @@ public: return _Mycomp; } - // set operations + // Set operations // NB: The non-const overloads are intentionally removed for brevity. This will not result in behavioral changes. _NODISCARD const_iterator find(const _Kty& _Val) const { return _Find(_Val); @@ -620,6 +647,7 @@ private: _Restore_invariants_after_insert<_NeedSorting>(_Old_size); _Guard._Target = nullptr; } + template _Rng> void _Insert_range(_Rng&& _Range) { const size_type _Old_size = size(); @@ -869,21 +897,23 @@ template <_Iterator_for_container _Iter, _Not_allocator_for_container _Compare = flat_set(_Iter, _Iter, _Compare = _Compare()) -> flat_set, _Compare>; template <_Iterator_for_container _Iter, _Not_allocator_for_container _Compare = less>> flat_set(sorted_unique_t, _Iter, _Iter, _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<_Kty>, _Compare = _Compare()) -> flat_set<_Kty, _Compare>; template > flat_set(sorted_unique_t, initializer_list<_Kty>, _Compare = _Compare()) -> flat_set<_Kty, _Compare>; - template <_Not_allocator_for_container _Container, _Valid_compare_for_container<_Container> _Compare = less> flat_multiset(_Container, _Compare = _Compare()) @@ -911,17 +941,20 @@ template <_Iterator_for_container _Iter, _Not_allocator_for_container _Compare = flat_multiset(_Iter, _Iter, _Compare = _Compare()) -> flat_multiset, _Compare>; template <_Iterator_for_container _Iter, _Not_allocator_for_container _Compare = less>> flat_multiset(sorted_equivalent_t, _Iter, _Iter, _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<_Kty>, _Compare = _Compare()) -> flat_multiset<_Kty, _Compare>; template > From d9f89433ad59bc92fbcf9b9c2b824bed94178e55 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Jan 2026 12:25:31 -0800 Subject: [PATCH 08/32] Improve `_Is_sorted_and_unique()` access control and overloads. The 1-arg overload was barely used. Make the 0-arg overload public only for the test suite. Move `_Value_compare_to_pass` down to its point of use. --- stl/inc/flat_map | 14 +++++++------- stl/inc/flat_set | 13 +++++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 5c8c68ebf64..85735878847 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -696,7 +696,7 @@ public: void replace(key_container_type&& _Key_cont, mapped_container_type&& _Mapped_cont) { _STL_ASSERT(_Key_cont.size() == _Mapped_cont.size(), "key_cont.size() != mapped_cont.size()"); - _STL_ASSERT(_Is_sorted_and_unique(_Key_cont), _Msg_not_sorted); + _STL_ASSERT(_Is_sorted_and_unique(_Key_cont.begin(), _Key_cont.end()), _Msg_not_sorted); _Clear_guard _Guard{this}; _Data.keys = _STD move(_Key_cont); _Data.values = _STD move(_Mapped_cont); @@ -1045,14 +1045,16 @@ private: _Mutating_iterator{_Data.keys.end(), _Data.values.end()}}; } +#ifdef _ENABLE_STL_INTERNAL_CHECK public: +#else +private: +#endif _NODISCARD bool _Is_sorted_and_unique() const { - return _Is_sorted_and_unique(_Data.keys); + return _Is_sorted_and_unique(_Data.keys.begin(), _Data.keys.end()); } private: - using _Value_compare_to_pass = _Value_compare_to_pass_in_flat_map<_Compare, _Key, _Mapped>; - _NODISCARD bool _Is_sorted_and_unique( const key_container_type::const_iterator _It, const key_container_type::const_iterator _End) const { if constexpr (_IsUnique) { @@ -1064,9 +1066,7 @@ private: } } - _NODISCARD bool _Is_sorted_and_unique(const key_container_type& _Cont) const { - return _Is_sorted_and_unique(_Cont.begin(), _Cont.end()); - } + using _Value_compare_to_pass = _Value_compare_to_pass_in_flat_map<_Compare, _Key, _Mapped>; void _Make_invariants_fulfilled() { if (empty()) { diff --git a/stl/inc/flat_set b/stl/inc/flat_set index e3f6d31694f..912db64b1c7 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -384,7 +384,7 @@ public: } void replace(container_type&& _Cont) { - _STL_ASSERT(_Is_sorted_and_unique(_Cont), _Msg_not_sorted); + _STL_ASSERT(_Is_sorted_and_unique(_Cont.begin(), _Cont.end()), _Msg_not_sorted); _Clear_guard _Guard{this}; _Mycont = _STD move(_Cont); _Guard._Target = nullptr; @@ -505,8 +505,13 @@ public: _Lhs.swap(_Rhs); } +#ifdef _ENABLE_STL_INTERNAL_CHECK +public: +#else +private: +#endif _NODISCARD bool _Is_sorted_and_unique() const { - return _Is_sorted_and_unique(_Mycont); + return _Is_sorted_and_unique(_Mycont.begin(), _Mycont.end()); } private: @@ -520,10 +525,6 @@ private: } } - _NODISCARD bool _Is_sorted_and_unique(const container_type& _Cont) const { - return _Is_sorted_and_unique(_Cont.begin(), _Cont.end()); - } - template _NODISCARD bool _Can_insert(const const_iterator _Where, const _Ty& _Val) const { _STL_INTERNAL_STATIC_ASSERT(is_same_v<_Ty, _Kty>); // only accepts _Kty From 4178c084fcdf2594783bf7c0a21e2c199782309c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Jan 2026 12:30:50 -0800 Subject: [PATCH 09/32] flat_map: Make `_Extract_using_allocator()` private, move above its only usage. --- stl/inc/flat_map | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 85735878847..9726295dbae 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -467,6 +467,15 @@ public: .values = _STD make_obj_using_allocator(_Alloc, _Other._Data.values)}, _Key_compare(_Other._Key_compare) {} +private: + template + _NODISCARD containers _Extract_using_allocator(const _Allocator& _Alloc) && { + _Clear_guard _Always_clear{this}; + return containers{.keys = _STD make_obj_using_allocator(_Alloc, _STD move(_Data.keys)), + .values = _STD make_obj_using_allocator(_Alloc, _STD move(_Data.values))}; + } + +public: template <_Usable_allocator_for _Allocator> _Flat_map_base(_Flat_map_base&& _Other, const _Allocator& _Alloc) : _Data{_STD move(_Other)._Extract_using_allocator(_Alloc)}, @@ -687,13 +696,6 @@ public: return _STD move(_Data); } - template - _NODISCARD containers _Extract_using_allocator(const _Allocator& _Alloc) && { - _Clear_guard _Always_clear{this}; - return containers{.keys = _STD make_obj_using_allocator(_Alloc, _STD move(_Data.keys)), - .values = _STD make_obj_using_allocator(_Alloc, _STD move(_Data.values))}; - } - void replace(key_container_type&& _Key_cont, mapped_container_type&& _Mapped_cont) { _STL_ASSERT(_Key_cont.size() == _Mapped_cont.size(), "key_cont.size() != mapped_cont.size()"); _STL_ASSERT(_Is_sorted_and_unique(_Key_cont.begin(), _Key_cont.end()), _Msg_not_sorted); From b76058daf6aaf2f887f4807a496760970adcafff Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Jan 2026 12:40:10 -0800 Subject: [PATCH 10/32] flat_map: `_Key_equal()` was dead. --- stl/inc/flat_map | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 9726295dbae..d8a216b7031 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -1005,16 +1005,6 @@ protected: _Guard._Target = nullptr; } - template - _NODISCARD bool _Key_equal(_KeyTy1&& _Left, _KeyTy2&& _Right) const { - _STL_INTERNAL_STATIC_ASSERT( - (is_same_v, key_type> && is_same_v, key_type>) - || (is_constructible_v && is_constructible_v - && _Transparent) ); - return !_Key_compare(_STD forward<_KeyTy1>(_Left), _STD forward<_KeyTy2>(_Right)) - && !_Key_compare(_STD forward<_KeyTy2>(_Right), _STD forward<_KeyTy1>(_Left)); - } - private: // typename is a workaround for VSO-2680018 (EDG) template From 62696ba22c168437879e210e7fc02fde6acbd684 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Jan 2026 15:38:55 -0800 Subject: [PATCH 11/32] flat_map: `_Insert_exact()` can be private. --- stl/inc/flat_map | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index d8a216b7031..4d6cb805d95 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -998,6 +998,7 @@ protected: return begin() + _Dist; } +private: void _Insert_exact(const const_iterator _Position, key_type&& _Key_val, mapped_type&& _Mapped_val) { _Clear_guard _Guard{this}; _Data.keys.insert(_Position._Key_it, _STD move(_Key_val)); @@ -1005,7 +1006,6 @@ protected: _Guard._Target = nullptr; } -private: // typename is a workaround for VSO-2680018 (EDG) template friend typename flat_map<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>::size_type erase_if( From c0afeb938f15b68420501fafab8cb75e5ee598a9 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Jan 2026 15:41:30 -0800 Subject: [PATCH 12/32] flat_map: Move `_Data`, `_Key_compare`, `_Pass_key_comp()` to the private section at the end, matching flat_set. This leaves only `_Try_emplace()` and `_Emplace_hint()` being protected. --- stl/inc/flat_map | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 4d6cb805d95..03354e847db 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -886,13 +886,6 @@ public: } protected: - containers _Data; - _MSVC_NO_UNIQUE_ADDRESS key_compare _Key_compare; - - _NODISCARD auto _Pass_key_comp() const noexcept { - return _STD _Pass_fn(_Key_compare); - } - template _NODISCARD conditional_t<_IsUnique, pair, iterator> _Try_emplace( _OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) { @@ -1220,6 +1213,13 @@ private: const difference_type _Offset = _Iter - _Self._Data.keys.cbegin(); return _Self.begin() + _Offset; } + + _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 From 3206520d0478d85690e6f27b70da9771a0b97dc1 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Jan 2026 15:47:48 -0800 Subject: [PATCH 13/32] flat_map: Simplify `erase_if()` because `size_type` is always `size_t`. --- stl/inc/flat_map | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 03354e847db..8f157e81631 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -999,16 +999,14 @@ private: _Guard._Target = nullptr; } - // typename is a workaround for VSO-2680018 (EDG) + // size_type is always size_t template - friend typename flat_map<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>::size_type erase_if( - flat_map<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>&, _Pred); + friend size_t erase_if(flat_map<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>&, _Pred); template - friend typename flat_multimap<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>::size_type erase_if( - flat_multimap<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>&, _Pred); + friend size_t erase_if(flat_multimap<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>&, _Pred); template - _NODISCARD size_type _Erase_if(_Predicate _Pred) { + _NODISCARD size_t _Erase_if(_Predicate _Pred) { _Clear_guard _Guard{this}; // N5032 [flat.map.erasure]/2 and [flat.multimap.erasure]/2 @@ -1490,8 +1488,7 @@ struct uses_allocator -flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>::size_type erase_if( - flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>& _Cont, _Predicate _Pred) { +size_t erase_if(flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>& _Cont, _Predicate _Pred) { return _Cont._Erase_if(_STD _Pass_fn(_Pred)); } @@ -1613,8 +1610,7 @@ struct uses_allocator -flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>::size_type erase_if( - flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>& _Cont, _Predicate _Pred) { +size_t erase_if(flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>& _Cont, _Predicate _Pred) { return _Cont._Erase_if(_STD _Pass_fn(_Pred)); } _STD_END From c13e357c72fac44dcafb7239dd893db3b78b2e9d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Jan 2026 16:18:38 -0800 Subject: [PATCH 14/32] flat_set: Harmonize operator=(initializer_list), avoid potential ambiguity. --- stl/inc/flat_map | 12 ++++++------ stl/inc/flat_set | 22 ++++++++++++---------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 8f157e81631..8a7ab293c70 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -1245,15 +1245,15 @@ public: flat_map(flat_map&& _Other, const _Allocator& _Al) : _Mybase(_STD move(_Other), _Al) {} #endif // ^^^ workaround ^^^ + 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& operator=(const flat_map&) = default; - flat_map& operator=(flat_map&&) = default; - // [flat.map.access] Access mapped_type& operator[](const key_type& _Key_val) requires is_default_constructible_v @@ -1512,14 +1512,14 @@ public: flat_multimap(flat_multimap&& _Other, const _Allocator& _Al) : _Mybase(_STD move(_Other), _Al) {} #endif // ^^^ workaround ^^^ + 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; } - - flat_multimap& operator=(const flat_multimap&) = default; - flat_multimap& operator=(flat_multimap&&) = default; }; template <_Not_allocator_for_container _KeyContainer, _Not_allocator_for_container _MappedContainer, diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 912db64b1c7..e65860b86b7 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -253,14 +253,6 @@ public: return *this; } - _Derived& operator=(const initializer_list<_Kty> _Ilist) { - _Clear_guard _Guard{this}; - _Mycont.assign(_Ilist); - _Make_invariants_fulfilled(); - _Guard._Target = nullptr; - return static_cast<_Derived&>(*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 { @@ -827,9 +819,14 @@ public: flat_set(flat_set&& _Other, const _Allocator& _Al) : _Mybase(_STD move(_Other), _Al) {} #endif // ^^^ workaround ^^^ - using _Mybase::operator=; // for operator=(initializer_list) flat_set& operator=(const flat_set&) = default; flat_set& operator=(flat_set&&) = default; + + flat_set& operator=(const initializer_list<_Kty> _Ilist) { + this->clear(); + this->insert(_Ilist.begin(), _Ilist.end()); + return *this; + } }; _EXPORT_STD template @@ -850,9 +847,14 @@ public: flat_multiset(flat_multiset&& _Other, const _Allocator& _Al) : _Mybase(_STD move(_Other), _Al) {} #endif // ^^^ workaround ^^^ - using _Mybase::operator=; // for operator=(initializer_list) flat_multiset& operator=(const flat_multiset&) = default; flat_multiset& operator=(flat_multiset&&) = default; + + flat_multiset& operator=(const initializer_list<_Kty> _Ilist) { + this->clear(); + this->insert(_Ilist.begin(), _Ilist.end()); + return *this; + } }; _EXPORT_STD template From 887ced4b3f71e4e756673924a9191ed18897f92a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 00:16:17 -0800 Subject: [PATCH 15/32] flat_set: In `_Equal_range()`, use `_Compare` (i.e. `_DEBUG_LT_PRED`) instead of `_Mycomp` directly. --- stl/inc/flat_set | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index e65860b86b7..dff7692f676 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -723,7 +723,7 @@ private: 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(_Mycont.begin(), _Mycont.end(), _Key_val, _Pass_comp()); - const bool _Missing = _First == _Mycont.end() || _Mycomp(_Key_val, *_First); + const bool _Missing = _First == _Mycont.end() || _Compare(_Key_val, *_First); return pair{_First, _Missing ? _First : _First + 1}; } else { return _STD equal_range(begin(), end(), _Key_val, _Pass_comp()); From 84ef4cec6292f7d31c1314d1aa5556beaab674bd Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 00:41:53 -0800 Subject: [PATCH 16/32] flat_set: Prefer to directly construct from `_First, _Last` instead of calling `assign()`. --- stl/inc/flat_set | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index dff7692f676..bfacd7fa754 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -122,8 +122,7 @@ public: template <_Iterator_for_container _Iter> _Flat_set_base(const _Iter _First, const _Iter _Last, const key_compare& _Comp = key_compare()) - : _Mycont(), _Mycomp(_Comp) { - _Mycont.assign(_First, _Last); + : _Mycont(_First, _Last), _Mycomp(_Comp) { _Make_invariants_fulfilled(); } @@ -182,15 +181,13 @@ public: template <_Iterator_for_container _Iter, _Usable_allocator_for _Alloc> _Flat_set_base(const _Iter _First, const _Iter _Last, const _Alloc& _Al) - : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp() { - _Mycont.assign(_First, _Last); + : _Mycont(_STD make_obj_using_allocator(_Al, _First, _Last)), _Mycomp() { _Make_invariants_fulfilled(); } template <_Iterator_for_container _Iter, _Usable_allocator_for _Alloc> _Flat_set_base(const _Iter _First, const _Iter _Last, const key_compare& _Comp, const _Alloc& _Al) - : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp(_Comp) { - _Mycont.assign(_First, _Last); + : _Mycont(_STD make_obj_using_allocator(_Al, _First, _Last)), _Mycomp(_Comp) { _Make_invariants_fulfilled(); } From fe4c952f294c0fc2dc0a67eda7cce168bdad8103 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 01:51:23 -0800 Subject: [PATCH 17/32] flat_set: Prefer uses-allocator construction from `_Al, from_range, _STD forward<_Rng>(_Range)` instead of calling `assign_range()`. --- stl/inc/flat_set | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index bfacd7fa754..bff689ac174 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -201,15 +201,15 @@ public: template <_Container_compatible_range<_Kty> _Rng, _Usable_allocator_for _Alloc> _Flat_set_base(from_range_t, _Rng&& _Range, const _Alloc& _Al) - : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp() { - _Mycont.assign_range(_STD forward<_Rng>(_Range)); + : _Mycont(_STD make_obj_using_allocator(_Al, from_range, _STD forward<_Rng>(_Range))), + _Mycomp() { _Make_invariants_fulfilled(); } template <_Container_compatible_range<_Kty> _Rng, _Usable_allocator_for _Alloc> _Flat_set_base(from_range_t, _Rng&& _Range, const key_compare& _Comp, const _Alloc& _Al) - : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp(_Comp) { - _Mycont.assign_range(_STD forward<_Rng>(_Range)); + : _Mycont(_STD make_obj_using_allocator(_Al, from_range, _STD forward<_Rng>(_Range))), + _Mycomp(_Comp) { _Make_invariants_fulfilled(); } From efb473a0d24ecf14601f05abac831e321465bec9 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 01:07:48 -0800 Subject: [PATCH 18/32] Fix alternative_vector, part 1: Remove default template arguments, never used. --- tests/std/tests/P1222R4_flat_set/test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index 242a27d47ea..ba4bd0e8380 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -29,8 +29,7 @@ enum class iterator_pair_construction : bool { no_allocator, with_allocator }; template concept container_compatible_range = ranges::input_range && convertible_to, T>; -template , - iterator_pair_construction Choice = iterator_pair_construction::with_allocator> +template class alternative_vector : private vector { // not allocator-aware, but can be uses-allocator constructed private: using base_type = vector; From df58f7abbb2affb77460ba9822e7e73e3c91b71e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 01:10:04 -0800 Subject: [PATCH 19/32] Fix alternative_vector, part 2: Always test sorted initializer_list/iter-pair construction with allocators. Nothing in the Standard allows this to be conditional. --- tests/std/tests/P1222R4_flat_set/test.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index ba4bd0e8380..7febdb88e05 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -268,13 +268,12 @@ void test_allocator_extended_constructors() { TEST_ASSERT(fs{sorted_unique, v_sorted_unique, ator} == s_expected); TEST_ASSERT(fs{sorted_unique, v_sorted_unique, comp, ator} == s_expected); - if constexpr (Choice == iterator_pair_construction::with_allocator) { - TEST_ASSERT(fs{sorted_unique, {1, 3, 7, 85, 222}, ator} == s_expected); - TEST_ASSERT(fs{sorted_unique, {1, 3, 7, 85, 222}, comp, ator} == s_expected); - TEST_ASSERT(fs{sorted_unique, v_sorted_unique.begin(), v_sorted_unique.end(), ator} == s_expected); - TEST_ASSERT(fs{sorted_unique, v_sorted_unique.begin(), v_sorted_unique.end(), comp, ator} == s_expected); - } + TEST_ASSERT(fs{sorted_unique, {1, 3, 7, 85, 222}, ator} == s_expected); + TEST_ASSERT(fs{sorted_unique, {1, 3, 7, 85, 222}, comp, ator} == s_expected); + + TEST_ASSERT(fs{sorted_unique, v_sorted_unique.begin(), v_sorted_unique.end(), ator} == s_expected); + TEST_ASSERT(fs{sorted_unique, v_sorted_unique.begin(), v_sorted_unique.end(), comp, ator} == s_expected); } { using fms = flat_multiset, vec>; @@ -304,13 +303,12 @@ void test_allocator_extended_constructors() { TEST_ASSERT(fms{sorted_equivalent, v_sorted_eq, ator} == s_expected); TEST_ASSERT(fms{sorted_equivalent, v_sorted_eq, comp, ator} == s_expected); - if constexpr (Choice == iterator_pair_construction::with_allocator) { - TEST_ASSERT(fms{sorted_equivalent, {1, 1, 3, 7, 85, 222}, ator} == s_expected); - TEST_ASSERT(fms{sorted_equivalent, {1, 1, 3, 7, 85, 222}, comp, ator} == s_expected); - TEST_ASSERT(fms{sorted_equivalent, v_sorted_eq.begin(), v_sorted_eq.end(), ator} == s_expected); - TEST_ASSERT(fms{sorted_equivalent, v_sorted_eq.begin(), v_sorted_eq.end(), comp, ator} == s_expected); - } + TEST_ASSERT(fms{sorted_equivalent, {1, 1, 3, 7, 85, 222}, ator} == s_expected); + TEST_ASSERT(fms{sorted_equivalent, {1, 1, 3, 7, 85, 222}, comp, ator} == s_expected); + + TEST_ASSERT(fms{sorted_equivalent, v_sorted_eq.begin(), v_sorted_eq.end(), ator} == s_expected); + TEST_ASSERT(fms{sorted_equivalent, v_sorted_eq.begin(), v_sorted_eq.end(), comp, ator} == s_expected); } } From 464fd376530df114ca7d5e87898c72d0df0ae153 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 01:15:13 -0800 Subject: [PATCH 20/32] Fix alternative_vector, part 3: Vary iterator_pair_construction between allocator_first and allocator_last. Followup to GH 4148. The method of construction can vary, but it must always work. N5032 [flat.set.cons.alloc]/1: "The constructors in this subclause shall not participate in overload resolution unless `uses_allocator_v` is `true`." [flat.set.cons.alloc]/6: "*Effects:* Equivalent to the corresponding non-allocator constructors except that *`c`* is constructed with uses-allocator construction ([allocator.uses.construction])." [allocator.uses.construction]/1: "*Uses-allocator construction* with allocator `alloc` and constructor arguments `args...` refers to the construction of an object of type `T` such that `alloc` is passed to the constructor of `T` if `T` uses an allocator type compatible with `alloc`. When applied to the construction of an object of type `T`, it is equivalent to initializing it with the value of the expression `make_obj_using_allocator(alloc, args...)`, described below." [sequence.reqmts]/8-10 requires iter-pair construction. If a container reports that `uses_allocator_v` is true (as `alternative_vector` does by virtue of having `allocator_type`), then the uses-allocator form of iter-pair construction must compile. --- tests/std/tests/P1222R4_flat_set/test.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index 7febdb88e05..185d5026189 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -24,7 +24,7 @@ using namespace std; -enum class iterator_pair_construction : bool { no_allocator, with_allocator }; +enum class iterator_pair_construction : bool { allocator_first, allocator_last }; template concept container_compatible_range = ranges::input_range && convertible_to, T>; @@ -55,9 +55,12 @@ class alternative_vector : private vector { // not allocator-aware, bu template constexpr explicit alternative_vector(InputIt first, InputIt last) : base_type(first, last) {} template - requires (Choice == iterator_pair_construction::with_allocator) + requires (Choice == iterator_pair_construction::allocator_first) constexpr explicit alternative_vector(allocator_arg_t, const Alloc& a, InputIt first, InputIt last) : base_type(first, last, a) {} + template + requires (Choice == iterator_pair_construction::allocator_last) + constexpr explicit alternative_vector(InputIt first, InputIt last, const Alloc& a) : base_type(first, last, a) {} template R> constexpr explicit alternative_vector(from_range_t, R&& rg) : base_type(from_range, forward(rg)) {} @@ -1343,8 +1346,8 @@ void run_normal_tests() { test_constructors>(); test_constructors>(); - test_allocator_extended_constructors(); - test_allocator_extended_constructors(); + test_allocator_extended_constructors(); + test_allocator_extended_constructors(); test_iterators_and_capacity>(); test_iterators_and_capacity>(); From 62c642483fe00963039426725ba2d2df902c7301 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 02:09:25 -0800 Subject: [PATCH 21/32] Fix alternative_vector, part 4: Add more allocator constructors. We don't actually need construction from `(size_type n)`. But we do need allocator constructors to be paired with `(size_type n, const T& v)`, `(from_range_t, R&& rg)`, and `(initializer_list il)`. --- tests/std/tests/P1222R4_flat_set/test.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index 185d5026189..bc47cbae256 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -50,8 +50,11 @@ class alternative_vector : private vector { // not allocator-aware, bu constexpr alternative_vector() noexcept(noexcept(Alloc())) : base_type(Alloc()) {} constexpr alternative_vector(allocator_arg_t, const Alloc& a) : base_type(a) {} - constexpr explicit alternative_vector(size_type n) : base_type(n) {} + constexpr explicit alternative_vector(size_type n, const T& v) : base_type(n, v) {} + constexpr explicit alternative_vector(allocator_arg_t, const Alloc& a, size_type n, const T& v) + : base_type(n, v, a) {} + template constexpr explicit alternative_vector(InputIt first, InputIt last) : base_type(first, last) {} template @@ -64,12 +67,17 @@ class alternative_vector : private vector { // not allocator-aware, bu template R> constexpr explicit alternative_vector(from_range_t, R&& rg) : base_type(from_range, forward(rg)) {} + template R> + constexpr explicit alternative_vector(allocator_arg_t, const Alloc& a, from_range_t, R&& rg) + : base_type(from_range, forward(rg), a) {} constexpr alternative_vector(allocator_arg_t, const type_identity_t& a, const alternative_vector& other) : base_type(other, a) {} constexpr alternative_vector(allocator_arg_t, const type_identity_t& a, alternative_vector&& other) : base_type(move(other), a) {} + constexpr explicit alternative_vector(initializer_list il) : base_type(il) {} + constexpr explicit alternative_vector(allocator_arg_t, const Alloc& a, initializer_list il) : base_type(il, a) {} alternative_vector(const alternative_vector&) = default; alternative_vector(alternative_vector&&) = default; From b8b9267469ce07d4a8456ca42d9fc84e02f3ec31 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 01:46:59 -0800 Subject: [PATCH 22/32] Reported LLVM-178624. --- tests/libcxx/expected_results.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index d21b291e7ab..927d723c914 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -70,6 +70,10 @@ std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp: # LLVM-176232: The implementation of P3567R2 "flat_meow Fixes" forgot to update `__cpp_lib_flat_set` std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp FAIL +# LLVM-178624: [libc++][test] flat_set tests have an EvilContainer that's too evil +std/containers/container.adaptors/flat.multiset/flat.multiset.cons/move.pass.cpp FAIL +std/containers/container.adaptors/flat.set/flat.set.cons/move.pass.cpp FAIL + # Non-Standard regex behavior. # "It seems likely that the test is still non-conforming due to how libc++ handles the 'w' character class." std/re/re.traits/lookup_classname.pass.cpp FAIL From acb376e358e5e863793db8192be8d8e8db401bfb Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 02:33:02 -0800 Subject: [PATCH 23/32] flat_set: Avoid delegating ctors. This is simpler and more efficient in debug mode, at the cost of a few lines. The repetitive nature is actually easier to review. --- stl/inc/flat_set | 79 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index bff689ac174..0c6e51409d0 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -99,7 +99,7 @@ public: "(N5032 [flat.set.overview]/7, [flat.multiset.overview]/7)"); // [flat.set.cons] Constructors - _Flat_set_base() : _Flat_set_base(key_compare()) {} + _Flat_set_base() : _Mycont(), _Mycomp() {} _Flat_set_base(const _Flat_set_base&) = default; @@ -127,22 +127,31 @@ public: } template <_Iterator_for_container _Iter> - _Flat_set_base(_Sorted_t _Tag, const _Iter _First, const _Iter _Last, const key_compare& _Comp = key_compare()) - : _Flat_set_base(_Tag, container_type(_First, _Last), _Comp) {} + _Flat_set_base(_Sorted_t, const _Iter _First, const _Iter _Last, const key_compare& _Comp = key_compare()) + : _Mycont(_First, _Last), _Mycomp(_Comp) { + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); + } template <_Container_compatible_range<_Kty> _Rng> - _Flat_set_base(from_range_t, _Rng&& _Range) - : _Flat_set_base(container_type(from_range, _STD forward<_Rng>(_Range))) {} + _Flat_set_base(from_range_t, _Rng&& _Range) : _Mycont(from_range, _STD forward<_Rng>(_Range)), _Mycomp() { + _Make_invariants_fulfilled(); + } template <_Container_compatible_range<_Kty> _Rng> _Flat_set_base(from_range_t, _Rng&& _Range, const key_compare& _Comp) - : _Flat_set_base(container_type(from_range, _STD forward<_Rng>(_Range)), _Comp) {} + : _Mycont(from_range, _STD forward<_Rng>(_Range)), _Mycomp(_Comp) { + _Make_invariants_fulfilled(); + } _Flat_set_base(const initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) - : _Flat_set_base(_Ilist.begin(), _Ilist.end(), _Comp) {} + : _Mycont(_Ilist.begin(), _Ilist.end()), _Mycomp(_Comp) { + _Make_invariants_fulfilled(); + } - _Flat_set_base(_Sorted_t _Tag, const initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) - : _Flat_set_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp) {} + _Flat_set_base(_Sorted_t, const initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) + : _Mycont(_Ilist.begin(), _Ilist.end()), _Mycomp(_Comp) { + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); + } // [flat.set.cons.alloc] Constructors with allocators template <_Usable_allocator_for _Alloc> @@ -155,19 +164,27 @@ public: template <_Usable_allocator_for _Alloc> _Flat_set_base(const container_type& _Cont, const _Alloc& _Al) - : _Flat_set_base(_STD make_obj_using_allocator(_Al, _Cont)) {} + : _Mycont(_STD make_obj_using_allocator(_Al, _Cont)), _Mycomp() { + _Make_invariants_fulfilled(); + } template <_Usable_allocator_for _Alloc> _Flat_set_base(const container_type& _Cont, const key_compare& _Comp, const _Alloc& _Al) - : _Flat_set_base(_STD make_obj_using_allocator(_Al, _Cont), _Comp) {} + : _Mycont(_STD make_obj_using_allocator(_Al, _Cont)), _Mycomp(_Comp) { + _Make_invariants_fulfilled(); + } template <_Usable_allocator_for _Alloc> - _Flat_set_base(_Sorted_t _Tag, const container_type& _Cont, const _Alloc& _Al) - : _Flat_set_base(_Tag, _STD make_obj_using_allocator(_Al, _Cont)) {} + _Flat_set_base(_Sorted_t, const container_type& _Cont, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al, _Cont)), _Mycomp() { + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); + } template <_Usable_allocator_for _Alloc> - _Flat_set_base(_Sorted_t _Tag, const container_type& _Cont, const key_compare& _Comp, const _Alloc& _Al) - : _Flat_set_base(_Tag, _STD make_obj_using_allocator(_Al, _Cont), _Comp) {} + _Flat_set_base(_Sorted_t, const container_type& _Cont, const key_compare& _Comp, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al, _Cont)), _Mycomp(_Comp) { + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); + } template <_Usable_allocator_for _Alloc> _Flat_set_base(const _Flat_set_base& _Other, const _Alloc& _Al) @@ -192,12 +209,16 @@ public: } template <_Iterator_for_container _Iter, _Usable_allocator_for _Alloc> - _Flat_set_base(_Sorted_t _Tag, const _Iter _First, const _Iter _Last, const _Alloc& _Al) - : _Flat_set_base(_Tag, _STD make_obj_using_allocator(_Al, _First, _Last)) {} + _Flat_set_base(_Sorted_t, const _Iter _First, const _Iter _Last, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al, _First, _Last)), _Mycomp() { + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); + } template <_Iterator_for_container _Iter, _Usable_allocator_for _Alloc> - _Flat_set_base(_Sorted_t _Tag, const _Iter _First, const _Iter _Last, const key_compare& _Comp, const _Alloc& _Al) - : _Flat_set_base(_Tag, _STD make_obj_using_allocator(_Al, _First, _Last), _Comp) {} + _Flat_set_base(_Sorted_t, const _Iter _First, const _Iter _Last, const key_compare& _Comp, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al, _First, _Last)), _Mycomp(_Comp) { + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); + } template <_Container_compatible_range<_Kty> _Rng, _Usable_allocator_for _Alloc> _Flat_set_base(from_range_t, _Rng&& _Range, const _Alloc& _Al) @@ -215,19 +236,27 @@ public: template <_Usable_allocator_for _Alloc> _Flat_set_base(const initializer_list<_Kty> _Ilist, const _Alloc& _Al) - : _Flat_set_base(_Ilist.begin(), _Ilist.end(), _Al) {} + : _Mycont(_STD make_obj_using_allocator(_Al, _Ilist.begin(), _Ilist.end())), _Mycomp() { + _Make_invariants_fulfilled(); + } template <_Usable_allocator_for _Alloc> _Flat_set_base(const initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) - : _Flat_set_base(_Ilist.begin(), _Ilist.end(), _Comp, _Al) {} + : _Mycont(_STD make_obj_using_allocator(_Al, _Ilist.begin(), _Ilist.end())), _Mycomp(_Comp) { + _Make_invariants_fulfilled(); + } template <_Usable_allocator_for _Alloc> - _Flat_set_base(_Sorted_t _Tag, const initializer_list<_Kty> _Ilist, const _Alloc& _Al) - : _Flat_set_base(_Tag, _Ilist.begin(), _Ilist.end(), _Al) {} + _Flat_set_base(_Sorted_t, const initializer_list<_Kty> _Ilist, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al, _Ilist.begin(), _Ilist.end())), _Mycomp() { + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); + } template <_Usable_allocator_for _Alloc> - _Flat_set_base(_Sorted_t _Tag, const initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) - : _Flat_set_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp, _Al) {} + _Flat_set_base(_Sorted_t, const initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al, _Ilist.begin(), _Ilist.end())), _Mycomp(_Comp) { + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); + } // Assignment operators _Flat_set_base& operator=(const _Flat_set_base& _Other) { From 14b29f37b2bb6407e504d5e29b9b89236187cfe3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 02:45:26 -0800 Subject: [PATCH 24/32] flat_map: Mostly avoid delegating ctors. This still uses some delegating ctors for allocators, but at least avoids double delegation. --- stl/inc/flat_map | 60 +++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 8a7ab293c70..bc0baed8816 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -366,7 +366,7 @@ public: }; // [flat.map.cons] Constructors - _Flat_map_base() : _Flat_map_base(key_compare()) {} + _Flat_map_base() : _Data(), _Key_compare() {} _Flat_map_base(const _Flat_map_base& _Other) : _Data(_Other._Data), _Key_compare(_Other._Key_compare) {} @@ -395,35 +395,43 @@ public: template <_Iterator_for_container _InputIterator> _Flat_map_base(const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp = key_compare()) - : _Flat_map_base(_Comp) { + : _Data(), _Key_compare(_Comp) { insert(_First, _Last); } template <_Iterator_for_container _InputIterator> _Flat_map_base( _Sorted_t, const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp = key_compare()) - : _Flat_map_base(_Comp) { + : _Data(), _Key_compare(_Comp) { _Insert_range(_First, _Last); } template <_Container_compatible_range _Rng> - _Flat_map_base(from_range_t _From_range, _Rng&& _Range) - : _Flat_map_base(_From_range, _STD forward<_Rng>(_Range), key_compare()) {} + _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) : _Flat_map_base(_Comp) { + _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()) - : _Flat_map_base(_Ilist.begin(), _Ilist.end(), _Comp) {} + : _Data(), _Key_compare(_Comp) { + insert(_Ilist.begin(), _Ilist.end()); + } - _Flat_map_base(_Sorted_t _Tag, const initializer_list _Ilist, const key_compare& _Comp = key_compare()) - : _Flat_map_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp) {} + _Flat_map_base(_Sorted_t, const initializer_list _Ilist, const key_compare& _Comp = key_compare()) + : _Data(), _Key_compare(_Comp) { + _Insert_range(_Ilist.begin(), _Ilist.end()); + } // [flat.map.cons.alloc] Constructors with allocators template <_Usable_allocator_for _Allocator> - explicit _Flat_map_base(const _Allocator& _Alloc) : _Flat_map_base(key_compare(), _Alloc) {} + explicit _Flat_map_base(const _Allocator& _Alloc) + : _Data{.keys = _STD make_obj_using_allocator(_Alloc), + .values = _STD make_obj_using_allocator(_Alloc)}, + _Key_compare() {} template <_Usable_allocator_for _Allocator> _Flat_map_base(const key_compare& _Comp, const _Allocator& _Alloc) @@ -499,8 +507,10 @@ public: template <_Iterator_for_container _InputIterator, _Usable_allocator_for _Allocator> - _Flat_map_base(_Sorted_t _Tag, const _InputIterator _First, const _InputIterator _Last, const _Allocator& _Alloc) - : _Flat_map_base(_Tag, _First, _Last, key_compare(), _Alloc) {} + _Flat_map_base(_Sorted_t, const _InputIterator _First, const _InputIterator _Last, const _Allocator& _Alloc) + : _Flat_map_base(_Alloc) { + _Insert_range(_First, _Last); + } template <_Iterator_for_container _InputIterator, _Usable_allocator_for _Allocator> @@ -512,8 +522,9 @@ public: template <_Container_compatible_range _Rng, _Usable_allocator_for _Allocator> - _Flat_map_base(from_range_t _From_range, _Rng&& _Range, const _Allocator& _Alloc) - : _Flat_map_base(_From_range, _STD forward<_Rng>(_Range), key_compare(), _Alloc) {} + _Flat_map_base(from_range_t, _Rng&& _Range, const _Allocator& _Alloc) : _Flat_map_base(_Alloc) { + insert_range(_STD forward<_Rng>(_Range)); + } template <_Container_compatible_range _Rng, _Usable_allocator_for _Allocator> @@ -523,21 +534,28 @@ public: } template <_Usable_allocator_for _Allocator> - _Flat_map_base(const initializer_list _Ilist, const _Allocator& _Alloc) - : _Flat_map_base(_Ilist, key_compare(), _Alloc) {} + _Flat_map_base(const initializer_list _Ilist, const _Allocator& _Alloc) : _Flat_map_base(_Alloc) { + insert(_Ilist.begin(), _Ilist.end()); + } template <_Usable_allocator_for _Allocator> _Flat_map_base(const initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) - : _Flat_map_base(_Ilist.begin(), _Ilist.end(), _Comp, _Alloc) {} + : _Flat_map_base(_Comp, _Alloc) { + insert(_Ilist.begin(), _Ilist.end()); + } template <_Usable_allocator_for _Allocator> - _Flat_map_base(_Sorted_t _Tag, const initializer_list _Ilist, const _Allocator& _Alloc) - : _Flat_map_base(_Tag, _Ilist, key_compare(), _Alloc) {} + _Flat_map_base(_Sorted_t, const initializer_list _Ilist, const _Allocator& _Alloc) + : _Flat_map_base(_Alloc) { + _Insert_range(_Ilist.begin(), _Ilist.end()); + } template <_Usable_allocator_for _Allocator> _Flat_map_base( - _Sorted_t _Tag, const initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) - : _Flat_map_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp, _Alloc) {} + _Sorted_t, const initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) + : _Flat_map_base(_Comp, _Alloc) { + _Insert_range(_Ilist.begin(), _Ilist.end()); + } // Assignment operators _Flat_map_base& operator=(const _Flat_map_base& _Other) { From a2612d31a2b48fd86f9f67c1532909752c35c886 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 03:25:17 -0800 Subject: [PATCH 25/32] flat_map: Use `= default;` for the copy ctor. This aligns with what flat_set does. --- stl/inc/flat_map | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index bc0baed8816..99d42bc165a 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -368,7 +368,7 @@ public: // [flat.map.cons] Constructors _Flat_map_base() : _Data(), _Key_compare() {} - _Flat_map_base(const _Flat_map_base& _Other) : _Data(_Other._Data), _Key_compare(_Other._Key_compare) {} + _Flat_map_base(const _Flat_map_base&) = default; _Flat_map_base(_Flat_map_base&& _Other) noexcept(is_nothrow_copy_constructible_v && is_nothrow_move_constructible_v From d49e5029502342bf521dde4b98a81032276f2bc3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 03:33:44 -0800 Subject: [PATCH 26/32] flat_map: Simplify how we call insert(). --- stl/inc/flat_map | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 99d42bc165a..0e17baac7b7 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -400,10 +400,10 @@ public: } template <_Iterator_for_container _InputIterator> - _Flat_map_base( - _Sorted_t, const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp = key_compare()) + _Flat_map_base(_Sorted_t _Tag, const _InputIterator _First, const _InputIterator _Last, + const key_compare& _Comp = key_compare()) : _Data(), _Key_compare(_Comp) { - _Insert_range(_First, _Last); + insert(_Tag, _First, _Last); } template <_Container_compatible_range _Rng> @@ -418,12 +418,12 @@ public: _Flat_map_base(const initializer_list _Ilist, const key_compare& _Comp = key_compare()) : _Data(), _Key_compare(_Comp) { - insert(_Ilist.begin(), _Ilist.end()); + insert(_Ilist); } - _Flat_map_base(_Sorted_t, const initializer_list _Ilist, const key_compare& _Comp = key_compare()) + _Flat_map_base(_Sorted_t _Tag, const initializer_list _Ilist, const key_compare& _Comp = key_compare()) : _Data(), _Key_compare(_Comp) { - _Insert_range(_Ilist.begin(), _Ilist.end()); + insert(_Tag, _Ilist); } // [flat.map.cons.alloc] Constructors with allocators @@ -507,17 +507,17 @@ public: template <_Iterator_for_container _InputIterator, _Usable_allocator_for _Allocator> - _Flat_map_base(_Sorted_t, const _InputIterator _First, const _InputIterator _Last, const _Allocator& _Alloc) + _Flat_map_base(_Sorted_t _Tag, const _InputIterator _First, const _InputIterator _Last, const _Allocator& _Alloc) : _Flat_map_base(_Alloc) { - _Insert_range(_First, _Last); + insert(_Tag, _First, _Last); } template <_Iterator_for_container _InputIterator, _Usable_allocator_for _Allocator> - _Flat_map_base(_Sorted_t, const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp, + _Flat_map_base(_Sorted_t _Tag, const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp, const _Allocator& _Alloc) : _Flat_map_base(_Comp, _Alloc) { - _Insert_range(_First, _Last); + insert(_Tag, _First, _Last); } template <_Container_compatible_range _Rng, @@ -535,26 +535,26 @@ public: template <_Usable_allocator_for _Allocator> _Flat_map_base(const initializer_list _Ilist, const _Allocator& _Alloc) : _Flat_map_base(_Alloc) { - insert(_Ilist.begin(), _Ilist.end()); + insert(_Ilist); } template <_Usable_allocator_for _Allocator> _Flat_map_base(const initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) : _Flat_map_base(_Comp, _Alloc) { - insert(_Ilist.begin(), _Ilist.end()); + insert(_Ilist); } template <_Usable_allocator_for _Allocator> - _Flat_map_base(_Sorted_t, const initializer_list _Ilist, const _Allocator& _Alloc) + _Flat_map_base(_Sorted_t _Tag, const initializer_list _Ilist, const _Allocator& _Alloc) : _Flat_map_base(_Alloc) { - _Insert_range(_Ilist.begin(), _Ilist.end()); + insert(_Tag, _Ilist); } template <_Usable_allocator_for _Allocator> _Flat_map_base( - _Sorted_t, const initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) + _Sorted_t _Tag, const initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) : _Flat_map_base(_Comp, _Alloc) { - _Insert_range(_Ilist.begin(), _Ilist.end()); + insert(_Tag, _Ilist); } // Assignment operators From f2f6149ad916c09157ed73cf1a8bc50b0b3696cb Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 03:46:11 -0800 Subject: [PATCH 27/32] flat_map: Extract `_Efficiently_copyable`, rename `_Key_compare` to `_Copy_or_ref`. `_Key_compare` is usually a data member name instead of a type, so this was confusing. --- stl/inc/flat_map | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 0e17baac7b7..80226ee2eda 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -275,13 +275,13 @@ struct _NODISCARD _Flat_map_swap_clear_guard { template struct _Value_compare_to_pass_in_flat_map { - using _Key_compare = - conditional_t, - is_trivially_copy_constructible<_Compare>, is_trivially_destructible<_Compare>>, - _Compare, const _Compare&>; + static constexpr bool _Efficiently_copyable = conjunction_v, + is_trivially_copy_constructible<_Compare>, is_trivially_destructible<_Compare>>; + + using _Copy_or_ref = conditional_t<_Efficiently_copyable, _Compare, const _Compare&>; using _Const_reference = pair; - _Key_compare _Key_comparator; + _Copy_or_ref _Key_comparator; _NODISCARD bool operator()(_Const_reference _Left, _Const_reference _Right) const { return _Key_comparator(_Left.first, _Right.first); From 58ba53e54ea2ecb1fc48c0dd4e91a2290c13bb63 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 04:08:58 -0800 Subject: [PATCH 28/32] flat_map: Avoid `pair` conversions when invoking `_Value_compare_to_pass_in_flat_map`. `pair` wasn't the right type! --- stl/inc/flat_map | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 80226ee2eda..2dda0d6bf6b 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -273,17 +273,17 @@ struct _NODISCARD _Flat_map_swap_clear_guard { void _Dismiss() noexcept {} }; -template +template struct _Value_compare_to_pass_in_flat_map { static constexpr bool _Efficiently_copyable = conjunction_v, is_trivially_copy_constructible<_Compare>, is_trivially_destructible<_Compare>>; - using _Copy_or_ref = conditional_t<_Efficiently_copyable, _Compare, const _Compare&>; - using _Const_reference = pair; + using _Copy_or_ref = conditional_t<_Efficiently_copyable, _Compare, const _Compare&>; _Copy_or_ref _Key_comparator; - _NODISCARD bool operator()(_Const_reference _Left, _Const_reference _Right) const { + template + _NODISCARD bool operator()(const _Pair1& _Left, const _Pair2& _Right) const { return _Key_comparator(_Left.first, _Right.first); } }; @@ -1067,7 +1067,7 @@ private: } } - using _Value_compare_to_pass = _Value_compare_to_pass_in_flat_map<_Compare, _Key, _Mapped>; + using _Value_compare_to_pass = _Value_compare_to_pass_in_flat_map<_Compare>; void _Make_invariants_fulfilled() { if (empty()) { From 1cd16310075a6f6d9829481161738b46916bdc52 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 04:11:11 -0800 Subject: [PATCH 29/32] flat_map: Move `_Value_compare_to_pass` within `_Flat_map_base`. --- stl/inc/flat_map | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 2dda0d6bf6b..7acee4d161a 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -273,21 +273,6 @@ struct _NODISCARD _Flat_map_swap_clear_guard { void _Dismiss() noexcept {} }; -template -struct _Value_compare_to_pass_in_flat_map { - static constexpr bool _Efficiently_copyable = conjunction_v, - is_trivially_copy_constructible<_Compare>, is_trivially_destructible<_Compare>>; - - using _Copy_or_ref = conditional_t<_Efficiently_copyable, _Compare, const _Compare&>; - - _Copy_or_ref _Key_comparator; - - template - _NODISCARD bool operator()(const _Pair1& _Left, const _Pair2& _Right) const { - return _Key_comparator(_Left.first, _Right.first); - } -}; - _EXPORT_STD template , class _KeyContainer = vector<_Key>, class _MappedContainer = vector<_Mapped>> class flat_map; @@ -1067,7 +1052,19 @@ private: } } - using _Value_compare_to_pass = _Value_compare_to_pass_in_flat_map<_Compare>; + struct _Value_compare_to_pass { + static constexpr bool _Efficiently_copyable = conjunction_v, + is_trivially_copy_constructible<_Compare>, is_trivially_destructible<_Compare>>; + + using _Copy_or_ref = conditional_t<_Efficiently_copyable, _Compare, const _Compare&>; + + _Copy_or_ref _Key_comparator; + + template + _NODISCARD bool operator()(const _Pair1& _Left, const _Pair2& _Right) const { + return _Key_comparator(_Left.first, _Right.first); + } + }; void _Make_invariants_fulfilled() { if (empty()) { From c26e4e26a49c2bbe2a1b6af07d779eb209bc160f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 04:31:50 -0800 Subject: [PATCH 30/32] flat_map: `_Erase_dupes_if_not_multi_pred()` should take `(const auto& _Left, const auto& _Right)` to avoid `pair` conversions too. --- stl/inc/flat_map | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 7acee4d161a..e42c1be571b 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -1089,12 +1089,10 @@ private: auto _Erase_dupes_if_not_multi_pred() { _STL_INTERNAL_STATIC_ASSERT(_IsUnique); if constexpr (_Equivalence_is_equality<_Compare, _Key>) { - return [](const_reference _Left, const_reference _Right) + return [](const auto& _Left, const auto& _Right) _STATIC_CALL_OPERATOR { return _Left.first == _Right.first; }; } else { - return [this](const_reference _Left, const_reference _Right) { - return !_Key_compare(_Left.first, _Right.first); - }; + return [this](const auto& _Left, const auto& _Right) { return !_Key_compare(_Left.first, _Right.first); }; } } From 45beb67e43114aac89b2fee115b0da4f9c964da5 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 04:43:28 -0800 Subject: [PATCH 31/32] flat_map: Use `_DEBUG_LT_PRED`. --- stl/inc/flat_map | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index e42c1be571b..75a3746027f 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -899,7 +899,7 @@ protected: 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() && !_Key_compare(*(_Key_it - 1), _STD forward<_OtherKey>(_Key_val))) { + if (_Key_it != _Data.keys.begin() && !_Compare_keys(*(_Key_it - 1), _STD forward<_OtherKey>(_Key_val))) { // Previous element is equivalent to key, no insert needed return {begin() + (_Index - 1), false}; } @@ -932,16 +932,16 @@ protected: const weak_ordering _Hint_order = [&] { if constexpr (_IsUnique) { - if (_Position == _End || _Key_compare(_Key_val, *_Position._Key_it)) { - if (_Position == _Begin || _Key_compare(*(_Position._Key_it - 1), _Key_val)) { + 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 || !_Key_compare(*_Position._Key_it, _Key_val)) { - if (_Position == _Begin || !_Key_compare(_Key_val, *(_Position._Key_it - 1))) { + 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; @@ -968,14 +968,14 @@ protected: if constexpr (_IsUnique) { if (_Hint_order == weak_ordering::less) { - if (_New_position != _End && !_Key_compare(_Key_val, *_New_position._Key_it)) { + if (_New_position != _End && !_Compare_keys(_Key_val, *_New_position._Key_it)) { if constexpr (_OverwriteIfExists) { *_New_position._Mapped_it = mapped_type(_STD forward<_MappedArgTypes>(_Args)...); } return _New_position; } } else { - if (_New_position != _Begin && !_Key_compare(*(_New_position._Key_it - 1), _Key_val)) { + 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>(_Args)...); @@ -1045,7 +1045,7 @@ private: 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 !_Key_compare(_Lhs, _Rhs); }; + 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()); @@ -1092,7 +1092,7 @@ private: return [](const auto& _Left, const auto& _Right) _STATIC_CALL_OPERATOR { return _Left.first == _Right.first; }; } else { - return [this](const auto& _Left, const auto& _Right) { return !_Key_compare(_Left.first, _Right.first); }; + return [this](const auto& _Left, const auto& _Right) { return !_Compare_keys(_Left.first, _Right.first); }; } } @@ -1164,7 +1164,7 @@ private: _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._Key_compare(_Key_val, *_Position)) { + if (_Position != _Self._Data.keys.end() && !_Self._Compare_keys(_Key_val, *_Position)) { return _Self._Iterator_from_key_iterator(_Position); } else { return _Self.end(); @@ -1208,7 +1208,7 @@ private: // 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._Key_compare(_Key_val, *_First); + 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 { @@ -1225,6 +1225,15 @@ private: 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( + _Transparent || (is_same_v && is_same_v) ); + + return _DEBUG_LT_PRED(_Key_compare, _Lhs, _Rhs); + } + _NODISCARD auto _Pass_key_comp() const noexcept { return _STD _Pass_fn(_Key_compare); } From 00acdcd21e453dc4078dfbe2f0c61443c7ccddc6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Jan 2026 08:18:17 -0800 Subject: [PATCH 32/32] Avoid spurious `-Wunused-lambda-capture` warning. --- stl/inc/flat_map | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 75a3746027f..b1f4b2f477e 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -1092,7 +1092,10 @@ private: return [](const auto& _Left, const auto& _Right) _STATIC_CALL_OPERATOR { return _Left.first == _Right.first; }; } else { - return [this](const auto& _Left, const auto& _Right) { return !_Compare_keys(_Left.first, _Right.first); }; + return [this](const auto& _Left, const auto& _Right) { + // TRANSITION, not yet reported: `this->` avoids spurious -Wunused-lambda-capture warning with Clang 20 + return !this->_Compare_keys(_Left.first, _Right.first); + }; } }