//===- llvm/unittest/ADT/DenseMapMap.cpp - DenseMap unit tests --*- C++ -*-===////// The LLVM Compiler Infrastructure//// This file is distributed under the University of Illinois Open Source// License. See LICENSE.TXT for details.////===----------------------------------------------------------------------===//#include"gtest/gtest.h"#include"llvm/ADT/DenseMap.h"#include<map>#include<set>usingnamespacellvm;namespace{uint32_tgetTestKey(inti,uint32_t*){returni;}uint32_tgetTestValue(inti,uint32_t*){return42+i;}uint32_t*getTestKey(inti,uint32_t**){staticuint32_tdummy_arr1[8192];assert(i<8192&&"Only support 8192 dummy keys.");return&dummy_arr1[i];}uint32_t*getTestValue(inti,uint32_t**){staticuint32_tdummy_arr1[8192];assert(i<8192&&"Only support 8192 dummy keys.");return&dummy_arr1[i];}/// \brief A test class that tries to check that construction and destruction/// occur correctly.classCtorTester{staticstd::set<CtorTester*>Constructed;intValue;public:explicitCtorTester(intValue=0):Value(Value){EXPECT_TRUE(Constructed.insert(this).second);}CtorTester(uint32_tValue):Value(Value){EXPECT_TRUE(Constructed.insert(this).second);}CtorTester(constCtorTester&Arg):Value(Arg.Value){EXPECT_TRUE(Constructed.insert(this).second);}~CtorTester(){EXPECT_EQ(1u,Constructed.erase(this));}operatoruint32_t()const{returnValue;}intgetValue()const{returnValue;}booloperator==(constCtorTester&RHS)const{returnValue==RHS.Value;}};std::set<CtorTester*>CtorTester::Constructed;structCtorTesterMapInfo{staticinlineCtorTestergetEmptyKey(){returnCtorTester(-1);}staticinlineCtorTestergetTombstoneKey(){returnCtorTester(-2);}staticunsignedgetHashValue(constCtorTester&Val){returnVal.getValue()*37u;}staticboolisEqual(constCtorTester&LHS,constCtorTester&RHS){returnLHS==RHS;}};CtorTestergetTestKey(inti,CtorTester*){returnCtorTester(i);}CtorTestergetTestValue(inti,CtorTester*){returnCtorTester(42+i);}// 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<typenameT>classDenseMapTest:public::testing::Test{protected:TMap;statictypenameT::key_type*constdummy_key_ptr;statictypenameT::mapped_type*constdummy_value_ptr;typenameT::key_typegetKey(inti=0){returngetTestKey(i,dummy_key_ptr);}typenameT::mapped_typegetValue(inti=0){returngetTestValue(i,dummy_value_ptr);}};template<typenameT>typenameT::key_type*constDenseMapTest<T>::dummy_key_ptr=0;template<typenameT>typenameT::mapped_type*constDenseMapTest<T>::dummy_value_ptr=0;// Register these types for testing.typedef::testing::Types<DenseMap<uint32_t,uint32_t>,DenseMap<uint32_t*,uint32_t*>,DenseMap<CtorTester,CtorTester,CtorTesterMapInfo>,SmallDenseMap<uint32_t,uint32_t>,SmallDenseMap<uint32_t*,uint32_t*>,SmallDenseMap<CtorTester,CtorTester,4,CtorTesterMapInfo>>DenseMapTestTypes;TYPED_TEST_CASE(DenseMapTest,DenseMapTestTypes);// Empty map testsTYPED_TEST(DenseMapTest,EmptyIntMapTest){// Size testsEXPECT_EQ(0u,this->Map.size());EXPECT_TRUE(this->Map.empty());// Iterator testsEXPECT_TRUE(this->Map.begin()==this->Map.end());// Lookup testsEXPECT_FALSE(this->Map.count(this->getKey()));EXPECT_TRUE(this->Map.find(this->getKey())==this->Map.end());#ifndef _MSC_VEREXPECT_EQ(typenameTypeParam::mapped_type(),this->Map.lookup(this->getKey()));#else// MSVC, at least old versions, cannot parse the typename to disambiguate// TypeParam::mapped_type as a type. However, because MSVC doesn't implement// two-phase name lookup, it also doesn't require the typename. Deal with// this mutual incompatibility through specialized code.EXPECT_EQ(TypeParam::mapped_type(),this->Map.lookup(this->getKey()));#endif}// Constant map testsTYPED_TEST(DenseMapTest,ConstEmptyMapTest){constTypeParam&ConstMap=this->Map;EXPECT_EQ(0u,ConstMap.size());EXPECT_TRUE(ConstMap.empty());EXPECT_TRUE(ConstMap.begin()==ConstMap.end());}// A map with a single entryTYPED_TEST(DenseMapTest,SingleEntryMapTest){this->Map[this->getKey()]=this->getValue();// Size testsEXPECT_EQ(1u,this->Map.size());EXPECT_FALSE(this->Map.begin()==this->Map.end());EXPECT_FALSE(this->Map.empty());// Iterator teststypenameTypeParam::iteratorit=this->Map.begin();EXPECT_EQ(this->getKey(),it->first);EXPECT_EQ(this->getValue(),it->second);++it;EXPECT_TRUE(it==this->Map.end());// Lookup testsEXPECT_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()]);}// Test clear() methodTYPED_TEST(DenseMapTest,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());}// Test erase(iterator) methodTYPED_TEST(DenseMapTest,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());}// Test erase(value) methodTYPED_TEST(DenseMapTest,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());}// Test insert() methodTYPED_TEST(DenseMapTest,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()]);}// Test copy constructor methodTYPED_TEST(DenseMapTest,CopyConstructorTest){this->Map[this->getKey()]=this->getValue();TypeParamcopyMap(this->Map);EXPECT_EQ(1u,copyMap.size());EXPECT_EQ(this->getValue(),copyMap[this->getKey()]);}// Test assignment operator methodTYPED_TEST(DenseMapTest,AssignmentTest){this->Map[this->getKey()]=this->getValue();TypeParamcopyMap=this->Map;EXPECT_EQ(1u,copyMap.size());EXPECT_EQ(this->getValue(),copyMap[this->getKey()]);}// Test swap methodTYPED_TEST(DenseMapTest,SwapTest){this->Map[this->getKey()]=this->getValue();TypeParamotherMap;this->Map.swap(otherMap);EXPECT_EQ(0u,this->Map.size());EXPECT_TRUE(this->Map.empty());EXPECT_EQ(1u,otherMap.size());EXPECT_EQ(this->getValue(),otherMap[this->getKey()]);this->Map.swap(otherMap);EXPECT_EQ(0u,otherMap.size());EXPECT_TRUE(otherMap.empty());EXPECT_EQ(1u,this->Map.size());EXPECT_EQ(this->getValue(),this->Map[this->getKey()]);// Make this more interesting by inserting 100 numbers into the map.for(inti=0;i<100;++i)this->Map[this->getKey(i)]=this->getValue(i);this->Map.swap(otherMap);EXPECT_EQ(0u,this->Map.size());EXPECT_TRUE(this->Map.empty());EXPECT_EQ(100u,otherMap.size());for(inti=0;i<100;++i)EXPECT_EQ(this->getValue(i),otherMap[this->getKey(i)]);this->Map.swap(otherMap);EXPECT_EQ(0u,otherMap.size());EXPECT_TRUE(otherMap.empty());EXPECT_EQ(100u,this->Map.size());for(inti=0;i<100;++i)EXPECT_EQ(this->getValue(i),this->Map[this->getKey(i)]);}// A more complex iteration testTYPED_TEST(DenseMapTest,IterationTest){boolvisited[100];std::map<typenameTypeParam::key_type,unsigned>visitedIndex;// Insert 100 numbers into the mapfor(inti=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(typenameTypeParam::iteratorit=this->Map.begin();it!=this->Map.end();++it)visited[visitedIndex[it->first]]=true;// Ensure every number was visited.for(inti=0;i<100;++i)ASSERT_TRUE(visited[i])<<"Entry #"<<i<<" was never visited";}// const_iterator testTYPED_TEST(DenseMapTest,ConstIteratorTest){// Check conversion from iterator to const_iterator.typenameTypeParam::iteratorit=this->Map.begin();typenameTypeParam::const_iteratorcit(it);EXPECT_TRUE(it==cit);// Check copying of const_iterators.typenameTypeParam::const_iteratorcit2(cit);EXPECT_TRUE(cit==cit2);}// Key traits that allows lookup with either an unsigned or char* key;// In the latter case, "a" == 0, "b" == 1 and so on.structTestDenseMapInfo{staticinlineunsignedgetEmptyKey(){return~0;}staticinlineunsignedgetTombstoneKey(){return~0U-1;}staticunsignedgetHashValue(constunsigned&Val){returnVal*37U;}staticunsignedgetHashValue(constchar*Val){return(unsigned)(Val[0]-'a')*37U;}staticboolisEqual(constunsigned&LHS,constunsigned&RHS){returnLHS==RHS;}staticboolisEqual(constchar*LHS,constunsigned&RHS){return(unsigned)(LHS[0]-'a')==RHS;}};// find_as() testsTEST(DenseMapCustomTest,FindAsTest){DenseMap<unsigned,unsigned,TestDenseMapInfo>map;map[0]=1;map[1]=2;map[2]=3;// Size testsEXPECT_EQ(3u,map.size());// Normal lookup testsEXPECT_EQ(1,map.count(1));EXPECT_EQ(1u,map.find(0)->second);EXPECT_EQ(2u,map.find(1)->second);EXPECT_EQ(3u,map.find(2)->second);EXPECT_TRUE(map.find(3)==map.end());// find_as() testsEXPECT_EQ(1u,map.find_as("a")->second);EXPECT_EQ(2u,map.find_as("b")->second);EXPECT_EQ(3u,map.find_as("c")->second);EXPECT_TRUE(map.find_as("d")==map.end());}structContiguousDenseMapInfo{staticinlineunsignedgetEmptyKey(){return~0;}staticinlineunsignedgetTombstoneKey(){return~0U-1;}staticunsignedgetHashValue(constunsigned&Val){returnVal;}staticboolisEqual(constunsigned&LHS,constunsigned&RHS){returnLHS==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(DenseMapCustomTest,SmallDenseMapGrowTest){SmallDenseMap<unsigned,unsigned,32,ContiguousDenseMapInfo>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(unsignedi=0;i<20;++i)map[i]=i+1;for(unsignedi=0;i<10;++i)map.erase(i);for(unsignedi=20;i<32;++i)map[i]=i+1;// Size testsEXPECT_EQ(22u,map.size());// Try to find an element which doesn't exist. There was a bug in// SmallDenseMap 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());}}