You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
604 lines
15 KiB
604 lines
15 KiB
4 months ago
|
// 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
|