2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserved.
3 * Copyright (C) 2011, Benjamin Poulain <ikipou@gmail.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 #ifndef WTF_ListHashSet_h
23 #define WTF_ListHashSet_h
25 #include "wtf/DefaultAllocator.h"
26 #include "wtf/HashSet.h"
27 #include "wtf/OwnPtr.h"
28 #include "wtf/PassOwnPtr.h"
32 // ListHashSet: Just like HashSet, this class provides a Set
33 // interface - a collection of unique objects with O(1) insertion,
34 // removal and test for containership. However, it also has an
35 // order - iterating it will always give back values in the order
36 // in which they are added.
38 // Unlike iteration of most WTF Hash data structures, iteration is
39 // guaranteed safe against mutation of the ListHashSet, except for
40 // removal of the item currently pointed to by a given iterator.
42 template<typename Value
, size_t inlineCapacity
, typename HashFunctions
, typename Allocator
> class ListHashSet
;
44 template<typename Set
> class ListHashSetIterator
;
45 template<typename Set
> class ListHashSetConstIterator
;
46 template<typename Set
> class ListHashSetReverseIterator
;
47 template<typename Set
> class ListHashSetConstReverseIterator
;
49 template<typename ValueArg
> class ListHashSetNodeBase
;
50 template<typename ValueArg
, typename Allocator
> class ListHashSetNode
;
51 template<typename ValueArg
, size_t inlineCapacity
> struct ListHashSetAllocator
;
53 template<typename HashArg
> struct ListHashSetNodeHashFunctions
;
54 template<typename HashArg
> struct ListHashSetTranslator
;
56 // Note that for a ListHashSet you cannot specify the HashTraits as a
57 // template argument. It uses the default hash traits for the ValueArg
59 template<typename ValueArg
, size_t inlineCapacity
= 256, typename HashArg
= typename DefaultHash
<ValueArg
>::Hash
, typename AllocatorArg
= ListHashSetAllocator
<ValueArg
, inlineCapacity
>> class ListHashSet
60 : public ConditionalDestructor
<ListHashSet
<ValueArg
, inlineCapacity
, HashArg
, AllocatorArg
>, AllocatorArg::isGarbageCollected
> {
61 typedef AllocatorArg Allocator
;
62 WTF_USE_ALLOCATOR(ListHashSet
, Allocator
);
64 typedef ListHashSetNode
<ValueArg
, Allocator
> Node
;
65 typedef HashTraits
<Node
*> NodeTraits
;
66 typedef ListHashSetNodeHashFunctions
<HashArg
> NodeHash
;
67 typedef ListHashSetTranslator
<HashArg
> BaseTranslator
;
69 typedef HashTable
<Node
*, Node
*, IdentityExtractor
, NodeHash
, NodeTraits
, NodeTraits
, typename
Allocator::TableAllocator
> ImplType
;
70 typedef HashTableIterator
<Node
*, Node
*, IdentityExtractor
, NodeHash
, NodeTraits
, NodeTraits
, typename
Allocator::TableAllocator
> ImplTypeIterator
;
71 typedef HashTableConstIterator
<Node
*, Node
*, IdentityExtractor
, NodeHash
, NodeTraits
, NodeTraits
, typename
Allocator::TableAllocator
> ImplTypeConstIterator
;
73 typedef HashArg HashFunctions
;
76 typedef ValueArg ValueType
;
77 typedef HashTraits
<ValueType
> ValueTraits
;
78 typedef typename
ValueTraits::PeekInType ValuePeekInType
;
79 typedef typename
ValueTraits::PassInType ValuePassInType
;
80 typedef typename
ValueTraits::PassOutType ValuePassOutType
;
82 typedef ListHashSetIterator
<ListHashSet
> iterator
;
83 typedef ListHashSetConstIterator
<ListHashSet
> const_iterator
;
84 friend class ListHashSetIterator
<ListHashSet
>;
85 friend class ListHashSetConstIterator
<ListHashSet
>;
87 typedef ListHashSetReverseIterator
<ListHashSet
> reverse_iterator
;
88 typedef ListHashSetConstReverseIterator
<ListHashSet
> const_reverse_iterator
;
89 friend class ListHashSetReverseIterator
<ListHashSet
>;
90 friend class ListHashSetConstReverseIterator
<ListHashSet
>;
92 template<typename ValueType
> struct HashTableAddResult
{
93 HashTableAddResult(Node
* storedValue
, bool isNewEntry
) : storedValue(storedValue
), isNewEntry(isNewEntry
) { }
97 typedef HashTableAddResult
<ValueType
> AddResult
;
100 ListHashSet(const ListHashSet
&);
101 ListHashSet
& operator=(const ListHashSet
&);
104 void swap(ListHashSet
&);
106 unsigned size() const { return m_impl
.size(); }
107 unsigned capacity() const { return m_impl
.capacity(); }
108 bool isEmpty() const { return m_impl
.isEmpty(); }
110 iterator
begin() { return makeIterator(m_head
); }
111 iterator
end() { return makeIterator(0); }
112 const_iterator
begin() const { return makeConstIterator(m_head
); }
113 const_iterator
end() const { return makeConstIterator(0); }
115 reverse_iterator
rbegin() { return makeReverseIterator(m_tail
); }
116 reverse_iterator
rend() { return makeReverseIterator(0); }
117 const_reverse_iterator
rbegin() const { return makeConstReverseIterator(m_tail
); }
118 const_reverse_iterator
rend() const { return makeConstReverseIterator(0); }
121 const ValueType
& first() const;
125 const ValueType
& last() const;
128 iterator
find(ValuePeekInType
);
129 const_iterator
find(ValuePeekInType
) const;
130 bool contains(ValuePeekInType
) const;
132 // An alternate version of find() that finds the object by hashing and comparing
133 // with some other type, to avoid the cost of type conversion.
134 // The HashTranslator interface is defined in HashSet.
135 template<typename HashTranslator
, typename T
> iterator
find(const T
&);
136 template<typename HashTranslator
, typename T
> const_iterator
find(const T
&) const;
137 template<typename HashTranslator
, typename T
> bool contains(const T
&) const;
139 // The return value of add is a pair of a pointer to the stored value,
140 // and a bool that is true if an new entry was added.
141 AddResult
add(ValuePassInType
);
143 // Same as add() except that the return value is an
144 // iterator. Useful in cases where it's needed to have the
145 // same return value as find() and where it's not possible to
146 // use a pointer to the storedValue.
147 iterator
addReturnIterator(ValuePassInType
);
149 // Add the value to the end of the collection. If the value was already in
150 // the list, it is moved to the end.
151 AddResult
appendOrMoveToLast(ValuePassInType
);
153 // Add the value to the beginning of the collection. If the value was already in
154 // the list, it is moved to the beginning.
155 AddResult
prependOrMoveToFirst(ValuePassInType
);
157 AddResult
insertBefore(ValuePeekInType beforeValue
, ValuePassInType newValue
);
158 AddResult
insertBefore(iterator
, ValuePassInType
);
160 void remove(ValuePeekInType value
) { return remove(find(value
)); }
161 void remove(iterator
);
163 template<typename Collection
>
164 void removeAll(const Collection
& other
) { WTF::removeAll(*this, other
); }
166 ValuePassOutType
take(iterator
);
167 ValuePassOutType
take(ValuePeekInType
);
168 ValuePassOutType
takeFirst();
170 template<typename VisitorDispatcher
>
171 void trace(VisitorDispatcher
);
175 void unlinkAndDelete(Node
*);
176 void appendNode(Node
*);
177 void prependNode(Node
*);
178 void insertNodeBefore(Node
* beforeNode
, Node
* newNode
);
179 void deleteAllNodes();
180 Allocator
* allocator() const { return m_allocatorProvider
.get(); }
181 void createAllocatorIfNeeded() { m_allocatorProvider
.createAllocatorIfNeeded(); }
182 void deallocate(Node
* node
) const { m_allocatorProvider
.deallocate(node
); }
184 iterator
makeIterator(Node
* position
) { return iterator(this, position
); }
185 const_iterator
makeConstIterator(Node
* position
) const { return const_iterator(this, position
); }
186 reverse_iterator
makeReverseIterator(Node
* position
) { return reverse_iterator(this, position
); }
187 const_reverse_iterator
makeConstReverseIterator(Node
* position
) const { return const_reverse_iterator(this, position
); }
192 typename
Allocator::AllocatorProvider m_allocatorProvider
;
195 // ListHashSetNode has this base class to hold the members because the MSVC
196 // compiler otherwise gets into circular template dependencies when trying
197 // to do sizeof on a node.
198 template<typename ValueArg
> class ListHashSetNodeBase
{
200 ListHashSetNodeBase(const ValueArg
& value
)
205 , m_isAllocated(true)
210 template <typename U
>
211 ListHashSetNodeBase(const U
& value
)
216 , m_isAllocated(true)
223 ListHashSetNodeBase
* m_prev
;
224 ListHashSetNodeBase
* m_next
;
230 // This allocator is only used for non-Heap ListHashSets.
231 template<typename ValueArg
, size_t inlineCapacity
>
232 struct ListHashSetAllocator
: public DefaultAllocator
{
233 typedef DefaultAllocator TableAllocator
;
234 typedef ListHashSetNode
<ValueArg
, ListHashSetAllocator
> Node
;
235 typedef ListHashSetNodeBase
<ValueArg
> NodeBase
;
236 class AllocatorProvider
{
238 AllocatorProvider() : m_allocator(nullptr) { }
239 void createAllocatorIfNeeded()
242 m_allocator
= new ListHashSetAllocator
;
245 void releaseAllocator()
248 m_allocator
= nullptr;
251 void swap(AllocatorProvider
& other
)
253 std::swap(m_allocator
, other
.m_allocator
);
256 void deallocate(Node
* node
) const
259 m_allocator
->deallocate(node
);
262 ListHashSetAllocator
* get() const
269 // Not using OwnPtr as this pointer should be deleted at
270 // releaseAllocator() method rather than at destructor.
271 ListHashSetAllocator
* m_allocator
;
274 ListHashSetAllocator()
276 , m_isDoneWithInitialFreeList(false)
278 memset(m_pool
.buffer
, 0, sizeof(m_pool
.buffer
));
283 Node
* result
= m_freeList
;
286 return static_cast<Node
*>(fastMalloc(sizeof(NodeBase
)));
288 ASSERT(!result
->m_isAllocated
);
290 Node
* next
= result
->next();
291 ASSERT(!next
|| !next
->m_isAllocated
);
292 if (!next
&& !m_isDoneWithInitialFreeList
) {
294 if (next
== pastPool()) {
295 m_isDoneWithInitialFreeList
= true;
298 ASSERT(inPool(next
));
299 ASSERT(!next
->m_isAllocated
);
307 void deallocate(Node
* node
)
311 node
->m_isAllocated
= false;
313 node
->m_next
= m_freeList
;
321 bool inPool(Node
* node
)
323 return node
>= pool() && node
< pastPool();
326 static void traceValue(typename
DefaultAllocator::Visitor
* visitor
, Node
* node
) { }
329 Node
* pool() { return reinterpret_cast_ptr
<Node
*>(m_pool
.buffer
); }
330 Node
* pastPool() { return pool() + m_poolSize
; }
333 bool m_isDoneWithInitialFreeList
;
334 #if defined(MEMORY_SANITIZER_INITIAL_SIZE)
335 // The allocation pool for nodes is one big chunk that ASAN has no
336 // insight into, so it can cloak errors. Make it as small as possible
337 // to force nodes to be allocated individually where ASAN can see them.
338 static const size_t m_poolSize
= 1;
340 static const size_t m_poolSize
= inlineCapacity
;
342 AlignedBuffer
<sizeof(NodeBase
) * m_poolSize
, WTF_ALIGN_OF(NodeBase
)> m_pool
;
345 template<typename ValueArg
, typename AllocatorArg
> class ListHashSetNode
: public ListHashSetNodeBase
<ValueArg
> {
347 typedef AllocatorArg NodeAllocator
;
348 typedef ValueArg Value
;
350 template <typename U
>
351 ListHashSetNode(U value
)
352 : ListHashSetNodeBase
<ValueArg
>(value
) { }
354 void* operator new(size_t, NodeAllocator
* allocator
)
356 static_assert(sizeof(ListHashSetNode
) == sizeof(ListHashSetNodeBase
<ValueArg
>), "please add any fields to the base");
357 return allocator
->allocateNode();
360 void setWasAlreadyDestructed()
362 if (NodeAllocator::isGarbageCollected
&& !IsTriviallyDestructible
<ValueArg
>::value
)
363 this->m_prev
= unlinkedNodePointer();
366 bool wasAlreadyDestructed() const
368 ASSERT(NodeAllocator::isGarbageCollected
);
369 return this->m_prev
== unlinkedNodePointer();
372 static void finalize(void* pointer
)
374 ASSERT(!IsTriviallyDestructible
<ValueArg
>::value
); // No need to waste time calling finalize if it's not needed.
375 ListHashSetNode
* self
= reinterpret_cast_ptr
<ListHashSetNode
*>(pointer
);
377 // Check whether this node was already destructed before being
378 // unlinked from the collection.
379 if (self
->wasAlreadyDestructed())
382 self
->m_value
.~ValueArg();
384 void finalizeGarbageCollectedObject()
389 void destroy(NodeAllocator
* allocator
)
391 this->~ListHashSetNode();
392 setWasAlreadyDestructed();
393 allocator
->deallocate(this);
396 // This is not called in normal tracing, but it is called if we find a
397 // pointer to a node on the stack using conservative scanning. Since
398 // the original ListHashSet may no longer exist we make sure to mark
399 // the neighbours in the chain too.
400 template<typename VisitorDispatcher
>
401 void trace(VisitorDispatcher visitor
)
403 // The conservative stack scan can find nodes that have been
404 // removed from the set and destructed. We don't need to trace
405 // these, and it would be wrong to do so, because the class will
406 // not expect the trace method to be called after the destructor.
407 // It's an error to remove a node from the ListHashSet while an
408 // iterator is positioned at that node, so there should be no valid
409 // pointers from the stack to a destructed node.
410 if (wasAlreadyDestructed())
412 NodeAllocator::traceValue(visitor
, this);
413 visitor
->mark(next());
414 visitor
->mark(prev());
417 ListHashSetNode
* next() const { return reinterpret_cast<ListHashSetNode
*>(this->m_next
); }
418 ListHashSetNode
* prev() const { return reinterpret_cast<ListHashSetNode
*>(this->m_prev
); }
420 // Don't add fields here, the ListHashSetNodeBase and this should have
423 static ListHashSetNode
* unlinkedNodePointer() { return reinterpret_cast<ListHashSetNode
*>(-1); }
425 template<typename HashArg
>
426 friend struct ListHashSetNodeHashFunctions
;
429 template<typename HashArg
> struct ListHashSetNodeHashFunctions
{
430 template<typename T
> static unsigned hash(const T
& key
) { return HashArg::hash(key
->m_value
); }
431 template<typename T
> static bool equal(const T
& a
, const T
& b
) { return HashArg::equal(a
->m_value
, b
->m_value
); }
432 static const bool safeToCompareToEmptyOrDeleted
= false;
435 template<typename Set
> class ListHashSetIterator
{
437 typedef typename
Set::const_iterator const_iterator
;
438 typedef typename
Set::Node Node
;
439 typedef typename
Set::ValueType ValueType
;
440 typedef ValueType
& ReferenceType
;
441 typedef ValueType
* PointerType
;
443 ListHashSetIterator(const Set
* set
, Node
* position
) : m_iterator(set
, position
) { }
446 ListHashSetIterator() { }
448 // default copy, assignment and destructor are OK
450 PointerType
get() const { return const_cast<PointerType
>(m_iterator
.get()); }
451 ReferenceType
operator*() const { return *get(); }
452 PointerType
operator->() const { return get(); }
454 ListHashSetIterator
& operator++() { ++m_iterator
; return *this; }
455 ListHashSetIterator
& operator--() { --m_iterator
; return *this; }
457 // Postfix ++ and -- intentionally omitted.
460 bool operator==(const ListHashSetIterator
& other
) const { return m_iterator
== other
.m_iterator
; }
461 bool operator!=(const ListHashSetIterator
& other
) const { return m_iterator
!= other
.m_iterator
; }
463 operator const_iterator() const { return m_iterator
; }
466 Node
* node() { return m_iterator
.node(); }
468 const_iterator m_iterator
;
470 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
471 friend class ListHashSet
;
474 template<typename Set
>
475 class ListHashSetConstIterator
{
477 typedef typename
Set::const_iterator const_iterator
;
478 typedef typename
Set::Node Node
;
479 typedef typename
Set::ValueType ValueType
;
480 typedef const ValueType
& ReferenceType
;
481 typedef const ValueType
* PointerType
;
483 friend class ListHashSetIterator
<Set
>;
485 ListHashSetConstIterator(const Set
* set
, Node
* position
)
487 , m_position(position
)
492 ListHashSetConstIterator()
496 PointerType
get() const
498 return &m_position
->m_value
;
500 ReferenceType
operator*() const { return *get(); }
501 PointerType
operator->() const { return get(); }
503 ListHashSetConstIterator
& operator++()
505 ASSERT(m_position
!= 0);
506 m_position
= m_position
->next();
510 ListHashSetConstIterator
& operator--()
512 ASSERT(m_position
!= m_set
->m_head
);
514 m_position
= m_set
->m_tail
;
516 m_position
= m_position
->prev();
520 // Postfix ++ and -- intentionally omitted.
523 bool operator==(const ListHashSetConstIterator
& other
) const
525 return m_position
== other
.m_position
;
527 bool operator!=(const ListHashSetConstIterator
& other
) const
529 return m_position
!= other
.m_position
;
533 Node
* node() { return m_position
; }
538 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
539 friend class ListHashSet
;
542 template<typename Set
>
543 class ListHashSetReverseIterator
{
545 typedef typename
Set::const_reverse_iterator const_reverse_iterator
;
546 typedef typename
Set::Node Node
;
547 typedef typename
Set::ValueType ValueType
;
548 typedef ValueType
& ReferenceType
;
549 typedef ValueType
* PointerType
;
551 ListHashSetReverseIterator(const Set
* set
, Node
* position
) : m_iterator(set
, position
) { }
554 ListHashSetReverseIterator() { }
556 // default copy, assignment and destructor are OK
558 PointerType
get() const { return const_cast<PointerType
>(m_iterator
.get()); }
559 ReferenceType
operator*() const { return *get(); }
560 PointerType
operator->() const { return get(); }
562 ListHashSetReverseIterator
& operator++() { ++m_iterator
; return *this; }
563 ListHashSetReverseIterator
& operator--() { --m_iterator
; return *this; }
565 // Postfix ++ and -- intentionally omitted.
568 bool operator==(const ListHashSetReverseIterator
& other
) const { return m_iterator
== other
.m_iterator
; }
569 bool operator!=(const ListHashSetReverseIterator
& other
) const { return m_iterator
!= other
.m_iterator
; }
571 operator const_reverse_iterator() const { return m_iterator
; }
574 Node
* node() { return m_iterator
.node(); }
576 const_reverse_iterator m_iterator
;
578 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
579 friend class ListHashSet
;
582 template<typename Set
> class ListHashSetConstReverseIterator
{
584 typedef typename
Set::reverse_iterator reverse_iterator
;
585 typedef typename
Set::Node Node
;
586 typedef typename
Set::ValueType ValueType
;
587 typedef const ValueType
& ReferenceType
;
588 typedef const ValueType
* PointerType
;
590 friend class ListHashSetReverseIterator
<Set
>;
592 ListHashSetConstReverseIterator(const Set
* set
, Node
* position
)
594 , m_position(position
)
599 ListHashSetConstReverseIterator()
603 PointerType
get() const
605 return &m_position
->m_value
;
607 ReferenceType
operator*() const { return *get(); }
608 PointerType
operator->() const { return get(); }
610 ListHashSetConstReverseIterator
& operator++()
612 ASSERT(m_position
!= 0);
613 m_position
= m_position
->prev();
617 ListHashSetConstReverseIterator
& operator--()
619 ASSERT(m_position
!= m_set
->m_tail
);
621 m_position
= m_set
->m_head
;
623 m_position
= m_position
->next();
627 // Postfix ++ and -- intentionally omitted.
630 bool operator==(const ListHashSetConstReverseIterator
& other
) const
632 return m_position
== other
.m_position
;
634 bool operator!=(const ListHashSetConstReverseIterator
& other
) const
636 return m_position
!= other
.m_position
;
640 Node
* node() { return m_position
; }
645 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
646 friend class ListHashSet
;
649 template<typename HashFunctions
>
650 struct ListHashSetTranslator
{
651 template<typename T
> static unsigned hash(const T
& key
) { return HashFunctions::hash(key
); }
652 template<typename T
, typename U
> static bool equal(const T
& a
, const U
& b
) { return HashFunctions::equal(a
->m_value
, b
); }
653 template<typename T
, typename U
, typename V
> static void translate(T
*& location
, const U
& key
, const V
& allocator
)
655 location
= new (const_cast<V
*>(&allocator
)) T(key
);
659 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
660 inline ListHashSet
<T
, inlineCapacity
, U
, V
>::ListHashSet()
666 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
667 inline ListHashSet
<T
, inlineCapacity
, U
, V
>::ListHashSet(const ListHashSet
& other
)
671 const_iterator end
= other
.end();
672 for (const_iterator it
= other
.begin(); it
!= end
; ++it
)
676 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
677 inline ListHashSet
<T
, inlineCapacity
, U
, V
>& ListHashSet
<T
, inlineCapacity
, U
, V
>::operator=(const ListHashSet
& other
)
679 ListHashSet
tmp(other
);
684 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
685 inline void ListHashSet
<T
, inlineCapacity
, U
, V
>::swap(ListHashSet
& other
)
687 m_impl
.swap(other
.m_impl
);
688 std::swap(m_head
, other
.m_head
);
689 std::swap(m_tail
, other
.m_tail
);
690 m_allocatorProvider
.swap(other
.m_allocatorProvider
);
693 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
694 inline void ListHashSet
<T
, inlineCapacity
, U
, V
>::finalize()
696 static_assert(!Allocator::isGarbageCollected
, "heap allocated ListHashSet should never call finalize()");
698 m_allocatorProvider
.releaseAllocator();
701 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
702 inline T
& ListHashSet
<T
, inlineCapacity
, U
, V
>::first()
705 return m_head
->m_value
;
708 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
709 inline void ListHashSet
<T
, inlineCapacity
, U
, V
>::removeFirst()
712 m_impl
.remove(m_head
);
713 unlinkAndDelete(m_head
);
716 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
717 inline const T
& ListHashSet
<T
, inlineCapacity
, U
, V
>::first() const
720 return m_head
->m_value
;
723 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
724 inline T
& ListHashSet
<T
, inlineCapacity
, U
, V
>::last()
727 return m_tail
->m_value
;
730 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
731 inline const T
& ListHashSet
<T
, inlineCapacity
, U
, V
>::last() const
734 return m_tail
->m_value
;
737 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
738 inline void ListHashSet
<T
, inlineCapacity
, U
, V
>::removeLast()
741 m_impl
.remove(m_tail
);
742 unlinkAndDelete(m_tail
);
745 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
746 inline typename ListHashSet
<T
, inlineCapacity
, U
, V
>::iterator ListHashSet
<T
, inlineCapacity
, U
, V
>::find(ValuePeekInType value
)
748 ImplTypeIterator it
= m_impl
.template find
<BaseTranslator
>(value
);
749 if (it
== m_impl
.end())
751 return makeIterator(*it
);
754 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
755 inline typename ListHashSet
<T
, inlineCapacity
, U
, V
>::const_iterator ListHashSet
<T
, inlineCapacity
, U
, V
>::find(ValuePeekInType value
) const
757 ImplTypeConstIterator it
= m_impl
.template find
<BaseTranslator
>(value
);
758 if (it
== m_impl
.end())
760 return makeConstIterator(*it
);
763 template<typename Translator
>
764 struct ListHashSetTranslatorAdapter
{
765 template<typename T
> static unsigned hash(const T
& key
) { return Translator::hash(key
); }
766 template<typename T
, typename U
> static bool equal(const T
& a
, const U
& b
) { return Translator::equal(a
->m_value
, b
); }
769 template<typename ValueType
, size_t inlineCapacity
, typename U
, typename V
>
770 template<typename HashTranslator
, typename T
>
771 inline typename ListHashSet
<ValueType
, inlineCapacity
, U
, V
>::iterator ListHashSet
<ValueType
, inlineCapacity
, U
, V
>::find(const T
& value
)
773 ImplTypeConstIterator it
= m_impl
.template find
<ListHashSetTranslatorAdapter
<HashTranslator
>>(value
);
774 if (it
== m_impl
.end())
776 return makeIterator(*it
);
779 template<typename ValueType
, size_t inlineCapacity
, typename U
, typename V
>
780 template<typename HashTranslator
, typename T
>
781 inline typename ListHashSet
<ValueType
, inlineCapacity
, U
, V
>::const_iterator ListHashSet
<ValueType
, inlineCapacity
, U
, V
>::find(const T
& value
) const
783 ImplTypeConstIterator it
= m_impl
.template find
<ListHashSetTranslatorAdapter
<HashTranslator
>>(value
);
784 if (it
== m_impl
.end())
786 return makeConstIterator(*it
);
789 template<typename ValueType
, size_t inlineCapacity
, typename U
, typename V
>
790 template<typename HashTranslator
, typename T
>
791 inline bool ListHashSet
<ValueType
, inlineCapacity
, U
, V
>::contains(const T
& value
) const
793 return m_impl
.template contains
<ListHashSetTranslatorAdapter
<HashTranslator
>>(value
);
796 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
797 inline bool ListHashSet
<T
, inlineCapacity
, U
, V
>::contains(ValuePeekInType value
) const
799 return m_impl
.template contains
<BaseTranslator
>(value
);
802 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
803 typename ListHashSet
<T
, inlineCapacity
, U
, V
>::AddResult ListHashSet
<T
, inlineCapacity
, U
, V
>::add(ValuePassInType value
)
805 createAllocatorIfNeeded();
806 // The second argument is a const ref. This is useful for the HashTable
807 // because it lets it take lvalues by reference, but for our purposes
808 // it's inconvenient, since it constrains us to be const, whereas the
809 // allocator actually changes when it does allocations.
810 auto result
= m_impl
.template add
<BaseTranslator
>(value
, *this->allocator());
811 if (result
.isNewEntry
)
812 appendNode(*result
.storedValue
);
813 return AddResult(*result
.storedValue
, result
.isNewEntry
);
816 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
817 typename ListHashSet
<T
, inlineCapacity
, U
, V
>::iterator ListHashSet
<T
, inlineCapacity
, U
, V
>::addReturnIterator(ValuePassInType value
)
819 return makeIterator(add(value
).storedValue
);
822 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
823 typename ListHashSet
<T
, inlineCapacity
, U
, V
>::AddResult ListHashSet
<T
, inlineCapacity
, U
, V
>::appendOrMoveToLast(ValuePassInType value
)
825 createAllocatorIfNeeded();
826 auto result
= m_impl
.template add
<BaseTranslator
>(value
, *this->allocator());
827 Node
* node
= *result
.storedValue
;
828 if (!result
.isNewEntry
)
831 return AddResult(*result
.storedValue
, result
.isNewEntry
);
834 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
835 typename ListHashSet
<T
, inlineCapacity
, U
, V
>::AddResult ListHashSet
<T
, inlineCapacity
, U
, V
>::prependOrMoveToFirst(ValuePassInType value
)
837 createAllocatorIfNeeded();
838 auto result
= m_impl
.template add
<BaseTranslator
>(value
, *this->allocator());
839 Node
* node
= *result
.storedValue
;
840 if (!result
.isNewEntry
)
843 return AddResult(*result
.storedValue
, result
.isNewEntry
);
846 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
847 typename ListHashSet
<T
, inlineCapacity
, U
, V
>::AddResult ListHashSet
<T
, inlineCapacity
, U
, V
>::insertBefore(iterator it
, ValuePassInType newValue
)
849 createAllocatorIfNeeded();
850 auto result
= m_impl
.template add
<BaseTranslator
>(newValue
, *this->allocator());
851 if (result
.isNewEntry
)
852 insertNodeBefore(it
.node(), *result
.storedValue
);
853 return AddResult(*result
.storedValue
, result
.isNewEntry
);
856 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
857 typename ListHashSet
<T
, inlineCapacity
, U
, V
>::AddResult ListHashSet
<T
, inlineCapacity
, U
, V
>::insertBefore(ValuePeekInType beforeValue
, ValuePassInType newValue
)
859 createAllocatorIfNeeded();
860 return insertBefore(find(beforeValue
), newValue
);
863 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
864 inline void ListHashSet
<T
, inlineCapacity
, U
, V
>::remove(iterator it
)
868 m_impl
.remove(it
.node());
869 unlinkAndDelete(it
.node());
872 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
873 inline void ListHashSet
<T
, inlineCapacity
, U
, V
>::clear()
881 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
882 typename ListHashSet
<T
, inlineCapacity
, U
, V
>::ValuePassOutType ListHashSet
<T
, inlineCapacity
, U
, V
>::take(iterator it
)
885 return ValueTraits::emptyValue();
887 m_impl
.remove(it
.node());
888 ValuePassOutType result
= ValueTraits::passOut(it
.node()->m_value
);
889 unlinkAndDelete(it
.node());
894 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
895 typename ListHashSet
<T
, inlineCapacity
, U
, V
>::ValuePassOutType ListHashSet
<T
, inlineCapacity
, U
, V
>::take(ValuePeekInType value
)
897 return take(find(value
));
900 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
901 typename ListHashSet
<T
, inlineCapacity
, U
, V
>::ValuePassOutType ListHashSet
<T
, inlineCapacity
, U
, V
>::takeFirst()
904 m_impl
.remove(m_head
);
905 ValuePassOutType result
= ValueTraits::passOut(m_head
->m_value
);
906 unlinkAndDelete(m_head
);
911 template<typename T
, size_t inlineCapacity
, typename U
, typename Allocator
>
912 void ListHashSet
<T
, inlineCapacity
, U
, Allocator
>::unlink(Node
* node
)
915 ASSERT(node
== m_head
);
916 m_head
= node
->next();
918 ASSERT(node
!= m_head
);
919 node
->m_prev
->m_next
= node
->m_next
;
923 ASSERT(node
== m_tail
);
924 m_tail
= node
->prev();
926 ASSERT(node
!= m_tail
);
927 node
->m_next
->m_prev
= node
->m_prev
;
931 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
932 void ListHashSet
<T
, inlineCapacity
, U
, V
>::unlinkAndDelete(Node
* node
)
935 node
->destroy(this->allocator());
938 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
939 void ListHashSet
<T
, inlineCapacity
, U
, V
>::appendNode(Node
* node
)
941 node
->m_prev
= m_tail
;
946 m_tail
->m_next
= node
;
955 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
956 void ListHashSet
<T
, inlineCapacity
, U
, V
>::prependNode(Node
* node
)
959 node
->m_next
= m_head
;
962 m_head
->m_prev
= node
;
969 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
970 void ListHashSet
<T
, inlineCapacity
, U
, V
>::insertNodeBefore(Node
* beforeNode
, Node
* newNode
)
973 return appendNode(newNode
);
975 newNode
->m_next
= beforeNode
;
976 newNode
->m_prev
= beforeNode
->m_prev
;
977 if (beforeNode
->m_prev
)
978 beforeNode
->m_prev
->m_next
= newNode
;
979 beforeNode
->m_prev
= newNode
;
981 if (!newNode
->m_prev
)
985 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
986 void ListHashSet
<T
, inlineCapacity
, U
, V
>::deleteAllNodes()
991 for (Node
* node
= m_head
, *next
= m_head
->next(); node
; node
= next
, next
= node
? node
->next() : 0)
992 node
->destroy(this->allocator());
995 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
996 template<typename VisitorDispatcher
>
997 void ListHashSet
<T
, inlineCapacity
, U
, V
>::trace(VisitorDispatcher visitor
)
999 static_assert(HashTraits
<T
>::weakHandlingFlag
== NoWeakHandlingInCollections
, "ListHashSet does not support weakness");
1000 // This marks all the nodes and their contents live that can be
1001 // accessed through the HashTable. That includes m_head and m_tail
1002 // so we do not have to explicitly trace them here.
1003 m_impl
.trace(visitor
);
1007 template<typename T
, size_t U
, typename V
>
1008 struct NeedsTracing
<ListHashSet
<T
, U
, V
>> {
1009 static const bool value
= false;
1015 using WTF::ListHashSet
;
1017 #endif /* WTF_ListHashSet_h */