From 16e58362a9af89f532eac6f94cf06a5cfb881a10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Fri, 19 Dec 2025 15:41:18 +0100 Subject: [PATCH 1/6] Consistently _STL_ASSERT that containers/ranges given to flat_meow functions with _Sorted_t tag are really sorted. Check is based on [flat.map.syn]/10 and similar. --- stl/inc/flat_map | 23 +++++++++++++---------- stl/inc/flat_set | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 1e6eac4961b..93f1fc2be2b 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -369,14 +369,15 @@ public: template <_Usable_allocator_for _Allocator> _Flat_map_base( const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, const _Allocator& _Alloc) - : _Flat_map_base(_Sorted_t{}, _Key_cont, _Mapped_cont, _Alloc) { - _Sort_and_erase_dupes_if_not_multi(); - } + : _Flat_map_base(_Key_cont, _Mapped_cont, key_compare(), _Alloc) {} template <_Usable_allocator_for _Allocator> _Flat_map_base(const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, const key_compare& _Comp, const _Allocator& _Alloc) - : _Flat_map_base(_Sorted_t{}, _Key_cont, _Mapped_cont, _Comp, _Alloc) { + : _Data{.keys = _STD make_obj_using_allocator(_Alloc, _Key_cont), + .values = _STD make_obj_using_allocator(_Alloc, _Mapped_cont)}, + _Key_compare(_Comp) { + _STL_ASSERT(_Data.keys.size() == _Data.values.size(), "key_cont.size() != mapped_cont.size()"); _Sort_and_erase_dupes_if_not_multi(); } @@ -384,16 +385,13 @@ public: 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(_Data.keys), _Msg_not_sorted); } template <_Usable_allocator_for _Allocator> - _Flat_map_base(_Sorted_t, const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, + _Flat_map_base(_Sorted_t _Tag, const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, const _Allocator& _Alloc) - : _Data{.keys = _STD make_obj_using_allocator(_Alloc, _Key_cont), - .values = _STD make_obj_using_allocator(_Alloc, _Mapped_cont)}, - _Key_compare(key_compare()) { - _STL_ASSERT(_Data.keys.size() == _Data.values.size(), "key_cont.size() != mapped_cont.size()"); - } + : _Flat_map_base(_Tag, _Key_cont, _Mapped_cont, key_compare(), _Alloc) {} template <_Usable_allocator_for _Allocator> _Flat_map_base(_Sorted_t, const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, @@ -402,6 +400,7 @@ public: .values = _STD make_obj_using_allocator(_Alloc, _Mapped_cont)}, _Key_compare(_Comp) { _STL_ASSERT(_Data.keys.size() == _Data.values.size(), "key_cont.size() != mapped_cont.size()"); + _STL_ASSERT(_Is_sorted(_Data.keys), _Msg_not_sorted); } template <_Iterator_for_container _InputIterator> @@ -1080,6 +1079,10 @@ private: auto _Sorted_new_elements = _Sorted_view; _Sorted_new_elements.advance(_Old_distance); _RANGES sort(_Sorted_new_elements, value_compare{_Key_compare}); + } else { + [[maybe_unused]] auto const _New_elements_begin = + _Data.keys.begin() + static_cast(_Old_distance); + _STL_ASSERT(_Is_sorted(_New_elements_begin, _Data.keys.end()), _Msg_not_sorted); } // Merge the newly inserted elements with the existing elements diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 08fbf79e031..dc0107636ef 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -683,7 +683,7 @@ private: if constexpr (_NeedSorting) { _STD sort(_Old_end, _End, _Pass_comp()); } else { - _STL_INTERNAL_CHECK(_Is_sorted(_Old_end, _End)); + _STL_ASSERT(_Is_sorted(_Old_end, _End), _Msg_not_sorted); } _STD inplace_merge(_Begin, _Old_end, _End, _Pass_comp()); From 0794b2997ebc0a9615a62dcc2423a9504c2c0602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Sun, 21 Dec 2025 15:44:08 +0100 Subject: [PATCH 2/6] Guard against self-assignment of _Flat_map_base --- stl/inc/flat_map | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 93f1fc2be2b..9a2d04a396a 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -520,10 +520,14 @@ 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) { - _Clear_guard _Guard{this}; - _Data = _STD move(_Other).extract(); - _Key_compare = _Other._Key_compare; // intentionally copy comparator, see LWG-2227 - _Guard._Target = nullptr; + + if (this != _STD addressof(_Other)) { + _Clear_guard _Guard{this}; + _Clear_guard _Always_clear{_STD addressof(_Other)}; + _Data = _STD move(_Other._Data); + _Key_compare = _Other._Key_compare; // intentionally copy comparator, see LWG-2227 + _Guard._Target = nullptr; + } return *this; } From 8e645cc7073b1867965e8cb29d3f9e5a2efc8138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Sun, 4 Jan 2026 16:05:43 +0100 Subject: [PATCH 3/6] Audit parameters and local variables for const values. --- stl/inc/flat_map | 83 +++++++++++++++++++++++++----------------------- stl/inc/flat_set | 49 ++++++++++++++-------------- 2 files changed, 68 insertions(+), 64 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 9a2d04a396a..7367372a045 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -404,20 +404,22 @@ public: } template <_Iterator_for_container _InputIterator> - _Flat_map_base(_InputIterator _First, _InputIterator _Last, const key_compare& _Comp = key_compare()) + _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, _Usable_allocator_for _Allocator> - _Flat_map_base(_InputIterator _First, _InputIterator _Last, const _Allocator& _Alloc) : _Flat_map_base(_Alloc) { + _Flat_map_base(const _InputIterator _First, const _InputIterator _Last, const _Allocator& _Alloc) + : _Flat_map_base(_Alloc) { insert(_First, _Last); } template <_Iterator_for_container _InputIterator, _Usable_allocator_for _Allocator> - _Flat_map_base(_InputIterator _First, _InputIterator _Last, const key_compare& _Comp, const _Allocator& _Alloc) + _Flat_map_base( + const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp, const _Allocator& _Alloc) : _Flat_map_base(_Comp, _Alloc) { insert(_First, _Last); } @@ -444,45 +446,46 @@ public: } template <_Iterator_for_container _InputIterator> - _Flat_map_base(_Sorted_t, _InputIterator _First, _InputIterator _Last, const key_compare& _Comp = key_compare()) + _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 <_Iterator_for_container _InputIterator, _Usable_allocator_for _Allocator> - _Flat_map_base( - _Sorted_t, _InputIterator _First, _InputIterator _Last, const key_compare& _Comp, const _Allocator& _Alloc) + _Flat_map_base(_Sorted_t, const _InputIterator _First, const _InputIterator _Last, const key_compare& _Comp, + const _Allocator& _Alloc) : _Flat_map_base(_Comp, _Alloc) { _Insert_range(_First, _Last); } template <_Iterator_for_container _InputIterator, _Usable_allocator_for _Allocator> - _Flat_map_base(_Sorted_t _Tag, _InputIterator _First, _InputIterator _Last, const _Allocator& _Alloc) + _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(initializer_list _Ilist, const key_compare& _Comp = key_compare()) + _Flat_map_base(const initializer_list _Ilist, const key_compare& _Comp = key_compare()) : _Flat_map_base(_Ilist.begin(), _Ilist.end(), _Comp) {} template <_Usable_allocator_for _Allocator> - _Flat_map_base(initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _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(initializer_list _Ilist, const _Allocator& _Alloc) + _Flat_map_base(const initializer_list _Ilist, const _Allocator& _Alloc) : _Flat_map_base(_Ilist, key_compare(), _Alloc) {} - _Flat_map_base(_Sorted_t _Tag, 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()) : _Flat_map_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp) {} template <_Usable_allocator_for _Allocator> _Flat_map_base( - _Sorted_t _Tag, 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(_Tag, _Ilist.begin(), _Ilist.end(), _Comp, _Alloc) {} template <_Usable_allocator_for _Allocator> - _Flat_map_base(_Sorted_t _Tag, initializer_list _Ilist, const _Allocator& _Alloc) + _Flat_map_base(_Sorted_t _Tag, const initializer_list _Ilist, const _Allocator& _Alloc) : _Flat_map_base(_Tag, _Ilist, key_compare(), _Alloc) {} // Copy constructors @@ -617,35 +620,35 @@ public: } template - iterator emplace_hint(const_iterator _Position, _ArgTypes&&... _Args) + iterator emplace_hint(const const_iterator _Position, _ArgTypes&&... _Args) requires is_constructible_v { value_type _Val(_STD forward<_ArgTypes>(_Args)...); return _Emplace_hint(_Position, _STD move(_Val.first), _STD move(_Val.second)); } - iterator insert(const_iterator _Position, const value_type& _Pair_val) { + iterator insert(const const_iterator _Position, const value_type& _Pair_val) { return emplace_hint(_Position, _Pair_val); } - iterator insert(const_iterator _Position, value_type&& _Pair_val) { + iterator insert(const const_iterator _Position, value_type&& _Pair_val) { return emplace_hint(_Position, _STD move(_Pair_val)); } template - iterator insert(const_iterator _Position, _PairValTy&& _Pair_val) + iterator insert(const const_iterator _Position, _PairValTy&& _Pair_val) requires is_constructible_v { return emplace_hint(_Position, _STD forward<_PairValTy>(_Pair_val)); } template <_Iterator_for_container _InputIterator> - void insert(_InputIterator _First, _InputIterator _Last) { + void insert(const _InputIterator _First, const _InputIterator _Last) { _Insert_range(_First, _Last); } template <_Iterator_for_container _InputIterator> - void insert(_Sorted_t, _InputIterator _First, _InputIterator _Last) { + void insert(_Sorted_t, const _InputIterator _First, const _InputIterator _Last) { _Insert_range(_First, _Last); } @@ -659,19 +662,19 @@ public: _Insert_range(_RANGES begin(_Range), _RANGES end(_Range)); } - void insert(initializer_list _Ilist) { + void insert(const initializer_list _Ilist) { _Insert_range(_Ilist.begin(), _Ilist.end()); } - void insert(_Sorted_t, initializer_list _Ilist) { + void insert(_Sorted_t, const initializer_list _Ilist) { _Insert_range(_Ilist.begin(), _Ilist.end()); } - iterator erase(iterator _Position) { + iterator erase(const iterator _Position) { return erase(static_cast(_Position)); } - iterator erase(const_iterator _Position) { + iterator erase(const const_iterator _Position) { _Clear_guard _Guard{this}; auto _Key_it = _Data.keys.erase(_Position._Key_it); auto _Val_it = _Data.values.erase(_Position._Mapped_it); @@ -679,7 +682,7 @@ public: return iterator{_STD move(_Key_it), _STD move(_Val_it)}; } - iterator erase(const_iterator _First, const_iterator _Last) { + 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); @@ -924,7 +927,7 @@ protected: if (_Hint_order == weak_ordering::less) { if (_New_position != _End && !_Key_compare(_Key_val, *_New_position._Key_it)) { const auto _Dist = _New_position._Key_it - _Begin._Key_it; - auto _It = begin() + _Dist; + const auto _It = begin() + _Dist; if constexpr (_OverwriteIfExists) { *_It._Mapped_it = mapped_type(_STD forward<_MappedArgTypes>(_Args)...); } @@ -933,7 +936,7 @@ protected: } else { if (_New_position != _Begin && !_Key_compare(*_STD prev(_New_position._Key_it), _Key_val)) { const auto _Dist = _STD prev(_New_position._Key_it) - _Begin._Key_it; - auto _It = begin() + _Dist; + const auto _It = begin() + _Dist; if constexpr (_OverwriteIfExists) { *_It._Mapped_it = mapped_type(_STD forward<_MappedArgTypes>(_Args)...); } @@ -951,7 +954,7 @@ protected: return begin() + _Dist; } - void _Insert_exact(const_iterator _Position, key_type&& _Key_val, mapped_type&& _Mapped_val) { + 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)); _Data.values.insert(_Position._Mapped_it, _STD move(_Mapped_val)); @@ -981,14 +984,14 @@ private: _NODISCARD size_type _Erase_if(_Predicate _Pred) { auto _View = _View_to_mutate(); auto _Mut_first = _View.begin(); - auto _Mut_last = _View.end(); + const auto _Mut_last = _View.end(); const auto _Old_size = size(); _Clear_guard _Guard{this}; _STD _Seek_wrapped(_Mut_first, _RANGES remove_if(_View, _Pred).begin()); - (void) _Data.keys.erase(_Mut_first._Key_it, _Mut_last._Key_it); - (void) _Data.values.erase(_Mut_first._Mapped_it, _Mut_last._Mapped_it); + _Data.keys.erase(_Mut_first._Key_it, _Mut_last._Key_it); + _Data.values.erase(_Mut_first._Mapped_it, _Mut_last._Mapped_it); _Guard._Target = nullptr; return _Old_size - size(); @@ -1002,7 +1005,7 @@ private: } _NODISCARD bool _Is_sorted( - typename key_container_type::const_iterator _It, const typename key_container_type::const_iterator _End) const { + 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); }; @@ -1041,8 +1044,8 @@ private: void _Erase_dupes_if_not_multi() { if constexpr (_IsUnique) { - auto _Sorted_view = _View_to_mutate(); - auto _Subrange = _RANGES unique(_Sorted_view, [this](const_reference _Left, const_reference _Right) { + auto _Sorted_view = _View_to_mutate(); + const auto _Subrange = _RANGES unique(_Sorted_view, [this](const_reference _Left, const_reference _Right) { return this->_Key_equal(_Left.first, _Right.first); }); const auto _Remaining_count = _Subrange.begin() - _Sorted_view.begin(); @@ -1056,7 +1059,7 @@ private: } template - void _Insert_range(_InputIterator _First, _Sentinel _Last) { + void _Insert_range(_InputIterator _First, const _Sentinel _Last) { _Clear_guard _Guard{this}; const auto _Old_distance = static_cast(size()); @@ -1332,14 +1335,14 @@ public: } template - iterator try_emplace(const_iterator _Position, const key_type& _Key_val, _MappedArgTypes&&... _Mapped_args) + iterator try_emplace(const const_iterator _Position, const key_type& _Key_val, _MappedArgTypes&&... _Mapped_args) requires is_constructible_v { return this->template _Emplace_hint(_Position, _Key_val, _STD forward<_MappedArgTypes>(_Mapped_args)...); } template - iterator try_emplace(const_iterator _Position, key_type&& _Key_val, _MappedArgTypes&&... _Mapped_args) + iterator try_emplace(const const_iterator _Position, key_type&& _Key_val, _MappedArgTypes&&... _Mapped_args) requires is_constructible_v { return this->template _Emplace_hint( @@ -1347,7 +1350,7 @@ public: } template - iterator try_emplace(const_iterator _Position, _OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) + iterator try_emplace(const const_iterator _Position, _OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) requires _Transparent && is_constructible_v && is_constructible_v { @@ -1378,21 +1381,21 @@ public: } template - iterator insert_or_assign(const_iterator _Position, const key_type& _Key_val, _MappedTy&& _Mapped_val) + iterator insert_or_assign(const const_iterator _Position, const key_type& _Key_val, _MappedTy&& _Mapped_val) requires is_assignable_v && is_constructible_v { return this->template _Emplace_hint(_Position, _Key_val, _STD forward<_MappedTy>(_Mapped_val)); } template - iterator insert_or_assign(const_iterator _Position, key_type&& _Key_val, _MappedTy&& _Mapped_val) + iterator insert_or_assign(const const_iterator _Position, key_type&& _Key_val, _MappedTy&& _Mapped_val) requires is_assignable_v && is_constructible_v { return this->template _Emplace_hint(_Position, _STD move(_Key_val), _STD forward<_MappedTy>(_Mapped_val)); } template - iterator insert_or_assign(const_iterator _Position, _OtherKey&& _Key_val, _MappedTy&& _Mapped_val) + iterator insert_or_assign(const const_iterator _Position, _OtherKey&& _Key_val, _MappedTy&& _Mapped_val) requires _Transparent && is_constructible_v && is_assignable_v && is_constructible_v { diff --git a/stl/inc/flat_set b/stl/inc/flat_set index dc0107636ef..0947d648c75 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -139,18 +139,19 @@ public: : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp() {} template <_Iterator_for_container _Iter> - _Flat_set_base(_Iter _First, _Iter _Last, const key_compare& _Comp = key_compare()) : _Mycont(), _Mycomp(_Comp) { + _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, _Usable_allocator_for _Alloc> - _Flat_set_base(_Iter _First, _Iter _Last, const key_compare& _Comp, const _Alloc& _Al) + _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(_Iter _First, _Iter _Last, const _Alloc& _Al) + _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(); @@ -176,31 +177,31 @@ public: } template <_Iterator_for_container _Iter> - _Flat_set_base(_Sorted_t _Tag, _Iter _First, _Iter _Last, const key_compare& _Comp = key_compare()) + _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, _Iter _First, _Iter _Last, const key_compare& _Comp, const _Alloc& _Al) + _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, _Iter _First, _Iter _Last, const _Alloc& _Al) + _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(initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) + _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(initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _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(initializer_list<_Kty> _Ilist, const _Alloc& _Al) + _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, initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) + _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, initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) + _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) {} template <_Usable_allocator_for _Alloc> - _Flat_set_base(_Sorted_t _Tag, initializer_list<_Kty> _Ilist, const _Alloc& _Al) + _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; @@ -229,7 +230,7 @@ public: return *this; } - _Derived& operator=(initializer_list<_Kty> _Ilist) { + _Derived& operator=(const initializer_list<_Kty> _Ilist) { _Clear_guard _Guard{this}; _Mycont.assign(_Ilist); _Make_invariants_fulfilled(); @@ -291,7 +292,7 @@ public: } } template - iterator emplace_hint(const_iterator _Hint, _Args&&... _Vals) { + iterator emplace_hint(const const_iterator _Hint, _Args&&... _Vals) { constexpr bool _Is_key_type = _In_place_key_extract_set<_Kty, remove_cvref_t<_Args>...>::_Extractable; if constexpr (_Is_key_type) { return _Emplace_hint(_Hint, _STD forward<_Args>(_Vals)...); @@ -312,24 +313,24 @@ public: return _Emplace(_STD forward<_Other>(_Val)); } - iterator insert(const_iterator _Hint, const _Kty& _Val) { + iterator insert(const const_iterator _Hint, const _Kty& _Val) { return _Emplace_hint(_Hint, _Val); } - iterator insert(const_iterator _Hint, _Kty&& _Val) { + iterator insert(const const_iterator _Hint, _Kty&& _Val) { return _Emplace_hint(_Hint, _STD move(_Val)); } template <_Different_from<_Kty> _Other> requires _IsUnique && _Transparent && is_constructible_v<_Kty, _Other> - iterator insert(const_iterator _Hint, _Other&& _Val) { + iterator insert(const const_iterator _Hint, _Other&& _Val) { return _Emplace_hint(_Hint, _STD forward<_Other>(_Val)); } template <_Iterator_for_container _Iter> - void insert(_Iter _First, _Iter _Last) { + void insert(const _Iter _First, const _Iter _Last) { _Insert_range(_First, _Last); } template <_Iterator_for_container _Iter> - void insert(_Sorted_t, _Iter _First, _Iter _Last) { + void insert(_Sorted_t, const _Iter _First, const _Iter _Last) { _Insert_range(_First, _Last); } template <_Container_compatible_range<_Kty> _Rng> @@ -340,10 +341,10 @@ public: void insert_range(_Sorted_t, _Rng&& _Range) { _Insert_range(_STD forward<_Rng>(_Range)); } - void insert(initializer_list<_Kty> _Ilist) { + void insert(const initializer_list<_Kty> _Ilist) { _Insert_range(_Ilist.begin(), _Ilist.end()); } - void insert(_Sorted_t, initializer_list<_Kty> _Ilist) { + void insert(_Sorted_t, const initializer_list<_Kty> _Ilist) { _Insert_range(_Ilist.begin(), _Ilist.end()); } @@ -362,7 +363,7 @@ public: } // NB: `erase(iterator)` is identical to `erase(const_iterator)` - iterator erase(const_iterator _Where) { + iterator erase(const const_iterator _Where) { return _Mycont.erase(_Where); } size_type erase(const _Kty& _Val) { @@ -373,7 +374,7 @@ public: size_type erase(_Other&& _Val) { return _Erase(_Val); } - iterator erase(const_iterator _First, const_iterator _Last) { + iterator erase(const const_iterator _First, const const_iterator _Last) { return _Mycont.erase(_First, _Last); } @@ -474,7 +475,7 @@ public: } private: - _NODISCARD bool _Is_sorted(const_iterator _It, const const_iterator _End) const { + _NODISCARD bool _Is_sorted(const const_iterator _It, const const_iterator _End) const { if constexpr (_IsUnique) { // sorted-unique auto _Negated = [this](const key_type& _Lhs, const key_type& _Rhs) { return !_Compare(_Lhs, _Rhs); }; From de4f293e9453ffb540af5d624f202607e52c2141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Sun, 4 Jan 2026 23:05:01 +0100 Subject: [PATCH 4/6] Publicly expose the flat_meow member _Is_sorted_and_unique to allow verification of invariants in tests. --- stl/inc/flat_map | 24 ++++++++++++++--------- stl/inc/flat_set | 20 +++++++++++-------- tests/std/tests/P1222R4_flat_set/test.cpp | 1 + 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 7367372a045..faf5d7b608f 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -385,7 +385,7 @@ public: 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(_Data.keys), _Msg_not_sorted); + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); } template <_Usable_allocator_for _Allocator> @@ -400,7 +400,7 @@ public: .values = _STD make_obj_using_allocator(_Alloc, _Mapped_cont)}, _Key_compare(_Comp) { _STL_ASSERT(_Data.keys.size() == _Data.values.size(), "key_cont.size() != mapped_cont.size()"); - _STL_ASSERT(_Is_sorted(_Data.keys), _Msg_not_sorted); + _STL_ASSERT(_Is_sorted_and_unique(), _Msg_not_sorted); } template <_Iterator_for_container _InputIterator> @@ -718,7 +718,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(_Key_cont), _Msg_not_sorted); + _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); @@ -1004,7 +1004,13 @@ private: _Mutating_iterator{_Data.keys.end(), _Data.values.end()}}; } - _NODISCARD bool _Is_sorted( +public: + _NODISCARD bool _Is_sorted_and_unique() const { + return _Is_sorted_and_unique(_Data.keys); + } + +private: + _NODISCARD bool _Is_sorted_and_unique( const key_container_type::const_iterator _It, const key_container_type::const_iterator _End) const { if constexpr (_IsUnique) { // sorted-unique @@ -1015,8 +1021,8 @@ private: } } - _NODISCARD bool _Is_sorted(const key_container_type& _Cont) const { - return _Is_sorted(_Cont.begin(), _Cont.end()); + _NODISCARD bool _Is_sorted_and_unique(const key_container_type& _Cont) const { + return _Is_sorted_and_unique(_Cont.begin(), _Cont.end()); } void _Sort_and_erase_dupes_if_not_multi() { @@ -1037,7 +1043,7 @@ private: _Erase_dupes_if_not_multi(); - _STL_INTERNAL_CHECK(_Is_sorted(_Data.keys)); + _STL_INTERNAL_CHECK(_Is_sorted_and_unique()); _Guard._Target = nullptr; } @@ -1089,14 +1095,14 @@ private: } else { [[maybe_unused]] auto const _New_elements_begin = _Data.keys.begin() + static_cast(_Old_distance); - _STL_ASSERT(_Is_sorted(_New_elements_begin, _Data.keys.end()), _Msg_not_sorted); + _STL_ASSERT(_Is_sorted_and_unique(_New_elements_begin, _Data.keys.end()), _Msg_not_sorted); } // Merge the newly inserted elements with the existing elements _RANGES inplace_merge(_Sorted_view, _Sorted_view.begin() + _Old_distance, value_compare{_Key_compare}); _Erase_dupes_if_not_multi(); - _STL_INTERNAL_CHECK(_Is_sorted(_Data.keys)); + _STL_INTERNAL_CHECK(_Is_sorted_and_unique()); _Guard._Target = nullptr; } diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 0947d648c75..b90bc901ede 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -121,7 +121,7 @@ public: _Flat_set_base(_Sorted_t, container_type _Cont, const key_compare& _Comp = key_compare()) : _Mycont(_STD move(_Cont)), _Mycomp(_Comp) { - _STL_ASSERT(_Is_sorted(_Mycont), _Msg_not_sorted); + _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) @@ -356,7 +356,7 @@ public: } void replace(container_type&& _Cont) { - _STL_ASSERT(_Is_sorted(_Cont), _Msg_not_sorted); + _STL_ASSERT(_Is_sorted_and_unique(_Cont), _Msg_not_sorted); _Clear_guard _Guard{this}; _Mycont = _STD move(_Cont); _Guard._Target = nullptr; @@ -474,8 +474,12 @@ public: _Lhs.swap(_Rhs); } + _NODISCARD bool _Is_sorted_and_unique() const { + return _Is_sorted_and_unique(_Mycont); + } + private: - _NODISCARD bool _Is_sorted(const const_iterator _It, const const_iterator _End) const { + _NODISCARD bool _Is_sorted_and_unique(const const_iterator _It, const const_iterator _End) const { if constexpr (_IsUnique) { // sorted-unique auto _Negated = [this](const key_type& _Lhs, const key_type& _Rhs) { return !_Compare(_Lhs, _Rhs); }; @@ -485,8 +489,8 @@ private: } } - _NODISCARD bool _Is_sorted(const container_type& _Cont) const { - return _Is_sorted(_Cont.begin(), _Cont.end()); + _NODISCARD bool _Is_sorted_and_unique(const container_type& _Cont) const { + return _Is_sorted_and_unique(_Cont.begin(), _Cont.end()); } template @@ -684,13 +688,13 @@ private: if constexpr (_NeedSorting) { _STD sort(_Old_end, _End, _Pass_comp()); } else { - _STL_ASSERT(_Is_sorted(_Old_end, _End), _Msg_not_sorted); + _STL_ASSERT(_Is_sorted_and_unique(_Old_end, _End), _Msg_not_sorted); } _STD inplace_merge(_Begin, _Old_end, _End, _Pass_comp()); _Erase_dupes_if_not_multi(); - _STL_INTERNAL_CHECK(_Is_sorted(_Mycont)); + _STL_INTERNAL_CHECK(_Is_sorted_and_unique()); } void _Make_invariants_fulfilled() { @@ -708,7 +712,7 @@ private: _STD inplace_merge(_Begin, _Begin_unsorted, _End, _Pass_comp()); _Erase_dupes_if_not_multi(); - _STL_INTERNAL_CHECK(_Is_sorted(_Mycont)); + _STL_INTERNAL_CHECK(_Is_sorted_and_unique()); } template diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index 8790079811a..40f7786a126 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -243,6 +243,7 @@ void assert_all_requirements(const T& s) { } } } + assert(s._Is_sorted_and_unique()); } template From 3b9fd6901cabc3319cf6f65eea7fbd6b3595a1bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Mon, 5 Jan 2026 03:33:57 +0100 Subject: [PATCH 5/6] Make flat_set default ctor delegate to another ctor, in line with standard's wording. --- stl/inc/flat_map | 1 - stl/inc/flat_set | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index faf5d7b608f..0cf3b7f5e76 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -345,7 +345,6 @@ public: using value_compare = _Flat_map_value_compare_provider::value_compare; using containers = _Flat_map_container_provider::containers; -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()) {} diff --git a/stl/inc/flat_set b/stl/inc/flat_set index b90bc901ede..f888efe8ee0 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -97,7 +97,8 @@ public: using reverse_iterator = const_reverse_iterator; using container_type = _Container; - _Flat_set_base() : _Mycont(), _Mycomp() {} + // [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) From 86f36029c522c234a4003afa6f9133cbf3cd7b2e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 5 Jan 2026 14:55:33 -0800 Subject: [PATCH 6/6] Avoid east const, avoid unused variable. --- stl/inc/flat_map | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 92a318d2633..a8a72666874 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -1135,9 +1135,10 @@ private: _Sorted_new_elements.advance(_Old_distance); _RANGES sort(_Sorted_new_elements, value_compare{_Key_compare}); } else { - [[maybe_unused]] auto const _New_elements_begin = - _Data.keys.begin() + static_cast(_Old_distance); - _STL_ASSERT(_Is_sorted_and_unique(_New_elements_begin, _Data.keys.end()), _Msg_not_sorted); + _STL_ASSERT(_Is_sorted_and_unique( + _Data.keys.begin() + static_cast(_Old_distance), + _Data.keys.end()), + _Msg_not_sorted); } // Merge the newly inserted elements with the existing elements