<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<p>The elements are never moved or copied, as FoldingSet doesn't own
the elements (I think intrusive_hash_set would have been a better
name). The elements are part of a singly linked list, with the
FoldingSet's buckets as the heads of those lists.</p>
<p>So the publicly visible way to write the test that you describe
would be to force a hash-table collision, but not a full
hash-value collision. The last element that collided would have a
non-null NextInFoldingSetBucket member. When you rehash /
reserve, if the unmasked parts of the hash-value start to differ,
then you would get a null NextInFoldingSetBucket member after the
rehash.</p>
<p>Making a partial hash-value collision seems like a lot of
trouble. It would be easier if the hashing algorithm could be
chosen, but most of that is baked into the implementation of
FoldingSetNodeID.<br>
</p>
<div class="moz-cite-prefix">On 6/3/2016 10:30 AM, David Blaikie
wrote:<br>
</div>
<blockquote
cite="mid:CAENS6EvSjDQx8=p8LBbR9ydNC2AdTzP5EMUW9a4FEq6yC4ke=g@mail.gmail.com"
type="cite">
<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
moz-do-not-send="true"
href="mailto:llvm-commits@lists.llvm.org" target="_blank"><a class="moz-txt-link-abbreviated" href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a></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 moz-do-not-send="true"
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 moz-do-not-send="true"
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 moz-do-not-send="true"
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 moz-do-not-send="true"
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 moz-do-not-send="true"
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 moz-do-not-send="true"
href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a moz-do-not-send="true"
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>
</blockquote>
<br>
<pre class="moz-signature" cols="72">--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
</pre>
</body>
</html>