<div dir="ltr">Would it be worth adding a test that tests the functionality of reserve? (start with a default constructed container, add some number of elements and demonstrate that at some point a reallocation occurs and elements are moved (I assume they're moved, right? like move-semantic moved, or copied, not just buffers passed around) and then do the same thing but with a reserve call before adding any elements and demonstrate that elements are not moved around)</div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Jun 3, 2016 at 6:54 AM, Ben Craig via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: bcraig<br>
Date: Fri Jun  3 08:54:48 2016<br>
New Revision: 271669<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=271669&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=271669&view=rev</a><br>
Log:<br>
Adding reserve and capacity methods to FoldingSet<br>
<br>
<a href="http://reviews.llvm.org/D20930" rel="noreferrer" target="_blank">http://reviews.llvm.org/D20930</a><br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/ADT/FoldingSet.h<br>
    llvm/trunk/lib/Support/FoldingSet.cpp<br>
    llvm/trunk/unittests/ADT/FoldingSet.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/ADT/FoldingSet.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/FoldingSet.h?rev=271669&r1=271668&r2=271669&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/FoldingSet.h?rev=271669&r1=271668&r2=271669&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ADT/FoldingSet.h (original)<br>
+++ llvm/trunk/include/llvm/ADT/FoldingSet.h Fri Jun  3 08:54:48 2016<br>
@@ -180,11 +180,21 @@ public:<br>
   /// empty - Returns true if there are no nodes in the folding set.<br>
   bool empty() const { return NumNodes == 0; }<br>
<br>
+  void reserve(unsigned EltCount);<br>
+  unsigned capacity() {<br>
+    // We allow a load factor of up to 2.0,<br>
+    // so that means our capacity is NumBuckets * 2<br>
+    return NumBuckets * 2;<br>
+  }<br>
+<br>
 private:<br>
   /// GrowHashTable - Double the size of the hash table and rehash everything.<br>
-  ///<br>
   void GrowHashTable();<br>
<br>
+  /// GrowBucketCount - resize the hash table and rehash everything.<br>
+  /// NewBucketCount must be a power of two, and must be greater than the old<br>
+  /// bucket count.<br>
+  void GrowBucketCount(unsigned NewBucketCount);<br>
 protected:<br>
   /// GetNodeProfile - Instantiations of the FoldingSet template implement<br>
   /// this function to gather data bits for the given node.<br>
<br>
Modified: llvm/trunk/lib/Support/FoldingSet.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/FoldingSet.cpp?rev=271669&r1=271668&r2=271669&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/FoldingSet.cpp?rev=271669&r1=271668&r2=271669&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Support/FoldingSet.cpp (original)<br>
+++ llvm/trunk/lib/Support/FoldingSet.cpp Fri Jun  3 08:54:48 2016<br>
@@ -266,12 +266,12 @@ void FoldingSetImpl::clear() {<br>
   NumNodes = 0;<br>
 }<br>
<br>
-/// GrowHashTable - Double the size of the hash table and rehash everything.<br>
-///<br>
-void FoldingSetImpl::GrowHashTable() {<br>
+void FoldingSetImpl::GrowBucketCount(unsigned NewBucketCount) {<br>
+  assert((NewBucketCount > NumBuckets) && "Can't shrink a folding set with GrowBucketCount");<br>
+  assert(isPowerOf2_32(NewBucketCount) && "Bad bucket count!");<br>
   void **OldBuckets = Buckets;<br>
   unsigned OldNumBuckets = NumBuckets;<br>
-  NumBuckets <<= 1;<br>
+  NumBuckets = NewBucketCount;<br>
<br>
   // Clear out new buckets.<br>
   Buckets = AllocateBuckets(NumBuckets);<br>
@@ -298,6 +298,21 @@ void FoldingSetImpl::GrowHashTable() {<br>
   free(OldBuckets);<br>
 }<br>
<br>
+/// GrowHashTable - Double the size of the hash table and rehash everything.<br>
+///<br>
+void FoldingSetImpl::GrowHashTable() {<br>
+  GrowBucketCount(NumBuckets * 2);<br>
+}<br>
+<br>
+void FoldingSetImpl::reserve(unsigned EltCount) {<br>
+  // This will give us somewhere between EltCount / 2 and<br>
+  // EltCount buckets.  This puts us in the load factor<br>
+  // range of 1.0 - 2.0.<br>
+  if(EltCount < capacity())<br>
+    return;<br>
+  GrowBucketCount(PowerOf2Floor(EltCount));<br>
+}<br>
+<br>
 /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,<br>
 /// return it.  If not, return the insertion token that will make insertion<br>
 /// faster.<br>
@@ -330,7 +345,7 @@ FoldingSetImpl::Node<br>
 void FoldingSetImpl::InsertNode(Node *N, void *InsertPos) {<br>
   assert(!N->getNextInBucket());<br>
   // Do we need to grow the hashtable?<br>
-  if (NumNodes+1 > NumBuckets*2) {<br>
+  if (NumNodes+1 > capacity()) {<br>
     GrowHashTable();<br>
     FoldingSetNodeID TempID;<br>
     InsertPos = GetBucketFor(ComputeNodeHash(N, TempID), Buckets, NumBuckets);<br>
<br>
Modified: llvm/trunk/unittests/ADT/FoldingSet.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/FoldingSet.cpp?rev=271669&r1=271668&r2=271669&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/FoldingSet.cpp?rev=271669&r1=271668&r2=271669&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/ADT/FoldingSet.cpp (original)<br>
+++ llvm/trunk/unittests/ADT/FoldingSet.cpp Fri Jun  3 08:54:48 2016<br>
@@ -35,5 +35,138 @@ TEST(FoldingSetTest, UnalignedStringTest<br>
   EXPECT_EQ(a.ComputeHash(), b.ComputeHash());<br>
 }<br>
<br>
+struct TrivialPair : public FoldingSetNode {<br>
+  unsigned Key = 0;<br>
+  unsigned Value = 0;<br>
+  TrivialPair(unsigned K, unsigned V) : FoldingSetNode(), Key(K), Value(V) {}<br>
+<br>
+  void Profile(FoldingSetNodeID &ID) const {<br>
+    ID.AddInteger(Key);<br>
+    ID.AddInteger(Value);<br>
+  }<br>
+};<br>
+<br>
+TEST(FoldingSetTest, IDComparison) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+<br>
+  TrivialPair T(99, 42);<br>
+  Trivial.InsertNode(&T);<br>
+<br>
+  void *InsertPos = nullptr;<br>
+  FoldingSetNodeID ID;<br>
+  T.Profile(ID);<br>
+  TrivialPair *N = Trivial.FindNodeOrInsertPos(ID, InsertPos);<br>
+  EXPECT_EQ(&T, N);<br>
+  EXPECT_EQ(nullptr, InsertPos);<br>
+}<br>
+<br>
+TEST(FoldingSetTest, MissedIDComparison) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+<br>
+  TrivialPair S(100, 42);<br>
+  TrivialPair T(99, 42);<br>
+  Trivial.InsertNode(&T);<br>
+<br>
+  void *InsertPos = nullptr;<br>
+  FoldingSetNodeID ID;<br>
+  S.Profile(ID);<br>
+  TrivialPair *N = Trivial.FindNodeOrInsertPos(ID, InsertPos);<br>
+  EXPECT_EQ(nullptr, N);<br>
+  EXPECT_NE(nullptr, InsertPos);<br>
+}<br>
+<br>
+TEST(FoldingSetTest, RemoveNodeThatIsPresent) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+<br>
+  TrivialPair T(99, 42);<br>
+  Trivial.InsertNode(&T);<br>
+  EXPECT_EQ(Trivial.size(), 1U);<br>
+<br>
+  bool WasThere = Trivial.RemoveNode(&T);<br>
+  EXPECT_TRUE(WasThere);<br>
+  EXPECT_EQ(0U, Trivial.size());<br>
+}<br>
+<br>
+TEST(FoldingSetTest, RemoveNodeThatIsAbsent) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+<br>
+  TrivialPair T(99, 42);<br>
+  bool WasThere = Trivial.RemoveNode(&T);<br>
+  EXPECT_FALSE(WasThere);<br>
+  EXPECT_EQ(0U, Trivial.size());<br>
+}<br>
+<br>
+TEST(FoldingSetTest, GetOrInsertInserting) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+<br>
+  TrivialPair T(99, 42);<br>
+  TrivialPair *N = Trivial.GetOrInsertNode(&T);<br>
+  EXPECT_EQ(&T, N);<br>
+}<br>
+<br>
+TEST(FoldingSetTest, GetOrInsertGetting) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+<br>
+  TrivialPair T(99, 42);<br>
+  TrivialPair T2(99, 42);<br>
+  Trivial.InsertNode(&T);<br>
+  TrivialPair *N = Trivial.GetOrInsertNode(&T2);<br>
+  EXPECT_EQ(&T, N);<br>
+}<br>
+<br>
+TEST(FoldingSetTest, InsertAtPos) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+<br>
+  void *InsertPos = nullptr;<br>
+  TrivialPair Finder(99, 42);<br>
+  FoldingSetNodeID ID;<br>
+  Finder.Profile(ID);<br>
+  Trivial.FindNodeOrInsertPos(ID, InsertPos);<br>
+<br>
+  TrivialPair T(99, 42);<br>
+  Trivial.InsertNode(&T, InsertPos);<br>
+  EXPECT_EQ(1U, Trivial.size());<br>
+}<br>
+<br>
+TEST(FoldingSetTest, EmptyIsTrue) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+  EXPECT_TRUE(Trivial.empty());<br>
+}<br>
+<br>
+TEST(FoldingSetTest, EmptyIsFalse) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+  TrivialPair T(99, 42);<br>
+  Trivial.InsertNode(&T);<br>
+  EXPECT_FALSE(Trivial.empty());<br>
+}<br>
+<br>
+TEST(FoldingSetTest, ClearOnEmpty) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+  Trivial.clear();<br>
+  EXPECT_TRUE(Trivial.empty());<br>
+}<br>
+<br>
+TEST(FoldingSetTest, ClearOnNonEmpty) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+  TrivialPair T(99, 42);<br>
+  Trivial.InsertNode(&T);<br>
+  Trivial.clear();<br>
+  EXPECT_TRUE(Trivial.empty());<br>
+}<br>
+<br>
+TEST(FoldingSetTest, CapacityLargerThanReserve) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+  auto OldCapacity = Trivial.capacity();<br>
+  Trivial.reserve(OldCapacity + 1);<br>
+  EXPECT_GE(Trivial.capacity(), OldCapacity + 1);<br>
+}<br>
+<br>
+TEST(FoldingSetTest, SmallReserveChangesNothing) {<br>
+  FoldingSet<TrivialPair> Trivial;<br>
+  auto OldCapacity = Trivial.capacity();<br>
+  Trivial.reserve(OldCapacity - 1);<br>
+  EXPECT_EQ(Trivial.capacity(), OldCapacity);<br>
+}<br>
+<br>
 }<br>
<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>