From 254a6f0004f4f695e991e214219f9dd4f50615a4 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 23 Aug 2023 00:42:07 +0800 Subject: [PATCH 01/20] 1. `_Compressed_pair` should try to compress `key_compare` --- stl/inc/flat_set | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index dda412494cd..92188930208 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -58,10 +58,10 @@ public: static_assert(random_access_iterator, "The C++ Standard forbids containers without random " "access iterators from being adapted. See [flatset.overview]."); - _Base_flat_set() : _My_pair(_Zero_then_variadic_args_t{}, _Keylt()) {} + _Base_flat_set() : _My_pair(_Zero_then_variadic_args_t{}) {} explicit _Base_flat_set(container_type _Cont, const key_compare& _Comp = key_compare()) - : _My_pair(_One_then_variadic_args_t{}, _STD move(_Cont), _Comp) { + : _My_pair(_One_then_variadic_args_t{}, _Comp, _STD move(_Cont)) { _Make_invariants_fulfilled(); } template <_Allocator_for _Alloc> @@ -71,7 +71,7 @@ public: : _Base_flat_set(container_type(_Cont, _Al), _Comp) {} _Base_flat_set(_Tsorted, container_type _Cont, const key_compare& _Comp = key_compare()) - : _My_pair(_One_then_variadic_args_t{}, _STD move(_Cont), _Comp) { + : _My_pair(_One_then_variadic_args_t{}, _Comp, _STD move(_Cont)) { _Assert_after_sorted_input(); } template <_Allocator_for _Alloc> @@ -81,7 +81,7 @@ public: _Base_flat_set(_Tsorted _Tsort, const container_type& _Cont, const key_compare& _Comp, const _Alloc& _Al) : _Base_flat_set(_Tsort, container_type(_Cont, _Al), _Comp) {} - explicit _Base_flat_set(const key_compare& _Comp) : _My_pair(_Zero_then_variadic_args_t{}, _Comp) {} + explicit _Base_flat_set(const key_compare& _Comp) : _My_pair(_One_then_variadic_args_t{}, _Comp) {} template <_Allocator_for _Alloc> _Base_flat_set(const key_compare& _Comp, const _Alloc& _Al) : _Base_flat_set(_Comp, container_type(_Al)) {} template <_Allocator_for _Alloc> @@ -578,22 +578,22 @@ private: } _NODISCARD const _Container& _Get_cont() const noexcept { - return _My_pair._Get_first(); + return _My_pair._Myval2; } _NODISCARD _Container& _Get_cont() noexcept { - return _My_pair._Get_first(); + return _My_pair._Myval2; } _NODISCARD const key_compare& _Get_comp() const noexcept { - return _My_pair._Myval2; + return _My_pair._Get_first(); } _NODISCARD key_compare& _Get_comp() noexcept { - return _My_pair._Myval2; + return _My_pair._Get_first(); } - _Compressed_pair _My_pair; + _Compressed_pair _My_pair; }; _EXPORT_STD struct sorted_unique_t { From 72e30c6589b9c332b0c66fe99c5c122accc9cf80 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 23 Aug 2023 01:07:48 +0800 Subject: [PATCH 02/20] 2. add routine guards --- stl/inc/flat_set | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 92188930208..64a1a01ed2e 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -16,6 +16,13 @@ _EMIT_STL_WARNING(STL4038, "The contents of are available only with C #include #include +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + _STD_BEGIN template @@ -719,6 +726,11 @@ flat_multiset(sorted_equivalent_t, initializer_list<_Kty>, _Keylt = _Keylt()) -> _STD_END +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) + #endif // ^^^ supported language mode ^^^ #endif // _STL_COMPILER_PREPROCESSOR #endif // _FLAT_SET_ From d9818fc1d7c81aa5ed992836f985b1263abef1b4 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 23 Aug 2023 11:47:38 +0800 Subject: [PATCH 03/20] 3. fix `_Find() const` --- 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 64a1a01ed2e..c24d8180a27 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -513,8 +513,8 @@ private: template requires _Keylt_transparent || is_same_v<_Other, _Kty> _NODISCARD const_iterator _Find(const _Other& _Val) const { - const iterator _End = end(); - const iterator _Where = lower_bound(_Val); + const const_iterator _End = end(); + const const_iterator _Where = lower_bound(_Val); if (_Where != _End && _Keys_equal(*_Where, _Val)) { return _Where; } else { From 07b5cfae916b93274dd7c7bd25f246e29046a429 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 23 Aug 2023 16:05:55 +0800 Subject: [PATCH 04/20] 4. fix iterator usage for `_Emplace_hint` --- stl/inc/flat_set | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index c24d8180a27..9296b02f553 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -432,11 +432,11 @@ private: template requires (_Keylt_transparent && is_constructible_v<_Kty, _Ty>) || is_same_v<_Ty, _Kty> - void _Emplace_hint(const_iterator _Where, _Ty&& _Val) { - _Container& _Cont = _Get_cont(); - _Keylt& _Compare = _Get_comp(); - const iterator _Begin = begin(); - const iterator _End = end(); + iterator _Emplace_hint(const_iterator _Where, _Ty&& _Val) { + _Container& _Cont = _Get_cont(); + _Keylt& _Compare = _Get_comp(); + const const_iterator _Begin = cbegin(); + const const_iterator _End = cend(); if (_Where == _End || !_Compare(*_Where, _Val)) { // _Val <= *_Where @@ -460,7 +460,7 @@ private: if (_Where == _End || !_Keys_equal(_Val, *_Where)) { return _Cont.insert(_Where, _STD forward<_Ty>(_Val)); } - return _Where; + return _Cont.begin() + (_Where - _Begin); } } From f8dbac0f27bf031595b77ec3e912d1113f79d939 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 23 Aug 2023 17:58:51 +0800 Subject: [PATCH 05/20] 5. nitpicks --- stl/inc/flat_set | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 9296b02f553..4dafb45cfdd 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -410,7 +410,7 @@ public: private: void _Assert_after_sorted_input() const { - _STL_ASSERT(_STD is_sorted(begin(), end(), _Get_comp()), "Input was not sorted!"); + _STL_ASSERT(_STD is_sorted(cbegin(), cend(), _Get_comp()), "Input was not sorted!"); if constexpr (!_Multi) { _STL_ASSERT(_Is_unique(), "Input was not unique!"); } @@ -420,8 +420,8 @@ private: if (empty()) { return true; } - const_iterator _End = cend(); - const_iterator _It = begin(); + const const_iterator _End = cend(); + const_iterator _It = cbegin(); while (++_It != _End) { if (_Keys_equal(*(_It - 1), *_It)) { return false; @@ -513,7 +513,7 @@ private: template requires _Keylt_transparent || is_same_v<_Other, _Kty> _NODISCARD const_iterator _Find(const _Other& _Val) const { - const const_iterator _End = end(); + const const_iterator _End = cend(); const const_iterator _Where = lower_bound(_Val); if (_Where != _End && _Keys_equal(*_Where, _Val)) { return _Where; @@ -541,12 +541,11 @@ private: void _Erase_dupes_if_needed() { if constexpr (!_Multi) { - iterator _End = end(); - iterator _New_end = + const iterator _End = end(); + const iterator _New_end = _STD unique(begin(), _End, [&](const _Kty& _Lhs, const _Kty& _Rhs) { return _Keys_equal(_Lhs, _Rhs); }); _Get_cont().erase(_New_end, _End); - } - if constexpr (!_Multi) { + _STL_INTERNAL_CHECK(_Is_unique()); } } From 1a9ed3e904531a8705bee0bb5c055c6d829e617e Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 23 Aug 2023 18:50:57 +0800 Subject: [PATCH 06/20] 6. for ease of future review, regroup/reorder non-constructor methods to keep in line with the standard --- stl/inc/flat_set | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 4dafb45cfdd..a3989c628c7 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -147,6 +147,7 @@ public: return static_cast<_Deriv&>(*this); } + // iterators _NODISCARD iterator begin() noexcept { return _Get_cont().begin(); } @@ -159,6 +160,7 @@ public: _NODISCARD const_iterator end() const noexcept { return _Get_cont().end(); } + _NODISCARD reverse_iterator rbegin() noexcept { return _Get_cont().rbegin(); } @@ -171,6 +173,7 @@ public: _NODISCARD const_reverse_iterator rend() const noexcept { return _Get_cont().rend(); } + _NODISCARD const_iterator cbegin() const noexcept { return _Get_cont().cbegin(); } @@ -184,6 +187,7 @@ public: return _Get_cont().crend(); } + // capacity _NODISCARD_EMPTY_MEMBER bool empty() const noexcept { return _Get_cont().empty(); } @@ -194,11 +198,11 @@ public: return _Get_cont().max_size(); } + // modifiers template auto emplace(_Args&&... _Vals) { insert<_Kty>(_Kty{_STD forward<_Args>(_Vals)...}); } - template iterator emplace_hint(const_iterator _Hint, _Args&&... _Vals) { return _Emplace_hint(_Hint, _Kty{_STD forward<_Args>(_Vals)...}); @@ -210,36 +214,32 @@ public: auto insert(value_type&& _Val) { return _Insert(_STD move(_Val)); } - template requires (!_Multi && _Keylt_transparent && is_constructible_v<_Kty, _Other>) auto insert(_Other&& _Val) { return _Insert(_STD forward<_Other>(_Val)); } - template - requires (!_Multi && _Keylt_transparent && is_constructible_v<_Kty, _Other>) - iterator insert(const_iterator _Hint, _Other&& _Val) { - return _Emplace_hint(_Hint, _STD forward<_Other>(_Val)); - } - iterator insert(const_iterator _Hint, const value_type& _Val) { return _Emplace_hint(_Hint, _Val); } iterator insert(const_iterator _Hint, value_type&& _Val) { return _Emplace_hint(_Hint, _STD move(_Val)); } + template + requires (!_Multi && _Keylt_transparent && is_constructible_v<_Kty, _Other>) + iterator insert(const_iterator _Hint, _Other&& _Val) { + return _Emplace_hint(_Hint, _STD forward<_Other>(_Val)); + } template void insert(const _Iter& _First, const _Iter& _Last) { _Insert_range(_First, _Last); } - template void insert(_Tsorted, _Iter _First, _Iter _Last) { _Insert_range(_First, _Last); } - template <_Container_compatible_range<_Kty> _Rng> void insert_range(_Rng&& _Range) { const size_type _Old_size = size(); @@ -247,6 +247,10 @@ public: _Restore_invariants_after_insert(_Old_size); } + // TODO, missing + void insert(initializer_list<_Kty> _Ilist); + void insert(_Tsorted, initializer_list<_Kty> _Ilist); + _NODISCARD container_type extract() && { container_type& _Cont = _Get_cont(); // always clears the container (N4950 [flat.set.modifiers]/14 and [flat.multiset.modifiers]/10) @@ -254,7 +258,6 @@ public: container_type _Temp = _STD move(_Cont); return _Temp; } - void replace(container_type&& _Cont) { _Get_cont() = _STD move(_Cont); _Assert_after_sorted_input(); @@ -269,13 +272,11 @@ public: size_type erase(const _Kty& _Val) { return _Erase(_Val); } - template requires _Keylt_transparent size_type erase(_Other&& _Val) { return _Erase(_STD forward<_Other>(_Val)); } - iterator erase(const_iterator _First, const_iterator _Last) { return _Get_cont().erase(_First, _Last); } @@ -284,11 +285,11 @@ public: _RANGES swap(_Get_comp(), _Other._Get_comp()); _RANGES swap(_Get_cont(), _Other._Get_cont()); } - void clear() noexcept { _Get_cont().clear(); } + // observers _NODISCARD key_compare key_comp() const { return _Get_comp(); } @@ -296,20 +297,18 @@ public: return _Get_comp(); } + // set operations _NODISCARD iterator find(const _Kty& _Val) { return _Find(_Val); } - _NODISCARD const_iterator find(const _Kty& _Val) const { return _Find(_Val); } - template requires _Keylt_transparent _NODISCARD iterator find(const _Other& _Val) { return _Find(_Val); } - template requires _Keylt_transparent _NODISCARD const_iterator find(const _Other& _Val) const { @@ -320,7 +319,6 @@ public: const auto [_First, _Last] = equal_range(_Val); return _STD distance(_First, _Last); } - template requires _Keylt_transparent _NODISCARD size_type count(const _Other& _Val) const { @@ -336,19 +334,18 @@ public: _NODISCARD bool contains(const _Other& _Val) const { return find(_Val) != end(); } + _NODISCARD iterator lower_bound(const _Kty& _Val) { return _STD lower_bound(begin(), end(), _Val, _Get_comp()); } _NODISCARD const_iterator lower_bound(const _Kty& _Val) const { return _STD lower_bound(cbegin(), cend(), _Val, _Get_comp()); } - template requires _Keylt_transparent _NODISCARD iterator lower_bound(const _Other& _Val) { return _STD lower_bound(begin(), end(), _Val, _Get_comp()); } - template requires _Keylt_transparent _NODISCARD const_iterator lower_bound(const _Other& _Val) const { @@ -358,17 +355,14 @@ public: _NODISCARD iterator upper_bound(const _Kty& _Val) { return _STD upper_bound(begin(), end(), _Val, _Get_comp()); } - _NODISCARD const_iterator upper_bound(const _Kty& _Val) const { return _STD upper_bound(cbegin(), cend(), _Val, _Get_comp()); } - template requires _Keylt_transparent _NODISCARD iterator upper_bound(const _Other& _Val) { return _STD upper_bound(begin(), end(), _Val, _Get_comp()); } - template requires _Keylt_transparent _NODISCARD const_iterator upper_bound(const _Other& _Val) const { @@ -378,17 +372,14 @@ public: _NODISCARD pair equal_range(const _Kty& _Val) { return _STD equal_range(begin(), end(), _Val, _Get_comp()); } - _NODISCARD pair equal_range(const _Kty& _Val) const { return _STD equal_range(cbegin(), cend(), _Val, _Get_comp()); } - template requires _Keylt_transparent _NODISCARD pair equal_range(const _Other& _Val) { return _STD equal_range(begin(), end(), _Val, _Get_comp()); } - template requires _Keylt_transparent _NODISCARD pair equal_range(const _Other& _Val) const { @@ -421,7 +412,7 @@ private: return true; } const const_iterator _End = cend(); - const_iterator _It = cbegin(); + const_iterator _It = cbegin(); while (++_It != _End) { if (_Keys_equal(*(_It - 1), *_It)) { return false; From d179a504cf714f08d2a3bf391639fd147c4cec91 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 23 Aug 2023 18:57:33 +0800 Subject: [PATCH 07/20] 7. implement missing `insert(initializer_list)`. --- stl/inc/flat_set | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index a3989c628c7..d629e733f3c 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -247,9 +247,12 @@ public: _Restore_invariants_after_insert(_Old_size); } - // TODO, missing - void insert(initializer_list<_Kty> _Ilist); - void insert(_Tsorted, initializer_list<_Kty> _Ilist); + void insert(initializer_list<_Kty> _Ilist) { + _Insert_range(_Ilist.begin(), _Ilist.end()); + } + void insert(_Tsorted, initializer_list<_Kty> _Ilist) { + _Insert_range(_Ilist.begin(), _Ilist.end()); + } _NODISCARD container_type extract() && { container_type& _Cont = _Get_cont(); From f83df1b4300fb027180db1f2f72e200425fe8e39 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 23 Aug 2023 20:35:33 +0800 Subject: [PATCH 08/20] 8. `binary_search` works better for `contains` --- 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 d629e733f3c..43ec9932cb6 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -330,12 +330,12 @@ public: } _NODISCARD bool contains(const _Kty& _Val) const { - return find(_Val) != end(); + return _STD binary_search(cbegin(), cend(), _Val, _Get_comp()); } template requires _Keylt_transparent _NODISCARD bool contains(const _Other& _Val) const { - return find(_Val) != end(); + return _STD binary_search(cbegin(), cend(), _Val, _Get_comp()); } _NODISCARD iterator lower_bound(const _Kty& _Val) { From ae69abd8c9dfb667b5c77116322da312c0c8e477 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 24 Aug 2023 00:10:09 +0800 Subject: [PATCH 09/20] 9. fix `insert` methods; both `_Insert` (should rename to `_Emplace`) and `_Emplace_hint` should not be constrainted. see comments. --- stl/inc/flat_set | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 43ec9932cb6..ac315553662 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -201,7 +201,7 @@ public: // modifiers template auto emplace(_Args&&... _Vals) { - insert<_Kty>(_Kty{_STD forward<_Args>(_Vals)...}); + _Emplace(_Kty{_STD forward<_Args>(_Vals)...}); } template iterator emplace_hint(const_iterator _Hint, _Args&&... _Vals) { @@ -209,15 +209,15 @@ public: } auto insert(const value_type& _Val) { - return _Insert<_Kty>(_Val); + return _Emplace(_Val); } auto insert(value_type&& _Val) { - return _Insert(_STD move(_Val)); + return _Emplace(_STD move(_Val)); } template requires (!_Multi && _Keylt_transparent && is_constructible_v<_Kty, _Other>) auto insert(_Other&& _Val) { - return _Insert(_STD forward<_Other>(_Val)); + return _Emplace(_STD forward<_Other>(_Val)); } iterator insert(const_iterator _Hint, const value_type& _Val) { @@ -425,7 +425,6 @@ private: } template - requires (_Keylt_transparent && is_constructible_v<_Kty, _Ty>) || is_same_v<_Ty, _Kty> iterator _Emplace_hint(const_iterator _Where, _Ty&& _Val) { _Container& _Cont = _Get_cont(); _Keylt& _Compare = _Get_comp(); @@ -467,8 +466,7 @@ private: } template - requires (!_Multi && _Keylt_transparent && is_constructible_v<_Kty, _Ty>) || is_same_v<_Ty, _Kty> - auto _Insert(_Ty&& _Val) { + auto _Emplace(_Ty&& _Val) { _Container& _Cont = _Get_cont(); const iterator _End = end(); const iterator _Where = lower_bound(_Val); From 4b4362408392906489c1991acb97c0a3bcce286b Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 24 Aug 2023 00:40:32 +0800 Subject: [PATCH 10/20] 10. expose `operator=(initializer_list)` --- stl/inc/flat_set | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index ac315553662..215f966d12c 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -607,15 +607,21 @@ _EXPORT_STD inline constexpr sorted_equivalent_t sorted_equivalent{}; _EXPORT_STD template , class _Container = vector<_Kty>> class flat_set : public _Base_flat_set<_Kty, _Keylt, _Container, false, flat_set<_Kty, _Keylt, _Container>, sorted_unique_t> { +private: + using _Mybase = _Base_flat_set<_Kty, _Keylt, _Container, false, flat_set, sorted_unique_t>; public: - using _Base_flat_set<_Kty, _Keylt, _Container, false, flat_set, sorted_unique_t>::_Base_flat_set; + using _Mybase::_Base_flat_set; + using _Mybase::operator=; }; _EXPORT_STD template , class _Container = vector<_Kty>> class flat_multiset : public _Base_flat_set<_Kty, _Keylt, _Container, true, flat_multiset<_Kty, _Keylt, _Container>, - sorted_equivalent_t> { + sorted_equivalent_t> { +private: + using _Mybase = _Base_flat_set<_Kty, _Keylt, _Container, true, flat_multiset, sorted_equivalent_t>; public: - using _Base_flat_set<_Kty, _Keylt, _Container, true, flat_multiset, sorted_equivalent_t>::_Base_flat_set; + using _Mybase::_Base_flat_set; + using _Mybase::operator=; }; _EXPORT_STD template From ea929648c8c7ab104331a9fc5ab5e06fb6b50156 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 24 Aug 2023 13:13:10 +0800 Subject: [PATCH 11/20] 11. cleanups: simplify `extract`; make comparision(`==`) more obvious; merge `_Sort_potentially_sorted` --- stl/inc/flat_set | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 215f966d12c..a2bf7864277 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -255,11 +255,9 @@ public: } _NODISCARD container_type extract() && { - container_type& _Cont = _Get_cont(); // always clears the container (N4950 [flat.set.modifiers]/14 and [flat.multiset.modifiers]/10) _Clear_scope_guard<_Base_flat_set> _Guard{this}; - container_type _Temp = _STD move(_Cont); - return _Temp; + return _STD move(_Get_cont()); } void replace(container_type&& _Cont) { _Get_cont() = _STD move(_Cont); @@ -390,7 +388,7 @@ public: } _NODISCARD friend bool operator==(const _Deriv& _Lhs, const _Deriv& _Rhs) { - return _RANGES equal(_Lhs, _Rhs); + return _RANGES equal(_Lhs._Get_cont(), _Rhs._Get_cont()); } _NODISCARD friend _Synth_three_way_result<_Kty> operator<=>(const _Deriv& _Lhs, const _Deriv& _Rhs) { @@ -521,16 +519,6 @@ private: return !_Compare(_Lhs, _Rhs) && !_Compare(_Rhs, _Lhs); } - // O(N) if already sorted. - void _Sort_potentially_sorted(const iterator& _Begin, const iterator& _End) { - key_compare& _Compare = _Get_comp(); - const iterator _Begin_unsorted = _STD is_sorted_until(_Begin, _End, _Compare); - - _STD sort(_Begin_unsorted, _End, _Compare); - - _STD inplace_merge(begin(), _Begin_unsorted, _End, _Compare); - } - void _Erase_dupes_if_needed() { if constexpr (!_Multi) { const iterator _End = end(); @@ -569,7 +557,13 @@ private: return; } - _Sort_potentially_sorted(_Begin, _End); + // O(N) if already sorted. + key_compare& _Compare = _Get_comp(); + const iterator _Begin_unsorted = _STD is_sorted_until(_Begin, _End, _Compare); + + _STD sort(_Begin_unsorted, _End, _Compare); + _STD inplace_merge(begin(), _Begin_unsorted, _End, _Compare); + _STL_INTERNAL_CHECK(_STD is_sorted(begin(), end(), _Get_comp())); _Erase_dupes_if_needed(); @@ -609,6 +603,7 @@ class flat_set : public _Base_flat_set<_Kty, _Keylt, _Container, false, flat_set<_Kty, _Keylt, _Container>, sorted_unique_t> { private: using _Mybase = _Base_flat_set<_Kty, _Keylt, _Container, false, flat_set, sorted_unique_t>; + public: using _Mybase::_Base_flat_set; using _Mybase::operator=; @@ -616,9 +611,10 @@ public: _EXPORT_STD template , class _Container = vector<_Kty>> class flat_multiset : public _Base_flat_set<_Kty, _Keylt, _Container, true, flat_multiset<_Kty, _Keylt, _Container>, - sorted_equivalent_t> { + sorted_equivalent_t> { private: using _Mybase = _Base_flat_set<_Kty, _Keylt, _Container, true, flat_multiset, sorted_equivalent_t>; + public: using _Mybase::_Base_flat_set; using _Mybase::operator=; From 8b246e8d79fb2e401e3e448b84da02a1d5876fcd Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 24 Aug 2023 14:44:14 +0800 Subject: [PATCH 12/20] 12. fix signature for `insert(iter, iter)`; some other nitpicks --- stl/inc/flat_set | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index a2bf7864277..abacddb5d05 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -233,7 +233,7 @@ public: } template - void insert(const _Iter& _First, const _Iter& _Last) { + void insert(_Iter _First, _Iter _Last) { _Insert_range(_First, _Last); } template @@ -456,7 +456,7 @@ private: } template - void _Insert_range(_Iter _First, _Iter _Last) { + void _Insert_range(const _Iter _First, const _Iter _Last) { const size_type _Old_size = size(); _Container& _Cont = _Get_cont(); _Cont.insert(_Cont.end(), _First, _Last); @@ -531,7 +531,7 @@ private: } template - void _Restore_invariants_after_insert(const size_type& _Old_size) { + void _Restore_invariants_after_insert(const size_type _Old_size) { key_compare& _Compare = _Get_comp(); const iterator _Old_end = begin() + static_cast(_Old_size); const iterator _New_end = end(); @@ -544,7 +544,7 @@ private: _STD inplace_merge(begin(), _Old_end, _New_end, _Compare); - _STL_INTERNAL_CHECK(_STD is_sorted(begin(), end(), _Get_comp())); + _STL_INTERNAL_CHECK(_STD is_sorted(begin(), end(), _Compare)); _Erase_dupes_if_needed(); } @@ -564,7 +564,7 @@ private: _STD sort(_Begin_unsorted, _End, _Compare); _STD inplace_merge(begin(), _Begin_unsorted, _End, _Compare); - _STL_INTERNAL_CHECK(_STD is_sorted(begin(), end(), _Get_comp())); + _STL_INTERNAL_CHECK(_STD is_sorted(begin(), end(), _Compare)); _Erase_dupes_if_needed(); } From 14a58cd074c6eeaacac58228e477b62126b9d6fe Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 24 Aug 2023 16:50:18 +0800 Subject: [PATCH 13/20] 13. implement LWG3884 `(flat_meow(flat_meow&&, al))` (applied in N4958) --- stl/inc/flat_set | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index abacddb5d05..321f177db7d 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -67,6 +67,13 @@ public: _Base_flat_set() : _My_pair(_Zero_then_variadic_args_t{}) {} + template <_Allocator_for _Alloc> + _Base_flat_set(const _Deriv& _Set, const _Alloc& _Al) + : _My_pair(_One_then_variadic_args_t{}, _Set._Get_comp(), _Set._Get_cont(), _Al) {} + template <_Allocator_for _Alloc> + _Base_flat_set(_Deriv&& _Set, const _Alloc& _Al) + : _My_pair(_One_then_variadic_args_t{}, _STD move(_Set._Get_comp()), _STD move(_Set._Get_cont()), _Al) {} + explicit _Base_flat_set(container_type _Cont, const key_compare& _Comp = key_compare()) : _My_pair(_One_then_variadic_args_t{}, _Comp, _STD move(_Cont)) { _Make_invariants_fulfilled(); From e3d41c56b31cd11a5df72b3d8defb1933b5e83c5 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 24 Aug 2023 19:39:54 +0800 Subject: [PATCH 14/20] 14. fix 10th commit; add test --- stl/inc/flat_set | 4 +- tests/std/tests/P1222R4_flat_set/test.cpp | 101 ++++++++++++++++++---- 2 files changed, 85 insertions(+), 20 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 321f177db7d..ba4d2fe5bf2 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -612,7 +612,7 @@ private: using _Mybase = _Base_flat_set<_Kty, _Keylt, _Container, false, flat_set, sorted_unique_t>; public: - using _Mybase::_Base_flat_set; + using _Mybase::_Mybase; using _Mybase::operator=; }; @@ -623,7 +623,7 @@ private: using _Mybase = _Base_flat_set<_Kty, _Keylt, _Container, true, flat_multiset, sorted_equivalent_t>; public: - using _Mybase::_Base_flat_set; + using _Mybase::_Mybase; using _Mybase::operator=; }; diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index a7739cc7353..32bc06245a3 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -98,19 +98,6 @@ void assert_all_requirements_and_equals(const T& s, const initializer_list -void assert_basic() { - T s{3, 2, 2, 2, 1}; - assert_all_requirements_and_equals(s, {1, 2, 3}); - - s.insert(43); - assert_all_requirements_and_equals(s, {1, 2, 3, 43}); - - int my_ints[] = {1, 2, 3, 4, 55}; - s.insert_range(my_ints); - assert_all_requirements_and_equals(s, {1, 2, 3, 4, 43, 55}); -} - template void test_constructors() { using lt = std::less; @@ -132,9 +119,74 @@ void test_constructors() { flat_set a{}; a = {1, 7, 7, 7, 2, 100, -1}; assert_all_requirements_and_equals(a, {-1, 1, 2, 7, 100}); + assert_all_requirements_and_equals(flat_set(a, allocator{}), {-1, 1, 2, 7, 100}); + assert_all_requirements_and_equals(flat_set(std::move(a), allocator{}), {-1, 1, 2, 7, 100}); flat_multiset b{}; b = {1, 7, 7, 7, 2, 100, -1}; assert_all_requirements_and_equals(b, {-1, 1, 2, 7, 7, 7, 100}); + assert_all_requirements_and_equals(flat_multiset(b, allocator{}), {-1, 1, 2, 7, 7, 7, 100}); + assert_all_requirements_and_equals(flat_multiset(std::move(b), allocator{}), {-1, 1, 2, 7, 7, 7, 100}); +} + +template +void test_insert() { + using lt = std::less; + + const int _dat[]{0, 1, 2}; + const int* volatile _beg = _dat; + const int* volatile _end = std::end(_dat); + { + flat_set a{5, 5}; + assert_all_requirements_and_equals(a, {5}); + a.emplace(0); + assert_all_requirements_and_equals(a, {0, 5}); + a.emplace_hint(a.end(), 8); + assert_all_requirements_and_equals(a, {0, 5, 8}); + a.insert(_dat[2]); + assert_all_requirements_and_equals(a, {0, 2, 5, 8}); + a.insert(2); + assert_all_requirements_and_equals(a, {0, 2, 5, 8}); + a.insert(a.begin(), _dat[1]); + assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8}); + a.insert(a.begin(), 9); + assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8, 9}); + a.insert(_beg, _end); + assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8, 9}); + a.insert(sorted_unique, _beg, _end); + assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8, 9}); + a.insert_range(_dat); + assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8, 9}); + a.insert({3, 6}); + assert_all_requirements_and_equals(a, {0, 1, 2, 3, 5, 6, 8, 9}); + a.insert(sorted_unique, {4, 5, 7}); + assert_all_requirements_and_equals(a, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + } + { + flat_multiset b{5, 5}; + assert_all_requirements_and_equals(b, {5, 5}); + b.emplace(0); + assert_all_requirements_and_equals(b, {0, 5, 5}); + b.emplace_hint(b.end(), 8); + assert_all_requirements_and_equals(b, {0, 5, 5, 8}); + b.insert(_dat[2]); + assert_all_requirements_and_equals(b, {0, 2, 5, 5, 8}); + b.insert(2); + assert_all_requirements_and_equals(b, {0, 2, 2, 5, 5, 8}); + b.insert(b.begin(), _dat[1]); + assert_all_requirements_and_equals(b, {0, 1, 2, 2, 5, 5, 8}); + b.insert(b.begin(), 9); + assert_all_requirements_and_equals(b, {0, 1, 2, 2, 5, 5, 8, 9}); + b.insert(_beg, _end); + assert_all_requirements_and_equals(b, {0, 0, 1, 1, 2, 2, 2, 5, 5, 8, 9}); + b.insert(sorted_equivalent, _beg, _end); + assert_all_requirements_and_equals(b, {0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 5, 5, 8, 9}); + b.insert_range(_dat); + assert_all_requirements_and_equals(b, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 5, 5, 8, 9}); + b.insert({3, 6}); + assert_all_requirements_and_equals(b, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 5, 5, 6, 8, 9}); + b.insert(sorted_equivalent, {4, 5, 7}); + assert_all_requirements_and_equals(b, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9}); + } } template @@ -191,6 +243,21 @@ void test_non_static_comparer() { assert_all_requirements_and_equals(a, {9, 7, 5, -1}); } +void test_ebco() { + using vec = vector; + using deq = deque; + + static_assert(sizeof(vec) == sizeof(flat_set, vec>)); + static_assert(sizeof(deq) == sizeof(flat_set, deq>)); + static_assert(sizeof(vec) == sizeof(flat_multiset, vec>)); + static_assert(sizeof(deq) == sizeof(flat_multiset, deq>)); + + static_assert(sizeof(vec) < sizeof(flat_set, vec>)); + static_assert(sizeof(deq) < sizeof(flat_set, deq>)); + static_assert(sizeof(vec) < sizeof(flat_multiset, vec>)); + static_assert(sizeof(deq) < sizeof(flat_multiset, deq>)); +} + template void test_extract() { constexpr int elements[]{1, 2, 3, 4}; @@ -222,6 +289,9 @@ int main() { test_constructors>(); test_constructors>(); + test_ebco(); + test_insert>(); + test_insert>(); test_non_static_comparer(); test_extract>(); @@ -229,9 +299,4 @@ int main() { test_erase_if>(); test_erase_if>(); - - assert_basic>(); - assert_basic, deque>>(); - - flat_multiset, deque> d; } From febbb91d9bb2502951dec9c640c1dbe76209c100 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Fri, 25 Aug 2023 11:12:33 +0800 Subject: [PATCH 15/20] 15. fix `return _Emplace`; unify practices of `_Emplace` and `_Emplace_hint`; use `const key_compare&` consistently; test nitpick --- stl/inc/flat_set | 50 +++++++++++------------ tests/std/tests/P1222R4_flat_set/test.cpp | 4 +- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index ba4d2fe5bf2..cc5cdce4150 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -208,7 +208,7 @@ public: // modifiers template auto emplace(_Args&&... _Vals) { - _Emplace(_Kty{_STD forward<_Args>(_Vals)...}); + return _Emplace(_Kty{_STD forward<_Args>(_Vals)...}); } template iterator emplace_hint(const_iterator _Hint, _Args&&... _Vals) { @@ -429,10 +429,25 @@ private: return true; } + template + auto _Emplace(_Ty&& _Val) { + _Container& _Cont = _Get_cont(); + const iterator _End = end(); + const iterator _Where = lower_bound(_Val); + if constexpr (_Multi) { + return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); + } else { + if (_Where != _End && _Keys_equal(*_Where, _Val)) { + return pair{_Where, false}; + } + return pair{_Cont.emplace(_Where, _STD forward<_Ty>(_Val)), true}; + } + } + template iterator _Emplace_hint(const_iterator _Where, _Ty&& _Val) { _Container& _Cont = _Get_cont(); - _Keylt& _Compare = _Get_comp(); + const key_compare& _Compare = _Get_comp(); const const_iterator _Begin = cbegin(); const const_iterator _End = cend(); @@ -453,12 +468,12 @@ private: } if constexpr (_Multi) { - return _Cont.insert(_Where, _STD forward<_Ty>(_Val)); + return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); } else { - if (_Where == _End || !_Keys_equal(_Val, *_Where)) { - return _Cont.insert(_Where, _STD forward<_Ty>(_Val)); + if (_Where != _End && _Keys_equal(_Val, *_Where)) { + return _Cont.begin() + (_Where - _Begin); } - return _Cont.begin() + (_Where - _Begin); + return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); } } @@ -470,21 +485,6 @@ private: _Restore_invariants_after_insert<_Presorted>(_Old_size); } - template - auto _Emplace(_Ty&& _Val) { - _Container& _Cont = _Get_cont(); - const iterator _End = end(); - const iterator _Where = lower_bound(_Val); - if constexpr (_Multi) { - return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); - } else { - if (_Where != _End && _Keys_equal(*_Where, _Val)) { - return pair{_Where, false}; - } - return pair{_Cont.emplace(_Where, _STD forward<_Ty>(_Val)), true}; - } - } - template requires _Keylt_transparent || is_same_v<_Ty, _Kty> size_type _Erase(_Ty&& _Val) { @@ -539,9 +539,9 @@ private: template void _Restore_invariants_after_insert(const size_type _Old_size) { - key_compare& _Compare = _Get_comp(); - const iterator _Old_end = begin() + static_cast(_Old_size); - const iterator _New_end = end(); + const key_compare& _Compare = _Get_comp(); + const iterator _Old_end = begin() + static_cast(_Old_size); + const iterator _New_end = end(); if constexpr (!_Presorted) { _STD sort(_Old_end, _New_end, _Compare); @@ -565,7 +565,7 @@ private: } // O(N) if already sorted. - key_compare& _Compare = _Get_comp(); + const key_compare& _Compare = _Get_comp(); const iterator _Begin_unsorted = _STD is_sorted_until(_Begin, _End, _Compare); _STD sort(_Begin_unsorted, _End, _Compare); diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index 32bc06245a3..c004d7dbd68 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -156,7 +156,7 @@ void test_insert() { assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8, 9}); a.insert_range(_dat); assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8, 9}); - a.insert({3, 6}); + a.insert({6, 3}); assert_all_requirements_and_equals(a, {0, 1, 2, 3, 5, 6, 8, 9}); a.insert(sorted_unique, {4, 5, 7}); assert_all_requirements_and_equals(a, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); @@ -182,7 +182,7 @@ void test_insert() { assert_all_requirements_and_equals(b, {0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 5, 5, 8, 9}); b.insert_range(_dat); assert_all_requirements_and_equals(b, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 5, 5, 8, 9}); - b.insert({3, 6}); + b.insert({6, 3}); assert_all_requirements_and_equals(b, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 5, 5, 6, 8, 9}); b.insert(sorted_equivalent, {4, 5, 7}); assert_all_requirements_and_equals(b, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9}); From 83d6a91bdc05bc0fa25d9fb763c1c2b4f989502e Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Fri, 25 Aug 2023 14:06:19 +0800 Subject: [PATCH 16/20] 16. fix behavior of `emplace` and `emplace_hint`; add debug for `flat_set::insert([hint,]auto&&)` --- stl/inc/flat_set | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index cc5cdce4150..648eaf5850a 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -208,11 +208,21 @@ public: // modifiers template auto emplace(_Args&&... _Vals) { - return _Emplace(_Kty{_STD forward<_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(_STD forward<_Args>(_Vals)...); + } else { + return _Emplace(_Kty{_STD forward<_Args>(_Vals)...}); + } } template iterator emplace_hint(const_iterator _Hint, _Args&&... _Vals) { - return _Emplace_hint(_Hint, _Kty{_STD forward<_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)...); + } else { + return _Emplace_hint(_Hint, _Kty{_STD forward<_Args>(_Vals)...}); + } } auto insert(const value_type& _Val) { @@ -435,12 +445,22 @@ private: const iterator _End = end(); const iterator _Where = lower_bound(_Val); if constexpr (_Multi) { + _STL_INTERNAL_STATIC_ASSERT(is_same_v, _Kty>); return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); } else { if (_Where != _End && _Keys_equal(*_Where, _Val)) { return pair{_Where, false}; } - return pair{_Cont.emplace(_Where, _STD forward<_Ty>(_Val)), true}; + if constexpr (is_same_v, _Kty>) { + return pair{_Cont.emplace(_Where, _STD forward<_Ty>(_Val)), true}; + } else { + // flat_set::insert(auto&&) + _STL_INTERNAL_STATIC_ASSERT(_Keylt_transparent && is_constructible_v<_Kty, _Ty>); + _Kty _Keyval{_STD forward<_Ty>(_Val)}; + _STL_ASSERT(lower_bound(_Keyval) == _Where && !_Keys_equal(_Keyval, *_Where), + "find(val) was not equal to find(key_type{forward(val)})"); + return pair{_Cont.emplace(_Where, _STD move(_Keyval)), true}; + } } } @@ -468,12 +488,22 @@ private: } if constexpr (_Multi) { + _STL_INTERNAL_STATIC_ASSERT(is_same_v, _Kty>); return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); } else { if (_Where != _End && _Keys_equal(_Val, *_Where)) { return _Cont.begin() + (_Where - _Begin); } - return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); + if constexpr (is_same_v, _Kty>) { + return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); + } else { + // flat_set::insert(hint,auto&&) + _STL_INTERNAL_STATIC_ASSERT(_Keylt_transparent && is_constructible_v<_Kty, _Ty>); + _Kty _Keyval{_STD forward<_Ty>(_Val)}; + _STL_ASSERT(lower_bound(_Keyval) == _Where && !_Keys_equal(_Keyval, *_Where), + "find(val) was not equal to find(key_type{forward(val)})"); + return _Cont.emplace(_Where, _STD move(_Keyval)); + } } } From 6bd95a175c57f4f2a7cf6ac965050a60c37abcea Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Fri, 25 Aug 2023 19:16:32 +0800 Subject: [PATCH 17/20] 17. `emplace` should use `upper_bound` for flat_multiset --- 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 648eaf5850a..b96ed120d1f 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -441,13 +441,13 @@ private: template auto _Emplace(_Ty&& _Val) { - _Container& _Cont = _Get_cont(); - const iterator _End = end(); - const iterator _Where = lower_bound(_Val); + _Container& _Cont = _Get_cont(); if constexpr (_Multi) { _STL_INTERNAL_STATIC_ASSERT(is_same_v, _Kty>); - return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); + return _Cont.emplace(upper_bound(_Val), _STD forward<_Ty>(_Val)); } else { + const iterator _End = end(); + const iterator _Where = lower_bound(_Val); if (_Where != _End && _Keys_equal(*_Where, _Val)) { return pair{_Where, false}; } From 732c4cc4fd66742b12691527c9f7c08a9eefad60 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Fri, 25 Aug 2023 20:47:35 +0800 Subject: [PATCH 18/20] 18. fix `emplace_hint`; add test --- stl/inc/flat_set | 42 +++++--- tests/std/tests/P1222R4_flat_set/test.cpp | 113 ++++++++++++++-------- 2 files changed, 101 insertions(+), 54 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index b96ed120d1f..cabf059a8db 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -471,20 +471,40 @@ private: const const_iterator _Begin = cbegin(); const const_iterator _End = cend(); - if (_Where == _End || !_Compare(*_Where, _Val)) { - // _Val <= *_Where - // Left of _Where - if (_Where == _Begin || !_Compare(_Val, *(_Where - 1))) { - // _Val >= (*_Where - 1) - // Insert before _Where + if constexpr (_Multi) { + // Find upper_bound for flat_multiset + if (_Where == _End || _Compare(_Val, *_Where)) { + // _Val < *_Where + if (_Where == _Begin || !_Compare(_Val, *(_Where - 1))) { + // _Val >= *(_Where-1) + // upper_bound is _Where + } else { + // _Val < *(_Where-1) + // upper_bound is in [_Begin,_Where-1] + _Where = _STD upper_bound(_Begin, _Where - 1, _Val); + } } else { - // _Val < (*_Where - 1) - _Where = _STD upper_bound(_Begin, _Where, _Val, _Compare); + // _Val >= *_Where + // upper_bound is in [_Where+1,_End] + _Where = _STD upper_bound(_Where + 1, _End, _Val); } } else { - // _Val > *_Where - // Right of _Where - _Where = _STD lower_bound(_Where + 1, _End, _Val, _Compare); + // Find lower_bound for flat_set + if (_Where == _End || !_Compare(*_Where, _Val)) { + // _Val <= *_Where + if (_Where == _Begin || _Compare(*(_Where - 1), _Val)) { + // _Val > *(_Where-1) + // lower_bound is _Where + } else { + // _Val <= *(_Where-1) + // lower_bound is in [_Begin,_Where-1] + _Where = _STD lower_bound(_Begin, _Where - 1, _Val); + } + } else { + // _Val > *_Where + // lower_bound is in [_Where+1,_End] + _Where = _STD lower_bound(_Where + 1, _End, _Val); + } } if constexpr (_Multi) { diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index c004d7dbd68..9eae7a98f88 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -129,7 +129,7 @@ void test_constructors() { } template -void test_insert() { +void test_insert_1() { using lt = std::less; const int _dat[]{0, 1, 2}; @@ -138,54 +138,77 @@ void test_insert() { { flat_set a{5, 5}; assert_all_requirements_and_equals(a, {5}); - a.emplace(0); + a.emplace(); assert_all_requirements_and_equals(a, {0, 5}); - a.emplace_hint(a.end(), 8); - assert_all_requirements_and_equals(a, {0, 5, 8}); + a.emplace(1); + assert_all_requirements_and_equals(a, {0, 1, 5}); a.insert(_dat[2]); - assert_all_requirements_and_equals(a, {0, 2, 5, 8}); + assert_all_requirements_and_equals(a, {0, 1, 2, 5}); a.insert(2); - assert_all_requirements_and_equals(a, {0, 2, 5, 8}); - a.insert(a.begin(), _dat[1]); - assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8}); - a.insert(a.begin(), 9); - assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8, 9}); + assert_all_requirements_and_equals(a, {0, 1, 2, 5}); a.insert(_beg, _end); - assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8, 9}); + assert_all_requirements_and_equals(a, {0, 1, 2, 5}); a.insert(sorted_unique, _beg, _end); - assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8, 9}); + assert_all_requirements_and_equals(a, {0, 1, 2, 5}); a.insert_range(_dat); - assert_all_requirements_and_equals(a, {0, 1, 2, 5, 8, 9}); - a.insert({6, 3}); - assert_all_requirements_and_equals(a, {0, 1, 2, 3, 5, 6, 8, 9}); - a.insert(sorted_unique, {4, 5, 7}); - assert_all_requirements_and_equals(a, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + assert_all_requirements_and_equals(a, {0, 1, 2, 5}); + a.insert({6, 2, 3}); + assert_all_requirements_and_equals(a, {0, 1, 2, 3, 5, 6}); + a.insert(sorted_unique, {4, 5}); + assert_all_requirements_and_equals(a, {0, 1, 2, 3, 4, 5, 6}); } { - flat_multiset b{5, 5}; - assert_all_requirements_and_equals(b, {5, 5}); - b.emplace(0); - assert_all_requirements_and_equals(b, {0, 5, 5}); - b.emplace_hint(b.end(), 8); - assert_all_requirements_and_equals(b, {0, 5, 5, 8}); - b.insert(_dat[2]); - assert_all_requirements_and_equals(b, {0, 2, 5, 5, 8}); - b.insert(2); - assert_all_requirements_and_equals(b, {0, 2, 2, 5, 5, 8}); - b.insert(b.begin(), _dat[1]); - assert_all_requirements_and_equals(b, {0, 1, 2, 2, 5, 5, 8}); - b.insert(b.begin(), 9); - assert_all_requirements_and_equals(b, {0, 1, 2, 2, 5, 5, 8, 9}); - b.insert(_beg, _end); - assert_all_requirements_and_equals(b, {0, 0, 1, 1, 2, 2, 2, 5, 5, 8, 9}); - b.insert(sorted_equivalent, _beg, _end); - assert_all_requirements_and_equals(b, {0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 5, 5, 8, 9}); - b.insert_range(_dat); - assert_all_requirements_and_equals(b, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 5, 5, 8, 9}); - b.insert({6, 3}); - assert_all_requirements_and_equals(b, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 5, 5, 6, 8, 9}); - b.insert(sorted_equivalent, {4, 5, 7}); - assert_all_requirements_and_equals(b, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9}); + flat_multiset a{5, 5}; + assert_all_requirements_and_equals(a, {5, 5}); + a.emplace(); + assert_all_requirements_and_equals(a, {0, 5, 5}); + a.emplace(1); + assert_all_requirements_and_equals(a, {0, 1, 5, 5}); + a.insert(_dat[2]); + assert_all_requirements_and_equals(a, {0, 1, 2, 5, 5}); + a.insert(2); + assert_all_requirements_and_equals(a, {0, 1, 2, 2, 5, 5}); + a.insert(_beg, _end); + assert_all_requirements_and_equals(a, {0, 0, 1, 1, 2, 2, 2, 5, 5}); + a.insert(sorted_equivalent, _beg, _end); + assert_all_requirements_and_equals(a, {0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 5, 5}); + a.insert_range(_dat); + assert_all_requirements_and_equals(a, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 5, 5}); + a.insert({6, 2, 3}); + assert_all_requirements_and_equals(a, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 5, 5, 6}); + a.insert(sorted_equivalent, {4, 5}); + assert_all_requirements_and_equals(a, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 5, 5, 6}); + } +} + +template +void test_insert_2() { + using lt = std::less; + + const int _dat[]{0, 1, 2}; + { + flat_set a{0, 5}; + assert_all_requirements_and_equals(a, {0, 5}); + a.emplace_hint(a.end()); + assert_all_requirements_and_equals(a, {0, 5}); + a.emplace_hint(a.end(), 0); + assert_all_requirements_and_equals(a, {0, 5}); + a.insert(a.begin(), 6); + assert_all_requirements_and_equals(a, {0, 5, 6}); + a.insert(a.begin(), _dat[1]); + assert_all_requirements_and_equals(a, {0, 1, 5, 6}); + } + { + flat_multiset a{0, 5}; + assert_all_requirements_and_equals(a, {0, 5}); + a.emplace_hint(a.end()); + assert_all_requirements_and_equals(a, {0, 0, 5}); + a.emplace_hint(a.end(), 0); + assert_all_requirements_and_equals(a, {0, 0, 0, 5}); + a.insert(a.begin(), 6); + assert_all_requirements_and_equals(a, {0, 0, 0, 5, 6}); + a.insert(a.begin(), _dat[1]); + assert_all_requirements_and_equals(a, {0, 0, 0, 1, 5, 6}); } } @@ -290,8 +313,12 @@ int main() { test_constructors>(); test_ebco(); - test_insert>(); - test_insert>(); + + test_insert_1>(); + test_insert_1>(); + test_insert_2>(); + test_insert_2>(); + test_non_static_comparer(); test_extract>(); From 42e379c48d29f2505a2278e15db8e3a0fb76d567 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 26 Aug 2023 00:30:15 +0800 Subject: [PATCH 19/20] 19. keep constructor declarations strictly in line with the standard, and some other nitpicks --- stl/inc/flat_set | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index cabf059a8db..e8b6c51d8b9 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -111,11 +111,14 @@ public: _Base_flat_set(_Iter _First, _Iter _Last, const _Alloc& _Al) : _Base_flat_set(container_type(_First, _Last, _Al)) {} template <_Container_compatible_range<_Kty> _Rng> - _Base_flat_set(from_range_t, _Rng&& _Range, const key_compare& _Comp = key_compare()) - : _Base_flat_set(container_type(from_range, _STD forward<_Rng>(_Range)), _Comp) {} + _Base_flat_set(from_range_t, _Rng&& _Range) + : _Base_flat_set(container_type(from_range, _STD forward<_Rng>(_Range))) {} template <_Container_compatible_range<_Kty> _Rng, _Allocator_for _Alloc> _Base_flat_set(from_range_t, _Rng&& _Range, const _Alloc& _Al) : _Base_flat_set(container_type(from_range, _STD forward<_Rng>(_Range), _Al)) {} + template <_Container_compatible_range<_Kty> _Rng> + _Base_flat_set(from_range_t, _Rng&& _Range, const key_compare& _Comp) + : _Base_flat_set(container_type(from_range, _STD forward<_Rng>(_Range)), _Comp) {} template <_Container_compatible_range<_Kty> _Rng, _Allocator_for _Alloc> _Base_flat_set(from_range_t, _Rng&& _Range, const key_compare& _Comp, const _Alloc& _Al) : _Base_flat_set(container_type(from_range, _STD forward<_Rng>(_Range), _Al), _Comp) {} @@ -131,7 +134,7 @@ public: : _Base_flat_set(_Tsort, container_type(_First, _Last, _Al)) {} _Base_flat_set(initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) - : _Base_flat_set(_Ilist.begin(), _Ilist.end(), _Comp) {} + : _Base_flat_set(container_type(_Ilist.begin(), _Ilist.end()), _Comp) {} template <_Allocator_for _Alloc> _Base_flat_set(initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) : _Base_flat_set(container_type(_Ilist.begin(), _Ilist.end(), _Al), _Comp) {} @@ -140,7 +143,7 @@ public: : _Base_flat_set(container_type(_Ilist.begin(), _Ilist.end(), _Al)) {} _Base_flat_set(_Tsorted _Tsort, initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) - : _Base_flat_set(_Tsort, _Ilist.begin(), _Ilist.end(), _Comp) {} + : _Base_flat_set(_Tsort, container_type(_Ilist.begin(), _Ilist.end()), _Comp) {} template <_Allocator_for _Alloc> _Base_flat_set(_Tsorted _Tsort, initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) : _Base_flat_set(_Tsort, container_type(_Ilist.begin(), _Ilist.end(), _Al), _Comp) {} @@ -149,7 +152,7 @@ public: : _Base_flat_set(_Tsort, container_type(_Ilist.begin(), _Ilist.end(), _Al)) {} _Deriv& operator=(initializer_list<_Kty> _Ilist) { - _Get_cont() = container_type(_Ilist.begin(), _Ilist.end()); + _Get_cont().assign(_Ilist.begin(), _Ilist.end()); _Make_invariants_fulfilled(); return static_cast<_Deriv&>(*this); } @@ -621,7 +624,7 @@ private: _STD sort(_Begin_unsorted, _End, _Compare); _STD inplace_merge(begin(), _Begin_unsorted, _End, _Compare); - _STL_INTERNAL_CHECK(_STD is_sorted(begin(), end(), _Compare)); + _STL_INTERNAL_CHECK(_STD is_sorted(_Begin, _End, _Compare)); _Erase_dupes_if_needed(); } From ce843fac9881b993254c1e06ca3c09820607ef47 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 26 Aug 2023 14:52:21 +0800 Subject: [PATCH 20/20] 20. nitpicks --- stl/inc/flat_set | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index e8b6c51d8b9..c231affaad2 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -97,9 +97,9 @@ public: explicit _Base_flat_set(const key_compare& _Comp) : _My_pair(_One_then_variadic_args_t{}, _Comp) {} template <_Allocator_for _Alloc> - _Base_flat_set(const key_compare& _Comp, const _Alloc& _Al) : _Base_flat_set(_Comp, container_type(_Al)) {} + _Base_flat_set(const key_compare& _Comp, const _Alloc& _Al) : _My_pair(_One_then_variadic_args_t{}, _Comp, _Al) {} template <_Allocator_for _Alloc> - explicit _Base_flat_set(const _Alloc& _Al) : _Base_flat_set(container_type(_Al)) {} + explicit _Base_flat_set(const _Alloc& _Al) : _My_pair(_Zero_then_variadic_args_t{}, _Al) {} template _Base_flat_set(_Iter _First, _Iter _Last, const key_compare& _Comp = key_compare()) @@ -424,7 +424,7 @@ private: void _Assert_after_sorted_input() const { _STL_ASSERT(_STD is_sorted(cbegin(), cend(), _Get_comp()), "Input was not sorted!"); if constexpr (!_Multi) { - _STL_ASSERT(_Is_unique(), "Input was not unique!"); + _STL_ASSERT(_Is_unique(), "Input was sorted but not unique!"); } }