-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Implement LWG-4135 The helper lambda of std::erase for list should specify return type as bool
#5131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Stephan T. Lavavej (StephanTLavavej)
merged 5 commits into
microsoft:main
from
frederick-vs-ja:lwg-4135
Dec 5, 2024
Merged
Implement LWG-4135 The helper lambda of std::erase for list should specify return type as bool
#5131
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
49d83e7
Implement LWG-4135 and improve test coverage for P1209R0
frederick-vs-ja 5a353ca
Include `<utility>` for `std::pair`.
StephanTLavavej de43b85
Improve sequence container test coverage.
StephanTLavavej 68451f3
Return `const pinned_condition<true>&`.
StephanTLavavej 033dc47
Add `explicit` to `pinned_condition()`.
StephanTLavavej File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| RUNALL_INCLUDE ..\usual_20_matrix.lst |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #include <cassert> | ||
| #include <deque> | ||
| #include <forward_list> | ||
| #include <list> | ||
| #include <map> | ||
| #include <set> | ||
| #include <string> | ||
| #include <unordered_map> | ||
| #include <unordered_set> | ||
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| // Note that the standard actually requires these to be copyable. As an extension, we want to ensure we don't copy them, | ||
| // because copying some functors (e.g. std::function) is comparatively expensive, and even for relatively cheap to copy | ||
| // function objects we care (somewhat) about debug mode perf. | ||
| struct no_copy { | ||
| no_copy() = default; | ||
| no_copy(const no_copy&) = delete; | ||
| no_copy(no_copy&&) = default; | ||
| no_copy& operator=(const no_copy&) = delete; | ||
| no_copy& operator=(no_copy&&) = delete; | ||
| }; | ||
|
|
||
| struct is_vowel : no_copy { | ||
| constexpr bool operator()(const char c) const { | ||
| return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'; | ||
| } | ||
| }; | ||
|
|
||
| struct is_odd : no_copy { | ||
| constexpr bool operator()(const int i) const { | ||
| return i % 2 != 0; | ||
| } | ||
| }; | ||
|
|
||
| struct is_first_odd : no_copy { | ||
| bool operator()(const std::pair<const int, int>& p) const { | ||
| return p.first % 2 != 0; | ||
| } | ||
| }; | ||
|
|
||
| constexpr bool test_string() { | ||
| std::string str1{"cute fluffy kittens"}; | ||
| const auto str1_removed = std::erase_if(str1, is_vowel{}); | ||
| assert(str1 == "ct flffy kttns"); | ||
| assert(str1_removed == 5); | ||
|
|
||
| std::string str2{"asynchronous beat"}; | ||
| const auto str2_removed = std::erase(str2, 'a'); | ||
| assert(str2 == "synchronous bet"); | ||
| assert(str2_removed == 2); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| template <class SequenceContainer> | ||
| constexpr bool test_sequence_container() { | ||
| SequenceContainer c{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, | ||
| 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9, 3, 7, 5, 1, 0}; | ||
|
|
||
| { | ||
| const auto removed1 = std::erase_if(c, is_odd{}); | ||
| assert(removed1 == 31); | ||
| const SequenceContainer expected1{4, 2, 6, 8, 2, 8, 4, 6, 2, 6, 4, 8, 2, 0, 2, 8, 8, 4, 6, 0}; | ||
| assert(c == expected1); | ||
| } | ||
|
|
||
| { | ||
| const auto removed2 = std::erase(c, 8); | ||
| assert(removed2 == 5); | ||
| const SequenceContainer expected2{4, 2, 6, 2, 4, 6, 2, 6, 4, 2, 0, 2, 4, 6, 0}; | ||
| assert(c == expected2); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| // Also test LWG-4135 "The helper lambda of std::erase for list should specify return type as bool" | ||
|
|
||
| template <bool B> | ||
| struct pinned_condition { | ||
| explicit pinned_condition() = default; | ||
| pinned_condition(const pinned_condition&) = delete; | ||
| pinned_condition& operator=(const pinned_condition&) = delete; | ||
|
|
||
| operator bool() const { | ||
| return B; | ||
| } | ||
|
|
||
| pinned_condition<!B> operator!() const { | ||
| return {}; | ||
| } | ||
| }; | ||
|
|
||
| struct lwg_4135_src { | ||
| static constexpr pinned_condition<true> result{}; | ||
|
|
||
| friend void operator==(int&, const lwg_4135_src&) = delete; | ||
| friend void operator==(const lwg_4135_src&, int&) = delete; | ||
|
|
||
| friend const pinned_condition<true>& operator==(const lwg_4135_src&, const int&) { | ||
| return result; | ||
| } | ||
| friend const pinned_condition<true>& operator==(const int&, const lwg_4135_src&) { | ||
| return result; | ||
| } | ||
| }; | ||
|
|
||
| template <class ListContainer> | ||
| void test_list_erase() { | ||
| ListContainer ls2{42, 1729}; | ||
| const auto ls2_removed = std::erase(ls2, lwg_4135_src{}); | ||
| assert(ls2.empty()); | ||
| assert(ls2_removed == 2); | ||
| } | ||
|
|
||
| static_assert(test_string()); | ||
| static_assert(test_sequence_container<std::vector<int>>()); | ||
|
|
||
| int main() { | ||
| test_string(); | ||
| test_sequence_container<std::deque<int>>(); | ||
| test_sequence_container<std::forward_list<int>>(); | ||
| test_sequence_container<std::list<int>>(); | ||
| test_sequence_container<std::vector<int>>(); | ||
|
|
||
| test_list_erase<std::forward_list<int>>(); | ||
| test_list_erase<std::list<int>>(); | ||
|
|
||
| std::map<int, int> m{{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5, 50}, {6, 60}, {7, 70}}; | ||
| const auto m_removed = std::erase_if(m, is_first_odd{}); | ||
| assert((m == std::map<int, int>{{2, 20}, {4, 40}, {6, 60}})); | ||
| assert(m_removed == 4); | ||
|
|
||
| std::multimap<int, int> mm{{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5, 50}, {6, 60}, {7, 70}}; | ||
| const auto mm_removed = std::erase_if(mm, is_first_odd{}); | ||
| assert((mm == std::multimap<int, int>{{2, 20}, {4, 40}, {6, 60}})); | ||
| assert(mm_removed == 4); | ||
|
|
||
| std::set<int> s{1, 2, 3, 4, 5, 6, 7}; | ||
| const auto s_removed = std::erase_if(s, is_odd{}); | ||
| assert((s == std::set<int>{2, 4, 6})); | ||
| assert(s_removed == 4); | ||
|
|
||
| std::multiset<int> ms{1, 2, 3, 4, 5, 6, 7}; | ||
| const auto ms_removed = std::erase_if(ms, is_odd{}); | ||
| assert((ms == std::multiset<int>{2, 4, 6})); | ||
| assert(ms_removed == 4); | ||
|
|
||
| // Note that unordered equality considers permutations. | ||
|
|
||
| std::unordered_map<int, int> um{{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5, 50}, {6, 60}, {7, 70}}; | ||
| const auto um_removed = std::erase_if(um, is_first_odd{}); | ||
| assert((um == std::unordered_map<int, int>{{2, 20}, {4, 40}, {6, 60}})); | ||
| assert(um_removed == 4); | ||
|
|
||
| std::unordered_multimap<int, int> umm{{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5, 50}, {6, 60}, {7, 70}}; | ||
| const auto umm_removed = std::erase_if(umm, is_first_odd{}); | ||
| assert((umm == std::unordered_multimap<int, int>{{2, 20}, {4, 40}, {6, 60}})); | ||
| assert(umm_removed == 4); | ||
|
|
||
| std::unordered_set<int> us{1, 2, 3, 4, 5, 6, 7}; | ||
| const auto us_removed = std::erase_if(us, is_odd{}); | ||
| assert((us == std::unordered_set<int>{2, 4, 6})); | ||
| assert(us_removed == 4); | ||
|
|
||
| std::unordered_multiset<int> ums{1, 2, 3, 4, 5, 6, 7}; | ||
| const auto ums_removed = std::erase_if(ums, is_odd{}); | ||
| assert((ums == std::unordered_multiset<int>{2, 4, 6})); | ||
| assert(ums_removed == 4); | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.