From 7f30ebfd3977be6096a3b59a471d146c7d4a013c Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 26 Aug 2023 15:03:04 +0800 Subject: [PATCH 01/13] 1. 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 dda412494cd..6936560423c 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 8fd855690f7b60ce26e4e50e1c0aa04353b0422e Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 26 Aug 2023 15:59:04 +0800 Subject: [PATCH 02/13] 2. Fix usage of `_Compressed_pair` --- stl/inc/flat_set | 18 +++++++++--------- tests/std/tests/P1222R4_flat_set/test.cpp | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 6936560423c..64a1a01ed2e 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -65,10 +65,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> @@ -78,7 +78,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> @@ -88,7 +88,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> @@ -585,22 +585,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 { diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index a7739cc7353..a2a9fa28293 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -191,6 +191,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 +237,8 @@ int main() { test_constructors>(); test_constructors>(); + test_ebco(); + test_non_static_comparer(); test_extract>(); From 31b311e3fa2281959485a814912945eaf75eb4d3 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 26 Aug 2023 16:05:38 +0800 Subject: [PATCH 03/13] 3.1. Implement LWG3884 (`flat_meow(flat_meow&&, al)`) 3.2. Make constructor declarations strictly in line with the standard 3.3. Various cleanups or enhancements for constructors 3.4. Expose `operator=(initializer_list)` --- stl/inc/flat_set | 41 ++++++++++++++++++----- tests/std/tests/P1222R4_flat_set/test.cpp | 4 +++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 64a1a01ed2e..c9d740c446f 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(); @@ -90,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()) @@ -104,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) {} @@ -124,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) {} @@ -133,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) {} @@ -142,11 +152,12 @@ 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); } + // iterators _NODISCARD iterator begin() noexcept { return _Get_cont().begin(); } @@ -184,6 +195,7 @@ public: return _Get_cont().crend(); } + // capacity _NODISCARD_EMPTY_MEMBER bool empty() const noexcept { return _Get_cont().empty(); } @@ -194,6 +206,7 @@ public: return _Get_cont().max_size(); } + // modifiers template auto emplace(_Args&&... _Vals) { insert<_Kty>(_Kty{_STD forward<_Args>(_Vals)...}); @@ -289,6 +302,7 @@ public: _Get_cont().clear(); } + // observers _NODISCARD key_compare key_comp() const { return _Get_comp(); } @@ -296,6 +310,7 @@ public: return _Get_comp(); } + // set operations _NODISCARD iterator find(const _Kty& _Val) { return _Find(_Val); } @@ -616,15 +631,23 @@ _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::_Mybase; + 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> { +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::_Mybase; + using _Mybase::operator=; }; _EXPORT_STD template diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index a2a9fa28293..494d6d5be67 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -132,9 +132,13 @@ 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 From b9acf69ee89133a7acaebe40b45efdaed47ea56f Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 26 Aug 2023 16:08:18 +0800 Subject: [PATCH 04/13] 4. Various cleanups or enhancements for other methods --- stl/inc/flat_set | 58 +++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index c9d740c446f..d8f1b8071f1 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -170,6 +170,7 @@ public: _NODISCARD const_iterator end() const noexcept { return _Get_cont().end(); } + _NODISCARD reverse_iterator rbegin() noexcept { return _Get_cont().rbegin(); } @@ -182,6 +183,7 @@ public: _NODISCARD const_reverse_iterator rend() const noexcept { return _Get_cont().rend(); } + _NODISCARD const_iterator cbegin() const noexcept { return _Get_cont().cbegin(); } @@ -261,13 +263,10 @@ 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); _Assert_after_sorted_input(); @@ -282,13 +281,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); } @@ -297,7 +294,6 @@ public: _RANGES swap(_Get_comp(), _Other._Get_comp()); _RANGES swap(_Get_cont(), _Other._Get_cont()); } - void clear() noexcept { _Get_cont().clear(); } @@ -314,7 +310,6 @@ public: _NODISCARD iterator find(const _Kty& _Val) { return _Find(_Val); } - _NODISCARD const_iterator find(const _Kty& _Val) const { return _Find(_Val); } @@ -324,7 +319,6 @@ public: _NODISCARD iterator find(const _Other& _Val) { return _Find(_Val); } - template requires _Keylt_transparent _NODISCARD const_iterator find(const _Other& _Val) const { @@ -335,7 +329,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 { @@ -344,13 +337,14 @@ 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) { return _STD lower_bound(begin(), end(), _Val, _Get_comp()); } @@ -363,7 +357,6 @@ public: _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 { @@ -373,7 +366,6 @@ 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()); } @@ -383,7 +375,6 @@ public: _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 { @@ -393,7 +384,6 @@ 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()); } @@ -403,7 +393,6 @@ public: _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 { @@ -411,7 +400,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) { @@ -425,9 +414,9 @@ 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!"); + _STL_ASSERT(_Is_unique(), "Input was sorted but not unique!"); } } @@ -435,8 +424,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; @@ -480,7 +469,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); @@ -528,8 +517,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 = cend(); + const const_iterator _Where = lower_bound(_Val); if (_Where != _End && _Keys_equal(*_Where, _Val)) { return _Where; } else { @@ -556,21 +545,20 @@ 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()); } } 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(); + void _Restore_invariants_after_insert(const size_type _Old_size) { + 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); @@ -580,7 +568,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(); } @@ -594,7 +582,7 @@ private: } _Sort_potentially_sorted(_Begin, _End); - _STL_INTERNAL_CHECK(_STD is_sorted(begin(), end(), _Get_comp())); + _STL_INTERNAL_CHECK(_STD is_sorted(_Begin, _End, _Compare)); _Erase_dupes_if_needed(); } From 59445c286561c241a80658867c934aa8403309fc Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 26 Aug 2023 16:10:38 +0800 Subject: [PATCH 05/13] 5. Merge `_Sort_potentially_sorted` --- stl/inc/flat_set | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index d8f1b8071f1..e4489c179c1 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -533,16 +533,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(); @@ -581,7 +571,13 @@ private: return; } - _Sort_potentially_sorted(_Begin, _End); + // O(N) if already sorted. + const 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, _Compare)); _Erase_dupes_if_needed(); From 5a66700631467800dc347a1312f612f3f97d170a Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 26 Aug 2023 16:43:27 +0800 Subject: [PATCH 06/13] 6.1. Fix `emplace[_hint]` and `insert([hint,]single_val)` functions 6.2. Fix signature for `insert(iter, iter)` 6.3. Implement `insert(initializer_list)` 6.4. Make declarations strictly in line with the standard --- stl/inc/flat_set | 150 ++++++++++++++-------- tests/std/tests/P1222R4_flat_set/test.cpp | 107 ++++++++++++--- 2 files changed, 186 insertions(+), 71 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index e4489c179c1..1efa3ac41f6 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -211,31 +211,33 @@ public: // modifiers template auto emplace(_Args&&... _Vals) { - insert<_Kty>(_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) { - 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)); - } - - 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)); + return _Emplace(_STD forward<_Other>(_Val)); } iterator insert(const_iterator _Hint, const value_type& _Val) { @@ -244,17 +246,20 @@ public: 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) { + void insert(_Iter _First, _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(); @@ -262,6 +267,13 @@ public: _Restore_invariants_after_insert(_Old_size); } + 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() && { // always clears the container (N4950 [flat.set.modifiers]/14 and [flat.multiset.modifiers]/10) _Clear_scope_guard<_Base_flat_set> _Guard{this}; @@ -435,36 +447,84 @@ 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(); + auto _Emplace(_Ty&& _Val) { + _Container& _Cont = _Get_cont(); + if constexpr (_Multi) { + _STL_INTERNAL_STATIC_ASSERT(is_same_v, _Kty>); + 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}; + } + 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}; + } + } + } + + template + iterator _Emplace_hint(const_iterator _Where, _Ty&& _Val) { + _Container& _Cont = _Get_cont(); + const key_compare& _Compare = _Get_comp(); + 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) { - return _Cont.insert(_Where, _STD forward<_Ty>(_Val)); + _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.insert(_Where, _STD forward<_Ty>(_Val)); + if (_Where != _End && _Keys_equal(_Val, *_Where)) { + return _Cont.begin() + (_Where - _Begin); + } + 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)); } - return _Where; } } @@ -476,22 +536,6 @@ private: _Restore_invariants_after_insert<_Presorted>(_Old_size); } - template - requires (!_Multi && _Keylt_transparent && is_constructible_v<_Kty, _Ty>) || is_same_v<_Ty, _Kty> - auto _Insert(_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) { diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index 494d6d5be67..9eae7a98f88 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; @@ -141,6 +128,90 @@ void test_constructors() { assert_all_requirements_and_equals(flat_multiset(std::move(b), allocator{}), {-1, 1, 2, 7, 7, 7, 100}); } +template +void test_insert_1() { + 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(); + assert_all_requirements_and_equals(a, {0, 5}); + a.emplace(1); + assert_all_requirements_and_equals(a, {0, 1, 5}); + a.insert(_dat[2]); + assert_all_requirements_and_equals(a, {0, 1, 2, 5}); + a.insert(2); + assert_all_requirements_and_equals(a, {0, 1, 2, 5}); + a.insert(_beg, _end); + 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}); + a.insert_range(_dat); + 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 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}); + } +} + template void test_spaceship_operator() { static constexpr bool multi = _Is_specialization_v; @@ -243,6 +314,11 @@ int main() { test_ebco(); + test_insert_1>(); + test_insert_1>(); + test_insert_2>(); + test_insert_2>(); + test_non_static_comparer(); test_extract>(); @@ -250,9 +326,4 @@ int main() { test_erase_if>(); test_erase_if>(); - - assert_basic>(); - assert_basic, deque>>(); - - flat_multiset, deque> d; } From a63e98ce35b465f81f27d2b389dcd4e9087eb2c8 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sun, 27 Aug 2023 14:28:23 +0800 Subject: [PATCH 07/13] 7. Try to fix and clarify `insert([hint,]auto&&)` --- stl/inc/flat_set | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 1efa3ac41f6..1f4a8f52285 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -446,6 +446,22 @@ private: return true; } + bool _Check_where(const const_iterator _Where, const _Kty& _Val) const { + // check that _Val can be inserted before _Where + const key_compare& _Compare = _Get_comp(); + if constexpr (_Multi) { + // check that _Where is the upper_bound for _Val + // equivalent to checking *(_Where-1) <= _Val < *_Where + return (_Where == cend() || _Compare(_Val, *_Where)) + && (_Where == cbegin() || !_Compare(_Val, *(_Where - 1))); + } else { + // check that _Where is the lower_bound for _Val, and *_Where is not equivalent to _Val + // equivalent to checking *(_Where-1) < _Val < *_Where + return (_Where == cend() || _Compare(_Val, *_Where)) + && (_Where == cbegin() || _Compare(*(_Where - 1), _Val)); + } + } + template auto _Emplace(_Ty&& _Val) { _Container& _Cont = _Get_cont(); @@ -461,11 +477,10 @@ private: if constexpr (is_same_v, _Kty>) { return pair{_Cont.emplace(_Where, _STD forward<_Ty>(_Val)), true}; } else { - // flat_set::insert(auto&&) + // for 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)})"); + _STL_ASSERT(_Check_where(_Where, _Keyval), "The input type was not equivalent to key_type!"); return pair{_Cont.emplace(_Where, _STD move(_Keyval)), true}; } } @@ -479,7 +494,7 @@ private: const const_iterator _End = cend(); if constexpr (_Multi) { - // Find upper_bound for flat_multiset + // look for the upper_bound for flat_multiset if (_Where == _End || _Compare(_Val, *_Where)) { // _Val < *_Where if (_Where == _Begin || !_Compare(_Val, *(_Where - 1))) { @@ -493,7 +508,7 @@ private: _Where = _STD upper_bound(_Where + 1, _End, _Val); } } else { - // Find lower_bound for flat_set + // look for the lower_bound for flat_set if (_Where == _End || !_Compare(*_Where, _Val)) { // _Val <= *_Where if (_Where == _Begin || _Compare(*(_Where - 1), _Val)) { @@ -510,19 +525,20 @@ private: if constexpr (_Multi) { _STL_INTERNAL_STATIC_ASSERT(is_same_v, _Kty>); + _STL_INTERNAL_CHECK(_Check_where(_Where, _Val)); return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); } else { if (_Where != _End && _Keys_equal(_Val, *_Where)) { return _Cont.begin() + (_Where - _Begin); } if constexpr (is_same_v, _Kty>) { + _STL_INTERNAL_CHECK(_Check_where(_Where, _Val)); return _Cont.emplace(_Where, _STD forward<_Ty>(_Val)); } else { - // flat_set::insert(hint,auto&&) + // for 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)})"); + _STL_ASSERT(_Check_where(_Where, _Keyval), "The input type was not equivalent to key_type!"); return _Cont.emplace(_Where, _STD move(_Keyval)); } } From cc83036c5352e3443778e6af0482e599409b68d8 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Mon, 28 Aug 2023 19:07:01 +0800 Subject: [PATCH 08/13] 8. Improve ebco test; add noexcept test --- tests/std/tests/P1222R4_flat_set/test.cpp | 58 ++++++++++++++++------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index 9eae7a98f88..ab0003d45d1 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -65,10 +65,52 @@ void assert_reversible_container_requirements(const T& s) { static_assert(is_convertible_v); } +template +void test_ebco() { + using container_type = T::container_type; + if constexpr (is_empty_v) { + static_assert(sizeof(container_type) == sizeof(T)); + } else { + static_assert(sizeof(container_type) < sizeof(T)); + } +} + +template +void test_noexcept() { + T st{}; + T& ref = st; + const T& cref = st; + + static_assert(noexcept(ref.begin())); + static_assert(noexcept(cref.begin())); + static_assert(noexcept(ref.end())); + static_assert(noexcept(cref.end())); + + static_assert(noexcept(ref.rbegin())); + static_assert(noexcept(cref.rbegin())); + static_assert(noexcept(ref.rend())); + static_assert(noexcept(cref.rend())); + + static_assert(noexcept(cref.cbegin())); + static_assert(noexcept(cref.cend())); + static_assert(noexcept(cref.crbegin())); + static_assert(noexcept(cref.crend())); + + static_assert(noexcept(cref.empty())); + static_assert(noexcept(cref.size())); + static_assert(noexcept(cref.max_size())); + + static_assert(noexcept(ref.clear())); + static_assert(noexcept(ref.swap(ref))); + static_assert(noexcept(ranges::swap(ref, ref))); +} + template void assert_all_requirements_and_equals(const T& s, const initializer_list& il) { assert_container_requirements(s); assert_reversible_container_requirements(s); + test_noexcept(); + test_ebco(); auto val_comp = s.value_comp(); auto begin_it = s.cbegin(); @@ -266,20 +308,6 @@ 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() { @@ -312,8 +340,6 @@ int main() { test_constructors>(); test_constructors>(); - test_ebco(); - test_insert_1>(); test_insert_1>(); test_insert_2>(); From 9be25df819a90cceea0b383bfc16885593d68dfe Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 30 Aug 2023 11:29:12 +0800 Subject: [PATCH 09/13] 9. Review feedback 9.1. Use direct-non-list-initialization in emplace functions 9.1 Remove irrelevant noexcept test; fix or improve some tests --- stl/inc/flat_set | 8 +-- tests/std/tests/P1222R4_flat_set/test.cpp | 60 ++++++----------------- 2 files changed, 18 insertions(+), 50 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 1f4a8f52285..7072658999c 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -215,7 +215,7 @@ public: if constexpr (_Is_key_type) { return _Emplace(_STD forward<_Args>(_Vals)...); } else { - return _Emplace(_Kty{_STD forward<_Args>(_Vals)...}); + return _Emplace(_Kty(_STD forward<_Args>(_Vals)...)); } } template @@ -224,7 +224,7 @@ public: if constexpr (_Is_key_type) { return _Emplace_hint(_Hint, _STD forward<_Args>(_Vals)...); } else { - return _Emplace_hint(_Hint, _Kty{_STD forward<_Args>(_Vals)...}); + return _Emplace_hint(_Hint, _Kty(_STD forward<_Args>(_Vals)...)); } } @@ -479,7 +479,7 @@ private: } else { // for flat_set::insert(auto&&) _STL_INTERNAL_STATIC_ASSERT(_Keylt_transparent && is_constructible_v<_Kty, _Ty>); - _Kty _Keyval{_STD forward<_Ty>(_Val)}; + _Kty _Keyval(_STD forward<_Ty>(_Val)); _STL_ASSERT(_Check_where(_Where, _Keyval), "The input type was not equivalent to key_type!"); return pair{_Cont.emplace(_Where, _STD move(_Keyval)), true}; } @@ -537,7 +537,7 @@ private: } else { // for flat_set::insert(hint,auto&&) _STL_INTERNAL_STATIC_ASSERT(_Keylt_transparent && is_constructible_v<_Kty, _Ty>); - _Kty _Keyval{_STD forward<_Ty>(_Val)}; + _Kty _Keyval(_STD forward<_Ty>(_Val)); _STL_ASSERT(_Check_where(_Where, _Keyval), "The input type was not equivalent to key_type!"); return _Cont.emplace(_Where, _STD move(_Keyval)); } diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index ab0003d45d1..c2624486abf 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -67,49 +67,19 @@ void assert_reversible_container_requirements(const T& s) { template void test_ebco() { + using key_compare = T::key_compare; using container_type = T::container_type; - if constexpr (is_empty_v) { + if constexpr (is_empty_v && !is_final_v) { static_assert(sizeof(container_type) == sizeof(T)); } else { static_assert(sizeof(container_type) < sizeof(T)); } } -template -void test_noexcept() { - T st{}; - T& ref = st; - const T& cref = st; - - static_assert(noexcept(ref.begin())); - static_assert(noexcept(cref.begin())); - static_assert(noexcept(ref.end())); - static_assert(noexcept(cref.end())); - - static_assert(noexcept(ref.rbegin())); - static_assert(noexcept(cref.rbegin())); - static_assert(noexcept(ref.rend())); - static_assert(noexcept(cref.rend())); - - static_assert(noexcept(cref.cbegin())); - static_assert(noexcept(cref.cend())); - static_assert(noexcept(cref.crbegin())); - static_assert(noexcept(cref.crend())); - - static_assert(noexcept(cref.empty())); - static_assert(noexcept(cref.size())); - static_assert(noexcept(cref.max_size())); - - static_assert(noexcept(ref.clear())); - static_assert(noexcept(ref.swap(ref))); - static_assert(noexcept(ranges::swap(ref, ref))); -} - template void assert_all_requirements_and_equals(const T& s, const initializer_list& il) { assert_container_requirements(s); assert_reversible_container_requirements(s); - test_noexcept(); test_ebco(); auto val_comp = s.value_comp(); @@ -174,9 +144,7 @@ template void test_insert_1() { using lt = std::less; - const int _dat[]{0, 1, 2}; - const int* volatile _beg = _dat; - const int* volatile _end = std::end(_dat); + const vector vec{0, 1, 2}; { flat_set a{5, 5}; assert_all_requirements_and_equals(a, {5}); @@ -184,15 +152,15 @@ void test_insert_1() { assert_all_requirements_and_equals(a, {0, 5}); a.emplace(1); assert_all_requirements_and_equals(a, {0, 1, 5}); - a.insert(_dat[2]); + a.insert(vec[2]); assert_all_requirements_and_equals(a, {0, 1, 2, 5}); a.insert(2); assert_all_requirements_and_equals(a, {0, 1, 2, 5}); - a.insert(_beg, _end); + a.insert(vec.rbegin(), vec.rend()); assert_all_requirements_and_equals(a, {0, 1, 2, 5}); - a.insert(sorted_unique, _beg, _end); + a.insert(sorted_unique, vec.begin(), vec.end()); assert_all_requirements_and_equals(a, {0, 1, 2, 5}); - a.insert_range(_dat); + a.insert_range(vec); 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}); @@ -206,15 +174,15 @@ void test_insert_1() { 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]); + a.insert(vec[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); + a.insert(vec.rbegin(), vec.rend()); assert_all_requirements_and_equals(a, {0, 0, 1, 1, 2, 2, 2, 5, 5}); - a.insert(sorted_equivalent, _beg, _end); + a.insert(sorted_equivalent, vec.begin(), vec.end()); assert_all_requirements_and_equals(a, {0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 5, 5}); - a.insert_range(_dat); + a.insert_range(vec); 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}); @@ -227,7 +195,7 @@ template void test_insert_2() { using lt = std::less; - const int _dat[]{0, 1, 2}; + const int val = 1; { flat_set a{0, 5}; assert_all_requirements_and_equals(a, {0, 5}); @@ -237,7 +205,7 @@ void test_insert_2() { 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]); + a.insert(a.begin(), val); assert_all_requirements_and_equals(a, {0, 1, 5, 6}); } { @@ -249,7 +217,7 @@ void test_insert_2() { 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]); + a.insert(a.begin(), val); assert_all_requirements_and_equals(a, {0, 0, 0, 1, 5, 6}); } } From f91419e813dc64d85114504aa962ec429ba1524b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 8 Sep 2023 12:44:29 -0700 Subject: [PATCH 10/13] Comment that we're testing an implementation-specific optimization. --- tests/std/tests/P1222R4_flat_set/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index c2624486abf..d609027f618 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -67,6 +67,7 @@ void assert_reversible_container_requirements(const T& s) { template void test_ebco() { + // This tests an implementation-specific optimization. using key_compare = T::key_compare; using container_type = T::container_type; if constexpr (is_empty_v && !is_final_v) { From be110a87848f95dd1b190ff8e9d9417c3a1dd13a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 8 Sep 2023 13:12:30 -0700 Subject: [PATCH 11/13] Include `` for `allocator`. --- tests/std/tests/P1222R4_flat_set/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index d609027f618..7547d6887df 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include using namespace std; From aaf902f17a6ef05c1cb59fcc6c5534f237baae86 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 8 Sep 2023 13:21:20 -0700 Subject: [PATCH 12/13] Pass `_Begin` instead of `begin()` to `inplace_merge()`. --- stl/inc/flat_set | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 7072658999c..e8973b05957 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -636,7 +636,7 @@ private: 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); + _STD inplace_merge(_Begin, _Begin_unsorted, _End, _Compare); _STL_INTERNAL_CHECK(_STD is_sorted(_Begin, _End, _Compare)); From 6e90eb97a46700312a66734fb83e72934049fc50 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 8 Sep 2023 13:36:12 -0700 Subject: [PATCH 13/13] Add newlines between non-chained `if`-statements. --- stl/inc/flat_set | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index e8973b05957..7767ba9b951 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -474,6 +474,7 @@ private: if (_Where != _End && _Keys_equal(*_Where, _Val)) { return pair{_Where, false}; } + if constexpr (is_same_v, _Kty>) { return pair{_Cont.emplace(_Where, _STD forward<_Ty>(_Val)), true}; } else { @@ -531,6 +532,7 @@ private: if (_Where != _End && _Keys_equal(_Val, *_Where)) { return _Cont.begin() + (_Where - _Begin); } + if constexpr (is_same_v, _Kty>) { _STL_INTERNAL_CHECK(_Check_where(_Where, _Val)); return _Cont.emplace(_Where, _STD forward<_Ty>(_Val));