llvm.org GIT mirror llvm / bf941ea
Adjust initial size in StringMap constructor to guarantee no grow() Summary: StringMap ctor accepts an initialize size, but expect it to be rounded to the next power of 2. The ctor can handle that directly instead of expecting clients to round it. Also, since the map will resize itself when 75% full, take this into account an initialize a larger initial size to avoid any growth. Reviewers: dblaikie Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D18344 From: Mehdi Amini <mehdi.amini@apple.com> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@264385 91177308-0d34-0410-b5e6-96231b3b80d8 Mehdi Amini 3 years ago
3 changed file(s) with 58 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
1414 #define LLVM_ADT_STRINGMAP_H
1515
1616 #include "llvm/ADT/StringRef.h"
17 #include "llvm/ADT/Twine.h"
1718 #include "llvm/Support/Allocator.h"
1819 #include
1920 #include
1616 #include
1717 using namespace llvm;
1818
19 /// Returns the number of buckets to allocate to ensure that the DenseMap can
20 /// accommodate \p NumEntries without need to grow().
21 static unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
22 // Ensure that "NumEntries * 4 < NumBuckets * 3"
23 if (NumEntries == 0)
24 return 0;
25 // +1 is required because of the strict equality.
26 // For example if NumEntries is 48, we need to return 401.
27 return NextPowerOf2(NumEntries * 4 / 3 + 1);
28 }
29
1930 StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
2031 ItemSize = itemSize;
2132
2233 // If a size is specified, initialize the table with that many buckets.
2334 if (InitSize) {
24 init(InitSize);
35 // The table will grow when the number of entries reach 3/4 of the number of
36 // buckets. To guarantee that "InitSize" number of entries can be inserted
37 // in the table without growing, we allocate just what is needed here.
38 init(getMinBucketToReserveForEntries(InitSize));
2539 return;
2640 }
2741
230230 // moved to a different bucket during internal rehashing. This depends on
231231 // the particular key, and the implementation of StringMap and HashString.
232232 // Changes to those might result in this test not actually checking that.
233 StringMap t(1);
234 EXPECT_EQ(1u, t.getNumBuckets());
233 StringMap t(0);
234 EXPECT_EQ(0u, t.getNumBuckets());
235235
236236 StringMap::iterator It =
237237 t.insert(std::make_pair("abcdef", 42)).first;
238 EXPECT_EQ(2u, t.getNumBuckets());
238 EXPECT_EQ(16u, t.getNumBuckets());
239239 EXPECT_EQ("abcdef", It->first());
240240 EXPECT_EQ(42u, It->second);
241241 }
355355 ASSERT_TRUE(B.empty());
356356 }
357357
358 namespace {
359 // Simple class that counts how many moves and copy happens when growing a map
360 struct CountCopyAndMove {
361 static unsigned Move;
362 static unsigned Copy;
363 CountCopyAndMove() {}
364
365 CountCopyAndMove(const CountCopyAndMove &) { Copy++; }
366 CountCopyAndMove &operator=(const CountCopyAndMove &) {
367 Copy++;
368 return *this;
369 }
370 CountCopyAndMove(CountCopyAndMove &&) { Move++; }
371 CountCopyAndMove &operator=(const CountCopyAndMove &&) {
372 Move++;
373 return *this;
374 }
375 };
376 unsigned CountCopyAndMove::Copy = 0;
377 unsigned CountCopyAndMove::Move = 0;
378
379 } // anonymous namespace
380
381 // Make sure creating the map with an initial size of N actually gives us enough
382 // buckets to insert N items without increasing allocation size.
383 TEST(StringMapCustomTest, InitialSizeTest) {
384 // 1 is an "edge value", 32 is an arbitrary power of two, and 67 is an
385 // arbitrary prime, picked without any good reason.
386 for (auto Size : {1, 32, 67}) {
387 StringMap Map(Size);
388 CountCopyAndMove::Copy = 0;
389 CountCopyAndMove::Move = 0;
390 for (int i = 0; i < Size; ++i)
391 Map.insert(std::make_pair(Twine(i).str(), CountCopyAndMove()));
392 EXPECT_EQ((unsigned)Size * 3, CountCopyAndMove::Move);
393 EXPECT_EQ(0u, CountCopyAndMove::Copy);
394 }
395 }
396
358397 } // end anonymous namespace