2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
28 #include "wtf/LinkedHashSet.h"
29 #include "wtf/ListHashSet.h"
30 #include "wtf/PassRefPtr.h"
31 #include "wtf/RefCounted.h"
32 #include "wtf/RefPtr.h"
33 #include <gtest/gtest.h>
39 template<typename Set
>
40 void removeFirstHelper()
49 EXPECT_EQ(-1, list
.first());
50 EXPECT_EQ(3, list
.last());
53 EXPECT_EQ(0, list
.first());
56 EXPECT_EQ(2, list
.last());
59 EXPECT_EQ(1, list
.first());
62 EXPECT_EQ(2, list
.first());
65 EXPECT_TRUE(list
.isEmpty());
68 TEST(ListHashSetTest
, RemoveFirst
)
70 removeFirstHelper
<ListHashSet
<int>>();
71 removeFirstHelper
<ListHashSet
<int, 1>>();
74 TEST(LinkedHashSetTest
, RemoveFirst
)
76 removeFirstHelper
<LinkedHashSet
<int>>();
79 template<typename Set
>
80 void appendOrMoveToLastNewItems()
83 typename
Set::AddResult result
= list
.appendOrMoveToLast(1);
84 EXPECT_TRUE(result
.isNewEntry
);
86 EXPECT_TRUE(result
.isNewEntry
);
87 result
= list
.appendOrMoveToLast(3);
88 EXPECT_TRUE(result
.isNewEntry
);
90 EXPECT_EQ(list
.size(), 3UL);
92 // The list should be in order 1, 2, 3.
93 typename
Set::iterator iterator
= list
.begin();
94 EXPECT_EQ(1, *iterator
);
96 EXPECT_EQ(2, *iterator
);
98 EXPECT_EQ(3, *iterator
);
102 TEST(ListHashSetTest
, AppendOrMoveToLastNewItems
)
104 appendOrMoveToLastNewItems
<ListHashSet
<int>>();
105 appendOrMoveToLastNewItems
<ListHashSet
<int, 1>>();
108 TEST(LinkedHashSetTest
, AppendOrMoveToLastNewItems
)
110 appendOrMoveToLastNewItems
<LinkedHashSet
<int>>();
113 template<typename Set
>
114 void appendOrMoveToLastWithDuplicates()
118 // Add a single element twice.
119 typename
Set::AddResult result
= list
.add(1);
120 EXPECT_TRUE(result
.isNewEntry
);
121 result
= list
.appendOrMoveToLast(1);
122 EXPECT_FALSE(result
.isNewEntry
);
123 EXPECT_EQ(1UL, list
.size());
127 EXPECT_EQ(3UL, list
.size());
129 // Appending 2 move it to the end.
130 EXPECT_EQ(3, list
.last());
131 result
= list
.appendOrMoveToLast(2);
132 EXPECT_FALSE(result
.isNewEntry
);
133 EXPECT_EQ(2, list
.last());
135 // Inverse the list by moving each element to end end.
136 result
= list
.appendOrMoveToLast(3);
137 EXPECT_FALSE(result
.isNewEntry
);
138 result
= list
.appendOrMoveToLast(2);
139 EXPECT_FALSE(result
.isNewEntry
);
140 result
= list
.appendOrMoveToLast(1);
141 EXPECT_FALSE(result
.isNewEntry
);
142 EXPECT_EQ(3UL, list
.size());
144 typename
Set::iterator iterator
= list
.begin();
145 EXPECT_EQ(3, *iterator
);
147 EXPECT_EQ(2, *iterator
);
149 EXPECT_EQ(1, *iterator
);
153 TEST(ListHashSetTest
, AppendOrMoveToLastWithDuplicates
)
155 appendOrMoveToLastWithDuplicates
<ListHashSet
<int>>();
156 appendOrMoveToLastWithDuplicates
<ListHashSet
<int, 1>>();
159 TEST(LinkedHashSetTest
, AppendOrMoveToLastWithDuplicates
)
161 appendOrMoveToLastWithDuplicates
<LinkedHashSet
<int>>();
164 template<typename Set
>
165 void prependOrMoveToFirstNewItems()
168 typename
Set::AddResult result
= list
.prependOrMoveToFirst(1);
169 EXPECT_TRUE(result
.isNewEntry
);
170 result
= list
.add(2);
171 EXPECT_TRUE(result
.isNewEntry
);
172 result
= list
.prependOrMoveToFirst(3);
173 EXPECT_TRUE(result
.isNewEntry
);
175 EXPECT_EQ(list
.size(), 3UL);
177 // The list should be in order 3, 1, 2.
178 typename
Set::iterator iterator
= list
.begin();
179 EXPECT_EQ(3, *iterator
);
181 EXPECT_EQ(1, *iterator
);
183 EXPECT_EQ(2, *iterator
);
187 TEST(ListHashSetTest
, PrependOrMoveToFirstNewItems
)
189 prependOrMoveToFirstNewItems
<ListHashSet
<int>>();
190 prependOrMoveToFirstNewItems
<ListHashSet
<int, 1>>();
193 TEST(LinkedHashSetTest
, PrependOrMoveToFirstNewItems
)
195 prependOrMoveToFirstNewItems
<LinkedHashSet
<int>>();
198 template<typename Set
>
199 void prependOrMoveToLastWithDuplicates()
203 // Add a single element twice.
204 typename
Set::AddResult result
= list
.add(1);
205 EXPECT_TRUE(result
.isNewEntry
);
206 result
= list
.prependOrMoveToFirst(1);
207 EXPECT_FALSE(result
.isNewEntry
);
208 EXPECT_EQ(1UL, list
.size());
212 EXPECT_EQ(3UL, list
.size());
214 // Prepending 2 move it to the beginning.
215 EXPECT_EQ(1, list
.first());
216 result
= list
.prependOrMoveToFirst(2);
217 EXPECT_FALSE(result
.isNewEntry
);
218 EXPECT_EQ(2, list
.first());
220 // Inverse the list by moving each element to the first position.
221 result
= list
.prependOrMoveToFirst(1);
222 EXPECT_FALSE(result
.isNewEntry
);
223 result
= list
.prependOrMoveToFirst(2);
224 EXPECT_FALSE(result
.isNewEntry
);
225 result
= list
.prependOrMoveToFirst(3);
226 EXPECT_FALSE(result
.isNewEntry
);
227 EXPECT_EQ(3UL, list
.size());
229 typename
Set::iterator iterator
= list
.begin();
230 EXPECT_EQ(3, *iterator
);
232 EXPECT_EQ(2, *iterator
);
234 EXPECT_EQ(1, *iterator
);
238 TEST(ListHashSetTest
, PrependOrMoveToLastWithDuplicates
)
240 prependOrMoveToLastWithDuplicates
<ListHashSet
<int>>();
241 prependOrMoveToLastWithDuplicates
<ListHashSet
<int, 1>>();
244 TEST(LinkedHashSetTest
, PrependOrMoveToLastWithDuplicates
)
246 prependOrMoveToLastWithDuplicates
<LinkedHashSet
<int>>();
249 class DummyRefCounted
: public RefCounted
<DummyRefCounted
> {
251 DummyRefCounted(bool& isDeleted
) : m_isDeleted(isDeleted
) { m_isDeleted
= false; }
252 ~DummyRefCounted() { m_isDeleted
= true; }
255 WTF::RefCounted
<DummyRefCounted
>::ref();
259 static int m_refInvokesCount
;
265 int DummyRefCounted::m_refInvokesCount
= 0;
267 template<typename Set
>
270 bool isDeleted
= false;
271 DummyRefCounted::m_refInvokesCount
= 0;
272 RefPtr
<DummyRefCounted
> ptr
= adoptRef(new DummyRefCounted(isDeleted
));
273 EXPECT_EQ(0, DummyRefCounted::m_refInvokesCount
);
277 // Referenced only once (to store a copy in the container).
278 EXPECT_EQ(1, DummyRefCounted::m_refInvokesCount
);
279 EXPECT_EQ(ptr
, set
.first());
280 EXPECT_EQ(1, DummyRefCounted::m_refInvokesCount
);
282 DummyRefCounted
* rawPtr
= ptr
.get();
284 EXPECT_TRUE(set
.contains(ptr
));
285 EXPECT_TRUE(set
.contains(rawPtr
));
286 EXPECT_EQ(1, DummyRefCounted::m_refInvokesCount
);
289 EXPECT_FALSE(isDeleted
);
290 EXPECT_EQ(1, DummyRefCounted::m_refInvokesCount
);
293 EXPECT_TRUE(isDeleted
);
295 EXPECT_EQ(1, DummyRefCounted::m_refInvokesCount
);
298 TEST(ListHashSetTest
, WithRefPtr
)
300 withRefPtr
<ListHashSet
<RefPtr
<DummyRefCounted
>>>();
301 withRefPtr
<ListHashSet
<RefPtr
<DummyRefCounted
>, 1>>();
304 TEST(LinkedHashSetTest
, WithRefPtr
)
306 withRefPtr
<LinkedHashSet
<RefPtr
<DummyRefCounted
>>>();
309 template<typename Set
, typename SetRef
, typename Iterator
>
320 Iterator it
= ref
.find(2);
329 TEST(ListHashSetTest
, Find
)
331 findHelper
<ListHashSet
<int>, const ListHashSet
<int>&, ListHashSet
<int>::const_iterator
>();
332 findHelper
<ListHashSet
<int>, ListHashSet
<int>&, ListHashSet
<int>::iterator
>();
333 findHelper
<ListHashSet
<int, 1>, const ListHashSet
<int, 1>&, ListHashSet
<int, 1>::const_iterator
>();
334 findHelper
<ListHashSet
<int, 1>, ListHashSet
<int, 1>&, ListHashSet
<int, 1>::iterator
>();
337 TEST(LinkedHashSetTest
, Find
)
339 findHelper
<LinkedHashSet
<int>, const LinkedHashSet
<int>&, LinkedHashSet
<int>::const_iterator
>();
340 findHelper
<LinkedHashSet
<int>, LinkedHashSet
<int>&, LinkedHashSet
<int>::iterator
>();
343 template<typename Set
>
344 void insertBeforeHelper(bool canModifyWhileIterating
)
352 typename
Set::iterator it
= set
.find(2);
354 set
.insertBefore(it
, 1);
355 if (!canModifyWhileIterating
)
359 EXPECT_EQ(5u, set
.size());
363 if (canModifyWhileIterating
) {
368 EXPECT_EQ(1u, set
.size());
371 EXPECT_EQ(it
, set
.end());
374 set
.insertBefore(it
, -1);
375 set
.insertBefore(it
, 0);
379 set
.insertBefore(2, 42);
380 set
.insertBefore(-1, 103);
381 EXPECT_EQ(103, set
.first());
382 if (!canModifyWhileIterating
)
386 EXPECT_EQ(7u, set
.size());
389 TEST(ListHashSetTest
, InsertBefore
)
391 insertBeforeHelper
<ListHashSet
<int>>(true);
392 insertBeforeHelper
<ListHashSet
<int, 1>>(true);
395 TEST(LinkedHashSetTest
, InsertBefore
)
397 insertBeforeHelper
<LinkedHashSet
<int>>(false);
400 template<typename Set
>
401 void addReturnIterator(bool canModifyWhileIterating
)
409 typename
Set::iterator it
= set
.addReturnIterator(3);
413 EXPECT_EQ(5u, set
.size());
418 it
= set
.addReturnIterator(4);
419 if (canModifyWhileIterating
) {
425 EXPECT_EQ(1u, set
.size());
429 EXPECT_EQ(it
, set
.end());
432 if (canModifyWhileIterating
) {
433 set
.insertBefore(it
, -1);
434 set
.insertBefore(it
, 0);
435 set
.insertBefore(it
, 1);
436 set
.insertBefore(it
, 2);
437 set
.insertBefore(it
, 3);
439 EXPECT_EQ(6u, set
.size());
440 it
= set
.addReturnIterator(5);
441 EXPECT_EQ(7u, set
.size());
443 EXPECT_EQ(6u, set
.size());
444 EXPECT_EQ(4, set
.last());
447 TEST(ListHashSetTest
, AddReturnIterator
)
449 addReturnIterator
<ListHashSet
<int>>(true);
450 addReturnIterator
<ListHashSet
<int, 1>>(true);
453 TEST(LinkedHashSetTest
, AddReturnIterator
)
455 addReturnIterator
<LinkedHashSet
<int>>(false);
458 template<typename Set
>
459 void excerciseValuePeekInType()
462 bool isDeleted
= false;
463 bool isDeleted2
= false;
465 RefPtr
<DummyRefCounted
> ptr
= adoptRef(new DummyRefCounted(isDeleted
));
466 RefPtr
<DummyRefCounted
> ptr2
= adoptRef(new DummyRefCounted(isDeleted2
));
468 typename
Set::AddResult addResult
= set
.add(ptr
);
469 EXPECT_TRUE(addResult
.isNewEntry
);
471 const Set
& constSet(set
);
473 EXPECT_TRUE(set
.contains(ptr
));
474 typename
Set::iterator it
= set
.addReturnIterator(ptr
);
475 set
.appendOrMoveToLast(ptr
);
476 set
.prependOrMoveToFirst(ptr
);
477 set
.insertBefore(ptr
, ptr
);
478 set
.insertBefore(it
, ptr
);
479 EXPECT_EQ(1u, set
.size());
484 EXPECT_FALSE(isDeleted
);
486 EXPECT_TRUE(isDeleted
);
488 EXPECT_FALSE(isDeleted2
);
490 EXPECT_TRUE(isDeleted2
);
492 EXPECT_EQ(0u, set
.size());
495 TEST(ListHashSetTest
, ExcerciseValuePeekInType
)
497 excerciseValuePeekInType
<ListHashSet
<RefPtr
<DummyRefCounted
>>>();
498 excerciseValuePeekInType
<ListHashSet
<RefPtr
<DummyRefCounted
>, 1>>();
501 TEST(LinkedHashSetTest
, ExcerciseValuePeekInType
)
503 excerciseValuePeekInType
<LinkedHashSet
<RefPtr
<DummyRefCounted
>>>();
507 Simple(int value
) : m_value(value
) { };
512 Complicated(int value
) : m_simple(value
)
514 s_objectsConstructed
++;
517 Complicated(const Complicated
& other
) : m_simple(other
.m_simple
)
519 s_objectsConstructed
++;
523 static int s_objectsConstructed
;
529 int Complicated::s_objectsConstructed
= 0;
531 struct ComplicatedHashFunctions
{
532 static unsigned hash(const Complicated
& key
) { return key
.m_simple
.m_value
; }
533 static bool equal(const Complicated
& a
, const Complicated
& b
) { return a
.m_simple
.m_value
== b
.m_simple
.m_value
; }
535 struct ComplexityTranslator
{
536 static unsigned hash(const Simple
& key
) { return key
.m_value
; }
537 static bool equal(const Complicated
& a
, const Simple
& b
) { return a
.m_simple
.m_value
== b
.m_value
; }
540 template<typename Set
>
541 void translatorTest()
544 set
.add(Complicated(42));
545 int baseLine
= Complicated::s_objectsConstructed
;
547 typename
Set::iterator it
= set
.template find
<ComplexityTranslator
>(Simple(42));
548 EXPECT_NE(it
, set
.end());
549 EXPECT_EQ(baseLine
, Complicated::s_objectsConstructed
);
551 it
= set
.template find
<ComplexityTranslator
>(Simple(103));
552 EXPECT_EQ(it
, set
.end());
553 EXPECT_EQ(baseLine
, Complicated::s_objectsConstructed
);
555 const Set
& constSet(set
);
557 typename
Set::const_iterator constIterator
= constSet
.template find
<ComplexityTranslator
>(Simple(42));
558 EXPECT_NE(constIterator
, constSet
.end());
559 EXPECT_EQ(baseLine
, Complicated::s_objectsConstructed
);
561 constIterator
= constSet
.template find
<ComplexityTranslator
>(Simple(103));
562 EXPECT_EQ(constIterator
, constSet
.end());
563 EXPECT_EQ(baseLine
, Complicated::s_objectsConstructed
);
566 TEST(ListHashSetTest
, ComplexityTranslator
)
568 translatorTest
<ListHashSet
<Complicated
, 256, ComplicatedHashFunctions
>>();
569 translatorTest
<ListHashSet
<Complicated
, 1, ComplicatedHashFunctions
>>();
572 TEST(LinkedHashSetTest
, ComplexityTranslator
)
574 translatorTest
<LinkedHashSet
<Complicated
, ComplicatedHashFunctions
>>();
578 Dummy(bool& deleted
) : deleted(deleted
) { }
588 TEST(ListHashSetTest
, WithOwnPtr
)
590 bool deleted1
= false, deleted2
= false;
592 typedef ListHashSet
<OwnPtr
<Dummy
>> OwnPtrSet
;
595 Dummy
* ptr1
= new Dummy(deleted1
);
597 // AddResult in a separate scope to avoid assertion hit,
598 // since we modify the container further.
599 OwnPtrSet::AddResult res1
= set
.add(adoptPtr(ptr1
));
600 EXPECT_EQ(res1
.storedValue
->m_value
.get(), ptr1
);
603 EXPECT_FALSE(deleted1
);
604 EXPECT_EQ(1UL, set
.size());
605 OwnPtrSet::iterator it1
= set
.find(ptr1
);
606 EXPECT_NE(set
.end(), it1
);
607 EXPECT_EQ(ptr1
, (*it1
));
609 Dummy
* ptr2
= new Dummy(deleted2
);
611 OwnPtrSet::AddResult res2
= set
.add(adoptPtr(ptr2
));
612 EXPECT_EQ(res2
.storedValue
->m_value
.get(), ptr2
);
615 EXPECT_FALSE(deleted2
);
616 EXPECT_EQ(2UL, set
.size());
617 OwnPtrSet::iterator it2
= set
.find(ptr2
);
618 EXPECT_NE(set
.end(), it2
);
619 EXPECT_EQ(ptr2
, (*it2
));
622 EXPECT_TRUE(deleted1
);
625 EXPECT_TRUE(deleted2
);
626 EXPECT_TRUE(set
.isEmpty());
632 set
.add(adoptPtr(new Dummy(deleted1
)));
633 set
.add(adoptPtr(new Dummy(deleted2
)));
635 EXPECT_TRUE(deleted1
);
636 EXPECT_TRUE(deleted2
);
641 OwnPtr
<Dummy
> ownPtr1
;
642 OwnPtr
<Dummy
> ownPtr2
;
643 ptr1
= new Dummy(deleted1
);
644 ptr2
= new Dummy(deleted2
);
647 set
.add(adoptPtr(ptr1
));
648 set
.add(adoptPtr(ptr2
));
649 ownPtr1
= set
.takeFirst();
650 EXPECT_EQ(1UL, set
.size());
651 ownPtr2
= set
.take(ptr2
);
652 EXPECT_TRUE(set
.isEmpty());
654 EXPECT_FALSE(deleted1
);
655 EXPECT_FALSE(deleted2
);
657 EXPECT_EQ(ptr1
, ownPtr1
);
658 EXPECT_EQ(ptr2
, ownPtr2
);
661 template<typename Set
>
662 void swapTestHelper()
668 for (int i
= 0; i
< num
; ++i
) {
673 typename
Set::iterator it1
= set1
.begin();
674 typename
Set::iterator it2
= set2
.begin();
675 for (int i
= 0; i
< num
; ++i
, ++it1
, ++it2
) {
676 EXPECT_EQ(*it1
, i
+ 1);
677 EXPECT_EQ(*it2
, num
- i
);
679 EXPECT_EQ(set0
.begin(), set0
.end());
680 EXPECT_EQ(it1
, set1
.end());
681 EXPECT_EQ(it2
, set2
.end());
683 // Shift sets: 2->1, 1->0, 0->2
684 set1
.swap(set2
); // Swap with non-empty sets.
685 set0
.swap(set2
); // Swap with an empty set.
689 for (int i
= 0; i
< num
; ++i
, ++it1
, ++it2
) {
690 EXPECT_EQ(*it1
, i
+ 1);
691 EXPECT_EQ(*it2
, num
- i
);
693 EXPECT_EQ(it1
, set0
.end());
694 EXPECT_EQ(it2
, set1
.end());
695 EXPECT_EQ(set2
.begin(), set2
.end());
697 int removedIndex
= num
>> 1;
698 set0
.remove(removedIndex
+ 1);
699 set1
.remove(num
- removedIndex
);
703 for (int i
= 0; i
< num
; ++i
, ++it1
, ++it2
) {
704 if (i
== removedIndex
)
706 EXPECT_EQ(*it1
, i
+ 1);
707 EXPECT_EQ(*it2
, num
- i
);
709 EXPECT_EQ(it1
, set0
.end());
710 EXPECT_EQ(it2
, set1
.end());
713 TEST(ListHashSetTest
, Swap
)
715 swapTestHelper
<ListHashSet
<int>>();
718 TEST(LinkedHashSetTest
, Swap
)
720 swapTestHelper
<LinkedHashSet
<int>>();
723 } // anonymous namespace