1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/containers/flat_map.h"
6
7 #include <string>
8 #include <string_view>
9 #include <type_traits>
10 #include <utility>
11 #include <vector>
12
13 #include "base/ranges/algorithm.h"
14 #include "base/test/move_only_int.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 // A flat_map is basically a interface to flat_tree. So several basic
19 // operations are tested to make sure things are set up properly, but the bulk
20 // of the tests are in flat_tree_unittests.cc.
21
22 using ::testing::ElementsAre;
23
24 namespace base {
25
26 namespace {
27
28 struct Unsortable {
29 int value;
30 };
31
operator ==(const Unsortable & lhs,const Unsortable & rhs)32 bool operator==(const Unsortable& lhs, const Unsortable& rhs) {
33 return lhs.value == rhs.value;
34 }
35
36 bool operator<(const Unsortable& lhs, const Unsortable& rhs) = delete;
37 bool operator<=(const Unsortable& lhs, const Unsortable& rhs) = delete;
38 bool operator>(const Unsortable& lhs, const Unsortable& rhs) = delete;
39 bool operator>=(const Unsortable& lhs, const Unsortable& rhs) = delete;
40
41 class ImplicitInt {
42 public:
43 // NOLINTNEXTLINE(google-explicit-constructor)
ImplicitInt(int data)44 ImplicitInt(int data) : data_(data) {}
45
46 private:
operator <(const ImplicitInt & lhs,const ImplicitInt & rhs)47 friend bool operator<(const ImplicitInt& lhs, const ImplicitInt& rhs) {
48 return lhs.data_ < rhs.data_;
49 }
50
51 int data_;
52 };
53
54 } // namespace
55
TEST(FlatMap,IncompleteType)56 TEST(FlatMap, IncompleteType) {
57 struct A {
58 using Map = flat_map<A, A>;
59 int data;
60 Map set_with_incomplete_type;
61 Map::iterator it;
62 Map::const_iterator cit;
63
64 // We do not declare operator< because clang complains that it's unused.
65 };
66
67 A a;
68 }
69
TEST(FlatMap,RangeConstructor)70 TEST(FlatMap, RangeConstructor) {
71 flat_map<int, int>::value_type input_vals[] = {
72 {1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}};
73
74 flat_map<int, int> first(std::begin(input_vals), std::end(input_vals));
75 EXPECT_THAT(first, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 1),
76 std::make_pair(3, 1)));
77 }
78
TEST(FlatMap,MoveConstructor)79 TEST(FlatMap, MoveConstructor) {
80 using pair = std::pair<MoveOnlyInt, MoveOnlyInt>;
81
82 flat_map<MoveOnlyInt, MoveOnlyInt> original;
83 original.insert(pair(MoveOnlyInt(1), MoveOnlyInt(1)));
84 original.insert(pair(MoveOnlyInt(2), MoveOnlyInt(2)));
85 original.insert(pair(MoveOnlyInt(3), MoveOnlyInt(3)));
86 original.insert(pair(MoveOnlyInt(4), MoveOnlyInt(4)));
87
88 flat_map<MoveOnlyInt, MoveOnlyInt> moved(std::move(original));
89
90 EXPECT_EQ(1U, moved.count(MoveOnlyInt(1)));
91 EXPECT_EQ(1U, moved.count(MoveOnlyInt(2)));
92 EXPECT_EQ(1U, moved.count(MoveOnlyInt(3)));
93 EXPECT_EQ(1U, moved.count(MoveOnlyInt(4)));
94 }
95
TEST(FlatMap,VectorConstructor)96 TEST(FlatMap, VectorConstructor) {
97 using IntPair = std::pair<int, int>;
98 using IntMap = flat_map<int, int>;
99 std::vector<IntPair> vect{{1, 1}, {1, 2}, {2, 1}};
100 IntMap map(std::move(vect));
101 EXPECT_THAT(map, ElementsAre(IntPair(1, 1), IntPair(2, 1)));
102 }
103
TEST(FlatMap,InitializerListConstructor)104 TEST(FlatMap, InitializerListConstructor) {
105 flat_map<int, int> cont(
106 {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {1, 2}, {10, 10}, {8, 8}});
107 EXPECT_THAT(cont, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2),
108 std::make_pair(3, 3), std::make_pair(4, 4),
109 std::make_pair(5, 5), std::make_pair(8, 8),
110 std::make_pair(10, 10)));
111 }
112
TEST(FlatMap,SortedRangeConstructor)113 TEST(FlatMap, SortedRangeConstructor) {
114 using PairType = std::pair<int, Unsortable>;
115 using MapType = flat_map<int, Unsortable>;
116 MapType::value_type input_vals[] = {{1, {1}}, {2, {1}}, {3, {1}}};
117 MapType map(sorted_unique, std::begin(input_vals), std::end(input_vals));
118 EXPECT_THAT(
119 map, ElementsAre(PairType(1, {1}), PairType(2, {1}), PairType(3, {1})));
120 }
121
TEST(FlatMap,SortedCopyFromVectorConstructor)122 TEST(FlatMap, SortedCopyFromVectorConstructor) {
123 using PairType = std::pair<int, Unsortable>;
124 using MapType = flat_map<int, Unsortable>;
125 std::vector<PairType> vect{{1, {1}}, {2, {1}}};
126 MapType map(sorted_unique, vect);
127 EXPECT_THAT(map, ElementsAre(PairType(1, {1}), PairType(2, {1})));
128 }
129
TEST(FlatMap,SortedMoveFromVectorConstructor)130 TEST(FlatMap, SortedMoveFromVectorConstructor) {
131 using PairType = std::pair<int, Unsortable>;
132 using MapType = flat_map<int, Unsortable>;
133 std::vector<PairType> vect{{1, {1}}, {2, {1}}};
134 MapType map(sorted_unique, std::move(vect));
135 EXPECT_THAT(map, ElementsAre(PairType(1, {1}), PairType(2, {1})));
136 }
137
TEST(FlatMap,SortedInitializerListConstructor)138 TEST(FlatMap, SortedInitializerListConstructor) {
139 using PairType = std::pair<int, Unsortable>;
140 flat_map<int, Unsortable> map(
141 sorted_unique,
142 {{1, {1}}, {2, {2}}, {3, {3}}, {4, {4}}, {5, {5}}, {8, {8}}, {10, {10}}});
143 EXPECT_THAT(map,
144 ElementsAre(PairType(1, {1}), PairType(2, {2}), PairType(3, {3}),
145 PairType(4, {4}), PairType(5, {5}), PairType(8, {8}),
146 PairType(10, {10})));
147 }
148
TEST(FlatMap,InitializerListAssignment)149 TEST(FlatMap, InitializerListAssignment) {
150 flat_map<int, int> cont;
151 cont = {{1, 1}, {2, 2}};
152 EXPECT_THAT(cont, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2)));
153 }
154
TEST(FlatMap,InsertFindSize)155 TEST(FlatMap, InsertFindSize) {
156 base::flat_map<int, int> s;
157 s.insert(std::make_pair(1, 1));
158 s.insert(std::make_pair(1, 1));
159 s.insert(std::make_pair(2, 2));
160
161 EXPECT_EQ(2u, s.size());
162 EXPECT_EQ(std::make_pair(1, 1), *s.find(1));
163 EXPECT_EQ(std::make_pair(2, 2), *s.find(2));
164 EXPECT_EQ(s.end(), s.find(7));
165 }
166
TEST(FlatMap,CopySwap)167 TEST(FlatMap, CopySwap) {
168 base::flat_map<int, int> original;
169 original.insert({1, 1});
170 original.insert({2, 2});
171 EXPECT_THAT(original,
172 ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2)));
173
174 base::flat_map<int, int> copy(original);
175 EXPECT_THAT(copy, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2)));
176
177 copy.erase(copy.begin());
178 copy.insert({10, 10});
179 EXPECT_THAT(copy, ElementsAre(std::make_pair(2, 2), std::make_pair(10, 10)));
180
181 original.swap(copy);
182 EXPECT_THAT(original,
183 ElementsAre(std::make_pair(2, 2), std::make_pair(10, 10)));
184 EXPECT_THAT(copy, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2)));
185 }
186
187 // operator[](const Key&)
TEST(FlatMap,SubscriptConstKey)188 TEST(FlatMap, SubscriptConstKey) {
189 base::flat_map<std::string, int> m;
190
191 // Default construct elements that don't exist yet.
192 int& s = m["a"];
193 EXPECT_EQ(0, s);
194 EXPECT_EQ(1u, m.size());
195
196 // The returned mapped reference should refer into the map.
197 s = 22;
198 EXPECT_EQ(22, m["a"]);
199
200 // Overwrite existing elements.
201 m["a"] = 44;
202 EXPECT_EQ(44, m["a"]);
203 }
204
205 // operator[](Key&&)
TEST(FlatMap,SubscriptMoveOnlyKey)206 TEST(FlatMap, SubscriptMoveOnlyKey) {
207 base::flat_map<MoveOnlyInt, int> m;
208
209 // Default construct elements that don't exist yet.
210 int& s = m[MoveOnlyInt(1)];
211 EXPECT_EQ(0, s);
212 EXPECT_EQ(1u, m.size());
213
214 // The returned mapped reference should refer into the map.
215 s = 22;
216 EXPECT_EQ(22, m[MoveOnlyInt(1)]);
217
218 // Overwrite existing elements.
219 m[MoveOnlyInt(1)] = 44;
220 EXPECT_EQ(44, m[MoveOnlyInt(1)]);
221 }
222
223 // Mapped& at(const Key&)
224 // const Mapped& at(const Key&) const
TEST(FlatMap,AtFunction)225 TEST(FlatMap, AtFunction) {
226 base::flat_map<int, std::string> m = {{1, "a"}, {2, "b"}};
227
228 // Basic Usage.
229 EXPECT_EQ("a", m.at(1));
230 EXPECT_EQ("b", m.at(2));
231
232 // Const reference works.
233 const std::string& const_ref = std::as_const(m).at(1);
234 EXPECT_EQ("a", const_ref);
235
236 // Reference works, can operate on the string.
237 m.at(1)[0] = 'x';
238 EXPECT_EQ("x", m.at(1));
239
240 // Out-of-bounds will CHECK.
241 EXPECT_DEATH_IF_SUPPORTED(m.at(-1), "");
242 EXPECT_DEATH_IF_SUPPORTED({ m.at(-1)[0] = 'z'; }, "");
243
244 // Heterogeneous look-up works.
245 base::flat_map<std::string, int> m2 = {{"a", 1}, {"b", 2}};
246 EXPECT_EQ(1, m2.at(std::string_view("a")));
247 EXPECT_EQ(2, std::as_const(m2).at(std::string_view("b")));
248 }
249
250 // insert_or_assign(K&&, M&&)
TEST(FlatMap,InsertOrAssignMoveOnlyKey)251 TEST(FlatMap, InsertOrAssignMoveOnlyKey) {
252 base::flat_map<MoveOnlyInt, MoveOnlyInt> m;
253
254 // Initial insertion should return an iterator to the element and set the
255 // second pair member to |true|. The inserted key and value should be moved
256 // from.
257 MoveOnlyInt key(1);
258 MoveOnlyInt val(22);
259 auto result = m.insert_or_assign(std::move(key), std::move(val));
260 EXPECT_EQ(1, result.first->first.data());
261 EXPECT_EQ(22, result.first->second.data());
262 EXPECT_TRUE(result.second);
263 EXPECT_EQ(1u, m.size());
264 EXPECT_EQ(0, key.data()); // moved from
265 EXPECT_EQ(0, val.data()); // moved from
266
267 // Second call with same key should result in an assignment, overwriting the
268 // old value. Assignment should be indicated by setting the second pair member
269 // to |false|. Only the inserted value should be moved from, the key should be
270 // left intact.
271 key = MoveOnlyInt(1);
272 val = MoveOnlyInt(44);
273 result = m.insert_or_assign(std::move(key), std::move(val));
274 EXPECT_EQ(1, result.first->first.data());
275 EXPECT_EQ(44, result.first->second.data());
276 EXPECT_FALSE(result.second);
277 EXPECT_EQ(1u, m.size());
278 EXPECT_EQ(1, key.data()); // not moved from
279 EXPECT_EQ(0, val.data()); // moved from
280
281 // Check that random insertion results in sorted range.
282 base::flat_map<MoveOnlyInt, int> map;
283 for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
284 map.insert_or_assign(MoveOnlyInt(i), i);
285 EXPECT_TRUE(ranges::is_sorted(map));
286 }
287 }
288
289 // insert_or_assign(const_iterator hint, K&&, M&&)
TEST(FlatMap,InsertOrAssignMoveOnlyKeyWithHint)290 TEST(FlatMap, InsertOrAssignMoveOnlyKeyWithHint) {
291 base::flat_map<MoveOnlyInt, MoveOnlyInt> m;
292
293 // Initial insertion should return an iterator to the element. The inserted
294 // key and value should be moved from.
295 MoveOnlyInt key(1);
296 MoveOnlyInt val(22);
297 auto result = m.insert_or_assign(m.end(), std::move(key), std::move(val));
298 EXPECT_EQ(1, result->first.data());
299 EXPECT_EQ(22, result->second.data());
300 EXPECT_EQ(1u, m.size());
301 EXPECT_EQ(0, key.data()); // moved from
302 EXPECT_EQ(0, val.data()); // moved from
303
304 // Second call with same key should result in an assignment, overwriting the
305 // old value. Only the inserted value should be moved from, the key should be
306 // left intact.
307 key = MoveOnlyInt(1);
308 val = MoveOnlyInt(44);
309 result = m.insert_or_assign(m.end(), std::move(key), std::move(val));
310 EXPECT_EQ(1, result->first.data());
311 EXPECT_EQ(44, result->second.data());
312 EXPECT_EQ(1u, m.size());
313 EXPECT_EQ(1, key.data()); // not moved from
314 EXPECT_EQ(0, val.data()); // moved from
315
316 // Check that random insertion results in sorted range.
317 base::flat_map<MoveOnlyInt, int> map;
318 for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
319 map.insert_or_assign(map.end(), MoveOnlyInt(i), i);
320 EXPECT_TRUE(ranges::is_sorted(map));
321 }
322 }
323
324 // try_emplace(K&&, Args&&...)
TEST(FlatMap,TryEmplaceMoveOnlyKey)325 TEST(FlatMap, TryEmplaceMoveOnlyKey) {
326 base::flat_map<MoveOnlyInt, std::pair<MoveOnlyInt, MoveOnlyInt>> m;
327
328 // Trying to emplace into an empty map should succeed. Insertion should return
329 // an iterator to the element and set the second pair member to |true|. The
330 // inserted key and value should be moved from.
331 MoveOnlyInt key(1);
332 MoveOnlyInt val1(22);
333 MoveOnlyInt val2(44);
334 // Test piecewise construction of mapped_type.
335 auto result = m.try_emplace(std::move(key), std::move(val1), std::move(val2));
336 EXPECT_EQ(1, result.first->first.data());
337 EXPECT_EQ(22, result.first->second.first.data());
338 EXPECT_EQ(44, result.first->second.second.data());
339 EXPECT_TRUE(result.second);
340 EXPECT_EQ(1u, m.size());
341 EXPECT_EQ(0, key.data()); // moved from
342 EXPECT_EQ(0, val1.data()); // moved from
343 EXPECT_EQ(0, val2.data()); // moved from
344
345 // Second call with same key should result in a no-op, returning an iterator
346 // to the existing element and returning false as the second pair member.
347 // Key and values that were attempted to be inserted should be left intact.
348 key = MoveOnlyInt(1);
349 auto paired_val = std::make_pair(MoveOnlyInt(33), MoveOnlyInt(55));
350 // Test construction of mapped_type from pair.
351 result = m.try_emplace(std::move(key), std::move(paired_val));
352 EXPECT_EQ(1, result.first->first.data());
353 EXPECT_EQ(22, result.first->second.first.data());
354 EXPECT_EQ(44, result.first->second.second.data());
355 EXPECT_FALSE(result.second);
356 EXPECT_EQ(1u, m.size());
357 EXPECT_EQ(1, key.data()); // not moved from
358 EXPECT_EQ(33, paired_val.first.data()); // not moved from
359 EXPECT_EQ(55, paired_val.second.data()); // not moved from
360
361 // Check that random insertion results in sorted range.
362 base::flat_map<MoveOnlyInt, int> map;
363 for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
364 map.try_emplace(MoveOnlyInt(i), i);
365 EXPECT_TRUE(ranges::is_sorted(map));
366 }
367 }
368
369 // try_emplace(const_iterator hint, K&&, Args&&...)
TEST(FlatMap,TryEmplaceMoveOnlyKeyWithHint)370 TEST(FlatMap, TryEmplaceMoveOnlyKeyWithHint) {
371 base::flat_map<MoveOnlyInt, std::pair<MoveOnlyInt, MoveOnlyInt>> m;
372
373 // Trying to emplace into an empty map should succeed. Insertion should return
374 // an iterator to the element. The inserted key and value should be moved
375 // from.
376 MoveOnlyInt key(1);
377 MoveOnlyInt val1(22);
378 MoveOnlyInt val2(44);
379 // Test piecewise construction of mapped_type.
380 auto result =
381 m.try_emplace(m.end(), std::move(key), std::move(val1), std::move(val2));
382 EXPECT_EQ(1, result->first.data());
383 EXPECT_EQ(22, result->second.first.data());
384 EXPECT_EQ(44, result->second.second.data());
385 EXPECT_EQ(1u, m.size());
386 EXPECT_EQ(0, key.data()); // moved from
387 EXPECT_EQ(0, val1.data()); // moved from
388 EXPECT_EQ(0, val2.data()); // moved from
389
390 // Second call with same key should result in a no-op, returning an iterator
391 // to the existing element. Key and values that were attempted to be inserted
392 // should be left intact.
393 key = MoveOnlyInt(1);
394 val1 = MoveOnlyInt(33);
395 val2 = MoveOnlyInt(55);
396 auto paired_val = std::make_pair(MoveOnlyInt(33), MoveOnlyInt(55));
397 // Test construction of mapped_type from pair.
398 result = m.try_emplace(m.end(), std::move(key), std::move(paired_val));
399 EXPECT_EQ(1, result->first.data());
400 EXPECT_EQ(22, result->second.first.data());
401 EXPECT_EQ(44, result->second.second.data());
402 EXPECT_EQ(1u, m.size());
403 EXPECT_EQ(1, key.data()); // not moved from
404 EXPECT_EQ(33, paired_val.first.data()); // not moved from
405 EXPECT_EQ(55, paired_val.second.data()); // not moved from
406
407 // Check that random insertion results in sorted range.
408 base::flat_map<MoveOnlyInt, int> map;
409 for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
410 map.try_emplace(map.end(), MoveOnlyInt(i), i);
411 EXPECT_TRUE(ranges::is_sorted(map));
412 }
413 }
414
TEST(FlatMap,UsingTransparentCompare)415 TEST(FlatMap, UsingTransparentCompare) {
416 using ExplicitInt = base::MoveOnlyInt;
417 base::flat_map<ExplicitInt, int> m;
418 const auto& m1 = m;
419 int x = 0;
420
421 // Check if we can use lookup functions without converting to key_type.
422 // Correctness is checked in flat_tree tests.
423 m.count(x);
424 m1.count(x);
425 m.find(x);
426 m1.find(x);
427 m.contains(x);
428 m1.contains(x);
429 m.equal_range(x);
430 m1.equal_range(x);
431 m.lower_bound(x);
432 m1.lower_bound(x);
433 m.upper_bound(x);
434 m1.upper_bound(x);
435 m.erase(x);
436
437 // Check if we broke overload resolution.
438 m.emplace(ExplicitInt(0), 0);
439 m.emplace(ExplicitInt(1), 0);
440 m.erase(m.begin());
441 m.erase(m.cbegin());
442 }
443
TEST(FlatMap,UsingInitializerList)444 TEST(FlatMap, UsingInitializerList) {
445 base::flat_map<ImplicitInt, int> m;
446 const auto& m1 = m;
447
448 // Check if the calls can be resolved. Correctness is checked in flat_tree
449 // tests.
450 m.count({1});
451 m1.count({2});
452 m.find({3});
453 m1.find({4});
454 m.contains({5});
455 m1.contains({6});
456 m.equal_range({7});
457 m1.equal_range({8});
458 m.lower_bound({9});
459 m1.lower_bound({10});
460 m.upper_bound({11});
461 m1.upper_bound({12});
462 m.erase({13});
463 }
464
TEST(FlatMap,DeductionGuides)465 TEST(FlatMap, DeductionGuides) {
466 {
467 std::vector<std::pair<int, float>> v = {{1, 4.0}, {2, 3.0}};
468 flat_map map{v};
469 static_assert(std::is_same_v<decltype(map), flat_map<int, float>>);
470 }
471
472 {
473 std::vector<std::pair<int, float>> v = {{1, 4.0}, {2, 3.0}};
474 flat_map map(std::move(v));
475 static_assert(std::is_same_v<decltype(map), flat_map<int, float>>);
476 }
477 }
478
479 } // namespace base
480