Add a copy constructor to StringMap

There is code under review that requires StringMap to have a copy constructor,
and this makes StringMap more consistent with our other containers (like
DenseMap) that have copy constructors.

Differential Revision: http://reviews.llvm.org/D18506

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@264906 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Hal Finkel 2016-03-30 19:54:56 +00:00
parent dfdada0adb
commit f5526fc013
2 changed files with 62 additions and 2 deletions

View File

@ -89,7 +89,8 @@ protected:
/// table, returning it. If the key is not in the table, this returns null.
StringMapEntryBase *RemoveKey(StringRef Key);
private:
/// Allocate the table with the specified number of buckets and otherwise
/// setup the map as empty.
void init(unsigned Size);
public:
@ -244,7 +245,39 @@ public:
return *this;
}
// FIXME: Implement copy operations if/when they're needed.
StringMap(const StringMap &RHS) :
StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
Allocator(RHS.Allocator) {
if (RHS.empty())
return;
// Allocate TheTable of the same size as RHS's TheTable, and set the
// sentinel appropriately (and NumBuckets).
init(RHS.NumBuckets);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1),
*RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1);
NumItems = RHS.NumItems;
NumTombstones = RHS.NumTombstones;
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
MapEntryTy *Bucket = ((MapEntryTy**) RHS.TheTable)[I];
if (!Bucket || Bucket == getTombstoneVal()) {
TheTable[I] = Bucket;
continue;
}
TheTable[I] = MapEntryTy::Create(Bucket->getKey(), Allocator,
Bucket->getValue());
HashTable[I] = RHSHashTable[I];
}
// Note that here we've copied everything from the RHS into this object,
// tombstones included. We could, instead, have re-probed for each key to
// instantiate this new object without any tombstone buckets. The
// assumption here is that items are rarely deleted from most StringMaps,
// and so tombstones are rare, so the cost of re-probing for all inputs is
// not worthwhile.
}
AllocatorTy &getAllocator() { return Allocator; }
const AllocatorTy &getAllocator() const { return Allocator; }

View File

@ -157,6 +157,33 @@ TEST_F(StringMapTest, SmallFullMapTest) {
EXPECT_EQ(5, Map.lookup("funf"));
}
TEST_F(StringMapTest, CopyCtorTest) {
llvm::StringMap<int> Map;
Map["eins"] = 1;
Map["zwei"] = 2;
Map["drei"] = 3;
Map.erase("drei");
Map.erase("eins");
Map["veir"] = 4;
Map["funf"] = 5;
EXPECT_EQ(3u, Map.size());
EXPECT_EQ(0, Map.lookup("eins"));
EXPECT_EQ(2, Map.lookup("zwei"));
EXPECT_EQ(0, Map.lookup("drei"));
EXPECT_EQ(4, Map.lookup("veir"));
EXPECT_EQ(5, Map.lookup("funf"));
llvm::StringMap<int> Map2(Map);
EXPECT_EQ(3u, Map2.size());
EXPECT_EQ(0, Map2.lookup("eins"));
EXPECT_EQ(2, Map2.lookup("zwei"));
EXPECT_EQ(0, Map2.lookup("drei"));
EXPECT_EQ(4, Map2.lookup("veir"));
EXPECT_EQ(5, Map2.lookup("funf"));
}
// A more complex iteration test.
TEST_F(StringMapTest, IterationTest) {
bool visited[100];