| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/containers/small_map.h" | 
 |  | 
 | #include <stddef.h> | 
 |  | 
 | #include <algorithm> | 
 | #include <functional> | 
 | #include <map> | 
 | #include <unordered_map> | 
 |  | 
 | #include "base/logging.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace base { | 
 |  | 
 | TEST(SmallMap, General) { | 
 |   small_map<std::unordered_map<int, int>> m; | 
 |  | 
 |   EXPECT_TRUE(m.empty()); | 
 |  | 
 |   m[0] = 5; | 
 |  | 
 |   EXPECT_FALSE(m.empty()); | 
 |   EXPECT_EQ(m.size(), 1u); | 
 |  | 
 |   m[9] = 2; | 
 |  | 
 |   EXPECT_FALSE(m.empty()); | 
 |   EXPECT_EQ(m.size(), 2u); | 
 |  | 
 |   EXPECT_EQ(m[9], 2); | 
 |   EXPECT_EQ(m[0], 5); | 
 |   EXPECT_FALSE(m.UsingFullMap()); | 
 |  | 
 |   small_map<std::unordered_map<int, int>>::iterator iter(m.begin()); | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, 0); | 
 |   EXPECT_EQ(iter->second, 5); | 
 |   ++iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ((*iter).first, 9); | 
 |   EXPECT_EQ((*iter).second, 2); | 
 |   ++iter; | 
 |   EXPECT_TRUE(iter == m.end()); | 
 |  | 
 |   m[8] = 23; | 
 |   m[1234] = 90; | 
 |   m[-5] = 6; | 
 |  | 
 |   EXPECT_EQ(m[   9],  2); | 
 |   EXPECT_EQ(m[   0],  5); | 
 |   EXPECT_EQ(m[1234], 90); | 
 |   EXPECT_EQ(m[   8], 23); | 
 |   EXPECT_EQ(m[  -5],  6); | 
 |   EXPECT_EQ(m.size(), 5u); | 
 |   EXPECT_FALSE(m.empty()); | 
 |   EXPECT_TRUE(m.UsingFullMap()); | 
 |  | 
 |   iter = m.begin(); | 
 |   for (int i = 0; i < 5; i++) { | 
 |     EXPECT_TRUE(iter != m.end()); | 
 |     ++iter; | 
 |   } | 
 |   EXPECT_TRUE(iter == m.end()); | 
 |  | 
 |   const small_map<std::unordered_map<int, int>>& ref = m; | 
 |   EXPECT_TRUE(ref.find(1234) != m.end()); | 
 |   EXPECT_TRUE(ref.find(5678) == m.end()); | 
 | } | 
 |  | 
 | TEST(SmallMap, PostFixIteratorIncrement) { | 
 |   small_map<std::unordered_map<int, int>> m; | 
 |   m[0] = 5; | 
 |   m[2] = 3; | 
 |  | 
 |   { | 
 |     small_map<std::unordered_map<int, int>>::iterator iter(m.begin()); | 
 |     small_map<std::unordered_map<int, int>>::iterator last(iter++); | 
 |     ++last; | 
 |     EXPECT_TRUE(last == iter); | 
 |   } | 
 |  | 
 |   { | 
 |     small_map<std::unordered_map<int, int>>::const_iterator iter(m.begin()); | 
 |     small_map<std::unordered_map<int, int>>::const_iterator last(iter++); | 
 |     ++last; | 
 |     EXPECT_TRUE(last == iter); | 
 |   } | 
 | } | 
 |  | 
 | // Based on the General testcase. | 
 | TEST(SmallMap, CopyConstructor) { | 
 |   small_map<std::unordered_map<int, int>> src; | 
 |  | 
 |   { | 
 |     small_map<std::unordered_map<int, int>> m(src); | 
 |     EXPECT_TRUE(m.empty()); | 
 |   } | 
 |  | 
 |   src[0] = 5; | 
 |  | 
 |   { | 
 |     small_map<std::unordered_map<int, int>> m(src); | 
 |     EXPECT_FALSE(m.empty()); | 
 |     EXPECT_EQ(m.size(), 1u); | 
 |   } | 
 |  | 
 |   src[9] = 2; | 
 |  | 
 |   { | 
 |     small_map<std::unordered_map<int, int>> m(src); | 
 |     EXPECT_FALSE(m.empty()); | 
 |     EXPECT_EQ(m.size(), 2u); | 
 |  | 
 |     EXPECT_EQ(m[9], 2); | 
 |     EXPECT_EQ(m[0], 5); | 
 |     EXPECT_FALSE(m.UsingFullMap()); | 
 |   } | 
 |  | 
 |   src[8] = 23; | 
 |   src[1234] = 90; | 
 |   src[-5] = 6; | 
 |  | 
 |   { | 
 |     small_map<std::unordered_map<int, int>> m(src); | 
 |     EXPECT_EQ(m[   9],  2); | 
 |     EXPECT_EQ(m[   0],  5); | 
 |     EXPECT_EQ(m[1234], 90); | 
 |     EXPECT_EQ(m[   8], 23); | 
 |     EXPECT_EQ(m[  -5],  6); | 
 |     EXPECT_EQ(m.size(), 5u); | 
 |     EXPECT_FALSE(m.empty()); | 
 |     EXPECT_TRUE(m.UsingFullMap()); | 
 |   } | 
 | } | 
 |  | 
 | template <class inner> | 
 | static bool SmallMapIsSubset(small_map<inner> const& a, | 
 |                              small_map<inner> const& b) { | 
 |   typename small_map<inner>::const_iterator it; | 
 |   for (it = a.begin(); it != a.end(); ++it) { | 
 |     typename small_map<inner>::const_iterator it_in_b = b.find(it->first); | 
 |     if (it_in_b == b.end() || it_in_b->second != it->second) | 
 |       return false; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | template <class inner> | 
 | static bool SmallMapEqual(small_map<inner> const& a, | 
 |                           small_map<inner> const& b) { | 
 |   return SmallMapIsSubset(a, b) && SmallMapIsSubset(b, a); | 
 | } | 
 |  | 
 | TEST(SmallMap, AssignmentOperator) { | 
 |   small_map<std::unordered_map<int, int>> src_small; | 
 |   small_map<std::unordered_map<int, int>> src_large; | 
 |  | 
 |   src_small[1] = 20; | 
 |   src_small[2] = 21; | 
 |   src_small[3] = 22; | 
 |   EXPECT_FALSE(src_small.UsingFullMap()); | 
 |  | 
 |   src_large[1] = 20; | 
 |   src_large[2] = 21; | 
 |   src_large[3] = 22; | 
 |   src_large[5] = 23; | 
 |   src_large[6] = 24; | 
 |   src_large[7] = 25; | 
 |   EXPECT_TRUE(src_large.UsingFullMap()); | 
 |  | 
 |   // Assignments to empty. | 
 |   small_map<std::unordered_map<int, int>> dest_small; | 
 |   dest_small = src_small; | 
 |   EXPECT_TRUE(SmallMapEqual(dest_small, src_small)); | 
 |   EXPECT_EQ(dest_small.UsingFullMap(), | 
 |             src_small.UsingFullMap()); | 
 |  | 
 |   small_map<std::unordered_map<int, int>> dest_large; | 
 |   dest_large = src_large; | 
 |   EXPECT_TRUE(SmallMapEqual(dest_large, src_large)); | 
 |   EXPECT_EQ(dest_large.UsingFullMap(), | 
 |             src_large.UsingFullMap()); | 
 |  | 
 |   // Assignments which assign from full to small, and vice versa. | 
 |   dest_small = src_large; | 
 |   EXPECT_TRUE(SmallMapEqual(dest_small, src_large)); | 
 |   EXPECT_EQ(dest_small.UsingFullMap(), | 
 |             src_large.UsingFullMap()); | 
 |  | 
 |   dest_large = src_small; | 
 |   EXPECT_TRUE(SmallMapEqual(dest_large, src_small)); | 
 |   EXPECT_EQ(dest_large.UsingFullMap(), | 
 |             src_small.UsingFullMap()); | 
 |  | 
 |   // Double check that SmallMapEqual works: | 
 |   dest_large[42] = 666; | 
 |   EXPECT_FALSE(SmallMapEqual(dest_large, src_small)); | 
 | } | 
 |  | 
 | TEST(SmallMap, Insert) { | 
 |   small_map<std::unordered_map<int, int>> sm; | 
 |  | 
 |   // loop through the transition from small map to map. | 
 |   for (int i = 1; i <= 10; ++i) { | 
 |     VLOG(1) << "Iteration " << i; | 
 |     // insert an element | 
 |     std::pair<small_map<std::unordered_map<int, int>>::iterator, bool> ret; | 
 |     ret = sm.insert(std::make_pair(i, 100*i)); | 
 |     EXPECT_TRUE(ret.second); | 
 |     EXPECT_TRUE(ret.first == sm.find(i)); | 
 |     EXPECT_EQ(ret.first->first, i); | 
 |     EXPECT_EQ(ret.first->second, 100*i); | 
 |  | 
 |     // try to insert it again with different value, fails, but we still get an | 
 |     // iterator back with the original value. | 
 |     ret = sm.insert(std::make_pair(i, -i)); | 
 |     EXPECT_FALSE(ret.second); | 
 |     EXPECT_TRUE(ret.first == sm.find(i)); | 
 |     EXPECT_EQ(ret.first->first, i); | 
 |     EXPECT_EQ(ret.first->second, 100*i); | 
 |  | 
 |     // check the state of the map. | 
 |     for (int j = 1; j <= i; ++j) { | 
 |       small_map<std::unordered_map<int, int>>::iterator it = sm.find(j); | 
 |       EXPECT_TRUE(it != sm.end()); | 
 |       EXPECT_EQ(it->first, j); | 
 |       EXPECT_EQ(it->second, j * 100); | 
 |     } | 
 |     EXPECT_EQ(sm.size(), static_cast<size_t>(i)); | 
 |     EXPECT_FALSE(sm.empty()); | 
 |   } | 
 | } | 
 |  | 
 | TEST(SmallMap, InsertRange) { | 
 |   // loop through the transition from small map to map. | 
 |   for (int elements = 0; elements <= 10; ++elements) { | 
 |     VLOG(1) << "Elements " << elements; | 
 |     std::unordered_map<int, int> normal_map; | 
 |     for (int i = 1; i <= elements; ++i) { | 
 |       normal_map.insert(std::make_pair(i, 100*i)); | 
 |     } | 
 |  | 
 |     small_map<std::unordered_map<int, int>> sm; | 
 |     sm.insert(normal_map.begin(), normal_map.end()); | 
 |     EXPECT_EQ(normal_map.size(), sm.size()); | 
 |     for (int i = 1; i <= elements; ++i) { | 
 |       VLOG(1) << "Iteration " << i; | 
 |       EXPECT_TRUE(sm.find(i) != sm.end()); | 
 |       EXPECT_EQ(sm.find(i)->first, i); | 
 |       EXPECT_EQ(sm.find(i)->second, 100*i); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | TEST(SmallMap, Erase) { | 
 |   small_map<std::unordered_map<std::string, int>> m; | 
 |   small_map<std::unordered_map<std::string, int>>::iterator iter; | 
 |  | 
 |   m["monday"] = 1; | 
 |   m["tuesday"] = 2; | 
 |   m["wednesday"] = 3; | 
 |  | 
 |   EXPECT_EQ(m["monday"   ], 1); | 
 |   EXPECT_EQ(m["tuesday"  ], 2); | 
 |   EXPECT_EQ(m["wednesday"], 3); | 
 |   EXPECT_EQ(m.count("tuesday"), 1u); | 
 |   EXPECT_FALSE(m.UsingFullMap()); | 
 |  | 
 |   iter = m.begin(); | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, "monday"); | 
 |   EXPECT_EQ(iter->second, 1); | 
 |   ++iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, "tuesday"); | 
 |   EXPECT_EQ(iter->second, 2); | 
 |   ++iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, "wednesday"); | 
 |   EXPECT_EQ(iter->second, 3); | 
 |   ++iter; | 
 |   EXPECT_TRUE(iter == m.end()); | 
 |  | 
 |   EXPECT_EQ(m.erase("tuesday"), 1u); | 
 |  | 
 |   EXPECT_EQ(m["monday"   ], 1); | 
 |   EXPECT_EQ(m["wednesday"], 3); | 
 |   EXPECT_EQ(m.count("tuesday"), 0u); | 
 |   EXPECT_EQ(m.erase("tuesday"), 0u); | 
 |  | 
 |   iter = m.begin(); | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, "monday"); | 
 |   EXPECT_EQ(iter->second, 1); | 
 |   ++iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, "wednesday"); | 
 |   EXPECT_EQ(iter->second, 3); | 
 |   ++iter; | 
 |   EXPECT_TRUE(iter == m.end()); | 
 |  | 
 |   m["thursday"] = 4; | 
 |   m["friday"] = 5; | 
 |   EXPECT_EQ(m.size(), 4u); | 
 |   EXPECT_FALSE(m.empty()); | 
 |   EXPECT_FALSE(m.UsingFullMap()); | 
 |  | 
 |   m["saturday"] = 6; | 
 |   EXPECT_TRUE(m.UsingFullMap()); | 
 |  | 
 |   EXPECT_EQ(m.count("friday"), 1u); | 
 |   EXPECT_EQ(m.erase("friday"), 1u); | 
 |   EXPECT_TRUE(m.UsingFullMap()); | 
 |   EXPECT_EQ(m.count("friday"), 0u); | 
 |   EXPECT_EQ(m.erase("friday"), 0u); | 
 |  | 
 |   EXPECT_EQ(m.size(), 4u); | 
 |   EXPECT_FALSE(m.empty()); | 
 |   EXPECT_EQ(m.erase("monday"), 1u); | 
 |   EXPECT_EQ(m.size(), 3u); | 
 |   EXPECT_FALSE(m.empty()); | 
 |  | 
 |   m.clear(); | 
 |   EXPECT_FALSE(m.UsingFullMap()); | 
 |   EXPECT_EQ(m.size(), 0u); | 
 |   EXPECT_TRUE(m.empty()); | 
 | } | 
 |  | 
 | TEST(SmallMap, EraseReturnsIteratorFollowingRemovedElement) { | 
 |   small_map<std::unordered_map<std::string, int>> m; | 
 |   small_map<std::unordered_map<std::string, int>>::iterator iter; | 
 |  | 
 |   m["a"] = 0; | 
 |   m["b"] = 1; | 
 |   m["c"] = 2; | 
 |  | 
 |   // Erase first item. | 
 |   auto following_iter = m.erase(m.begin()); | 
 |   EXPECT_EQ(m.begin(), following_iter); | 
 |   EXPECT_EQ(2u, m.size()); | 
 |   EXPECT_EQ(m.count("a"), 0u); | 
 |   EXPECT_EQ(m.count("b"), 1u); | 
 |   EXPECT_EQ(m.count("c"), 1u); | 
 |  | 
 |   // Iterate to last item and erase it. | 
 |   ++following_iter; | 
 |   following_iter = m.erase(following_iter); | 
 |   ASSERT_EQ(1u, m.size()); | 
 |   EXPECT_EQ(m.end(), following_iter); | 
 |   EXPECT_EQ(m.count("b"), 0u); | 
 |   EXPECT_EQ(m.count("c"), 1u); | 
 |  | 
 |   // Erase remaining item. | 
 |   following_iter = m.erase(m.begin()); | 
 |   EXPECT_TRUE(m.empty()); | 
 |   EXPECT_EQ(m.end(), following_iter); | 
 | } | 
 |  | 
 | TEST(SmallMap, NonHashMap) { | 
 |   small_map<std::map<int, int>, 4, std::equal_to<int>> m; | 
 |   EXPECT_TRUE(m.empty()); | 
 |  | 
 |   m[9] = 2; | 
 |   m[0] = 5; | 
 |  | 
 |   EXPECT_EQ(m[9], 2); | 
 |   EXPECT_EQ(m[0], 5); | 
 |   EXPECT_EQ(m.size(), 2u); | 
 |   EXPECT_FALSE(m.empty()); | 
 |   EXPECT_FALSE(m.UsingFullMap()); | 
 |  | 
 |   small_map<std::map<int, int>, 4, std::equal_to<int>>::iterator iter( | 
 |       m.begin()); | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, 9); | 
 |   EXPECT_EQ(iter->second, 2); | 
 |   ++iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, 0); | 
 |   EXPECT_EQ(iter->second, 5); | 
 |   ++iter; | 
 |   EXPECT_TRUE(iter == m.end()); | 
 |   --iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, 0); | 
 |   EXPECT_EQ(iter->second, 5); | 
 |  | 
 |   m[8] = 23; | 
 |   m[1234] = 90; | 
 |   m[-5] = 6; | 
 |  | 
 |   EXPECT_EQ(m[   9],  2); | 
 |   EXPECT_EQ(m[   0],  5); | 
 |   EXPECT_EQ(m[1234], 90); | 
 |   EXPECT_EQ(m[   8], 23); | 
 |   EXPECT_EQ(m[  -5],  6); | 
 |   EXPECT_EQ(m.size(), 5u); | 
 |   EXPECT_FALSE(m.empty()); | 
 |   EXPECT_TRUE(m.UsingFullMap()); | 
 |  | 
 |   iter = m.begin(); | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, -5); | 
 |   EXPECT_EQ(iter->second, 6); | 
 |   ++iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, 0); | 
 |   EXPECT_EQ(iter->second, 5); | 
 |   ++iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, 8); | 
 |   EXPECT_EQ(iter->second, 23); | 
 |   ++iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, 9); | 
 |   EXPECT_EQ(iter->second, 2); | 
 |   ++iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, 1234); | 
 |   EXPECT_EQ(iter->second, 90); | 
 |   ++iter; | 
 |   EXPECT_TRUE(iter == m.end()); | 
 |   --iter; | 
 |   ASSERT_TRUE(iter != m.end()); | 
 |   EXPECT_EQ(iter->first, 1234); | 
 |   EXPECT_EQ(iter->second, 90); | 
 | } | 
 |  | 
 | TEST(SmallMap, DefaultEqualKeyWorks) { | 
 |   // If these tests compile, they pass. The EXPECT calls are only there to avoid | 
 |   // unused variable warnings. | 
 |   small_map<std::unordered_map<int, int>> hm; | 
 |   EXPECT_EQ(0u, hm.size()); | 
 |   small_map<std::map<int, int>> m; | 
 |   EXPECT_EQ(0u, m.size()); | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | class unordered_map_add_item : public std::unordered_map<int, int> { | 
 |  public: | 
 |   unordered_map_add_item() = default; | 
 |   explicit unordered_map_add_item(const std::pair<int, int>& item) { | 
 |     insert(item); | 
 |   } | 
 | }; | 
 |  | 
 | void InitMap(unordered_map_add_item* map_ctor) { | 
 |   new (map_ctor) unordered_map_add_item(std::make_pair(0, 0)); | 
 | } | 
 |  | 
 | class unordered_map_add_item_initializer { | 
 |  public: | 
 |   explicit unordered_map_add_item_initializer(int item_to_add) | 
 |       : item_(item_to_add) {} | 
 |   unordered_map_add_item_initializer() : item_(0) {} | 
 |   void operator()(unordered_map_add_item* map_ctor) const { | 
 |     new (map_ctor) unordered_map_add_item(std::make_pair(item_, item_)); | 
 |   } | 
 |  | 
 |   int item_; | 
 | }; | 
 |  | 
 | }  // anonymous namespace | 
 |  | 
 | TEST(SmallMap, SubclassInitializationWithFunctionPointer) { | 
 |   small_map<unordered_map_add_item, 4, std::equal_to<int>, | 
 |             void (&)(unordered_map_add_item*)> | 
 |       m(InitMap); | 
 |  | 
 |   EXPECT_TRUE(m.empty()); | 
 |  | 
 |   m[1] = 1; | 
 |   m[2] = 2; | 
 |   m[3] = 3; | 
 |   m[4] = 4; | 
 |  | 
 |   EXPECT_EQ(4u, m.size()); | 
 |   EXPECT_EQ(0u, m.count(0)); | 
 |  | 
 |   m[5] = 5; | 
 |   EXPECT_EQ(6u, m.size()); | 
 |   // Our function adds an extra item when we convert to a map. | 
 |   EXPECT_EQ(1u, m.count(0)); | 
 | } | 
 |  | 
 | TEST(SmallMap, SubclassInitializationWithFunctionObject) { | 
 |   small_map<unordered_map_add_item, 4, std::equal_to<int>, | 
 |             unordered_map_add_item_initializer> | 
 |       m(unordered_map_add_item_initializer(-1)); | 
 |  | 
 |   EXPECT_TRUE(m.empty()); | 
 |  | 
 |   m[1] = 1; | 
 |   m[2] = 2; | 
 |   m[3] = 3; | 
 |   m[4] = 4; | 
 |  | 
 |   EXPECT_EQ(4u, m.size()); | 
 |   EXPECT_EQ(0u, m.count(-1)); | 
 |  | 
 |   m[5] = 5; | 
 |   EXPECT_EQ(6u, m.size()); | 
 |   // Our functor adds an extra item when we convert to a map. | 
 |   EXPECT_EQ(1u, m.count(-1)); | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | // This class acts as a basic implementation of a move-only type. The canonical | 
 | // example of such a type is scoped_ptr/unique_ptr. | 
 | template <typename V> | 
 | class MoveOnlyType { | 
 |  public: | 
 |   MoveOnlyType() : value_(0) {} | 
 |   explicit MoveOnlyType(V value) : value_(value) {} | 
 |  | 
 |   MoveOnlyType(MoveOnlyType&& other) { | 
 |     *this = std::move(other); | 
 |   } | 
 |  | 
 |   MoveOnlyType& operator=(MoveOnlyType&& other) { | 
 |     value_ = other.value_; | 
 |     other.value_ = 0; | 
 |     return *this; | 
 |   } | 
 |  | 
 |   MoveOnlyType(const MoveOnlyType&) = delete; | 
 |   MoveOnlyType& operator=(const MoveOnlyType&) = delete; | 
 |  | 
 |   V value() const { return value_; } | 
 |  | 
 |  private: | 
 |   V value_; | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | TEST(SmallMap, MoveOnlyValueType) { | 
 |   small_map<std::map<int, MoveOnlyType<int>>, 2> m; | 
 |  | 
 |   m[0] = MoveOnlyType<int>(1); | 
 |   m[1] = MoveOnlyType<int>(2); | 
 |   m.erase(m.begin()); | 
 |  | 
 |   // small_map will move m[1] to an earlier index in the internal array. | 
 |   EXPECT_EQ(m.size(), 1u); | 
 |   EXPECT_EQ(m[1].value(), 2); | 
 |  | 
 |   m[0] = MoveOnlyType<int>(1); | 
 |   // small_map must move the values from the array into the internal std::map. | 
 |   m[2] = MoveOnlyType<int>(3); | 
 |  | 
 |   EXPECT_EQ(m.size(), 3u); | 
 |   EXPECT_EQ(m[0].value(), 1); | 
 |   EXPECT_EQ(m[1].value(), 2); | 
 |   EXPECT_EQ(m[2].value(), 3); | 
 |  | 
 |   m.erase(m.begin()); | 
 |  | 
 |   // small_map should also let internal std::map erase with a move-only type. | 
 |   EXPECT_EQ(m.size(), 2u); | 
 |   EXPECT_EQ(m[1].value(), 2); | 
 |   EXPECT_EQ(m[2].value(), 3); | 
 | } | 
 |  | 
 | TEST(SmallMap, Emplace) { | 
 |   small_map<std::map<size_t, MoveOnlyType<size_t>>> sm; | 
 |  | 
 |   // loop through the transition from small map to map. | 
 |   for (size_t i = 1; i <= 10; ++i) { | 
 |     // insert an element | 
 |     auto ret = sm.emplace(i, MoveOnlyType<size_t>(100 * i)); | 
 |     EXPECT_TRUE(ret.second); | 
 |     EXPECT_TRUE(ret.first == sm.find(i)); | 
 |     EXPECT_EQ(ret.first->first, i); | 
 |     EXPECT_EQ(ret.first->second.value(), 100 * i); | 
 |  | 
 |     // try to insert it again with different value, fails, but we still get an | 
 |     // iterator back with the original value. | 
 |     ret = sm.emplace(i, MoveOnlyType<size_t>(i)); | 
 |     EXPECT_FALSE(ret.second); | 
 |     EXPECT_TRUE(ret.first == sm.find(i)); | 
 |     EXPECT_EQ(ret.first->first, i); | 
 |     EXPECT_EQ(ret.first->second.value(), 100 * i); | 
 |  | 
 |     // check the state of the map. | 
 |     for (size_t j = 1; j <= i; ++j) { | 
 |       const auto it = sm.find(j); | 
 |       EXPECT_TRUE(it != sm.end()); | 
 |       EXPECT_EQ(it->first, j); | 
 |       EXPECT_EQ(it->second.value(), j * 100); | 
 |     } | 
 |     EXPECT_EQ(sm.size(), i); | 
 |     EXPECT_FALSE(sm.empty()); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace base |