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 | // UNSUPPORTED: availability-pmr-missing |
11 | |
12 | // <flat_map> |
13 | |
14 | // Test various constructors with pmr |
15 | |
16 | #include <algorithm> |
17 | #include <cassert> |
18 | #include <deque> |
19 | #include <flat_map> |
20 | #include <functional> |
21 | #include <memory_resource> |
22 | #include <ranges> |
23 | #include <vector> |
24 | #include <string> |
25 | |
26 | #include "test_iterators.h" |
27 | #include "test_macros.h" |
28 | #include "test_allocator.h" |
29 | #include "../../../test_compare.h" |
30 | |
31 | int main(int, char**) { |
32 | { |
33 | // flat_map(const Allocator& a); |
34 | using M = std::flat_map<int, short, std::less<int>, std::pmr::vector<int>, std::pmr::vector<short>>; |
35 | std::pmr::monotonic_buffer_resource mr; |
36 | std::pmr::polymorphic_allocator<int> pa = &mr; |
37 | auto m1 = M(pa); |
38 | assert(m1.empty()); |
39 | assert(m1.keys().get_allocator() == pa); |
40 | assert(m1.values().get_allocator() == pa); |
41 | auto m2 = M(&mr); |
42 | assert(m2.empty()); |
43 | assert(m2.keys().get_allocator() == pa); |
44 | assert(m2.values().get_allocator() == pa); |
45 | } |
46 | { |
47 | // flat_map(const key_compare& comp, const Alloc& a); |
48 | using M = std::flat_map<int, int, std::function<bool(int, int)>, std::pmr::vector<int>, std::pmr::vector<int>>; |
49 | std::pmr::monotonic_buffer_resource mr; |
50 | std::pmr::vector<M> vm(&mr); |
51 | vm.emplace_back(std::greater<int>()); |
52 | assert(vm[0] == M{}); |
53 | assert(vm[0].key_comp()(2, 1) == true); |
54 | assert(vm[0].value_comp()({2, 0}, {1, 0}) == true); |
55 | assert(vm[0].keys().get_allocator().resource() == &mr); |
56 | assert(vm[0].values().get_allocator().resource() == &mr); |
57 | } |
58 | { |
59 | // flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, |
60 | // const Allocator& a); |
61 | using M = std::flat_map<int, int, std::less<int>, std::pmr::vector<int>, std::pmr::vector<int>>; |
62 | std::pmr::monotonic_buffer_resource mr; |
63 | std::pmr::vector<M> vm(&mr); |
64 | std::pmr::vector<int> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; |
65 | std::pmr::vector<int> vs = {1, 1, 1, 2, 2, 3, 2, 3, 3}; |
66 | assert(ks.get_allocator().resource() != &mr); |
67 | assert(vs.get_allocator().resource() != &mr); |
68 | vm.emplace_back(ks, vs); |
69 | assert(ks.size() == 9); // ks' value is unchanged, since it was an lvalue above |
70 | assert(vs.size() == 9); // vs' value is unchanged, since it was an lvalue above |
71 | assert((vm[0] == M{{1, 1}, {2, 2}, {3, 3}})); |
72 | assert(vm[0].keys().get_allocator().resource() == &mr); |
73 | assert(vm[0].values().get_allocator().resource() == &mr); |
74 | } |
75 | { |
76 | // flat_map(const flat_map&, const allocator_type&); |
77 | using C = test_less<int>; |
78 | using M = std::flat_map<int, int, C, std::pmr::vector<int>, std::pmr::vector<int>>; |
79 | std::pmr::monotonic_buffer_resource mr1; |
80 | std::pmr::monotonic_buffer_resource mr2; |
81 | M mo = M({1, 2, 3}, {2, 2, 1}, C(5), &mr1); |
82 | M m = {mo, &mr2}; // also test the implicitness of this constructor |
83 | |
84 | assert(m.key_comp() == C(5)); |
85 | assert((m.keys() == std::pmr::vector<int>{1, 2, 3})); |
86 | assert((m.values() == std::pmr::vector<int>{2, 2, 1})); |
87 | assert(m.keys().get_allocator().resource() == &mr2); |
88 | assert(m.values().get_allocator().resource() == &mr2); |
89 | |
90 | // mo is unchanged |
91 | assert(mo.key_comp() == C(5)); |
92 | assert((mo.keys() == std::pmr::vector<int>{1, 2, 3})); |
93 | assert((mo.values() == std::pmr::vector<int>{2, 2, 1})); |
94 | assert(mo.keys().get_allocator().resource() == &mr1); |
95 | assert(mo.values().get_allocator().resource() == &mr1); |
96 | } |
97 | { |
98 | // flat_map(const flat_map&, const allocator_type&); |
99 | using M = std::flat_map<int, int, std::less<>, std::pmr::vector<int>, std::pmr::deque<int>>; |
100 | std::pmr::vector<M> vs; |
101 | M m = {{1, 2}, {2, 2}, {3, 1}}; |
102 | vs.push_back(m); |
103 | assert(vs[0] == m); |
104 | } |
105 | { |
106 | // flat_map& operator=(const flat_map& m); |
107 | // pmr allocator is not propagated |
108 | using M = std::flat_map<int, int, std::less<>, std::pmr::deque<int>, std::pmr::vector<int>>; |
109 | std::pmr::monotonic_buffer_resource mr1; |
110 | std::pmr::monotonic_buffer_resource mr2; |
111 | M mo = M({{1, 1}, {2, 2}, {3, 3}}, &mr1); |
112 | M m = M({{4, 4}, {5, 5}}, &mr2); |
113 | m = mo; |
114 | assert((m == M{{1, 1}, {2, 2}, {3, 3}})); |
115 | assert(m.keys().get_allocator().resource() == &mr2); |
116 | assert(m.values().get_allocator().resource() == &mr2); |
117 | |
118 | // mo is unchanged |
119 | assert((mo == M{{1, 1}, {2, 2}, {3, 3}})); |
120 | assert(mo.keys().get_allocator().resource() == &mr1); |
121 | } |
122 | { |
123 | // flat_map(const flat_map& m); |
124 | using C = test_less<int>; |
125 | std::pmr::monotonic_buffer_resource mr; |
126 | using M = std::flat_map<int, int, C, std::pmr::vector<int>, std::pmr::vector<int>>; |
127 | auto mo = M({{1, 1}, {2, 2}, {3, 3}}, C(5), &mr); |
128 | auto m = mo; |
129 | |
130 | assert(m.key_comp() == C(5)); |
131 | assert((m == M{{1, 1}, {2, 2}, {3, 3}})); |
132 | auto [ks, vs] = std::move(m).extract(); |
133 | assert(ks.get_allocator().resource() == std::pmr::get_default_resource()); |
134 | assert(vs.get_allocator().resource() == std::pmr::get_default_resource()); |
135 | |
136 | // mo is unchanged |
137 | assert(mo.key_comp() == C(5)); |
138 | assert((mo == M{{1, 1}, {2, 2}, {3, 3}})); |
139 | auto [kso, vso] = std::move(mo).extract(); |
140 | assert(kso.get_allocator().resource() == &mr); |
141 | assert(vso.get_allocator().resource() == &mr); |
142 | } |
143 | { |
144 | // flat_map(initializer_list<value_type> il, const Alloc& a); |
145 | using M = std::flat_map<int, int, std::less<int>, std::pmr::vector<int>, std::pmr::vector<int>>; |
146 | std::pmr::monotonic_buffer_resource mr; |
147 | std::pmr::vector<M> vm(&mr); |
148 | std::initializer_list<M::value_type> il = {{3, 3}, {1, 1}, {4, 4}, {1, 1}, {5, 5}}; |
149 | vm.emplace_back(il); |
150 | assert((vm[0] == M{{1, 1}, {3, 3}, {4, 4}, {5, 5}})); |
151 | assert(vm[0].keys().get_allocator().resource() == &mr); |
152 | assert(vm[0].values().get_allocator().resource() == &mr); |
153 | } |
154 | { |
155 | // flat_map(initializer_list<value_type> il, const key_compare& comp, const Alloc& a); |
156 | using C = test_less<int>; |
157 | using M = std::flat_map<int, int, C, std::pmr::vector<int>, std::pmr::deque<int>>; |
158 | std::pmr::monotonic_buffer_resource mr; |
159 | std::pmr::vector<M> vm(&mr); |
160 | std::initializer_list<M::value_type> il = {{3, 3}, {1, 1}, {4, 4}, {1, 1}, {5, 5}}; |
161 | vm.emplace_back(il, C(5)); |
162 | assert((vm[0] == M{{1, 1}, {3, 3}, {4, 4}, {5, 5}})); |
163 | assert(vm[0].keys().get_allocator().resource() == &mr); |
164 | assert(vm[0].values().get_allocator().resource() == &mr); |
165 | assert(vm[0].key_comp() == C(5)); |
166 | } |
167 | { |
168 | // flat_map(InputIterator first, InputIterator last, const Allocator& a); |
169 | using P = std::pair<int, short>; |
170 | P ar[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {2, 7}, {3, 8}, {3, 9}}; |
171 | P expected[] = {{1, 1}, {2, 4}, {3, 6}}; |
172 | { |
173 | // cpp17 iterator |
174 | using M = std::flat_map<int, short, std::less<int>, std::pmr::vector<int>, std::pmr::vector<short>>; |
175 | std::pmr::monotonic_buffer_resource mr; |
176 | std::pmr::vector<M> vm(&mr); |
177 | vm.emplace_back(cpp17_input_iterator<const P*>(ar), cpp17_input_iterator<const P*>(ar + 9)); |
178 | assert(std::ranges::equal(vm[0].keys(), expected | std::views::elements<0>)); |
179 | LIBCPP_ASSERT(std::ranges::equal(vm[0], expected)); |
180 | assert(vm[0].keys().get_allocator().resource() == &mr); |
181 | assert(vm[0].values().get_allocator().resource() == &mr); |
182 | } |
183 | { |
184 | using M = std::flat_map<int, short, std::less<int>, std::pmr::vector<int>, std::pmr::vector<short>>; |
185 | std::pmr::monotonic_buffer_resource mr; |
186 | std::pmr::vector<M> vm(&mr); |
187 | vm.emplace_back(ar, ar); |
188 | assert(vm[0].empty()); |
189 | assert(vm[0].keys().get_allocator().resource() == &mr); |
190 | assert(vm[0].values().get_allocator().resource() == &mr); |
191 | } |
192 | } |
193 | { |
194 | // flat_map(flat_map&&, const allocator_type&); |
195 | std::pair<int, int> expected[] = {{1, 1}, {2, 2}, {3, 1}}; |
196 | using C = test_less<int>; |
197 | using M = std::flat_map<int, int, C, std::pmr::vector<int>, std::pmr::deque<int>>; |
198 | std::pmr::monotonic_buffer_resource mr1; |
199 | std::pmr::monotonic_buffer_resource mr2; |
200 | M mo = M({{1, 1}, {3, 1}, {1, 1}, {2, 2}}, C(5), &mr1); |
201 | M m = {std::move(mo), &mr2}; // also test the implicitness of this constructor |
202 | |
203 | assert(m.key_comp() == C(5)); |
204 | assert(m.size() == 3); |
205 | assert(m.keys().get_allocator().resource() == &mr2); |
206 | assert(m.values().get_allocator().resource() == &mr2); |
207 | assert(std::equal(m.begin(), m.end(), expected, expected + 3)); |
208 | |
209 | // The original flat_map is moved-from. |
210 | assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); |
211 | assert(mo.key_comp() == C(5)); |
212 | assert(mo.keys().get_allocator().resource() == &mr1); |
213 | assert(mo.values().get_allocator().resource() == &mr1); |
214 | } |
215 | { |
216 | // flat_map(flat_map&&, const allocator_type&); |
217 | using M = std::flat_map<int, int, std::less<>, std::pmr::deque<int>, std::pmr::vector<int>>; |
218 | std::pmr::vector<M> vs; |
219 | M m = {{1, 1}, {3, 1}, {1, 1}, {2, 2}}; |
220 | vs.push_back(std::move(m)); |
221 | assert((vs[0].keys() == std::pmr::deque<int>{1, 2, 3})); |
222 | assert((vs[0].values() == std::pmr::vector<int>{1, 2, 1})); |
223 | } |
224 | { |
225 | // flat_map& operator=(flat_map&&); |
226 | using M = |
227 | std::flat_map<std::pmr::string, int, std::less<>, std::pmr::vector<std::pmr::string>, std::pmr::vector<int>>; |
228 | std::pmr::monotonic_buffer_resource mr1; |
229 | std::pmr::monotonic_buffer_resource mr2; |
230 | M mo = M({{"short" , 1}, |
231 | {"very long string that definitely won't fit in the SSO buffer and therefore becomes empty on move" , 2}}, |
232 | &mr1); |
233 | M m = M({{"don't care" , 3}}, &mr2); |
234 | m = std::move(mo); |
235 | assert(m.size() == 2); |
236 | assert(std::is_sorted(m.begin(), m.end(), m.value_comp())); |
237 | assert(m.begin()->first.get_allocator().resource() == &mr2); |
238 | |
239 | assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp())); |
240 | mo.insert({"foo" , 1}); |
241 | assert(mo.begin()->first.get_allocator().resource() == &mr1); |
242 | } |
243 | { |
244 | // flat_map(from_range_t, R&&, const Alloc&); |
245 | using P = std::pair<int, short>; |
246 | P ar[] = {{1, 1}, {1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {2, 7}, {3, 8}, {3, 9}}; |
247 | P expected[] = {{1, 1}, {2, 4}, {3, 6}}; |
248 | { |
249 | // input_range |
250 | using M = std::flat_map<int, short, std::less<int>, std::pmr::vector<int>, std::pmr::vector<short>>; |
251 | using Iter = cpp20_input_iterator<const P*>; |
252 | using Sent = sentinel_wrapper<Iter>; |
253 | using R = std::ranges::subrange<Iter, Sent>; |
254 | std::pmr::monotonic_buffer_resource mr; |
255 | std::pmr::vector<M> vm(&mr); |
256 | vm.emplace_back(std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))); |
257 | assert(std::ranges::equal(vm[0].keys(), expected | std::views::elements<0>)); |
258 | LIBCPP_ASSERT(std::ranges::equal(vm[0], expected)); |
259 | assert(vm[0].keys().get_allocator().resource() == &mr); |
260 | assert(vm[0].values().get_allocator().resource() == &mr); |
261 | } |
262 | { |
263 | using M = std::flat_map<int, short, std::less<int>, std::pmr::vector<int>, std::pmr::vector<short>>; |
264 | using R = std::ranges::subrange<const P*>; |
265 | std::pmr::monotonic_buffer_resource mr; |
266 | std::pmr::vector<M> vm(&mr); |
267 | vm.emplace_back(std::from_range, R(ar, ar)); |
268 | assert(vm[0].empty()); |
269 | assert(vm[0].keys().get_allocator().resource() == &mr); |
270 | assert(vm[0].values().get_allocator().resource() == &mr); |
271 | } |
272 | } |
273 | { |
274 | // flat_map(sorted_unique_t, const key_container_type& key_cont, |
275 | // const mapped_container_type& mapped_cont, const Alloc& a); |
276 | using M = std::flat_map<int, int, std::less<int>, std::pmr::vector<int>, std::pmr::vector<int>>; |
277 | std::pmr::monotonic_buffer_resource mr; |
278 | std::pmr::vector<M> vm(&mr); |
279 | std::pmr::vector<int> ks = {1, 2, 4, 10}; |
280 | std::pmr::vector<int> vs = {4, 3, 2, 1}; |
281 | vm.emplace_back(std::sorted_unique, ks, vs); |
282 | assert(!ks.empty()); // it was an lvalue above |
283 | assert(!vs.empty()); // it was an lvalue above |
284 | assert((vm[0] == M{{1, 4}, {2, 3}, {4, 2}, {10, 1}})); |
285 | assert(vm[0].keys().get_allocator().resource() == &mr); |
286 | assert(vm[0].values().get_allocator().resource() == &mr); |
287 | } |
288 | { |
289 | // flat_map(sorted_unique_t, const key_container_type& key_cont, |
290 | // const mapped_container_type& mapped_cont, const Alloc& a); |
291 | using M = std::flat_map<int, int, std::less<int>, std::pmr::vector<int>, std::pmr::vector<int>>; |
292 | std::pmr::monotonic_buffer_resource mr; |
293 | std::pmr::vector<M> vm(&mr); |
294 | std::pmr::vector<int> ks({1, 2, 4, 10}, &mr); |
295 | std::pmr::vector<int> vs({4, 3, 2, 1}, &mr); |
296 | vm.emplace_back(std::sorted_unique, ks, vs); |
297 | assert((vm[0] == M{{1, 4}, {2, 3}, {4, 2}, {10, 1}})); |
298 | assert(vm[0].keys().get_allocator().resource() == &mr); |
299 | assert(vm[0].values().get_allocator().resource() == &mr); |
300 | } |
301 | { |
302 | // flat_map(sorted_unique_t, initializer_list<value_type> il, const Alloc& a); |
303 | // cpp_17 |
304 | using C = test_less<int>; |
305 | using M = std::flat_map<int, int, C, std::pmr::vector<int>, std::pmr::vector<int>>; |
306 | std::pmr::monotonic_buffer_resource mr; |
307 | std::pmr::vector<M> vm(&mr); |
308 | using P = std::pair<int, int>; |
309 | P ar[] = {{1, 1}, {2, 2}, {4, 4}, {5, 5}}; |
310 | vm.emplace_back( |
311 | std::sorted_unique, cpp17_input_iterator<const P*>(ar), cpp17_input_iterator<const P*>(ar + 4), C(3)); |
312 | assert((vm[0] == M{{1, 1}, {2, 2}, {4, 4}, {5, 5}})); |
313 | assert(vm[0].key_comp() == C(3)); |
314 | assert(vm[0].keys().get_allocator().resource() == &mr); |
315 | assert(vm[0].values().get_allocator().resource() == &mr); |
316 | } |
317 | { |
318 | // flat_map(sorted_unique_t, initializer_list<value_type> il, const Alloc& a); |
319 | using C = test_less<int>; |
320 | using M = std::flat_map<int, int, C, std::pmr::vector<int>, std::pmr::vector<int>>; |
321 | std::pmr::monotonic_buffer_resource mr; |
322 | std::pmr::vector<M> vm(&mr); |
323 | std::pair<int, int> ar[1] = {{42, 42}}; |
324 | vm.emplace_back(std::sorted_unique, ar, ar, C(4)); |
325 | assert(vm[0] == M{}); |
326 | assert(vm[0].key_comp() == C(4)); |
327 | assert(vm[0].keys().get_allocator().resource() == &mr); |
328 | assert(vm[0].values().get_allocator().resource() == &mr); |
329 | } |
330 | { |
331 | // flat_map(InputIterator first, InputIterator last, const Alloc& a); |
332 | // cpp_17 |
333 | using C = test_less<int>; |
334 | using M = std::flat_map<int, int, C, std::pmr::vector<int>, std::pmr::vector<int>>; |
335 | std::pmr::monotonic_buffer_resource mr; |
336 | std::pmr::vector<M> vm(&mr); |
337 | using P = std::pair<int, int>; |
338 | P ar[] = {{1, 1}, {2, 2}, {4, 4}, {5, 5}}; |
339 | vm.emplace_back( |
340 | std::sorted_unique, cpp17_input_iterator<const P*>(ar), cpp17_input_iterator<const P*>(ar + 4), C(3)); |
341 | assert((vm[0] == M{{1, 1}, {2, 2}, {4, 4}, {5, 5}})); |
342 | assert(vm[0].key_comp() == C(3)); |
343 | assert(vm[0].keys().get_allocator().resource() == &mr); |
344 | assert(vm[0].values().get_allocator().resource() == &mr); |
345 | } |
346 | { |
347 | // flat_map(InputIterator first, InputIterator last, const Alloc& a); |
348 | using C = test_less<int>; |
349 | using M = std::flat_map<int, int, C, std::pmr::vector<int>, std::pmr::vector<int>>; |
350 | std::pmr::monotonic_buffer_resource mr; |
351 | std::pmr::vector<M> vm(&mr); |
352 | std::pair<int, int> ar[1] = {{42, 42}}; |
353 | vm.emplace_back(std::sorted_unique, ar, ar, C(4)); |
354 | assert(vm[0] == M{}); |
355 | assert(vm[0].key_comp() == C(4)); |
356 | assert(vm[0].keys().get_allocator().resource() == &mr); |
357 | assert(vm[0].values().get_allocator().resource() == &mr); |
358 | } |
359 | |
360 | return 0; |
361 | } |
362 | |