mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
656 lines
19 KiB
C++
656 lines
19 KiB
C++
//===--- BlotMapVectorTest.cpp --------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Basic/BlotMapVector.h"
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "swift/Basic/Lazy.h"
|
|
#include "swift/Basic/NullablePtr.h"
|
|
#include "llvm/ADT/Optional.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "gtest/gtest.h"
|
|
#include <map>
|
|
#include <set>
|
|
|
|
using namespace swift;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Test Key/Value Generation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
|
|
uint32_t getTestKey(int i, uint32_t *) { return i; }
|
|
uint32_t getTestValue(int i, uint32_t *) { return 42 + i; }
|
|
|
|
uint32_t *getTestKey(int i, uint32_t **) {
|
|
static uint32_t dummy_arr1[8192];
|
|
assert(i < 8192 && "Only support 8192 dummy keys.");
|
|
return &dummy_arr1[i];
|
|
}
|
|
|
|
uint32_t *getTestValue(int i, uint32_t **) {
|
|
static uint32_t dummy_arr1[8192];
|
|
assert(i < 8192 && "Only support 8192 dummy keys.");
|
|
return &dummy_arr1[i];
|
|
}
|
|
|
|
} // end anonymous namespace
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// CtorTester
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
|
|
class CtorTester;
|
|
|
|
class CtorTesterSet {
|
|
bool IsClearing = false;
|
|
std::set<CtorTester *> Constructed;
|
|
|
|
public:
|
|
void init() { IsClearing = false; }
|
|
void dumpLiveTesters() const;
|
|
void verifyTesters() const;
|
|
bool hasLiveTesters() const;
|
|
bool numLiveTesters() const;
|
|
void clearTesters();
|
|
void finalize();
|
|
bool isLive(CtorTester *T) const;
|
|
bool insert(CtorTester *T);
|
|
unsigned erase(CtorTester *T);
|
|
bool isClearing() const { return IsClearing; }
|
|
};
|
|
|
|
Lazy<CtorTesterSet> ConstructedTesters;
|
|
|
|
/// \brief A test class that tries to check that construction and destruction
|
|
/// occur correctly.
|
|
class CtorTester {
|
|
friend class CtorTesterSet;
|
|
|
|
NullablePtr<int> Value;
|
|
|
|
public:
|
|
bool isLive() const {
|
|
return ConstructedTesters->isLive(const_cast<CtorTester *>(this));
|
|
}
|
|
|
|
enum class EmptyTester { Kind };
|
|
enum class TombstoneTester { Kind };
|
|
|
|
CtorTester() : Value(new int(-1)) {
|
|
dump("Constructing ()");
|
|
llvm::outs() << "\n";
|
|
// EXPECT_TRUE(ConstructedTesters->insert(this));
|
|
assert(!isLive());
|
|
fflush(stdout);
|
|
}
|
|
|
|
explicit CtorTester(EmptyTester) : Value(new int(-2)) {
|
|
dump("Constructing Empty");
|
|
llvm::outs() << "\n";
|
|
// EXPECT_TRUE(ConstructedTesters->insert(this));
|
|
assert(!isLive());
|
|
fflush(stdout);
|
|
}
|
|
|
|
explicit CtorTester(TombstoneTester) : Value(new int(-3)) {
|
|
dump("Constructing Tombstone");
|
|
llvm::outs() << "\n";
|
|
// EXPECT_TRUE(ConstructedTesters->insert(this));
|
|
assert(!isLive());
|
|
fflush(stdout);
|
|
}
|
|
|
|
explicit CtorTester(int V) : Value(new int(V)) {
|
|
dump("Constructing Normal");
|
|
llvm::outs() << "\n";
|
|
EXPECT_TRUE(ConstructedTesters->insert(this));
|
|
assert(!isIgnorableTester());
|
|
assert(isLive());
|
|
fflush(stdout);
|
|
}
|
|
|
|
explicit CtorTester(uint32_t V) : Value(new int(V)) {
|
|
dump("Constructing Normal");
|
|
llvm::outs() << "\n";
|
|
EXPECT_TRUE(ConstructedTesters->insert(this));
|
|
assert(!isIgnorableTester());
|
|
assert(isLive());
|
|
fflush(stdout);
|
|
}
|
|
|
|
CtorTester(const CtorTester &Arg) : Value(new int(*Arg.Value.get())) {
|
|
dump("CopyConstructing");
|
|
Arg.dump(" From");
|
|
llvm::outs() << "\n";
|
|
if (!Arg.isIgnorableTester()) {
|
|
EXPECT_TRUE(ConstructedTesters->insert(this));
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
CtorTester(CtorTester &&Arg) : Value(new int(-1)) {
|
|
dump("Operator Move Constructor");
|
|
Arg.dump(" From");
|
|
llvm::outs() << "\n";
|
|
assert(Value);
|
|
assert(Arg.Value);
|
|
// If Arg is not ignorable, it will be now and we will not be.
|
|
if (!Arg.isIgnorableTester()) {
|
|
EXPECT_TRUE(ConstructedTesters->insert(this));
|
|
EXPECT_EQ(1u, ConstructedTesters->erase(&Arg));
|
|
}
|
|
std::swap(Value, Arg.Value);
|
|
fflush(stdout);
|
|
}
|
|
|
|
CtorTester &operator=(const CtorTester &Arg) {
|
|
dump("Operator Copy Assignment");
|
|
Arg.dump(" From");
|
|
llvm::outs() << "\n";
|
|
assert(Value);
|
|
assert(Arg.Value);
|
|
|
|
// If arg is not an ignorable tester, but we are an ignorable tester, we
|
|
// need to be inserted into the constructed testers set.
|
|
if (!Arg.isIgnorableTester() && isIgnorableTester()) {
|
|
EXPECT_TRUE(ConstructedTesters->insert(this));
|
|
}
|
|
*Value.get() = Arg.getValue();
|
|
fflush(stdout);
|
|
return *this;
|
|
}
|
|
|
|
CtorTester &operator=(CtorTester &&Arg) {
|
|
dump("Operator Move Assignment");
|
|
Arg.dump(" From");
|
|
llvm::outs() << "\n";
|
|
assert(Value);
|
|
assert(Arg.Value);
|
|
if (!Arg.isIgnorableTester() && isIgnorableTester()) {
|
|
EXPECT_EQ(1u, ConstructedTesters->erase(&Arg));
|
|
EXPECT_TRUE(ConstructedTesters->insert(this));
|
|
} else if (Arg.isIgnorableTester() && !isIgnorableTester()) {
|
|
EXPECT_EQ(1u, ConstructedTesters->erase(this));
|
|
EXPECT_TRUE(ConstructedTesters->insert(&Arg));
|
|
}
|
|
|
|
std::swap(Value, Arg.Value);
|
|
fflush(stdout);
|
|
return *this;
|
|
}
|
|
|
|
~CtorTester() {
|
|
bool IsIgnorable = isIgnorableTester();
|
|
dump("Destroying");
|
|
llvm::outs() << "\n";
|
|
delete Value.get();
|
|
Value = nullptr;
|
|
fflush(stdout);
|
|
if (ConstructedTesters->isClearing() || IsIgnorable)
|
|
return;
|
|
EXPECT_EQ(1u, ConstructedTesters->erase(this));
|
|
}
|
|
|
|
operator uint32_t() const { return *Value.get(); }
|
|
|
|
int getValue() const { return *Value.get(); }
|
|
|
|
bool operator==(const CtorTester &RHS) const {
|
|
return *Value.get() == *RHS.Value.get();
|
|
}
|
|
|
|
bool isIgnorableTester() const {
|
|
return *Value.get() >= -3 && *Value.get() < 0;
|
|
}
|
|
|
|
private:
|
|
void dump(StringRef Name) const {
|
|
std::string Addr = "0x";
|
|
Addr += llvm::utohexstr(uintptr_t(this));
|
|
std::string ValueAddr = "0x";
|
|
ValueAddr += llvm::utohexstr(uintptr_t(Value.get()));
|
|
llvm::outs() << Name << " <Tester Addr:" << Addr
|
|
<< " ValueAddr:" << ValueAddr << " Value:" << *Value.get()
|
|
<< ">";
|
|
}
|
|
};
|
|
|
|
void CtorTesterSet::dumpLiveTesters() const {
|
|
for (auto *Tester : Constructed) {
|
|
if (Tester->isIgnorableTester())
|
|
continue;
|
|
llvm::SmallString<64> Hex;
|
|
std::string Addr = llvm::utohexstr(uintptr_t(Tester));
|
|
llvm::outs() << "<Tester Addr:" << Addr << " Value:" << Tester->getValue()
|
|
<< ">\n";
|
|
}
|
|
}
|
|
|
|
void CtorTesterSet::verifyTesters() const {
|
|
for (auto *Tester : Constructed)
|
|
EXPECT_TRUE(Tester->Value.isNonNull());
|
|
}
|
|
|
|
bool CtorTesterSet::hasLiveTesters() const {
|
|
return std::any_of(Constructed.begin(), Constructed.end(),
|
|
[](CtorTester *T) -> bool {
|
|
assert(T);
|
|
return !T->isIgnorableTester();
|
|
});
|
|
}
|
|
|
|
bool CtorTesterSet::numLiveTesters() const {
|
|
return llvm::count_if(Constructed, [](CtorTester *T) -> bool {
|
|
assert(T);
|
|
return !T->isIgnorableTester();
|
|
});
|
|
}
|
|
|
|
void CtorTesterSet::clearTesters() {
|
|
IsClearing = true;
|
|
Constructed.clear();
|
|
IsClearing = false;
|
|
}
|
|
|
|
bool CtorTesterSet::isLive(CtorTester *T) const {
|
|
// if (IsClearing)
|
|
// return true;
|
|
return Constructed.count(T);
|
|
}
|
|
|
|
bool CtorTesterSet::insert(CtorTester *T) {
|
|
return Constructed.insert(T).second;
|
|
}
|
|
|
|
unsigned CtorTesterSet::erase(CtorTester *T) { return Constructed.erase(T); }
|
|
|
|
void CtorTesterSet::finalize() {
|
|
IsClearing = true;
|
|
Constructed.clear();
|
|
}
|
|
|
|
struct CtorTesterMapInfo {
|
|
static inline CtorTester getEmptyKey() {
|
|
return CtorTester(CtorTester::EmptyTester::Kind);
|
|
}
|
|
static inline CtorTester getTombstoneKey() {
|
|
return CtorTester(CtorTester::TombstoneTester::Kind);
|
|
}
|
|
static unsigned getHashValue(const CtorTester &Val) {
|
|
return Val.getValue() * 37u;
|
|
}
|
|
static bool isEqual(const CtorTester &LHS, const CtorTester &RHS) {
|
|
return LHS == RHS;
|
|
}
|
|
};
|
|
|
|
CtorTester getTestKey(int i, CtorTester *) { return CtorTester(i); }
|
|
CtorTester getTestValue(int i, CtorTester *) { return CtorTester(42 + i); }
|
|
|
|
} // end anonymous namespace
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Tests
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
|
|
// Test fixture, with helper functions implemented by forwarding to global
|
|
// function overloads selected by component types of the type parameter. This
|
|
// allows all of the map implementations to be tested with shared
|
|
// implementations of helper routines.
|
|
template <typename T> class BlotMapVectorTest : public ::testing::Test {
|
|
protected:
|
|
T Map;
|
|
|
|
Optional<unsigned> NumExpectedLiveTesters;
|
|
|
|
static typename T::key_type *const dummy_key_ptr;
|
|
static typename T::mapped_type *const dummy_value_ptr;
|
|
|
|
public:
|
|
void SetUp() override {
|
|
ConstructedTesters->init();
|
|
EXPECT_TRUE(!ConstructedTesters->hasLiveTesters());
|
|
}
|
|
|
|
~BlotMapVectorTest() {
|
|
ConstructedTesters->verifyTesters();
|
|
llvm::outs() << "Destroying Fixture\n";
|
|
ConstructedTesters->finalize();
|
|
}
|
|
|
|
void TearDown() override {
|
|
if (std::is_same<T, CtorTester>::value)
|
|
EXPECT_EQ(ConstructedTesters->numLiveTesters(), *NumExpectedLiveTesters);
|
|
}
|
|
|
|
protected:
|
|
typename T::key_type getKey(int i = 4) {
|
|
return getTestKey(i, dummy_key_ptr);
|
|
}
|
|
typename T::mapped_type getValue(int i = 5) {
|
|
return getTestValue(i, dummy_value_ptr);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
typename T::key_type *const BlotMapVectorTest<T>::dummy_key_ptr = nullptr;
|
|
template <typename T>
|
|
typename T::mapped_type *const BlotMapVectorTest<T>::dummy_value_ptr = nullptr;
|
|
|
|
// Register these types for testing.
|
|
typedef ::testing::Types<
|
|
BlotMapVector<uint32_t, uint32_t>, BlotMapVector<uint32_t *, uint32_t *>,
|
|
BlotMapVector<CtorTester, CtorTester,
|
|
llvm::DenseMap<CtorTester, size_t, CtorTesterMapInfo>>,
|
|
SmallBlotMapVector<uint32_t, uint32_t, 4>,
|
|
SmallBlotMapVector<uint32_t *, uint32_t *, 4>,
|
|
SmallBlotMapVector<
|
|
CtorTester, CtorTester, 4,
|
|
llvm::SmallDenseMap<CtorTester, unsigned, 4, CtorTesterMapInfo>>>
|
|
BlotMapVectorTestTypes;
|
|
TYPED_TEST_CASE(BlotMapVectorTest, BlotMapVectorTestTypes);
|
|
|
|
// Empty map tests
|
|
TYPED_TEST(BlotMapVectorTest, EmptyIntMapTest) {
|
|
// Size tests
|
|
EXPECT_EQ(0u, this->Map.size());
|
|
EXPECT_TRUE(this->Map.empty());
|
|
|
|
// Iterator tests
|
|
EXPECT_TRUE(this->Map.begin() == this->Map.end());
|
|
|
|
// Lookup tests
|
|
EXPECT_FALSE(this->Map.count(this->getKey()));
|
|
EXPECT_TRUE(this->Map.find(this->getKey()) == this->Map.end());
|
|
EXPECT_EQ(typename TypeParam::mapped_type(),
|
|
this->Map.lookup(this->getKey()));
|
|
}
|
|
|
|
// Constant map tests
|
|
TYPED_TEST(BlotMapVectorTest, ConstEmptyMapTest) {
|
|
const TypeParam &ConstMap = this->Map;
|
|
EXPECT_EQ(0u, ConstMap.size());
|
|
EXPECT_TRUE(ConstMap.empty());
|
|
EXPECT_TRUE(ConstMap.begin() == ConstMap.end());
|
|
}
|
|
|
|
// A map with a single entry
|
|
TYPED_TEST(BlotMapVectorTest, SingleEntryMapTest) {
|
|
this->Map[this->getKey()] = this->getValue();
|
|
|
|
ConstructedTesters->verifyTesters();
|
|
// Size tests
|
|
EXPECT_EQ(1u, this->Map.size());
|
|
EXPECT_FALSE(this->Map.begin() == this->Map.end());
|
|
EXPECT_FALSE(this->Map.empty());
|
|
|
|
// Iterator tests
|
|
typename TypeParam::iterator it = this->Map.begin();
|
|
EXPECT_EQ(this->getKey(), (*it)->first);
|
|
EXPECT_EQ(this->getValue(), (*it)->second);
|
|
++it;
|
|
EXPECT_TRUE(it == this->Map.end());
|
|
|
|
// Lookup tests
|
|
EXPECT_TRUE(this->Map.count(this->getKey()));
|
|
EXPECT_TRUE(this->Map.find(this->getKey()) == this->Map.begin());
|
|
EXPECT_EQ(this->getValue(), this->Map.lookup(this->getKey()));
|
|
EXPECT_EQ(this->getValue(), this->Map[this->getKey()]);
|
|
|
|
this->NumExpectedLiveTesters = 1;
|
|
}
|
|
|
|
// Test clear() method
|
|
TYPED_TEST(BlotMapVectorTest, ClearTest) {
|
|
this->Map[this->getKey()] = this->getValue();
|
|
this->Map.clear();
|
|
|
|
EXPECT_EQ(0u, this->Map.size());
|
|
EXPECT_TRUE(this->Map.empty());
|
|
EXPECT_TRUE(this->Map.begin() == this->Map.end());
|
|
this->NumExpectedLiveTesters = 0;
|
|
}
|
|
|
|
// Test erase(iterator) method
|
|
TYPED_TEST(BlotMapVectorTest, EraseTest) {
|
|
this->Map[this->getKey()] = this->getValue();
|
|
this->Map.erase(this->Map.begin());
|
|
|
|
EXPECT_EQ(0u, this->Map.size());
|
|
EXPECT_TRUE(this->Map.empty());
|
|
EXPECT_TRUE(this->Map.begin() != this->Map.end());
|
|
EXPECT_EQ(std::next(this->Map.begin()), this->Map.end());
|
|
|
|
this->NumExpectedLiveTesters = 0;
|
|
}
|
|
|
|
// Test erase(value) method
|
|
TYPED_TEST(BlotMapVectorTest, EraseTest2) {
|
|
this->Map[this->getKey()] = this->getValue();
|
|
this->Map.erase(this->getKey());
|
|
|
|
EXPECT_EQ(0u, this->Map.size());
|
|
EXPECT_TRUE(this->Map.empty());
|
|
EXPECT_TRUE(this->Map.begin() != this->Map.end());
|
|
EXPECT_EQ(std::next(this->Map.begin()), this->Map.end());
|
|
this->NumExpectedLiveTesters = 0;
|
|
}
|
|
|
|
// Test insert() method
|
|
TYPED_TEST(BlotMapVectorTest, InsertTest) {
|
|
this->Map.insert(std::make_pair(this->getKey(), this->getValue()));
|
|
EXPECT_EQ(1u, this->Map.size());
|
|
EXPECT_EQ(this->getValue(), this->Map[this->getKey()]);
|
|
EXPECT_EQ(1u, this->Map.size());
|
|
this->NumExpectedLiveTesters = 1;
|
|
}
|
|
|
|
// Test copy constructor method
|
|
TYPED_TEST(BlotMapVectorTest, CopyConstructorTest) {
|
|
this->Map[this->getKey()] = this->getValue();
|
|
TypeParam copyMap(this->Map);
|
|
|
|
EXPECT_EQ(1u, copyMap.size());
|
|
EXPECT_EQ(this->getValue(), copyMap[this->getKey()]);
|
|
EXPECT_EQ(1u, copyMap.size());
|
|
this->NumExpectedLiveTesters = 1;
|
|
}
|
|
|
|
// Test copy constructor method where SmallBlotMapVector isn't small.
|
|
TYPED_TEST(BlotMapVectorTest, CopyConstructorNotSmallTest) {
|
|
for (int Key = 0; Key < 5; ++Key)
|
|
this->Map[this->getKey(Key)] = this->getValue(Key);
|
|
TypeParam copyMap(this->Map);
|
|
|
|
EXPECT_EQ(5u, copyMap.size());
|
|
for (int Key = 0; Key < 5; ++Key)
|
|
EXPECT_EQ(this->getValue(Key), copyMap[this->getKey(Key)]);
|
|
this->NumExpectedLiveTesters = 10;
|
|
}
|
|
|
|
// Test copying from a default-constructed map.
|
|
TYPED_TEST(BlotMapVectorTest, CopyConstructorFromDefaultTest) {
|
|
TypeParam copyMap(this->Map);
|
|
|
|
EXPECT_TRUE(copyMap.empty());
|
|
this->NumExpectedLiveTesters = 0;
|
|
}
|
|
|
|
// Test copying from an empty map where SmallBlotMapVector isn't small.
|
|
TYPED_TEST(BlotMapVectorTest, CopyConstructorFromEmptyTest) {
|
|
for (int Key = 0; Key < 5; ++Key)
|
|
this->Map[this->getKey(Key)] = this->getValue(Key);
|
|
this->Map.clear();
|
|
TypeParam copyMap(this->Map);
|
|
|
|
EXPECT_TRUE(copyMap.empty());
|
|
this->NumExpectedLiveTesters = 0;
|
|
}
|
|
|
|
// Test assignment operator method
|
|
TYPED_TEST(BlotMapVectorTest, AssignmentTest) {
|
|
this->Map[this->getKey()] = this->getValue();
|
|
TypeParam copyMap = this->Map;
|
|
|
|
EXPECT_EQ(1u, copyMap.size());
|
|
EXPECT_EQ(this->getValue(), copyMap[this->getKey()]);
|
|
|
|
// test self-assignment.
|
|
copyMap = copyMap;
|
|
EXPECT_EQ(1u, copyMap.size());
|
|
EXPECT_EQ(this->getValue(), copyMap[this->getKey()]);
|
|
this->NumExpectedLiveTesters = 2;
|
|
}
|
|
|
|
// A more complex iteration test
|
|
TYPED_TEST(BlotMapVectorTest, IterationTest) {
|
|
bool visited[100];
|
|
std::map<typename TypeParam::key_type, unsigned> visitedIndex;
|
|
|
|
// Insert 100 numbers into the map
|
|
for (int i = 0; i < 100; ++i) {
|
|
visited[i] = false;
|
|
visitedIndex[this->getKey(i)] = i;
|
|
|
|
this->Map[this->getKey(i)] = this->getValue(i);
|
|
}
|
|
|
|
// Iterate over all numbers and mark each one found.
|
|
for (typename TypeParam::iterator it = this->Map.begin();
|
|
it != this->Map.end(); ++it)
|
|
visited[visitedIndex[(*it)->first]] = true;
|
|
|
|
// Ensure every number was visited.
|
|
for (int i = 0; i < 100; ++i)
|
|
ASSERT_TRUE(visited[i]) << "Entry #" << i << " was never visited";
|
|
this->NumExpectedLiveTesters = 100;
|
|
}
|
|
|
|
// const_iterator test
|
|
TYPED_TEST(BlotMapVectorTest, ConstIteratorTest) {
|
|
// Check conversion from iterator to const_iterator.
|
|
typename TypeParam::iterator it = this->Map.begin();
|
|
typename TypeParam::const_iterator cit(it);
|
|
EXPECT_TRUE(it == cit);
|
|
|
|
// Check copying of const_iterators.
|
|
typename TypeParam::const_iterator cit2(cit);
|
|
EXPECT_TRUE(cit == cit2);
|
|
}
|
|
|
|
// Make sure BlotMapVector works with StringRef keys.
|
|
TEST(BlotMapVectorCustomTest, StringRefTest) {
|
|
BlotMapVector<StringRef, int> M;
|
|
|
|
M["a"] = 1;
|
|
M["b"] = 2;
|
|
M["c"] = 3;
|
|
|
|
EXPECT_EQ(3u, M.size());
|
|
EXPECT_EQ(1, M.lookup("a"));
|
|
EXPECT_EQ(2, M.lookup("b"));
|
|
EXPECT_EQ(3, M.lookup("c"));
|
|
|
|
EXPECT_EQ(0, M.lookup("q"));
|
|
|
|
// Test the empty string, spelled various ways.
|
|
EXPECT_EQ(0, M.lookup(""));
|
|
EXPECT_EQ(0, M.lookup(StringRef()));
|
|
EXPECT_EQ(0, M.lookup(StringRef("a", 0)));
|
|
M[""] = 42;
|
|
EXPECT_EQ(42, M.lookup(""));
|
|
EXPECT_EQ(42, M.lookup(StringRef()));
|
|
EXPECT_EQ(42, M.lookup(StringRef("a", 0)));
|
|
}
|
|
|
|
// Key traits that allows lookup with either an unsigned or char* key;
|
|
// In the latter case, "a" == 0, "b" == 1 and so on.
|
|
struct TestBlotMapVectorInfo {
|
|
static inline unsigned getEmptyKey() { return ~0; }
|
|
static inline unsigned getTombstoneKey() { return ~0U - 1; }
|
|
static unsigned getHashValue(const unsigned &Val) { return Val * 37U; }
|
|
static unsigned getHashValue(const char *Val) {
|
|
return (unsigned)(Val[0] - 'a') * 37U;
|
|
}
|
|
static bool isEqual(const unsigned &LHS, const unsigned &RHS) {
|
|
return LHS == RHS;
|
|
}
|
|
static bool isEqual(const char *LHS, const unsigned &RHS) {
|
|
return (unsigned)(LHS[0] - 'a') == RHS;
|
|
}
|
|
};
|
|
|
|
// find_as() tests
|
|
TEST(BlotMapVectorCustomTest, FindAsTest) {
|
|
BlotMapVector<unsigned, unsigned,
|
|
llvm::DenseMap<unsigned, unsigned, TestBlotMapVectorInfo>> map;
|
|
map[0] = 1;
|
|
map[1] = 2;
|
|
map[2] = 3;
|
|
|
|
// Size tests
|
|
EXPECT_EQ(3u, map.size());
|
|
|
|
// Normal lookup tests
|
|
EXPECT_EQ(1u, map.count(1));
|
|
EXPECT_EQ(1u, map.find(0)->getValue().second);
|
|
EXPECT_EQ(2u, map.find(1)->getValue().second);
|
|
EXPECT_EQ(3u, map.find(2)->getValue().second);
|
|
EXPECT_TRUE(map.find(3) == map.end());
|
|
}
|
|
|
|
struct ContiguousBlotMapVectorInfo {
|
|
static inline unsigned getEmptyKey() { return ~0; }
|
|
static inline unsigned getTombstoneKey() { return ~0U - 1; }
|
|
static unsigned getHashValue(const unsigned &Val) { return Val; }
|
|
static bool isEqual(const unsigned &LHS, const unsigned &RHS) {
|
|
return LHS == RHS;
|
|
}
|
|
};
|
|
|
|
// Test that filling a small dense map with exactly the number of elements in
|
|
// the map grows to have enough space for an empty bucket.
|
|
TEST(BlotMapVectorCustomTest, SmallBlotMapVectorGrowTest) {
|
|
SmallBlotMapVector<unsigned, unsigned, 32,
|
|
llvm::SmallDenseMap<unsigned, unsigned, 32,
|
|
ContiguousBlotMapVectorInfo>> map;
|
|
// Add some number of elements, then delete a few to leave us some tombstones.
|
|
// If we just filled the map with 32 elements we'd grow because of not enough
|
|
// tombstones which masks the issue here.
|
|
for (unsigned i = 0; i < 20; ++i)
|
|
map[i] = i + 1;
|
|
for (unsigned i = 0; i < 10; ++i)
|
|
map.erase(i);
|
|
for (unsigned i = 20; i < 32; ++i)
|
|
map[i] = i + 1;
|
|
|
|
// Size tests
|
|
EXPECT_EQ(22u, map.size());
|
|
|
|
// Try to find an element which doesn't exist. There was a bug in
|
|
// SmallBlotMapVector which led to a map with num elements == small capacity
|
|
// not
|
|
// having an empty bucket any more. Finding an element not in the map would
|
|
// therefore never terminate.
|
|
EXPECT_TRUE(map.find(32) == map.end());
|
|
}
|
|
|
|
} // end anonymous namespace
|