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_map>
12
13#include <flat_map>
14#include <cassert>
15#include <deque>
16
17#include "MinSequenceContainer.h"
18#include "MoveOnly.h"
19#include "min_allocator.h"
20#include "test_macros.h"
21#include "../helpers.h"
22
23// template<class K, class M>
24// pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
25// template<class K, class M>
26// iterator insert_or_assign(const_iterator hint, K&& k, M&& obj);
27
28// Constraints:
29// The qualified-id Compare::is_transparent is valid and denotes a type.
30// is_constructible_v<key_type, K> is true.
31// is_assignable_v<mapped_type&, M> is true.
32// is_constructible_v<mapped_type, M> is true.
33
34template <class Map, class K, class M>
35concept CanInsertOrAssign =
36 requires(Map map, K&& k, M&& m) { map.insert_or_assign(std::forward<K>(k), std::forward<M>(m)); };
37
38template <class Map, class K, class M>
39concept CanInsertOrAssignIter = requires(Map map, typename Map::const_iterator iter, K&& k, M&& m) {
40 map.insert_or_assign(iter, std::forward<K>(k), std::forward<M>(m));
41};
42
43template <class From>
44struct ConstructAndAssignFrom {
45 explicit ConstructAndAssignFrom(From);
46 ConstructAndAssignFrom& operator=(From);
47};
48
49template <class From>
50struct ConstructFrom {
51 explicit ConstructFrom(From);
52};
53
54template <class From>
55struct AssignFrom {
56 AssignFrom& operator=(From);
57};
58
59struct V {};
60
61static_assert(CanInsertOrAssign<std::flat_map<int, ConstructAndAssignFrom<V>, TransparentComparator>,
62 ConvertibleTransparent<int>,
63 V>);
64static_assert(!CanInsertOrAssign<std::flat_map<int, ConstructAndAssignFrom<V>, TransparentComparator>,
65 NonConvertibleTransparent<int>,
66 V>);
67static_assert(!CanInsertOrAssign<std::flat_map<int, ConstructAndAssignFrom<V>, NonTransparentComparator>,
68 NonConvertibleTransparent<int>,
69 V>);
70static_assert(!CanInsertOrAssign<std::flat_map<int, ConstructAndAssignFrom<V>, TransparentComparator>,
71 ConvertibleTransparent<int>,
72 int>);
73static_assert(
74 !CanInsertOrAssign<std::flat_map<int, ConstructFrom<V>, TransparentComparator>, ConvertibleTransparent<int>, V>);
75static_assert(
76 !CanInsertOrAssign<std::flat_map<int, AssignFrom<V>, TransparentComparator>, ConvertibleTransparent<int>, V>);
77
78static_assert(CanInsertOrAssignIter<std::flat_map<int, ConstructAndAssignFrom<V>, TransparentComparator>,
79 ConvertibleTransparent<int>,
80 V>);
81static_assert(!CanInsertOrAssignIter<std::flat_map<int, ConstructAndAssignFrom<V>, TransparentComparator>,
82 NonConvertibleTransparent<int>,
83 V>);
84static_assert(!CanInsertOrAssignIter<std::flat_map<int, ConstructAndAssignFrom<V>, NonTransparentComparator>,
85 NonConvertibleTransparent<int>,
86 V>);
87static_assert(!CanInsertOrAssignIter<std::flat_map<int, ConstructAndAssignFrom<V>, TransparentComparator>,
88 ConvertibleTransparent<int>,
89 int>);
90static_assert(!CanInsertOrAssignIter<std::flat_map<int, ConstructFrom<V>, TransparentComparator>,
91 ConvertibleTransparent<int>,
92 V>);
93static_assert(
94 !CanInsertOrAssignIter<std::flat_map<int, AssignFrom<V>, TransparentComparator>, ConvertibleTransparent<int>, V>);
95
96template <class KeyContainer, class ValueContainer>
97void test() {
98 using Key = typename KeyContainer::value_type;
99 using Value = typename ValueContainer::value_type;
100 using M = std::flat_map<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
101 {
102 // pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
103 using R = std::pair<typename M::iterator, bool>;
104 M m;
105 for (int i = 0; i < 20; i += 2)
106 m.emplace(i, Moveable(i, (double)i));
107 assert(m.size() == 10);
108
109 for (int i = 0; i < 20; i += 2) {
110 Moveable mv(i + 1, i + 1);
111 std::same_as<R> decltype(auto) r1 = m.insert_or_assign(ConvertibleTransparent<int>{i}, std::move(mv));
112 assert(m.size() == 10);
113 assert(!r1.second); // was not inserted
114 assert(mv.moved()); // was moved from
115 assert(r1.first->first == i); // key
116 assert(r1.first->second.get() == i + 1); // value
117 }
118
119 Moveable mv1(5, 5.0);
120 std::same_as<R> decltype(auto) r2 = m.insert_or_assign(ConvertibleTransparent<int>{-1}, std::move(mv1));
121 assert(m.size() == 11);
122 assert(r2.second); // was inserted
123 assert(mv1.moved()); // was moved from
124 assert(r2.first->first == -1); // key
125 assert(r2.first->second.get() == 5); // value
126
127 Moveable mv2(9, 9.0);
128 std::same_as<R> decltype(auto) r3 = m.insert_or_assign(ConvertibleTransparent<int>{3}, std::move(mv2));
129 assert(m.size() == 12);
130 assert(r3.second); // was inserted
131 assert(mv2.moved()); // was moved from
132 assert(r3.first->first == 3); // key
133 assert(r3.first->second.get() == 9); // value
134
135 Moveable mv3(-1, 5.0);
136 std::same_as<R> decltype(auto) r4 = m.insert_or_assign(ConvertibleTransparent<int>{117}, std::move(mv3));
137 assert(m.size() == 13);
138 assert(r4.second); // was inserted
139 assert(mv3.moved()); // was moved from
140 assert(r4.first->first == 117); // key
141 assert(r4.first->second.get() == -1); // value
142 }
143 {
144 // iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
145 using R = M::iterator;
146 M m;
147 for (int i = 0; i < 20; i += 2)
148 m.emplace(i, Moveable(i, (double)i));
149 assert(m.size() == 10);
150 typename M::const_iterator it = m.find(2);
151
152 Moveable mv1(3, 3.0);
153 std::same_as<R> decltype(auto) r1 = m.insert_or_assign(it, ConvertibleTransparent<int>{2}, std::move(mv1));
154 assert(m.size() == 10);
155 assert(mv1.moved()); // was moved from
156 assert(r1->first == 2); // key
157 assert(r1->second.get() == 3); // value
158
159 Moveable mv2(5, 5.0);
160 std::same_as<R> decltype(auto) r2 = m.insert_or_assign(it, ConvertibleTransparent<int>{3}, std::move(mv2));
161 assert(m.size() == 11);
162 assert(mv2.moved()); // was moved from
163 assert(r2->first == 3); // key
164 assert(r2->second.get() == 5); // value
165
166 // wrong hint: begin()
167 Moveable mv3(7, 7.0);
168 std::same_as<R> decltype(auto) r3 = m.insert_or_assign(m.begin(), ConvertibleTransparent<int>{4}, std::move(mv3));
169 assert(m.size() == 11);
170 assert(mv3.moved()); // was moved from
171 assert(r3->first == 4); // key
172 assert(r3->second.get() == 7); // value
173
174 Moveable mv4(9, 9.0);
175 std::same_as<R> decltype(auto) r4 = m.insert_or_assign(m.begin(), ConvertibleTransparent<int>{5}, std::move(mv4));
176 assert(m.size() == 12);
177 assert(mv4.moved()); // was moved from
178 assert(r4->first == 5); // key
179 assert(r4->second.get() == 9); // value
180
181 // wrong hint: end()
182 Moveable mv5(11, 11.0);
183 std::same_as<R> decltype(auto) r5 = m.insert_or_assign(m.end(), ConvertibleTransparent<int>{6}, std::move(mv5));
184 assert(m.size() == 12);
185 assert(mv5.moved()); // was moved from
186 assert(r5->first == 6); // key
187 assert(r5->second.get() == 11); // value
188
189 Moveable mv6(13, 13.0);
190 std::same_as<R> decltype(auto) r6 = m.insert_or_assign(m.end(), ConvertibleTransparent<int>{7}, std::move(mv6));
191 assert(m.size() == 13);
192 assert(mv6.moved()); // was moved from
193 assert(r6->first == 7); // key
194 assert(r6->second.get() == 13); // value
195
196 // wrong hint: third element
197 Moveable mv7(15, 15.0);
198 std::same_as<R> decltype(auto) r7 =
199 m.insert_or_assign(std::next(m.begin(), 2), ConvertibleTransparent<int>{8}, std::move(mv7));
200 assert(m.size() == 13);
201 assert(mv7.moved()); // was moved from
202 assert(r7->first == 8); // key
203 assert(r7->second.get() == 15); // value
204
205 Moveable mv8(17, 17.0);
206 std::same_as<R> decltype(auto) r8 =
207 m.insert_or_assign(std::next(m.begin(), 2), ConvertibleTransparent<int>{9}, std::move(mv8));
208 assert(m.size() == 14);
209 assert(mv8.moved()); // was moved from
210 assert(r8->first == 9); // key
211 assert(r8->second.get() == 17); // value
212 }
213}
214
215int main(int, char**) {
216 test<std::vector<int>, std::vector<Moveable>>();
217 test<std::deque<int>, std::vector<Moveable>>();
218 test<MinSequenceContainer<int>, MinSequenceContainer<Moveable>>();
219 test<std::vector<int, min_allocator<int>>, std::vector<Moveable, min_allocator<Moveable>>>();
220
221 {
222 bool transparent_used = false;
223 TransparentComparator c(transparent_used);
224 std::flat_map<int, int, TransparentComparator> m(std::sorted_unique, {{1, 1}, {2, 2}, {3, 3}}, c);
225 assert(!transparent_used);
226 auto p = m.insert_or_assign(ConvertibleTransparent<int>{3}, 5);
227 assert(!p.second);
228 assert(transparent_used);
229 }
230 {
231 bool transparent_used = false;
232 TransparentComparator c(transparent_used);
233 std::flat_map<int, int, TransparentComparator> m(std::sorted_unique, {{1, 1}, {2, 2}, {3, 3}}, c);
234 assert(!transparent_used);
235 auto it = m.insert_or_assign(m.begin(), ConvertibleTransparent<int>{3}, 5);
236 assert(it->second == 5);
237 assert(transparent_used);
238 }
239
240 {
241 auto insert_or_assign = [](auto& m, auto key_arg, auto value_arg) {
242 using M = std::decay_t<decltype(m)>;
243 using Key = typename M::key_type;
244 m.insert_or_assign(ConvertibleTransparent<Key>{key_arg}, value_arg);
245 };
246 test_emplace_exception_guarantee(emplace_function&: insert_or_assign);
247 }
248
249 {
250 auto insert_or_assign_iter = [](auto& m, auto key_arg, auto value_arg) {
251 using M = std::decay_t<decltype(m)>;
252 using Key = typename M::key_type;
253 m.insert_or_assign(m.begin(), ConvertibleTransparent<Key>{key_arg}, value_arg);
254 };
255 test_emplace_exception_guarantee(emplace_function&: insert_or_assign_iter);
256 }
257 {
258 // LWG4239 std::string and C string literal
259 using M = std::flat_map<std::string, int, std::less<>>;
260 M m{{"alpha", 1}, {"beta", 2}, {"epsilon", 1}, {"eta", 3}, {"gamma", 3}};
261 auto [it, inserted] = m.insert_or_assign("alpha", 2);
262 assert(!inserted);
263 assert(it == m.begin());
264 assert(it->second == 2);
265 auto it2 = m.insert_or_assign(m.begin(), "beta2", 2);
266 assert(it2 == m.begin() + 2);
267 assert(it2->second == 2);
268 }
269
270 return 0;
271}
272

source code of libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_or_assign_transparent.pass.cpp