From 8e80e0403758929185ed73f9190656e9b432e39e Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 25 Jun 2023 23:38:01 +0800 Subject: [PATCH 1/6] Fix `erase_if` for flat container adaptors --- stl/inc/flat_set | 14 +++++++++----- tests/std/tests/P1222R4_flat_set/test.cpp | 13 +++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 67dc93c4da7..da5f9de1721 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -405,7 +405,7 @@ public: } private: - void inline _Assert_after_sorted_input() const { + void _Assert_after_sorted_input() const { _STL_ASSERT(_STD is_sorted(begin(), end(), _Get_comp()), "Input was not sorted!"); if constexpr (!_Multi) { _STL_ASSERT(_Is_unique(), "Input was not unique!"); @@ -624,15 +624,19 @@ public: }; _EXPORT_STD template -size_t erase_if(flat_set<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { +typename _Container::size_type erase_if(flat_set<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { _Clear_scope_guard _Guard{&_Val}; - return _Erase_remove_if(_Val, _Pass_fn(_Predicate)); + const auto _Erased_count = _Erase_remove_if(_Val, _Pass_fn(_Predicate)); + _Guard._Clearable = nullptr; + return _Erased_count; } _EXPORT_STD template -size_t erase_if(flat_multiset<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { +typename _Container::size_type erase_if(flat_multiset<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { _Clear_scope_guard _Guard{&_Val}; - return _Erase_remove_if(_Val, _Pass_fn(_Predicate)); + const auto _Erased_count = _Erase_remove_if(_Val, _Pass_fn(_Predicate)); + _Guard._Clearable = nullptr; + return _Erased_count; } template diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index 6a3ae2e1223..2c6d46d4d07 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include #include @@ -190,6 +191,15 @@ void test_non_static_comparer() { assert_all_requirements_and_equals(a, {9, 7, 5, -1}); } +template +void test_erase_if() { + constexpr int erased_result[]{1, 3}; + C fs{1, 2, 3, 4}; + erase_if(fs, [](int n) { return n % 2 == 0; }); + assert(fs.size() == 2); + assert(ranges::equal(fs, erased_result)); +} + int main() { test_spaceship_operator>(); test_spaceship_operator>(); @@ -205,6 +215,9 @@ int main() { test_non_static_comparer(); + test_erase_if>(); + test_erase_if>(); + assert_basic>(); assert_basic, deque>>(); From f3185f7188481865f9933fa0041743e906fac77d Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 26 Jun 2023 06:22:03 +0800 Subject: [PATCH 2/6] Down with `typename` Co-authored-by: Jakub Mazurkiewicz --- 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 da5f9de1721..8988824ddeb 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -624,7 +624,7 @@ public: }; _EXPORT_STD template -typename _Container::size_type erase_if(flat_set<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { +_Container::size_type erase_if(flat_set<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { _Clear_scope_guard _Guard{&_Val}; const auto _Erased_count = _Erase_remove_if(_Val, _Pass_fn(_Predicate)); _Guard._Clearable = nullptr; @@ -632,7 +632,7 @@ typename _Container::size_type erase_if(flat_set<_Kty, _Keylt, _Container>& _Val } _EXPORT_STD template -typename _Container::size_type erase_if(flat_multiset<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { +_Container::size_type erase_if(flat_multiset<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { _Clear_scope_guard _Guard{&_Val}; const auto _Erased_count = _Erase_remove_if(_Val, _Pass_fn(_Predicate)); _Guard._Clearable = nullptr; From 81ae6d2928564fd52821b4409953be47fb7aa669 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 26 Jun 2023 06:38:07 +0800 Subject: [PATCH 3/6] Drop CTAD due to LLVM-54049 Cite N4950 in comments to clarify the intent --- 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 8988824ddeb..ad2504a93a2 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -242,11 +242,9 @@ public: } _NODISCARD container_type extract() && { - // The container NEEDS to be cleared no matter what, - // which is not guaranteed by simply moving it away - // ("... valid but unspecified ...") container_type& _Cont = _Get_cont(); - _Clear_scope_guard _Guard{this}; + // always clears the container (N4950 [flat.set.modifiers]/15 and [flat.multiset.modifiers]/10) + _Clear_scope_guard<_Base_flat_set> _Guard{this}; container_type _Temp = _STD move(_Cont); return _Temp; } @@ -625,7 +623,8 @@ public: _EXPORT_STD template _Container::size_type erase_if(flat_set<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { - _Clear_scope_guard _Guard{&_Val}; + // clears the container to maintain the invariants when an exception is thrown (N4950 [flat.set.erasure]/5) + _Clear_scope_guard> _Guard{&_Val}; const auto _Erased_count = _Erase_remove_if(_Val, _Pass_fn(_Predicate)); _Guard._Clearable = nullptr; return _Erased_count; @@ -633,7 +632,8 @@ _Container::size_type erase_if(flat_set<_Kty, _Keylt, _Container>& _Val, _Pred _ _EXPORT_STD template _Container::size_type erase_if(flat_multiset<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { - _Clear_scope_guard _Guard{&_Val}; + // clears the container to maintain the invariants when an exception is thrown (N4950 [flat.multiset.erasure]/5) + _Clear_scope_guard> _Guard{&_Val}; const auto _Erased_count = _Erase_remove_if(_Val, _Pass_fn(_Predicate)); _Guard._Clearable = nullptr; return _Erased_count; From 3a6d96495082d3d77419b4c45d89817194cb86e8 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 26 Jun 2023 06:39:38 +0800 Subject: [PATCH 4/6] Test member function `test_extract` --- tests/std/tests/P1222R4_flat_set/test.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index 2c6d46d4d07..a7739cc7353 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -191,6 +191,15 @@ void test_non_static_comparer() { assert_all_requirements_and_equals(a, {9, 7, 5, -1}); } +template +void test_extract() { + constexpr int elements[]{1, 2, 3, 4}; + C fs{1, 2, 3, 4}; + auto cont = std::move(fs).extract(); + assert(fs.empty()); + assert(ranges::equal(cont, elements)); +} + template void test_erase_if() { constexpr int erased_result[]{1, 3}; @@ -215,6 +224,9 @@ int main() { test_non_static_comparer(); + test_extract>(); + test_extract>(); + test_erase_if>(); test_erase_if>(); From 4f283065d8fe91ed4b0f7ae5d789d7f39cbc437f Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 26 Jun 2023 09:51:46 +0800 Subject: [PATCH 5/6] Use `addressof` to avoid ADL-hijacking `operator&` --- 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 ad2504a93a2..bc9e1d94e5e 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -624,7 +624,7 @@ public: _EXPORT_STD template _Container::size_type erase_if(flat_set<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { // clears the container to maintain the invariants when an exception is thrown (N4950 [flat.set.erasure]/5) - _Clear_scope_guard> _Guard{&_Val}; + _Clear_scope_guard> _Guard{_STD addressof(_Val)}; const auto _Erased_count = _Erase_remove_if(_Val, _Pass_fn(_Predicate)); _Guard._Clearable = nullptr; return _Erased_count; @@ -633,7 +633,7 @@ _Container::size_type erase_if(flat_set<_Kty, _Keylt, _Container>& _Val, _Pred _ _EXPORT_STD template _Container::size_type erase_if(flat_multiset<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { // clears the container to maintain the invariants when an exception is thrown (N4950 [flat.multiset.erasure]/5) - _Clear_scope_guard> _Guard{&_Val}; + _Clear_scope_guard> _Guard{_STD addressof(_Val)}; const auto _Erased_count = _Erase_remove_if(_Val, _Pass_fn(_Predicate)); _Guard._Clearable = nullptr; return _Erased_count; From b12c6b4eacc97b838d9fc287dc7b023caa541508 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 30 Jun 2023 17:27:56 -0700 Subject: [PATCH 6/6] Fix citation. --- 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 bc9e1d94e5e..1bfb5e191f9 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -243,7 +243,7 @@ public: _NODISCARD container_type extract() && { container_type& _Cont = _Get_cont(); - // always clears the container (N4950 [flat.set.modifiers]/15 and [flat.multiset.modifiers]/10) + // 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;