1//===----------------------------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10
11// <flat_set>
12
13// size_type erase(K&& k);
14
15#include <compare>
16#include <concepts>
17#include <deque>
18#include <flat_set>
19#include <functional>
20#include <string>
21#include <utility>
22#include <vector>
23
24#include "MinSequenceContainer.h"
25#include "../helpers.h"
26#include "test_macros.h"
27#include "min_allocator.h"
28
29// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type.
30template <class M>
31concept CanErase = requires(M m, Transparent<int> k) { m.erase(k); };
32using TransparentSet = std::flat_set<int, TransparentComparator>;
33using NonTransparentSet = std::flat_set<int, NonTransparentComparator>;
34static_assert(CanErase<TransparentSet>);
35static_assert(!CanErase<const TransparentSet>);
36static_assert(!CanErase<NonTransparentSet>);
37static_assert(!CanErase<const NonTransparentSet>);
38
39template <class Key, class It>
40struct HeterogeneousKey {
41 constexpr explicit HeterogeneousKey(Key key, It it) : key_(key), it_(it) {}
42 constexpr operator It() && { return it_; }
43 constexpr auto operator<=>(Key key) const { return key_ <=> key; }
44 constexpr friend bool operator<(const HeterogeneousKey&, const HeterogeneousKey&) {
45 assert(false);
46 return false;
47 }
48 Key key_;
49 It it_;
50};
51
52template <class KeyContainer>
53constexpr void test_one() {
54 using Key = typename KeyContainer::value_type;
55 using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
56
57 M m = {1, 2, 3, 4};
58 ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type);
59 auto n = m.erase(3); // erase(K&&) [with K=int]
60 assert(n == 1);
61 assert((m == M{1, 2, 4}));
62 typename M::key_type lvalue = 2;
63 n = m.erase(lvalue); // erase(K&&) [with K=int&]
64 assert(n == 1);
65 assert((m == M{1, 4}));
66 const typename M::key_type const_lvalue = 1;
67 n = m.erase(const_lvalue); // erase(const key_type&)
68 assert(n == 1);
69 assert((m == M{4}));
70}
71
72template <class KeyContainer>
73constexpr void test_transparent_comparator() {
74 using M = std::flat_set<std::string, TransparentComparator, KeyContainer>;
75 {
76 M m = {"alpha", "beta", "epsilon", "eta", "gamma"};
77 ASSERT_SAME_TYPE(decltype(m.erase(Transparent<std::string>{"abc"})), typename M::size_type);
78
79 auto n = m.erase(Transparent<std::string>{.t: "epsilon"});
80 assert(n == 1);
81
82 M expected = {"alpha", "beta", "eta", "gamma"};
83 assert(m == expected);
84
85 auto n2 = m.erase(Transparent<std::string>{.t: "aaa"});
86 assert(n2 == 0);
87 assert(m == expected);
88 }
89 {
90 // was empty
91 M m;
92 auto n = m.erase(Transparent<std::string>{.t: "epsilon"});
93 assert(n == 0);
94 assert(m.empty());
95 }
96}
97
98constexpr bool test() {
99 test_one<std::vector<int>>();
100#ifndef __cpp_lib_constexpr_deque
101 if (!TEST_IS_CONSTANT_EVALUATED)
102#endif
103 test_one<std::deque<int>>();
104 test_one<MinSequenceContainer<int>>();
105 test_one<std::vector<int, min_allocator<int>>>();
106
107 test_transparent_comparator<std::vector<std::string>>();
108#ifndef __cpp_lib_constexpr_deque
109 if (!TEST_IS_CONSTANT_EVALUATED)
110#endif
111 test_transparent_comparator<std::deque<std::string>>();
112 test_transparent_comparator<MinSequenceContainer<std::string>>();
113 test_transparent_comparator<std::vector<std::string, min_allocator<std::string>>>();
114
115 {
116 // P2077's HeterogeneousKey example
117 using M = std::flat_set<int, std::less<>>;
118 M m = {1, 2, 3, 4, 5, 6, 7, 8};
119 auto h1 = HeterogeneousKey<int, M::iterator>(8, m.begin());
120 std::same_as<M::size_type> auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match
121 assert(n == 1);
122 assert((m == M{1, 2, 3, 4, 5, 6, 7}));
123 std::same_as<M::iterator> auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out
124 assert(it == m.begin());
125 assert((m == M{2, 3, 4, 5, 6, 7}));
126 }
127 {
128 using M = std::flat_set<int, std::less<>>;
129 M m = {1, 2, 3, 4, 5, 6, 7, 8};
130 auto h1 = HeterogeneousKey<int, M::const_iterator>(8, m.begin());
131 std::same_as<M::size_type> auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match
132 assert(n == 1);
133 assert((m == M{1, 2, 3, 4, 5, 6, 7}));
134 std::same_as<M::iterator> auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out
135 assert(it == m.begin());
136 assert((m == M{2, 3, 4, 5, 6, 7}));
137 }
138 {
139 bool transparent_used = false;
140 TransparentComparator c(transparent_used);
141 std::flat_set<int, TransparentComparator> m(std::sorted_unique, {1, 2, 3}, c);
142 assert(!transparent_used);
143 auto n = m.erase(Transparent<int>{3});
144 assert(n == 1);
145 assert(transparent_used);
146 }
147 {
148 // LWG4239 std::string and C string literal
149 using M = std::flat_set<std::string, std::less<>>;
150 M m{"alpha", "beta", "epsilon", "eta", "gamma"};
151 auto n = m.erase("beta");
152 assert(n == 1);
153 }
154
155 return true;
156}
157
158void test_exception() {
159 auto erase_transparent = [](auto& m, auto key_arg) {
160 using Set = std::decay_t<decltype(m)>;
161 using Key = typename Set::key_type;
162 m.erase(Transparent<Key>{key_arg});
163 };
164 test_erase_exception_guarantee(erase_function&: erase_transparent);
165}
166
167int main(int, char**) {
168 test();
169 test_exception();
170#if TEST_STD_VER >= 26
171 static_assert(test());
172#endif
173
174 return 0;
175}
176

source code of libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/erase_key_transparent.pass.cpp