From f5f12d84190ea4ac298aadd924440e8774907007 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 03:42:52 -0800 Subject: [PATCH 01/13] flat_map: Deduplicate codepaths in `_Emplace_hint()`. --- stl/inc/flat_map | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 7ab9517882c..38c024ca13b 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -949,18 +949,9 @@ protected: return weak_ordering::less; }(); - if (_Hint_order == weak_ordering::equivalent) { - const auto _Dist = _Position._Key_it - _Begin._Key_it; - { - key_type _Key_to_insert(_STD forward<_OtherKey>(_Key_val)); - mapped_type _Mapped_to_insert(_STD forward<_MappedArgTypes>(_Args)...); - _Insert_exact(_Position, _STD move(_Key_to_insert), _STD move(_Mapped_to_insert)); - } - return begin() + _Dist; - } - const auto _New_position = _Iterator_from_key_iterator( - _Hint_order == weak_ordering::less + _Hint_order == weak_ordering::equivalent ? _Position._Key_it + : _Hint_order == weak_ordering::less ? _STD lower_bound(_Position._Key_it, _Data.keys.cend(), _Key_val, _Pass_key_comp()) : _STD upper_bound(_Data.keys.cbegin(), _Position._Key_it, _Key_val, _Pass_key_comp())); @@ -972,7 +963,7 @@ protected: } return _New_position; } - } else { + } else if (_Hint_order == weak_ordering::greater) { if (_New_position != _Begin && !_Compare_keys(*(_New_position._Key_it - 1), _Key_val)) { const auto _It = _New_position - 1; if constexpr (_OverwriteIfExists) { From c98aeaee5664a1ac5d4396ba116816995d56ac7f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 03:50:03 -0800 Subject: [PATCH 02/13] flat_map: `_Emplace_hint()`: `_MappedArgTypes&&... _Args` => `_MappedArgTypes&&... _Mapped_args` --- stl/inc/flat_map | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 38c024ca13b..95a3f836f3f 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -917,7 +917,7 @@ protected: template _NODISCARD iterator _Emplace_hint( - const const_iterator _Position, _OtherKey&& _Key_val, _MappedArgTypes&&... _Args) { + const const_iterator _Position, _OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) { _STL_INTERNAL_STATIC_ASSERT(is_constructible_v); _STL_INTERNAL_STATIC_ASSERT(is_same_v, key_type> || (is_constructible_v && _Transparent) ); @@ -959,7 +959,7 @@ protected: if (_Hint_order == weak_ordering::less) { if (_New_position != _End && !_Compare_keys(_Key_val, *_New_position._Key_it)) { if constexpr (_OverwriteIfExists) { - *_New_position._Mapped_it = mapped_type(_STD forward<_MappedArgTypes>(_Args)...); + *_New_position._Mapped_it = mapped_type(_STD forward<_MappedArgTypes>(_Mapped_args)...); } return _New_position; } @@ -967,7 +967,7 @@ protected: 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)...); + *_It._Mapped_it = mapped_type(_STD forward<_MappedArgTypes>(_Mapped_args)...); } return _It; } @@ -977,7 +977,7 @@ protected: const auto _Dist = _New_position - begin(); { key_type _Key_to_insert(_STD forward<_OtherKey>(_Key_val)); - mapped_type _Mapped_to_insert(_STD forward<_MappedArgTypes>(_Args)...); + mapped_type _Mapped_to_insert(_STD forward<_MappedArgTypes>(_Mapped_args)...); _Insert_exact(_New_position, _STD move(_Key_to_insert), _STD move(_Mapped_to_insert)); } return begin() + _Dist; From e3851ab7c30aa2b927448a91d0a7f836717448bc Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 03:56:54 -0800 Subject: [PATCH 03/13] flat_map: Upgrade `_Insert_exact()` into `_Emplace_exact()`. --- stl/inc/flat_map | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 95a3f836f3f..c2daf8e50cc 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -904,9 +904,8 @@ protected: } // Need to insert - key_type _Key_to_insert(_STD forward<_OtherKey>(_Key_val)); - mapped_type _Mapped_to_insert(_STD forward<_MappedArgTypes>(_Mapped_args)...); - _Insert_exact(cbegin() + _Index, _STD move(_Key_to_insert), _STD move(_Mapped_to_insert)); + _Emplace_exact( + cbegin() + _Index, _STD forward<_OtherKey>(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); if constexpr (_IsUnique) { return {begin() + _Index, true}; @@ -975,11 +974,8 @@ protected: } const auto _Dist = _New_position - begin(); - { - key_type _Key_to_insert(_STD forward<_OtherKey>(_Key_val)); - mapped_type _Mapped_to_insert(_STD forward<_MappedArgTypes>(_Mapped_args)...); - _Insert_exact(_New_position, _STD move(_Key_to_insert), _STD move(_Mapped_to_insert)); - } + _Emplace_exact( + _New_position, _STD forward<_OtherKey>(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); return begin() + _Dist; } @@ -1080,10 +1076,11 @@ private: _Restore_invariants(_Sorted_size); } - void _Insert_exact(const const_iterator _Position, key_type&& _Key_val, mapped_type&& _Mapped_val) { + template + void _Emplace_exact(const const_iterator _Position, _OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) { _Clear_guard _Guard{this}; - _Data.keys.insert(_Position._Key_it, _STD move(_Key_val)); - _Data.values.insert(_Position._Mapped_it, _STD move(_Mapped_val)); + _Data.keys.emplace(_Position._Key_it, _STD forward<_OtherKey>(_Key_val)); + _Data.values.emplace(_Position._Mapped_it, _STD forward<_MappedArgTypes>(_Mapped_args)...); _Guard._Target = nullptr; } From ebbf6fe81f9765756ba864ad845b5f976cb58d0d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 04:08:27 -0800 Subject: [PATCH 04/13] Style: We generally construct `_Clear_guard` immediately. --- stl/inc/flat_map | 4 ++-- stl/inc/flat_set | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index c2daf8e50cc..f2b994b060d 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -1086,10 +1086,10 @@ private: template void _Insert_range(_InIt _First, const _Sentinel _Last) { - const size_type _Old_size = size(); - _Clear_guard _Guard{this}; + const size_type _Old_size = size(); + // Insert the new elements at the end for (; _First != _Last; ++_First) { value_type _Val = *_First; diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 12a6f90268f..1ddeac44a03 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -710,8 +710,8 @@ private: template void _Insert_range(const _InIt _First, const _InIt _Last) { - const size_type _Old_size = size(); _Clear_guard _Guard{this}; + const size_type _Old_size = size(); _Data.insert(_Data.end(), _First, _Last); _Restore_invariants<_NeedSorting>(_Old_size); _Guard._Target = nullptr; @@ -719,8 +719,8 @@ private: template _Rng> void _Insert_range(_Rng&& _Range) { - const size_type _Old_size = size(); _Clear_guard _Guard{this}; + const size_type _Old_size = size(); if constexpr (_Has_guaranteed_append_range) { _Data.append_range(_STD forward<_Rng>(_Range)); } else { From f82bdb1abb138734ac74eaf9eb193c633426a090 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 05:05:53 -0800 Subject: [PATCH 05/13] flat_map: `_Unwrapped_pairing_iterator` was used only once, fuse it. --- stl/inc/flat_map | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index f2b994b060d..2ad0c4753cf 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -43,10 +43,6 @@ template concept _Can_unwrap_pairing_iterator = !conjunction_v, _KeyIter>, is_same<_Unwrapped_t<_MappedIter>, _MappedIter>>; -template -using _Unwrapped_pairing_iterator = _Pairing_iterator_provider<_Unwrapped_t<_KeyIter>, _Unwrapped_t<_MappedIter>, - _Unwrapped_t<_MappedConvIter>>::_Iterator; - template struct _Pairing_iterator_provider { class _Iterator { @@ -71,7 +67,8 @@ struct _Pairing_iterator_provider { : _Key_it(_STD move(_Key_iter)), _Mapped_it(_STD move(_Mapped_iter)) {} using _Const_iterator = _Pairing_iterator_provider<_KeyIter, _MappedConvIter, _MappedConvIter>::_Iterator; - using _Unwrapped_iterator = _Unwrapped_pairing_iterator<_KeyIter, _MappedIter, _MappedConvIter>; + using _Unwrapped_iterator = _Pairing_iterator_provider<_Unwrapped_t<_KeyIter>, _Unwrapped_t<_MappedIter>, + _Unwrapped_t<_MappedConvIter>>::_Iterator; class _Arrow_proxy { public: From d5e833f7ddc3f040eae712cb3edb9cb44d7b2724 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 05:12:58 -0800 Subject: [PATCH 06/13] flat_map: `operator+()` and `operator-()`: `_Old` => `_Tmp` --- 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 2ad0c4753cf..b31254bf029 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -145,15 +145,15 @@ struct _Pairing_iterator_provider { } _NODISCARD _Iterator operator+(const difference_type _Off) const { - auto _Old = *this; - _Old += _Off; - return _Old; + auto _Tmp = *this; + _Tmp += _Off; + return _Tmp; } _NODISCARD _Iterator operator-(const difference_type _Off) const { - auto _Old = *this; - _Old -= _Off; - return _Old; + auto _Tmp = *this; + _Tmp -= _Off; + return _Tmp; } _NODISCARD reference operator[](const difference_type _Off) const { From 91fd278eaf714ae7452df311ab720bbaf20735b6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 05:21:04 -0800 Subject: [PATCH 07/13] flat_map bugfix: Comparing against `_KeyIter()` and `_MappedIter()` is bogus. --- stl/inc/flat_map | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index b31254bf029..9483317d170 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -201,14 +201,10 @@ struct _Pairing_iterator_provider { void _Verify_offset(const difference_type _Off) const noexcept { if constexpr (_Offset_verifiable_v<_KeyIter>) { _Key_it._Verify_offset(_Off); - } else { - _STL_VERIFY(_Off == 0 || _Key_it != _KeyIter(), "cannot seek value-initialized iterator"); } if constexpr (_Offset_verifiable_v<_MappedIter>) { _Mapped_it._Verify_offset(_Off); - } else { - _STL_VERIFY(_Off == 0 || _Mapped_it != _MappedIter(), "cannot seek value-initialized iterator"); } } From 93ed1f9f99e0e9dc40225bbd495086642a908d2d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 05:29:58 -0800 Subject: [PATCH 08/13] flat_map: Private ctors can additionally be `explicit`. --- stl/inc/flat_map | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 9483317d170..5b6d5b06634 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -62,7 +62,7 @@ struct _Pairing_iterator_provider { template friend struct _Pairing_iterator_provider; - _Iterator(_KeyIter _Key_iter, _MappedIter _Mapped_iter) + explicit _Iterator(_KeyIter _Key_iter, _MappedIter _Mapped_iter) noexcept(is_nothrow_move_constructible_v<_KeyIter> && is_nothrow_move_constructible_v<_MappedIter>) : _Key_it(_STD move(_Key_iter)), _Mapped_it(_STD move(_Mapped_iter)) {} @@ -344,7 +344,7 @@ public: private: friend _Flat_map_base; - value_compare(const key_compare& _Comp) : _Key_comparator(_Comp) {} + explicit value_compare(const key_compare& _Comp) : _Key_comparator(_Comp) {} key_compare _Key_comparator; }; From a92898cf915647e047892ac3e513a067446fc1b6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 05:42:41 -0800 Subject: [PATCH 09/13] flat_map: Improve `_Arrow_proxy` construction. Grant friendship to make the ctor private. Drop `noexcept` which achieved nothing. Take `const _Iterator& _Iter` to hopefully avoid materializing an extra pair. --- stl/inc/flat_map | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 5b6d5b06634..10bdcf4f8e2 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -72,13 +72,15 @@ struct _Pairing_iterator_provider { class _Arrow_proxy { public: - explicit _Arrow_proxy(const reference& _Rx) noexcept : _Ref{_Rx} {} - _NODISCARD const reference* operator->() const noexcept { return _STD addressof(_Ref); } private: + friend _Iterator; + + explicit _Arrow_proxy(const _Iterator& _Iter) : _Ref{*_Iter} {} + reference _Ref; }; @@ -95,7 +97,7 @@ struct _Pairing_iterator_provider { } _NODISCARD pointer operator->() const { - return pointer{**this}; + return pointer{*this}; } _Iterator& operator++() { From 2ddf11852a6143bbd29d2c56334d5f8d80c85162 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 06:18:29 -0800 Subject: [PATCH 10/13] flat_map: Consistently check `key_compare` traits last. --- 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 10bdcf4f8e2..1b4260ce377 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -361,9 +361,9 @@ public: _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 - && is_nothrow_move_constructible_v) // strengthened + _Flat_map_base(_Flat_map_base&& _Other) noexcept(is_nothrow_move_constructible_v + && is_nothrow_move_constructible_v + && is_nothrow_copy_constructible_v) // strengthened : _Data(_STD move(_Other).extract()), _Key_compare(_Other._Key_compare) // intentionally copy comparator, see LWG-2227 {} @@ -547,8 +547,8 @@ 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) /* strengthened */ { + noexcept(is_nothrow_move_assignable_v && is_nothrow_move_assignable_v + && is_nothrow_copy_assignable_v) /* strengthened */ { if (this != _STD addressof(_Other)) { _Clear_guard _Guard{this}; _Clear_guard _Always_clear{_STD addressof(_Other)}; From c719b6954c514e5dacb5ff1735732680c8c06efc Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 06:35:28 -0800 Subject: [PATCH 11/13] flat_set: Don't `remove_cvref_t` when using `_In_place_key_extract_set`, it will `_Remove_const_ref_t`. --- stl/inc/flat_set | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 1ddeac44a03..eb644e8dfe0 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -333,7 +333,7 @@ public: auto emplace(_ArgTypes&&... _Args) requires is_constructible_v { - constexpr bool _Is_key_type = _In_place_key_extract_set...>::_Extractable; + constexpr bool _Is_key_type = _In_place_key_extract_set::_Extractable; if constexpr (_Is_key_type) { return _Emplace(_STD forward<_ArgTypes>(_Args)...); } else { @@ -345,7 +345,7 @@ public: iterator emplace_hint(const const_iterator _Position, _ArgTypes&&... _Args) requires is_constructible_v { - constexpr bool _Is_key_type = _In_place_key_extract_set...>::_Extractable; + constexpr bool _Is_key_type = _In_place_key_extract_set::_Extractable; if constexpr (_Is_key_type) { return _Emplace_hint(_Position, _STD forward<_ArgTypes>(_Args)...); } else { From e27f95ef23cdee1235cb6ea238c455ec814d6927 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 06:44:56 -0800 Subject: [PATCH 12/13] flat_map: `swap()` doesn't need to `static_cast<_Flat_map_base&>`. --- stl/inc/flat_map | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 1b4260ce377..4e7011d06fd 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -740,12 +740,11 @@ public: 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); + _STD addressof(_Data), _STD addressof(_Other._Data)}; + _RANGES swap(_Data.keys, _Other._Data.keys); + _RANGES swap(_Data.values, _Other._Data.values); + _RANGES swap(_Key_compare, _Other._Key_compare); _Guard._Dismiss(); } From a2e22e571699f7d8c3c68054926a70a0239bfe6a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 4 Feb 2026 06:58:57 -0800 Subject: [PATCH 13/13] flat_set: Update comment after GH 6057 reworked `operator=(initializer_list)`. --- stl/inc/flat_set | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index eb644e8dfe0..d0f59f48c1f 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -563,8 +563,7 @@ private: template void _Restore_invariants(const size_type _Old_size) { // No _Clear_guard needed. This is called only by _Insert_range() (which has a _Clear_guard) - // and _Establish_invariants() (which is called only by constructors which don't need guards - // and operator=() which has a _Clear_guard). + // and _Establish_invariants() (which is called only by constructors which don't need guards). const auto _Begin = _Data.begin(); const auto _Old_end = _Begin + static_cast(_Old_size);