1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10 // UNSUPPORTED: no-exceptions
14 // template<class Key, class T, class Compare, class KeyContainer, class MappedContainer, class Predicate>
15 // typename flat_map<Key, T, Compare, KeyContainer, MappedContainer>::size_type
16 // erase_if(flat_map<Key, T, Compare, KeyContainer, MappedContainer>& c, Predicate pred);
17 // If any member function in [flat.set.defn] exits via an exception, the invariant is restored.
18 // (This is not a member function, but let's respect the invariant anyway.)
28 #include "../helpers.h"
29 #include "test_macros.h"
42 Counter g_counter
= {0, 0, 0};
44 struct ThrowingAssignment
{
45 ThrowingAssignment(int i
) : i_(i
) {}
46 ThrowingAssignment(const ThrowingAssignment
&) = default;
47 ThrowingAssignment
& operator=(const ThrowingAssignment
& rhs
) {
53 operator int() const { return i_
; }
57 struct ThrowingComparator
{
58 bool operator()(const ThrowingAssignment
& a
, const ThrowingAssignment
& b
) const {
64 struct ErasurePredicate
{
65 bool operator()(const auto& x
) const { return (3 <= x
.first
&& x
.first
<= 5); }
68 int main(int, char**) {
69 const std::pair
<int, int> expected
[] = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7}, {8, 8}};
71 using M
= std::flat_map
<ThrowingAssignment
, int, ThrowingComparator
>;
72 for (int first_throw
= 1; first_throw
< 99; ++first_throw
) {
73 for (int second_throw
= 1; second_throw
< 99; ++second_throw
) {
74 g_counter
= {0, 0, 0};
75 M m
= M({1, 2, 3, 4, 5, 6, 7, 8}, {1, 2, 3, 4, 5, 6, 7, 8});
77 g_counter
= {first_throw
, second_throw
, 0};
78 auto n
= std::erase_if(m
, ErasurePredicate());
80 // If it didn't throw at all, we're done.
81 g_counter
= {0, 0, 0};
82 assert((m
== M
{{1, 1}, {2, 2}, {6, 6}, {7, 7}, {8, 8}}));
83 first_throw
= 99; // "done"
88 LIBCPP_ASSERT(m
.empty() || std::equal(m
.begin(), m
.end(), expected
, expected
+ 8));
89 if (g_counter
.throws
== 1) {
90 // We reached the first throw but not the second throw.
98 using M
= std::flat_map
<int, ThrowingAssignment
, ThrowingComparator
>;
99 for (int first_throw
= 1; first_throw
< 99; ++first_throw
) {
100 for (int second_throw
= 1; second_throw
< 99; ++second_throw
) {
101 g_counter
= {0, 0, 0};
102 M m
= M({1, 2, 3, 4, 5, 6, 7, 8}, {1, 2, 3, 4, 5, 6, 7, 8});
104 g_counter
= {first_throw
, second_throw
, 0};
105 auto n
= std::erase_if(m
, ErasurePredicate());
107 // If it didn't throw at all, we're done.
108 g_counter
= {0, 0, 0};
109 assert((m
== M
{{1, 1}, {2, 2}, {6, 6}, {7, 7}, {8, 8}}));
110 first_throw
= 99; // "done"
115 LIBCPP_ASSERT(m
.empty() || std::equal(m
.begin(), m
.end(), expected
, expected
+ 8));
116 if (g_counter
.throws
== 1) {
117 // We reached the first throw but not the second throw.
126 std::flat_map
<ThrowingAssignment
, int, ThrowingComparator
, std::deque
<ThrowingAssignment
>, std::deque
<int>>;
127 for (int first_throw
= 1; first_throw
< 99; ++first_throw
) {
128 for (int second_throw
= 1; second_throw
< 99; ++second_throw
) {
129 g_counter
= {0, 0, 0};
130 std::deque
<ThrowingAssignment
> container
= {5, 6, 7, 8};
131 container
.insert(container
.begin(), {1, 2, 3, 4});
132 M m
= M(std::move(container
), {1, 2, 3, 4, 5, 6, 7, 8});
134 g_counter
= {first_throw
, second_throw
, 0};
135 auto n
= std::erase_if(m
, ErasurePredicate());
137 // If it didn't throw at all, we're done.
138 g_counter
= {0, 0, 0};
139 assert((m
== M
{{1, 1}, {2, 2}, {6, 6}, {7, 7}, {8, 8}}));
140 first_throw
= 99; // "done"
145 LIBCPP_ASSERT(m
.empty() || std::equal(m
.begin(), m
.end(), expected
, expected
+ 8));
146 if (g_counter
.throws
== 1) {
147 // We reached the first throw but not the second throw.