xref: /aosp_15_r20/external/cronet/base/containers/flat_map_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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