17612cfd3SVitaly Buka //===- sanitizer_dense_map_test.cpp -----------------------------*- C++ -*-===//
254adc167SVitaly Buka //
354adc167SVitaly Buka // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
454adc167SVitaly Buka // See https://llvm.org/LICENSE.txt for license information.
554adc167SVitaly Buka // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
654adc167SVitaly Buka //
754adc167SVitaly Buka //===----------------------------------------------------------------------===//
854adc167SVitaly Buka
97612cfd3SVitaly Buka #include "sanitizer_common/sanitizer_dense_map.h"
107612cfd3SVitaly Buka
117612cfd3SVitaly Buka #include <initializer_list>
1254adc167SVitaly Buka #include <map>
1354adc167SVitaly Buka #include <set>
1454adc167SVitaly Buka
15234a8301SVitaly Buka #include "gtest/gtest.h"
16234a8301SVitaly Buka
177612cfd3SVitaly Buka using namespace __sanitizer;
1854adc167SVitaly Buka
1954adc167SVitaly Buka namespace {
2054adc167SVitaly Buka
21c26dbc4aSVitaly Buka // Helps to keep some tests.
22c26dbc4aSVitaly Buka template <typename KeyT, typename ValueT,
23c26dbc4aSVitaly Buka typename KeyInfoT = DenseMapInfo<KeyT>>
24c26dbc4aSVitaly Buka class TestDenseMap : public DenseMap<KeyT, ValueT, KeyInfoT> {
25c26dbc4aSVitaly Buka using BaseT = DenseMap<KeyT, ValueT, KeyInfoT>;
26c26dbc4aSVitaly Buka
27c26dbc4aSVitaly Buka public:
28c26dbc4aSVitaly Buka using BaseT::BaseT;
29c26dbc4aSVitaly Buka
TestDenseMap(std::initializer_list<typename BaseT::value_type> Vals)30c26dbc4aSVitaly Buka TestDenseMap(std::initializer_list<typename BaseT::value_type> Vals)
31c26dbc4aSVitaly Buka : BaseT(Vals.size()) {
32c26dbc4aSVitaly Buka for (const auto &V : Vals) this->BaseT::insert(V);
33c26dbc4aSVitaly Buka }
34c26dbc4aSVitaly Buka
35c26dbc4aSVitaly Buka template <typename I>
TestDenseMap(I B,I E)36c26dbc4aSVitaly Buka TestDenseMap(I B, I E) : BaseT(std::distance(B, E)) {
37c26dbc4aSVitaly Buka for (; B != E; ++B) this->BaseT::insert(*B);
38c26dbc4aSVitaly Buka }
39c26dbc4aSVitaly Buka };
40c26dbc4aSVitaly Buka
41c26dbc4aSVitaly Buka template <typename... T>
42c26dbc4aSVitaly Buka using DenseMap = TestDenseMap<T...>;
43c26dbc4aSVitaly Buka
getTestKey(int i,uint32_t *)4454adc167SVitaly Buka uint32_t getTestKey(int i, uint32_t *) { return i; }
getTestValue(int i,uint32_t *)4554adc167SVitaly Buka uint32_t getTestValue(int i, uint32_t *) { return 42 + i; }
4654adc167SVitaly Buka
getTestKey(int i,uint32_t **)4754adc167SVitaly Buka uint32_t *getTestKey(int i, uint32_t **) {
4854adc167SVitaly Buka static uint32_t dummy_arr1[8192];
4954adc167SVitaly Buka assert(i < 8192 && "Only support 8192 dummy keys.");
5054adc167SVitaly Buka return &dummy_arr1[i];
5154adc167SVitaly Buka }
getTestValue(int i,uint32_t **)5254adc167SVitaly Buka uint32_t *getTestValue(int i, uint32_t **) {
5354adc167SVitaly Buka static uint32_t dummy_arr1[8192];
5454adc167SVitaly Buka assert(i < 8192 && "Only support 8192 dummy keys.");
5554adc167SVitaly Buka return &dummy_arr1[i];
5654adc167SVitaly Buka }
5754adc167SVitaly Buka
5854adc167SVitaly Buka /// A test class that tries to check that construction and destruction
5954adc167SVitaly Buka /// occur correctly.
6054adc167SVitaly Buka class CtorTester {
6154adc167SVitaly Buka static std::set<CtorTester *> Constructed;
6254adc167SVitaly Buka int Value;
6354adc167SVitaly Buka
6454adc167SVitaly Buka public:
CtorTester(int Value=0)6554adc167SVitaly Buka explicit CtorTester(int Value = 0) : Value(Value) {
6654adc167SVitaly Buka EXPECT_TRUE(Constructed.insert(this).second);
6754adc167SVitaly Buka }
CtorTester(uint32_t Value)6854adc167SVitaly Buka CtorTester(uint32_t Value) : Value(Value) {
6954adc167SVitaly Buka EXPECT_TRUE(Constructed.insert(this).second);
7054adc167SVitaly Buka }
CtorTester(const CtorTester & Arg)7154adc167SVitaly Buka CtorTester(const CtorTester &Arg) : Value(Arg.Value) {
7254adc167SVitaly Buka EXPECT_TRUE(Constructed.insert(this).second);
7354adc167SVitaly Buka }
7454adc167SVitaly Buka CtorTester &operator=(const CtorTester &) = default;
~CtorTester()75234a8301SVitaly Buka ~CtorTester() { EXPECT_EQ(1u, Constructed.erase(this)); }
operator uint32_t() const7654adc167SVitaly Buka operator uint32_t() const { return Value; }
7754adc167SVitaly Buka
getValue() const7854adc167SVitaly Buka int getValue() const { return Value; }
operator ==(const CtorTester & RHS) const7954adc167SVitaly Buka bool operator==(const CtorTester &RHS) const { return Value == RHS.Value; }
8054adc167SVitaly Buka };
8154adc167SVitaly Buka
8254adc167SVitaly Buka std::set<CtorTester *> CtorTester::Constructed;
8354adc167SVitaly Buka
8454adc167SVitaly Buka struct CtorTesterMapInfo {
getEmptyKey__anon65fcc02b0111::CtorTesterMapInfo8554adc167SVitaly Buka static inline CtorTester getEmptyKey() { return CtorTester(-1); }
getTombstoneKey__anon65fcc02b0111::CtorTesterMapInfo8654adc167SVitaly Buka static inline CtorTester getTombstoneKey() { return CtorTester(-2); }
getHashValue__anon65fcc02b0111::CtorTesterMapInfo8754adc167SVitaly Buka static unsigned getHashValue(const CtorTester &Val) {
8854adc167SVitaly Buka return Val.getValue() * 37u;
8954adc167SVitaly Buka }
isEqual__anon65fcc02b0111::CtorTesterMapInfo9054adc167SVitaly Buka static bool isEqual(const CtorTester &LHS, const CtorTester &RHS) {
9154adc167SVitaly Buka return LHS == RHS;
9254adc167SVitaly Buka }
9354adc167SVitaly Buka };
9454adc167SVitaly Buka
getTestKey(int i,CtorTester *)9554adc167SVitaly Buka CtorTester getTestKey(int i, CtorTester *) { return CtorTester(i); }
getTestValue(int i,CtorTester *)9654adc167SVitaly Buka CtorTester getTestValue(int i, CtorTester *) { return CtorTester(42 + i); }
9754adc167SVitaly Buka
9854adc167SVitaly Buka // Test fixture, with helper functions implemented by forwarding to global
9954adc167SVitaly Buka // function overloads selected by component types of the type parameter. This
10054adc167SVitaly Buka // allows all of the map implementations to be tested with shared
10154adc167SVitaly Buka // implementations of helper routines.
10254adc167SVitaly Buka template <typename T>
10354adc167SVitaly Buka class DenseMapTest : public ::testing::Test {
10454adc167SVitaly Buka protected:
10554adc167SVitaly Buka T Map;
10654adc167SVitaly Buka
10754adc167SVitaly Buka static typename T::key_type *const dummy_key_ptr;
10854adc167SVitaly Buka static typename T::mapped_type *const dummy_value_ptr;
10954adc167SVitaly Buka
getKey(int i=0)11054adc167SVitaly Buka typename T::key_type getKey(int i = 0) {
11154adc167SVitaly Buka return getTestKey(i, dummy_key_ptr);
11254adc167SVitaly Buka }
getValue(int i=0)11354adc167SVitaly Buka typename T::mapped_type getValue(int i = 0) {
11454adc167SVitaly Buka return getTestValue(i, dummy_value_ptr);
11554adc167SVitaly Buka }
11654adc167SVitaly Buka };
11754adc167SVitaly Buka
11854adc167SVitaly Buka template <typename T>
11954adc167SVitaly Buka typename T::key_type *const DenseMapTest<T>::dummy_key_ptr = nullptr;
12054adc167SVitaly Buka template <typename T>
12154adc167SVitaly Buka typename T::mapped_type *const DenseMapTest<T>::dummy_value_ptr = nullptr;
12254adc167SVitaly Buka
12354adc167SVitaly Buka // Register these types for testing.
124c26dbc4aSVitaly Buka typedef ::testing::Types<DenseMap<uint32_t, uint32_t>,
125c26dbc4aSVitaly Buka DenseMap<uint32_t *, uint32_t *>,
126c26dbc4aSVitaly Buka DenseMap<CtorTester, CtorTester, CtorTesterMapInfo>>
127234a8301SVitaly Buka DenseMapTestTypes;
12854adc167SVitaly Buka TYPED_TEST_SUITE(DenseMapTest, DenseMapTestTypes, );
12954adc167SVitaly Buka
13054adc167SVitaly Buka // Empty map tests
TYPED_TEST(DenseMapTest,EmptyIntMapTest)13154adc167SVitaly Buka TYPED_TEST(DenseMapTest, EmptyIntMapTest) {
13254adc167SVitaly Buka // Size tests
13354adc167SVitaly Buka EXPECT_EQ(0u, this->Map.size());
13454adc167SVitaly Buka EXPECT_TRUE(this->Map.empty());
13554adc167SVitaly Buka
13654adc167SVitaly Buka // Lookup tests
13754adc167SVitaly Buka EXPECT_FALSE(this->Map.count(this->getKey()));
138c26dbc4aSVitaly Buka EXPECT_EQ(nullptr, this->Map.find(this->getKey()));
13954adc167SVitaly Buka EXPECT_EQ(typename TypeParam::mapped_type(),
14054adc167SVitaly Buka this->Map.lookup(this->getKey()));
14154adc167SVitaly Buka }
14254adc167SVitaly Buka
14354adc167SVitaly Buka // Constant map tests
TYPED_TEST(DenseMapTest,ConstEmptyMapTest)14454adc167SVitaly Buka TYPED_TEST(DenseMapTest, ConstEmptyMapTest) {
14554adc167SVitaly Buka const TypeParam &ConstMap = this->Map;
14654adc167SVitaly Buka EXPECT_EQ(0u, ConstMap.size());
14754adc167SVitaly Buka EXPECT_TRUE(ConstMap.empty());
14854adc167SVitaly Buka }
14954adc167SVitaly Buka
15054adc167SVitaly Buka // A map with a single entry
TYPED_TEST(DenseMapTest,SingleEntryMapTest)15154adc167SVitaly Buka TYPED_TEST(DenseMapTest, SingleEntryMapTest) {
15254adc167SVitaly Buka this->Map[this->getKey()] = this->getValue();
15354adc167SVitaly Buka
15454adc167SVitaly Buka // Size tests
15554adc167SVitaly Buka EXPECT_EQ(1u, this->Map.size());
15654adc167SVitaly Buka EXPECT_FALSE(this->Map.empty());
15754adc167SVitaly Buka
15854adc167SVitaly Buka // Lookup tests
15954adc167SVitaly Buka EXPECT_TRUE(this->Map.count(this->getKey()));
160c26dbc4aSVitaly Buka EXPECT_NE(nullptr, this->Map.find(this->getKey()));
16154adc167SVitaly Buka EXPECT_EQ(this->getValue(), this->Map.lookup(this->getKey()));
16254adc167SVitaly Buka EXPECT_EQ(this->getValue(), this->Map[this->getKey()]);
16354adc167SVitaly Buka }
16454adc167SVitaly Buka
16554adc167SVitaly Buka // Test clear() method
TYPED_TEST(DenseMapTest,ClearTest)16654adc167SVitaly Buka TYPED_TEST(DenseMapTest, ClearTest) {
16754adc167SVitaly Buka this->Map[this->getKey()] = this->getValue();
16854adc167SVitaly Buka this->Map.clear();
16954adc167SVitaly Buka
17054adc167SVitaly Buka EXPECT_EQ(0u, this->Map.size());
17154adc167SVitaly Buka EXPECT_TRUE(this->Map.empty());
17254adc167SVitaly Buka }
17354adc167SVitaly Buka
17454adc167SVitaly Buka // Test erase(iterator) method
TYPED_TEST(DenseMapTest,EraseTest)17554adc167SVitaly Buka TYPED_TEST(DenseMapTest, EraseTest) {
17654adc167SVitaly Buka this->Map[this->getKey()] = this->getValue();
177c26dbc4aSVitaly Buka this->Map.erase(this->Map.find(this->getKey()));
17854adc167SVitaly Buka
17954adc167SVitaly Buka EXPECT_EQ(0u, this->Map.size());
18054adc167SVitaly Buka EXPECT_TRUE(this->Map.empty());
18154adc167SVitaly Buka }
18254adc167SVitaly Buka
18354adc167SVitaly Buka // Test erase(value) method
TYPED_TEST(DenseMapTest,EraseTest2)18454adc167SVitaly Buka TYPED_TEST(DenseMapTest, EraseTest2) {
18554adc167SVitaly Buka this->Map[this->getKey()] = this->getValue();
18654adc167SVitaly Buka this->Map.erase(this->getKey());
18754adc167SVitaly Buka
18854adc167SVitaly Buka EXPECT_EQ(0u, this->Map.size());
18954adc167SVitaly Buka EXPECT_TRUE(this->Map.empty());
19054adc167SVitaly Buka }
19154adc167SVitaly Buka
19254adc167SVitaly Buka // Test insert() method
TYPED_TEST(DenseMapTest,InsertTest)19354adc167SVitaly Buka TYPED_TEST(DenseMapTest, InsertTest) {
194c26dbc4aSVitaly Buka this->Map.insert(
195c26dbc4aSVitaly Buka typename TypeParam::value_type(this->getKey(), this->getValue()));
19654adc167SVitaly Buka EXPECT_EQ(1u, this->Map.size());
19754adc167SVitaly Buka EXPECT_EQ(this->getValue(), this->Map[this->getKey()]);
19854adc167SVitaly Buka }
19954adc167SVitaly Buka
20054adc167SVitaly Buka // Test copy constructor method
TYPED_TEST(DenseMapTest,CopyConstructorTest)20154adc167SVitaly Buka TYPED_TEST(DenseMapTest, CopyConstructorTest) {
20254adc167SVitaly Buka this->Map[this->getKey()] = this->getValue();
20354adc167SVitaly Buka TypeParam copyMap(this->Map);
20454adc167SVitaly Buka
20554adc167SVitaly Buka EXPECT_EQ(1u, copyMap.size());
20654adc167SVitaly Buka EXPECT_EQ(this->getValue(), copyMap[this->getKey()]);
20754adc167SVitaly Buka }
20854adc167SVitaly Buka
20954adc167SVitaly Buka // Test copy constructor method where SmallDenseMap isn't small.
TYPED_TEST(DenseMapTest,CopyConstructorNotSmallTest)21054adc167SVitaly Buka TYPED_TEST(DenseMapTest, CopyConstructorNotSmallTest) {
21154adc167SVitaly Buka for (int Key = 0; Key < 5; ++Key)
21254adc167SVitaly Buka this->Map[this->getKey(Key)] = this->getValue(Key);
21354adc167SVitaly Buka TypeParam copyMap(this->Map);
21454adc167SVitaly Buka
21554adc167SVitaly Buka EXPECT_EQ(5u, copyMap.size());
21654adc167SVitaly Buka for (int Key = 0; Key < 5; ++Key)
21754adc167SVitaly Buka EXPECT_EQ(this->getValue(Key), copyMap[this->getKey(Key)]);
21854adc167SVitaly Buka }
21954adc167SVitaly Buka
22054adc167SVitaly Buka // Test copying from a default-constructed map.
TYPED_TEST(DenseMapTest,CopyConstructorFromDefaultTest)22154adc167SVitaly Buka TYPED_TEST(DenseMapTest, CopyConstructorFromDefaultTest) {
22254adc167SVitaly Buka TypeParam copyMap(this->Map);
22354adc167SVitaly Buka
22454adc167SVitaly Buka EXPECT_TRUE(copyMap.empty());
22554adc167SVitaly Buka }
22654adc167SVitaly Buka
22754adc167SVitaly Buka // Test copying from an empty map where SmallDenseMap isn't small.
TYPED_TEST(DenseMapTest,CopyConstructorFromEmptyTest)22854adc167SVitaly Buka TYPED_TEST(DenseMapTest, CopyConstructorFromEmptyTest) {
22954adc167SVitaly Buka for (int Key = 0; Key < 5; ++Key)
23054adc167SVitaly Buka this->Map[this->getKey(Key)] = this->getValue(Key);
23154adc167SVitaly Buka this->Map.clear();
23254adc167SVitaly Buka TypeParam copyMap(this->Map);
23354adc167SVitaly Buka
23454adc167SVitaly Buka EXPECT_TRUE(copyMap.empty());
23554adc167SVitaly Buka }
23654adc167SVitaly Buka
23754adc167SVitaly Buka // Test assignment operator method
TYPED_TEST(DenseMapTest,AssignmentTest)23854adc167SVitaly Buka TYPED_TEST(DenseMapTest, AssignmentTest) {
23954adc167SVitaly Buka this->Map[this->getKey()] = this->getValue();
24054adc167SVitaly Buka TypeParam copyMap = this->Map;
24154adc167SVitaly Buka
24254adc167SVitaly Buka EXPECT_EQ(1u, copyMap.size());
24354adc167SVitaly Buka EXPECT_EQ(this->getValue(), copyMap[this->getKey()]);
24454adc167SVitaly Buka
24554adc167SVitaly Buka // test self-assignment.
24654adc167SVitaly Buka copyMap = static_cast<TypeParam &>(copyMap);
24754adc167SVitaly Buka EXPECT_EQ(1u, copyMap.size());
24854adc167SVitaly Buka EXPECT_EQ(this->getValue(), copyMap[this->getKey()]);
24954adc167SVitaly Buka }
25054adc167SVitaly Buka
TYPED_TEST(DenseMapTest,AssignmentTestNotSmall)25154adc167SVitaly Buka TYPED_TEST(DenseMapTest, AssignmentTestNotSmall) {
25254adc167SVitaly Buka for (int Key = 0; Key < 5; ++Key)
25354adc167SVitaly Buka this->Map[this->getKey(Key)] = this->getValue(Key);
25454adc167SVitaly Buka TypeParam copyMap = this->Map;
25554adc167SVitaly Buka
25654adc167SVitaly Buka EXPECT_EQ(5u, copyMap.size());
25754adc167SVitaly Buka for (int Key = 0; Key < 5; ++Key)
25854adc167SVitaly Buka EXPECT_EQ(this->getValue(Key), copyMap[this->getKey(Key)]);
25954adc167SVitaly Buka
26054adc167SVitaly Buka // test self-assignment.
26154adc167SVitaly Buka copyMap = static_cast<TypeParam &>(copyMap);
26254adc167SVitaly Buka EXPECT_EQ(5u, copyMap.size());
26354adc167SVitaly Buka for (int Key = 0; Key < 5; ++Key)
26454adc167SVitaly Buka EXPECT_EQ(this->getValue(Key), copyMap[this->getKey(Key)]);
26554adc167SVitaly Buka }
26654adc167SVitaly Buka
26754adc167SVitaly Buka // Test swap method
TYPED_TEST(DenseMapTest,SwapTest)26854adc167SVitaly Buka TYPED_TEST(DenseMapTest, SwapTest) {
26954adc167SVitaly Buka this->Map[this->getKey()] = this->getValue();
27054adc167SVitaly Buka TypeParam otherMap;
27154adc167SVitaly Buka
27254adc167SVitaly Buka this->Map.swap(otherMap);
27354adc167SVitaly Buka EXPECT_EQ(0u, this->Map.size());
27454adc167SVitaly Buka EXPECT_TRUE(this->Map.empty());
27554adc167SVitaly Buka EXPECT_EQ(1u, otherMap.size());
27654adc167SVitaly Buka EXPECT_EQ(this->getValue(), otherMap[this->getKey()]);
27754adc167SVitaly Buka
27854adc167SVitaly Buka this->Map.swap(otherMap);
27954adc167SVitaly Buka EXPECT_EQ(0u, otherMap.size());
28054adc167SVitaly Buka EXPECT_TRUE(otherMap.empty());
28154adc167SVitaly Buka EXPECT_EQ(1u, this->Map.size());
28254adc167SVitaly Buka EXPECT_EQ(this->getValue(), this->Map[this->getKey()]);
28354adc167SVitaly Buka
28454adc167SVitaly Buka // Make this more interesting by inserting 100 numbers into the map.
285234a8301SVitaly Buka for (int i = 0; i < 100; ++i) this->Map[this->getKey(i)] = this->getValue(i);
28654adc167SVitaly Buka
28754adc167SVitaly Buka this->Map.swap(otherMap);
28854adc167SVitaly Buka EXPECT_EQ(0u, this->Map.size());
28954adc167SVitaly Buka EXPECT_TRUE(this->Map.empty());
29054adc167SVitaly Buka EXPECT_EQ(100u, otherMap.size());
29154adc167SVitaly Buka for (int i = 0; i < 100; ++i)
29254adc167SVitaly Buka EXPECT_EQ(this->getValue(i), otherMap[this->getKey(i)]);
29354adc167SVitaly Buka
29454adc167SVitaly Buka this->Map.swap(otherMap);
29554adc167SVitaly Buka EXPECT_EQ(0u, otherMap.size());
29654adc167SVitaly Buka EXPECT_TRUE(otherMap.empty());
29754adc167SVitaly Buka EXPECT_EQ(100u, this->Map.size());
29854adc167SVitaly Buka for (int i = 0; i < 100; ++i)
29954adc167SVitaly Buka EXPECT_EQ(this->getValue(i), this->Map[this->getKey(i)]);
30054adc167SVitaly Buka }
30154adc167SVitaly Buka
30209256fe9SVitaly Buka // A more complex iteration test
TYPED_TEST(DenseMapTest,IterationTest)30309256fe9SVitaly Buka TYPED_TEST(DenseMapTest, IterationTest) {
30409256fe9SVitaly Buka int visited[100];
30509256fe9SVitaly Buka std::map<typename TypeParam::key_type, unsigned> visitedIndex;
30609256fe9SVitaly Buka
30709256fe9SVitaly Buka // Insert 100 numbers into the map
30809256fe9SVitaly Buka for (int i = 0; i < 100; ++i) {
30909256fe9SVitaly Buka visited[i] = 0;
31009256fe9SVitaly Buka visitedIndex[this->getKey(i)] = i;
31109256fe9SVitaly Buka
31209256fe9SVitaly Buka this->Map[this->getKey(i)] = this->getValue(i);
31309256fe9SVitaly Buka }
31409256fe9SVitaly Buka
31509256fe9SVitaly Buka // Iterate over all numbers and mark each one found.
31609256fe9SVitaly Buka this->Map.forEach([&](const typename TypeParam::value_type &kv) {
31709256fe9SVitaly Buka ++visited[visitedIndex[kv.first]];
31809256fe9SVitaly Buka return true;
31909256fe9SVitaly Buka });
32009256fe9SVitaly Buka
32109256fe9SVitaly Buka // Ensure every number was visited.
32209256fe9SVitaly Buka for (int i = 0; i < 100; ++i) ASSERT_EQ(1, visited[i]);
32309256fe9SVitaly Buka }
32409256fe9SVitaly Buka
32554adc167SVitaly Buka namespace {
32654adc167SVitaly Buka // Simple class that counts how many moves and copy happens when growing a map
32754adc167SVitaly Buka struct CountCopyAndMove {
32854adc167SVitaly Buka static int Move;
32954adc167SVitaly Buka static int Copy;
CountCopyAndMove__anon65fcc02b0111::__anon65fcc02b0311::CountCopyAndMove33054adc167SVitaly Buka CountCopyAndMove() {}
33154adc167SVitaly Buka
CountCopyAndMove__anon65fcc02b0111::__anon65fcc02b0311::CountCopyAndMove33254adc167SVitaly Buka CountCopyAndMove(const CountCopyAndMove &) { Copy++; }
operator =__anon65fcc02b0111::__anon65fcc02b0311::CountCopyAndMove33354adc167SVitaly Buka CountCopyAndMove &operator=(const CountCopyAndMove &) {
33454adc167SVitaly Buka Copy++;
33554adc167SVitaly Buka return *this;
33654adc167SVitaly Buka }
CountCopyAndMove__anon65fcc02b0111::__anon65fcc02b0311::CountCopyAndMove33754adc167SVitaly Buka CountCopyAndMove(CountCopyAndMove &&) { Move++; }
operator =__anon65fcc02b0111::__anon65fcc02b0311::CountCopyAndMove33854adc167SVitaly Buka CountCopyAndMove &operator=(const CountCopyAndMove &&) {
33954adc167SVitaly Buka Move++;
34054adc167SVitaly Buka return *this;
34154adc167SVitaly Buka }
34254adc167SVitaly Buka };
34354adc167SVitaly Buka int CountCopyAndMove::Copy = 0;
34454adc167SVitaly Buka int CountCopyAndMove::Move = 0;
34554adc167SVitaly Buka
34654adc167SVitaly Buka } // anonymous namespace
34754adc167SVitaly Buka
34854adc167SVitaly Buka // Test initializer list construction.
TEST(DenseMapCustomTest,InitializerList)34954adc167SVitaly Buka TEST(DenseMapCustomTest, InitializerList) {
35054adc167SVitaly Buka DenseMap<int, int> M({{0, 0}, {0, 1}, {1, 2}});
35154adc167SVitaly Buka EXPECT_EQ(2u, M.size());
35254adc167SVitaly Buka EXPECT_EQ(1u, M.count(0));
35354adc167SVitaly Buka EXPECT_EQ(0, M[0]);
35454adc167SVitaly Buka EXPECT_EQ(1u, M.count(1));
35554adc167SVitaly Buka EXPECT_EQ(2, M[1]);
35654adc167SVitaly Buka }
35754adc167SVitaly Buka
35854adc167SVitaly Buka // Test initializer list construction.
TEST(DenseMapCustomTest,EqualityComparison)35954adc167SVitaly Buka TEST(DenseMapCustomTest, EqualityComparison) {
36054adc167SVitaly Buka DenseMap<int, int> M1({{0, 0}, {1, 2}});
36154adc167SVitaly Buka DenseMap<int, int> M2({{0, 0}, {1, 2}});
36254adc167SVitaly Buka DenseMap<int, int> M3({{0, 0}, {1, 3}});
36354adc167SVitaly Buka
36454adc167SVitaly Buka EXPECT_EQ(M1, M2);
36554adc167SVitaly Buka EXPECT_NE(M1, M3);
36654adc167SVitaly Buka }
36754adc167SVitaly Buka
368*0d4b6f1fSRainer Orth const int ExpectedInitialBucketCount = GetPageSizeCached() / /* sizeof(KV) */ 8;
369*0d4b6f1fSRainer Orth
37054adc167SVitaly Buka // Test for the default minimum size of a DenseMap
TEST(DenseMapCustomTest,DefaultMinReservedSizeTest)37154adc167SVitaly Buka TEST(DenseMapCustomTest, DefaultMinReservedSizeTest) {
37254adc167SVitaly Buka // Formula from DenseMap::getMinBucketToReserveForEntries()
37354adc167SVitaly Buka const int ExpectedMaxInitialEntries = ExpectedInitialBucketCount * 3 / 4 - 1;
37454adc167SVitaly Buka
37554adc167SVitaly Buka DenseMap<int, CountCopyAndMove> Map;
37654adc167SVitaly Buka // Will allocate 64 buckets
37754adc167SVitaly Buka Map.reserve(1);
37854adc167SVitaly Buka unsigned MemorySize = Map.getMemorySize();
37954adc167SVitaly Buka CountCopyAndMove::Copy = 0;
38054adc167SVitaly Buka CountCopyAndMove::Move = 0;
381c26dbc4aSVitaly Buka for (int i = 0; i < ExpectedMaxInitialEntries; ++i) {
382c26dbc4aSVitaly Buka detail::DenseMapPair<int, CountCopyAndMove> KV;
383c26dbc4aSVitaly Buka KV.first = i;
384c26dbc4aSVitaly Buka Map.insert(move(KV));
385c26dbc4aSVitaly Buka }
38654adc167SVitaly Buka // Check that we didn't grow
38754adc167SVitaly Buka EXPECT_EQ(MemorySize, Map.getMemorySize());
38854adc167SVitaly Buka // Check that move was called the expected number of times
38954adc167SVitaly Buka EXPECT_EQ(ExpectedMaxInitialEntries, CountCopyAndMove::Move);
39054adc167SVitaly Buka // Check that no copy occurred
39154adc167SVitaly Buka EXPECT_EQ(0, CountCopyAndMove::Copy);
39254adc167SVitaly Buka
39354adc167SVitaly Buka // Adding one extra element should grow the map
394c26dbc4aSVitaly Buka detail::DenseMapPair<int, CountCopyAndMove> KV;
395c26dbc4aSVitaly Buka KV.first = ExpectedMaxInitialEntries;
396c26dbc4aSVitaly Buka Map.insert(move(KV));
39754adc167SVitaly Buka // Check that we grew
39854adc167SVitaly Buka EXPECT_NE(MemorySize, Map.getMemorySize());
39954adc167SVitaly Buka // Check that move was called the expected number of times
40054adc167SVitaly Buka // This relies on move-construction elision, and cannot be reliably tested.
40154adc167SVitaly Buka // EXPECT_EQ(ExpectedMaxInitialEntries + 2, CountCopyAndMove::Move);
40254adc167SVitaly Buka // Check that no copy occurred
40354adc167SVitaly Buka EXPECT_EQ(0, CountCopyAndMove::Copy);
40454adc167SVitaly Buka }
40554adc167SVitaly Buka
40654adc167SVitaly Buka // Make sure creating the map with an initial size of N actually gives us enough
40754adc167SVitaly Buka // buckets to insert N items without increasing allocation size.
TEST(DenseMapCustomTest,InitialSizeTest)40854adc167SVitaly Buka TEST(DenseMapCustomTest, InitialSizeTest) {
409c26dbc4aSVitaly Buka // Test a few different size, 341 is *not* a random choice: we need a value
41054adc167SVitaly Buka // that is 2/3 of a power of two to stress the grow() condition, and the power
411c26dbc4aSVitaly Buka // of two has to be at least 512 because of minimum size allocation in the
412*0d4b6f1fSRainer Orth // DenseMap (see DefaultMinReservedSizeTest).
413*0d4b6f1fSRainer Orth for (auto Size : {1, 2, 48, 66, 341, ExpectedInitialBucketCount + 1}) {
41454adc167SVitaly Buka DenseMap<int, CountCopyAndMove> Map(Size);
41554adc167SVitaly Buka unsigned MemorySize = Map.getMemorySize();
41654adc167SVitaly Buka CountCopyAndMove::Copy = 0;
41754adc167SVitaly Buka CountCopyAndMove::Move = 0;
418c26dbc4aSVitaly Buka for (int i = 0; i < Size; ++i) {
419c26dbc4aSVitaly Buka detail::DenseMapPair<int, CountCopyAndMove> KV;
420c26dbc4aSVitaly Buka KV.first = i;
421c26dbc4aSVitaly Buka Map.insert(move(KV));
422c26dbc4aSVitaly Buka }
42354adc167SVitaly Buka // Check that we didn't grow
42454adc167SVitaly Buka EXPECT_EQ(MemorySize, Map.getMemorySize());
42554adc167SVitaly Buka // Check that move was called the expected number of times
42654adc167SVitaly Buka EXPECT_EQ(Size, CountCopyAndMove::Move);
42754adc167SVitaly Buka // Check that no copy occurred
42854adc167SVitaly Buka EXPECT_EQ(0, CountCopyAndMove::Copy);
42954adc167SVitaly Buka }
43054adc167SVitaly Buka }
43154adc167SVitaly Buka
43254adc167SVitaly Buka // Make sure creating the map with a iterator range does not trigger grow()
TEST(DenseMapCustomTest,InitFromIterator)43354adc167SVitaly Buka TEST(DenseMapCustomTest, InitFromIterator) {
434c26dbc4aSVitaly Buka std::vector<detail::DenseMapPair<int, CountCopyAndMove>> Values;
43554adc167SVitaly Buka // The size is a random value greater than 64 (hardcoded DenseMap min init)
43654adc167SVitaly Buka const int Count = 65;
437234a8301SVitaly Buka for (int i = 0; i < Count; i++) Values.emplace_back(i, CountCopyAndMove());
43854adc167SVitaly Buka
43954adc167SVitaly Buka CountCopyAndMove::Move = 0;
44054adc167SVitaly Buka CountCopyAndMove::Copy = 0;
44154adc167SVitaly Buka DenseMap<int, CountCopyAndMove> Map(Values.begin(), Values.end());
44254adc167SVitaly Buka // Check that no move occurred
44354adc167SVitaly Buka EXPECT_EQ(0, CountCopyAndMove::Move);
44454adc167SVitaly Buka // Check that copy was called the expected number of times
44554adc167SVitaly Buka EXPECT_EQ(Count, CountCopyAndMove::Copy);
44654adc167SVitaly Buka }
44754adc167SVitaly Buka
44854adc167SVitaly Buka // Make sure reserve actually gives us enough buckets to insert N items
44954adc167SVitaly Buka // without increasing allocation size.
TEST(DenseMapCustomTest,ReserveTest)45054adc167SVitaly Buka TEST(DenseMapCustomTest, ReserveTest) {
451c26dbc4aSVitaly Buka // Test a few different size, 341 is *not* a random choice: we need a value
45254adc167SVitaly Buka // that is 2/3 of a power of two to stress the grow() condition, and the power
453c26dbc4aSVitaly Buka // of two has to be at least 512 because of minimum size allocation in the
454*0d4b6f1fSRainer Orth // DenseMap (see DefaultMinReservedSizeTest).
455*0d4b6f1fSRainer Orth for (auto Size : {1, 2, 48, 66, 341, ExpectedInitialBucketCount + 1}) {
45654adc167SVitaly Buka DenseMap<int, CountCopyAndMove> Map;
45754adc167SVitaly Buka Map.reserve(Size);
45854adc167SVitaly Buka unsigned MemorySize = Map.getMemorySize();
45954adc167SVitaly Buka CountCopyAndMove::Copy = 0;
46054adc167SVitaly Buka CountCopyAndMove::Move = 0;
461c26dbc4aSVitaly Buka for (int i = 0; i < Size; ++i) {
462c26dbc4aSVitaly Buka detail::DenseMapPair<int, CountCopyAndMove> KV;
463c26dbc4aSVitaly Buka KV.first = i;
464c26dbc4aSVitaly Buka Map.insert(move(KV));
465c26dbc4aSVitaly Buka }
46654adc167SVitaly Buka // Check that we didn't grow
46754adc167SVitaly Buka EXPECT_EQ(MemorySize, Map.getMemorySize());
46854adc167SVitaly Buka // Check that move was called the expected number of times
46954adc167SVitaly Buka EXPECT_EQ(Size, CountCopyAndMove::Move);
47054adc167SVitaly Buka // Check that no copy occurred
47154adc167SVitaly Buka EXPECT_EQ(0, CountCopyAndMove::Copy);
47254adc167SVitaly Buka }
47354adc167SVitaly Buka }
47454adc167SVitaly Buka
47554adc167SVitaly Buka // Key traits that allows lookup with either an unsigned or char* key;
47654adc167SVitaly Buka // In the latter case, "a" == 0, "b" == 1 and so on.
47754adc167SVitaly Buka struct TestDenseMapInfo {
getEmptyKey__anon65fcc02b0111::TestDenseMapInfo47854adc167SVitaly Buka static inline unsigned getEmptyKey() { return ~0; }
getTombstoneKey__anon65fcc02b0111::TestDenseMapInfo47954adc167SVitaly Buka static inline unsigned getTombstoneKey() { return ~0U - 1; }
getHashValue__anon65fcc02b0111::TestDenseMapInfo48054adc167SVitaly Buka static unsigned getHashValue(const unsigned &Val) { return Val * 37U; }
getHashValue__anon65fcc02b0111::TestDenseMapInfo48154adc167SVitaly Buka static unsigned getHashValue(const char *Val) {
48254adc167SVitaly Buka return (unsigned)(Val[0] - 'a') * 37U;
48354adc167SVitaly Buka }
isEqual__anon65fcc02b0111::TestDenseMapInfo48454adc167SVitaly Buka static bool isEqual(const unsigned &LHS, const unsigned &RHS) {
48554adc167SVitaly Buka return LHS == RHS;
48654adc167SVitaly Buka }
isEqual__anon65fcc02b0111::TestDenseMapInfo48754adc167SVitaly Buka static bool isEqual(const char *LHS, const unsigned &RHS) {
48854adc167SVitaly Buka return (unsigned)(LHS[0] - 'a') == RHS;
48954adc167SVitaly Buka }
49054adc167SVitaly Buka };
49154adc167SVitaly Buka
49254adc167SVitaly Buka // find_as() tests
TEST(DenseMapCustomTest,FindAsTest)49354adc167SVitaly Buka TEST(DenseMapCustomTest, FindAsTest) {
49454adc167SVitaly Buka DenseMap<unsigned, unsigned, TestDenseMapInfo> map;
49554adc167SVitaly Buka map[0] = 1;
49654adc167SVitaly Buka map[1] = 2;
49754adc167SVitaly Buka map[2] = 3;
49854adc167SVitaly Buka
49954adc167SVitaly Buka // Size tests
50054adc167SVitaly Buka EXPECT_EQ(3u, map.size());
50154adc167SVitaly Buka
50254adc167SVitaly Buka // Normal lookup tests
50354adc167SVitaly Buka EXPECT_EQ(1u, map.count(1));
50454adc167SVitaly Buka EXPECT_EQ(1u, map.find(0)->second);
50554adc167SVitaly Buka EXPECT_EQ(2u, map.find(1)->second);
50654adc167SVitaly Buka EXPECT_EQ(3u, map.find(2)->second);
507c26dbc4aSVitaly Buka EXPECT_EQ(nullptr, map.find(3));
50854adc167SVitaly Buka
50954adc167SVitaly Buka // find_as() tests
51054adc167SVitaly Buka EXPECT_EQ(1u, map.find_as("a")->second);
51154adc167SVitaly Buka EXPECT_EQ(2u, map.find_as("b")->second);
51254adc167SVitaly Buka EXPECT_EQ(3u, map.find_as("c")->second);
513c26dbc4aSVitaly Buka EXPECT_EQ(nullptr, map.find_as("d"));
51454adc167SVitaly Buka }
51554adc167SVitaly Buka
TEST(DenseMapCustomTest,TryEmplaceTest)51654adc167SVitaly Buka TEST(DenseMapCustomTest, TryEmplaceTest) {
51754adc167SVitaly Buka DenseMap<int, std::unique_ptr<int>> Map;
51854adc167SVitaly Buka std::unique_ptr<int> P(new int(2));
51954adc167SVitaly Buka auto Try1 = Map.try_emplace(0, new int(1));
52054adc167SVitaly Buka EXPECT_TRUE(Try1.second);
52154adc167SVitaly Buka auto Try2 = Map.try_emplace(0, std::move(P));
52254adc167SVitaly Buka EXPECT_FALSE(Try2.second);
52354adc167SVitaly Buka EXPECT_EQ(Try1.first, Try2.first);
52454adc167SVitaly Buka EXPECT_NE(nullptr, P);
52554adc167SVitaly Buka }
52654adc167SVitaly Buka
52754adc167SVitaly Buka struct IncompleteStruct;
52854adc167SVitaly Buka
TEST(DenseMapCustomTest,OpaquePointerKey)52954adc167SVitaly Buka TEST(DenseMapCustomTest, OpaquePointerKey) {
53054adc167SVitaly Buka // Test that we can use a pointer to an incomplete type as a DenseMap key.
53154adc167SVitaly Buka // This is an important build time optimization, since many classes have
53254adc167SVitaly Buka // DenseMap members.
53354adc167SVitaly Buka DenseMap<IncompleteStruct *, int> Map;
53454adc167SVitaly Buka int Keys[3] = {0, 0, 0};
53554adc167SVitaly Buka IncompleteStruct *K1 = reinterpret_cast<IncompleteStruct *>(&Keys[0]);
53654adc167SVitaly Buka IncompleteStruct *K2 = reinterpret_cast<IncompleteStruct *>(&Keys[1]);
53754adc167SVitaly Buka IncompleteStruct *K3 = reinterpret_cast<IncompleteStruct *>(&Keys[2]);
53854adc167SVitaly Buka Map.insert({K1, 1});
53954adc167SVitaly Buka Map.insert({K2, 2});
54054adc167SVitaly Buka Map.insert({K3, 3});
54154adc167SVitaly Buka EXPECT_EQ(Map.count(K1), 1u);
54254adc167SVitaly Buka EXPECT_EQ(Map[K1], 1);
54354adc167SVitaly Buka EXPECT_EQ(Map[K2], 2);
54454adc167SVitaly Buka EXPECT_EQ(Map[K3], 3);
54554adc167SVitaly Buka Map.clear();
546c26dbc4aSVitaly Buka EXPECT_EQ(nullptr, Map.find(K1));
547c26dbc4aSVitaly Buka EXPECT_EQ(nullptr, Map.find(K2));
548c26dbc4aSVitaly Buka EXPECT_EQ(nullptr, Map.find(K3));
54954adc167SVitaly Buka }
550234a8301SVitaly Buka } // namespace
551