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 // Don't declare a destructor for HeapAllocated ListHashSet.
57 template<typename Derived, typename Allocator, bool isGarbageCollected>
58 class ListHashSetDestructorBase;
60 template<typename Derived, typename Allocator>
61 class ListHashSetDestructorBase<Derived, Allocator, true> {
63 typename Allocator::AllocatorProvider m_allocatorProvider;
66 template<typename Derived, typename Allocator>
67 class ListHashSetDestructorBase<Derived, Allocator, false> {
69 ~ListHashSetDestructorBase() { static_cast<Derived*>(this)->finalize(); }
71 typename Allocator::AllocatorProvider m_allocatorProvider;
74 // Note that for a ListHashSet you cannot specify the HashTraits as a
75 // template argument. It uses the default hash traits for the ValueArg
77 template<typename ValueArg, size_t inlineCapacity = 256, typename HashArg = typename DefaultHash<ValueArg>::Hash, typename AllocatorArg = ListHashSetAllocator<ValueArg, inlineCapacity> > class ListHashSet
78 : public ListHashSetDestructorBase<ListHashSet<ValueArg, inlineCapacity, HashArg, AllocatorArg>, AllocatorArg, AllocatorArg::isGarbageCollected> {
79 typedef AllocatorArg Allocator;
80 WTF_USE_ALLOCATOR(ListHashSet, Allocator);
82 typedef ListHashSetNode<ValueArg, Allocator> Node;
83 typedef HashTraits<Node*> NodeTraits;
84 typedef ListHashSetNodeHashFunctions<HashArg> NodeHash;
85 typedef ListHashSetTranslator<HashArg> BaseTranslator;
87 typedef HashTable<Node*, Node*, IdentityExtractor, NodeHash, NodeTraits, NodeTraits, typename Allocator::TableAllocator> ImplType;
88 typedef HashTableIterator<Node*, Node*, IdentityExtractor, NodeHash, NodeTraits, NodeTraits, typename Allocator::TableAllocator> ImplTypeIterator;
89 typedef HashTableConstIterator<Node*, Node*, IdentityExtractor, NodeHash, NodeTraits, NodeTraits, typename Allocator::TableAllocator> ImplTypeConstIterator;
91 typedef HashArg HashFunctions;
94 typedef ValueArg ValueType;
95 typedef HashTraits<ValueType> ValueTraits;
96 typedef typename ValueTraits::PeekInType ValuePeekInType;
97 typedef typename ValueTraits::PassInType ValuePassInType;
98 typedef typename ValueTraits::PassOutType ValuePassOutType;
100 typedef ListHashSetIterator<ListHashSet> iterator;
101 typedef ListHashSetConstIterator<ListHashSet> const_iterator;
102 friend class ListHashSetIterator<ListHashSet>;
103 friend class ListHashSetConstIterator<ListHashSet>;
105 typedef ListHashSetReverseIterator<ListHashSet> reverse_iterator;
106 typedef ListHashSetConstReverseIterator<ListHashSet> const_reverse_iterator;
107 friend class ListHashSetReverseIterator<ListHashSet>;
108 friend class ListHashSetConstReverseIterator<ListHashSet>;
110 template<typename ValueType> struct HashTableAddResult {
111 HashTableAddResult(Node* storedValue, bool isNewEntry) : storedValue(storedValue), isNewEntry(isNewEntry) { }
115 typedef HashTableAddResult<ValueType> AddResult;
118 ListHashSet(const ListHashSet&);
119 ListHashSet& operator=(const ListHashSet&);
122 void swap(ListHashSet&);
124 unsigned size() const { return m_impl.size(); }
125 unsigned capacity() const { return m_impl.capacity(); }
126 bool isEmpty() const { return m_impl.isEmpty(); }
128 iterator begin() { return makeIterator(m_head); }
129 iterator end() { return makeIterator(0); }
130 const_iterator begin() const { return makeConstIterator(m_head); }
131 const_iterator end() const { return makeConstIterator(0); }
133 reverse_iterator rbegin() { return makeReverseIterator(m_tail); }
134 reverse_iterator rend() { return makeReverseIterator(0); }
135 const_reverse_iterator rbegin() const { return makeConstReverseIterator(m_tail); }
136 const_reverse_iterator rend() const { return makeConstReverseIterator(0); }
139 const ValueType& first() const;
143 const ValueType& last() const;
146 iterator find(ValuePeekInType);
147 const_iterator find(ValuePeekInType) const;
148 bool contains(ValuePeekInType) const;
150 // An alternate version of find() that finds the object by hashing and comparing
151 // with some other type, to avoid the cost of type conversion.
152 // The HashTranslator interface is defined in HashSet.
153 template<typename HashTranslator, typename T> iterator find(const T&);
154 template<typename HashTranslator, typename T> const_iterator find(const T&) const;
155 template<typename HashTranslator, typename T> bool contains(const T&) const;
157 // The return value of add is a pair of a pointer to the stored value,
158 // and a bool that is true if an new entry was added.
159 AddResult add(ValuePassInType);
161 // Same as add() except that the return value is an
162 // iterator. Useful in cases where it's needed to have the
163 // same return value as find() and where it's not possible to
164 // use a pointer to the storedValue.
165 iterator addReturnIterator(ValuePassInType);
167 // Add the value to the end of the collection. If the value was already in
168 // the list, it is moved to the end.
169 AddResult appendOrMoveToLast(ValuePassInType);
171 // Add the value to the beginning of the collection. If the value was already in
172 // the list, it is moved to the beginning.
173 AddResult prependOrMoveToFirst(ValuePassInType);
175 AddResult insertBefore(ValuePeekInType beforeValue, ValuePassInType newValue);
176 AddResult insertBefore(iterator, ValuePassInType);
178 void remove(ValuePeekInType value) { return remove(find(value)); }
179 void remove(iterator);
181 template<typename Collection>
182 void removeAll(const Collection& other) { WTF::removeAll(*this, other); }
184 ValuePassOutType take(iterator);
185 ValuePassOutType take(ValuePeekInType);
186 ValuePassOutType takeFirst();
188 void trace(typename Allocator::Visitor*);
192 void unlinkAndDelete(Node*);
193 void appendNode(Node*);
194 void prependNode(Node*);
195 void insertNodeBefore(Node* beforeNode, Node* newNode);
196 void deleteAllNodes();
197 Allocator* allocator() const { return this->m_allocatorProvider.get(); }
198 void createAllocatorIfNeeded() { this->m_allocatorProvider.createAllocatorIfNeeded(); }
199 void deallocate(Node* node) const { this->m_allocatorProvider.deallocate(node); }
201 iterator makeIterator(Node* position) { return iterator(this, position); }
202 const_iterator makeConstIterator(Node* position) const { return const_iterator(this, position); }
203 reverse_iterator makeReverseIterator(Node* position) { return reverse_iterator(this, position); }
204 const_reverse_iterator makeConstReverseIterator(Node* position) const { return const_reverse_iterator(this, position); }
211 // ListHashSetNode has this base class to hold the members because the MSVC
212 // compiler otherwise gets into circular template dependencies when trying
213 // to do sizeof on a node.
214 template<typename ValueArg> class ListHashSetNodeBase {
216 ListHashSetNodeBase(const ValueArg& value)
221 , m_isAllocated(true)
226 template <typename U>
227 ListHashSetNodeBase(const U& value)
232 , m_isAllocated(true)
239 ListHashSetNodeBase* m_prev;
240 ListHashSetNodeBase* m_next;
246 // This allocator is only used for non-Heap ListHashSets.
247 template<typename ValueArg, size_t inlineCapacity>
248 struct ListHashSetAllocator : public DefaultAllocator {
249 typedef DefaultAllocator TableAllocator;
250 typedef ListHashSetNode<ValueArg, ListHashSetAllocator> Node;
251 typedef ListHashSetNodeBase<ValueArg> NodeBase;
252 class AllocatorProvider {
254 void createAllocatorIfNeeded()
257 m_allocator = adoptPtr(new ListHashSetAllocator);
260 void swap(AllocatorProvider& other)
262 m_allocator.swap(other.m_allocator);
265 void deallocate(Node* node) const
268 m_allocator->deallocate(node);
271 ListHashSetAllocator* get() const
274 return m_allocator.get();
278 OwnPtr<ListHashSetAllocator> m_allocator;
281 ListHashSetAllocator()
283 , m_isDoneWithInitialFreeList(false)
285 memset(m_pool.buffer, 0, sizeof(m_pool.buffer));
290 Node* result = m_freeList;
293 return static_cast<Node*>(fastMalloc(sizeof(NodeBase)));
295 ASSERT(!result->m_isAllocated);
297 Node* next = result->next();
298 ASSERT(!next || !next->m_isAllocated);
299 if (!next && !m_isDoneWithInitialFreeList) {
301 if (next == pastPool()) {
302 m_isDoneWithInitialFreeList = true;
305 ASSERT(inPool(next));
306 ASSERT(!next->m_isAllocated);
314 void deallocate(Node* node)
318 node->m_isAllocated = false;
320 node->m_next = m_freeList;
328 bool inPool(Node* node)
330 return node >= pool() && node < pastPool();
333 static void traceValue(typename DefaultAllocator::Visitor* visitor, Node* node) { }
336 Node* pool() { return reinterpret_cast_ptr<Node*>(m_pool.buffer); }
337 Node* pastPool() { return pool() + m_poolSize; }
340 bool m_isDoneWithInitialFreeList;
341 #if defined(MEMORY_SANITIZER_INITIAL_SIZE)
342 // The allocation pool for nodes is one big chunk that ASAN has no
343 // insight into, so it can cloak errors. Make it as small as possible
344 // to force nodes to be allocated individually where ASAN can see them.
345 static const size_t m_poolSize = 1;
347 static const size_t m_poolSize = inlineCapacity;
349 AlignedBuffer<sizeof(NodeBase) * m_poolSize, WTF_ALIGN_OF(NodeBase)> m_pool;
352 template<typename ValueArg, typename AllocatorArg> class ListHashSetNode : public ListHashSetNodeBase<ValueArg> {
354 typedef AllocatorArg NodeAllocator;
355 typedef ValueArg Value;
357 template <typename U>
358 ListHashSetNode(U value)
359 : ListHashSetNodeBase<ValueArg>(value) { }
361 void* operator new(size_t, NodeAllocator* allocator)
363 COMPILE_ASSERT(sizeof(ListHashSetNode) == sizeof(ListHashSetNodeBase<ValueArg>), PleaseAddAnyFieldsToTheBase);
364 return allocator->allocateNode();
367 void setWasAlreadyDestructed()
369 if (NodeAllocator::isGarbageCollected && HashTraits<ValueArg>::needsDestruction)
370 this->m_prev = unlinkedNodePointer();
373 bool wasAlreadyDestructed() const
375 ASSERT(NodeAllocator::isGarbageCollected);
376 return this->m_prev == unlinkedNodePointer();
379 static void finalize(void* pointer)
381 ASSERT(HashTraits<ValueArg>::needsDestruction); // No need to waste time calling finalize if it's not needed.
382 ListHashSetNode* self = reinterpret_cast_ptr<ListHashSetNode*>(pointer);
384 // Check whether this node was already destructed before being
385 // unlinked from the collection.
386 if (self->wasAlreadyDestructed())
389 self->m_value.~ValueArg();
392 void destroy(NodeAllocator* allocator)
394 this->~ListHashSetNode();
395 setWasAlreadyDestructed();
396 allocator->deallocate(this);
399 // This is not called in normal tracing, but it is called if we find a
400 // pointer to a node on the stack using conservative scanning. Since
401 // the original ListHashSet may no longer exist we make sure to mark
402 // the neighbours in the chain too.
403 void trace(typename NodeAllocator::Visitor* visitor)
405 // The conservative stack scan can find nodes that have been
406 // removed from the set and destructed. We don't need to trace
407 // these, and it would be wrong to do so, because the class will
408 // not expect the trace method to be called after the destructor.
409 // It's an error to remove a node from the ListHashSet while an
410 // iterator is positioned at that node, so there should be no valid
411 // pointers from the stack to a destructed node.
412 if (wasAlreadyDestructed())
414 NodeAllocator::traceValue(visitor, this);
415 visitor->mark(next());
416 visitor->mark(prev());
419 ListHashSetNode* next() const { return reinterpret_cast<ListHashSetNode*>(this->m_next); }
420 ListHashSetNode* prev() const { return reinterpret_cast<ListHashSetNode*>(this->m_prev); }
422 // Don't add fields here, the ListHashSetNodeBase and this should have
425 static ListHashSetNode* unlinkedNodePointer() { return reinterpret_cast<ListHashSetNode*>(-1); }
427 template<typename HashArg>
428 friend struct ListHashSetNodeHashFunctions;
431 template<typename HashArg> struct ListHashSetNodeHashFunctions {
432 template<typename T> static unsigned hash(const T& key) { return HashArg::hash(key->m_value); }
433 template<typename T> static bool equal(const T& a, const T& b) { return HashArg::equal(a->m_value, b->m_value); }
434 static const bool safeToCompareToEmptyOrDeleted = false;
437 template<typename Set> class ListHashSetIterator {
439 typedef typename Set::const_iterator const_iterator;
440 typedef typename Set::Node Node;
441 typedef typename Set::ValueType ValueType;
442 typedef ValueType& ReferenceType;
443 typedef ValueType* PointerType;
445 ListHashSetIterator(const Set* set, Node* position) : m_iterator(set, position) { }
448 ListHashSetIterator() { }
450 // default copy, assignment and destructor are OK
452 PointerType get() const { return const_cast<PointerType>(m_iterator.get()); }
453 ReferenceType operator*() const { return *get(); }
454 PointerType operator->() const { return get(); }
456 ListHashSetIterator& operator++() { ++m_iterator; return *this; }
457 ListHashSetIterator& operator--() { --m_iterator; return *this; }
459 // Postfix ++ and -- intentionally omitted.
462 bool operator==(const ListHashSetIterator& other) const { return m_iterator == other.m_iterator; }
463 bool operator!=(const ListHashSetIterator& other) const { return m_iterator != other.m_iterator; }
465 operator const_iterator() const { return m_iterator; }
468 Node* node() { return m_iterator.node(); }
470 const_iterator m_iterator;
472 template<typename T, size_t inlineCapacity, typename U, typename V>
473 friend class ListHashSet;
476 template<typename Set>
477 class ListHashSetConstIterator {
479 typedef typename Set::const_iterator const_iterator;
480 typedef typename Set::Node Node;
481 typedef typename Set::ValueType ValueType;
482 typedef const ValueType& ReferenceType;
483 typedef const ValueType* PointerType;
485 friend class ListHashSetIterator<Set>;
487 ListHashSetConstIterator(const Set* set, Node* position)
489 , m_position(position)
494 ListHashSetConstIterator()
498 PointerType get() const
500 return &m_position->m_value;
502 ReferenceType operator*() const { return *get(); }
503 PointerType operator->() const { return get(); }
505 ListHashSetConstIterator& operator++()
507 ASSERT(m_position != 0);
508 m_position = m_position->next();
512 ListHashSetConstIterator& operator--()
514 ASSERT(m_position != m_set->m_head);
516 m_position = m_set->m_tail;
518 m_position = m_position->prev();
522 // Postfix ++ and -- intentionally omitted.
525 bool operator==(const ListHashSetConstIterator& other) const
527 return m_position == other.m_position;
529 bool operator!=(const ListHashSetConstIterator& other) const
531 return m_position != other.m_position;
535 Node* node() { return m_position; }
540 template<typename T, size_t inlineCapacity, typename U, typename V>
541 friend class ListHashSet;
544 template<typename Set>
545 class ListHashSetReverseIterator {
547 typedef typename Set::const_reverse_iterator const_reverse_iterator;
548 typedef typename Set::Node Node;
549 typedef typename Set::ValueType ValueType;
550 typedef ValueType& ReferenceType;
551 typedef ValueType* PointerType;
553 ListHashSetReverseIterator(const Set* set, Node* position) : m_iterator(set, position) { }
556 ListHashSetReverseIterator() { }
558 // default copy, assignment and destructor are OK
560 PointerType get() const { return const_cast<PointerType>(m_iterator.get()); }
561 ReferenceType operator*() const { return *get(); }
562 PointerType operator->() const { return get(); }
564 ListHashSetReverseIterator& operator++() { ++m_iterator; return *this; }
565 ListHashSetReverseIterator& operator--() { --m_iterator; return *this; }
567 // Postfix ++ and -- intentionally omitted.
570 bool operator==(const ListHashSetReverseIterator& other) const { return m_iterator == other.m_iterator; }
571 bool operator!=(const ListHashSetReverseIterator& other) const { return m_iterator != other.m_iterator; }
573 operator const_reverse_iterator() const { return m_iterator; }
576 Node* node() { return m_iterator.node(); }
578 const_reverse_iterator m_iterator;
580 template<typename T, size_t inlineCapacity, typename U, typename V>
581 friend class ListHashSet;
584 template<typename Set> class ListHashSetConstReverseIterator {
586 typedef typename Set::reverse_iterator reverse_iterator;
587 typedef typename Set::Node Node;
588 typedef typename Set::ValueType ValueType;
589 typedef const ValueType& ReferenceType;
590 typedef const ValueType* PointerType;
592 friend class ListHashSetReverseIterator<Set>;
594 ListHashSetConstReverseIterator(const Set* set, Node* position)
596 , m_position(position)
601 ListHashSetConstReverseIterator()
605 PointerType get() const
607 return &m_position->m_value;
609 ReferenceType operator*() const { return *get(); }
610 PointerType operator->() const { return get(); }
612 ListHashSetConstReverseIterator& operator++()
614 ASSERT(m_position != 0);
615 m_position = m_position->prev();
619 ListHashSetConstReverseIterator& operator--()
621 ASSERT(m_position != m_set->m_tail);
623 m_position = m_set->m_head;
625 m_position = m_position->next();
629 // Postfix ++ and -- intentionally omitted.
632 bool operator==(const ListHashSetConstReverseIterator& other) const
634 return m_position == other.m_position;
636 bool operator!=(const ListHashSetConstReverseIterator& other) const
638 return m_position != other.m_position;
642 Node* node() { return m_position; }
647 template<typename T, size_t inlineCapacity, typename U, typename V>
648 friend class ListHashSet;
651 template<typename HashFunctions>
652 struct ListHashSetTranslator {
653 template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
654 template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a->m_value, b); }
655 template<typename T, typename U, typename V> static void translate(T*& location, const U& key, const V& allocator)
657 location = new (const_cast<V*>(&allocator)) T(key);
661 template<typename T, size_t inlineCapacity, typename U, typename V>
662 inline ListHashSet<T, inlineCapacity, U, V>::ListHashSet()
668 template<typename T, size_t inlineCapacity, typename U, typename V>
669 inline ListHashSet<T, inlineCapacity, U, V>::ListHashSet(const ListHashSet& other)
673 const_iterator end = other.end();
674 for (const_iterator it = other.begin(); it != end; ++it)
678 template<typename T, size_t inlineCapacity, typename U, typename V>
679 inline ListHashSet<T, inlineCapacity, U, V>& ListHashSet<T, inlineCapacity, U, V>::operator=(const ListHashSet& other)
681 ListHashSet tmp(other);
686 template<typename T, size_t inlineCapacity, typename U, typename V>
687 inline void ListHashSet<T, inlineCapacity, U, V>::swap(ListHashSet& other)
689 m_impl.swap(other.m_impl);
690 std::swap(m_head, other.m_head);
691 std::swap(m_tail, other.m_tail);
692 this->m_allocatorProvider.swap(other.m_allocatorProvider);
695 template<typename T, size_t inlineCapacity, typename U, typename V>
696 inline void ListHashSet<T, inlineCapacity, U, V>::finalize()
698 COMPILE_ASSERT(!Allocator::isGarbageCollected, FinalizeOnHeapAllocatedListHashSetShouldNeverBeCalled);
702 template<typename T, size_t inlineCapacity, typename U, typename V>
703 inline T& ListHashSet<T, inlineCapacity, U, V>::first()
706 return m_head->m_value;
709 template<typename T, size_t inlineCapacity, typename U, typename V>
710 inline void ListHashSet<T, inlineCapacity, U, V>::removeFirst()
713 m_impl.remove(m_head);
714 unlinkAndDelete(m_head);
717 template<typename T, size_t inlineCapacity, typename U, typename V>
718 inline const T& ListHashSet<T, inlineCapacity, U, V>::first() const
721 return m_head->m_value;
724 template<typename T, size_t inlineCapacity, typename U, typename V>
725 inline T& ListHashSet<T, inlineCapacity, U, V>::last()
728 return m_tail->m_value;
731 template<typename T, size_t inlineCapacity, typename U, typename V>
732 inline const T& ListHashSet<T, inlineCapacity, U, V>::last() const
735 return m_tail->m_value;
738 template<typename T, size_t inlineCapacity, typename U, typename V>
739 inline void ListHashSet<T, inlineCapacity, U, V>::removeLast()
742 m_impl.remove(m_tail);
743 unlinkAndDelete(m_tail);
746 template<typename T, size_t inlineCapacity, typename U, typename V>
747 inline typename ListHashSet<T, inlineCapacity, U, V>::iterator ListHashSet<T, inlineCapacity, U, V>::find(ValuePeekInType value)
749 ImplTypeIterator it = m_impl.template find<BaseTranslator>(value);
750 if (it == m_impl.end())
752 return makeIterator(*it);
755 template<typename T, size_t inlineCapacity, typename U, typename V>
756 inline typename ListHashSet<T, inlineCapacity, U, V>::const_iterator ListHashSet<T, inlineCapacity, U, V>::find(ValuePeekInType value) const
758 ImplTypeConstIterator it = m_impl.template find<BaseTranslator>(value);
759 if (it == m_impl.end())
761 return makeConstIterator(*it);
764 template<typename Translator>
765 struct ListHashSetTranslatorAdapter {
766 template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
767 template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a->m_value, b); }
770 template<typename ValueType, size_t inlineCapacity, typename U, typename V>
771 template<typename HashTranslator, typename T>
772 inline typename ListHashSet<ValueType, inlineCapacity, U, V>::iterator ListHashSet<ValueType, inlineCapacity, U, V>::find(const T& value)
774 ImplTypeConstIterator it = m_impl.template find<ListHashSetTranslatorAdapter<HashTranslator> >(value);
775 if (it == m_impl.end())
777 return makeIterator(*it);
780 template<typename ValueType, size_t inlineCapacity, typename U, typename V>
781 template<typename HashTranslator, typename T>
782 inline typename ListHashSet<ValueType, inlineCapacity, U, V>::const_iterator ListHashSet<ValueType, inlineCapacity, U, V>::find(const T& value) const
784 ImplTypeConstIterator it = m_impl.template find<ListHashSetTranslatorAdapter<HashTranslator> >(value);
785 if (it == m_impl.end())
787 return makeConstIterator(*it);
790 template<typename ValueType, size_t inlineCapacity, typename U, typename V>
791 template<typename HashTranslator, typename T>
792 inline bool ListHashSet<ValueType, inlineCapacity, U, V>::contains(const T& value) const
794 return m_impl.template contains<ListHashSetTranslatorAdapter<HashTranslator> >(value);
797 template<typename T, size_t inlineCapacity, typename U, typename V>
798 inline bool ListHashSet<T, inlineCapacity, U, V>::contains(ValuePeekInType value) const
800 return m_impl.template contains<BaseTranslator>(value);
803 template<typename T, size_t inlineCapacity, typename U, typename V>
804 typename ListHashSet<T, inlineCapacity, U, V>::AddResult ListHashSet<T, inlineCapacity, U, V>::add(ValuePassInType value)
806 createAllocatorIfNeeded();
807 // The second argument is a const ref. This is useful for the HashTable
808 // because it lets it take lvalues by reference, but for our purposes
809 // it's inconvenient, since it constrains us to be const, whereas the
810 // allocator actually changes when it does allocations.
811 typename ImplType::AddResult result = m_impl.template add<BaseTranslator>(value, *this->allocator());
812 if (result.isNewEntry)
813 appendNode(*result.storedValue);
814 return AddResult(*result.storedValue, result.isNewEntry);
817 template<typename T, size_t inlineCapacity, typename U, typename V>
818 typename ListHashSet<T, inlineCapacity, U, V>::iterator ListHashSet<T, inlineCapacity, U, V>::addReturnIterator(ValuePassInType value)
820 return makeIterator(add(value).storedValue);
823 template<typename T, size_t inlineCapacity, typename U, typename V>
824 typename ListHashSet<T, inlineCapacity, U, V>::AddResult ListHashSet<T, inlineCapacity, U, V>::appendOrMoveToLast(ValuePassInType value)
826 createAllocatorIfNeeded();
827 typename ImplType::AddResult result = m_impl.template add<BaseTranslator>(value, *this->allocator());
828 Node* node = *result.storedValue;
829 if (!result.isNewEntry)
832 return AddResult(*result.storedValue, result.isNewEntry);
835 template<typename T, size_t inlineCapacity, typename U, typename V>
836 typename ListHashSet<T, inlineCapacity, U, V>::AddResult ListHashSet<T, inlineCapacity, U, V>::prependOrMoveToFirst(ValuePassInType value)
838 createAllocatorIfNeeded();
839 typename ImplType::AddResult result = m_impl.template add<BaseTranslator>(value, *this->allocator());
840 Node* node = *result.storedValue;
841 if (!result.isNewEntry)
844 return AddResult(*result.storedValue, result.isNewEntry);
847 template<typename T, size_t inlineCapacity, typename U, typename V>
848 typename ListHashSet<T, inlineCapacity, U, V>::AddResult ListHashSet<T, inlineCapacity, U, V>::insertBefore(iterator it, ValuePassInType newValue)
850 createAllocatorIfNeeded();
851 typename ImplType::AddResult result = m_impl.template add<BaseTranslator>(newValue, *this->allocator());
852 if (result.isNewEntry)
853 insertNodeBefore(it.node(), *result.storedValue);
854 return AddResult(*result.storedValue, result.isNewEntry);
857 template<typename T, size_t inlineCapacity, typename U, typename V>
858 typename ListHashSet<T, inlineCapacity, U, V>::AddResult ListHashSet<T, inlineCapacity, U, V>::insertBefore(ValuePeekInType beforeValue, ValuePassInType newValue)
860 createAllocatorIfNeeded();
861 return insertBefore(find(beforeValue), newValue);
864 template<typename T, size_t inlineCapacity, typename U, typename V>
865 inline void ListHashSet<T, inlineCapacity, U, V>::remove(iterator it)
869 m_impl.remove(it.node());
870 unlinkAndDelete(it.node());
873 template<typename T, size_t inlineCapacity, typename U, typename V>
874 inline void ListHashSet<T, inlineCapacity, U, V>::clear()
882 template<typename T, size_t inlineCapacity, typename U, typename V>
883 typename ListHashSet<T, inlineCapacity, U, V>::ValuePassOutType ListHashSet<T, inlineCapacity, U, V>::take(iterator it)
886 return ValueTraits::emptyValue();
888 m_impl.remove(it.node());
889 ValuePassOutType result = ValueTraits::passOut(it.node()->m_value);
890 unlinkAndDelete(it.node());
895 template<typename T, size_t inlineCapacity, typename U, typename V>
896 typename ListHashSet<T, inlineCapacity, U, V>::ValuePassOutType ListHashSet<T, inlineCapacity, U, V>::take(ValuePeekInType value)
898 return take(find(value));
901 template<typename T, size_t inlineCapacity, typename U, typename V>
902 typename ListHashSet<T, inlineCapacity, U, V>::ValuePassOutType ListHashSet<T, inlineCapacity, U, V>::takeFirst()
905 m_impl.remove(m_head);
906 ValuePassOutType result = ValueTraits::passOut(m_head->m_value);
907 unlinkAndDelete(m_head);
912 template<typename T, size_t inlineCapacity, typename U, typename Allocator>
913 void ListHashSet<T, inlineCapacity, U, Allocator>::unlink(Node* node)
916 ASSERT(node == m_head);
917 m_head = node->next();
919 ASSERT(node != m_head);
920 node->m_prev->m_next = node->m_next;
924 ASSERT(node == m_tail);
925 m_tail = node->prev();
927 ASSERT(node != m_tail);
928 node->m_next->m_prev = node->m_prev;
932 template<typename T, size_t inlineCapacity, typename U, typename V>
933 void ListHashSet<T, inlineCapacity, U, V>::unlinkAndDelete(Node* node)
936 node->destroy(this->allocator());
939 template<typename T, size_t inlineCapacity, typename U, typename V>
940 void ListHashSet<T, inlineCapacity, U, V>::appendNode(Node* node)
942 node->m_prev = m_tail;
947 m_tail->m_next = node;
956 template<typename T, size_t inlineCapacity, typename U, typename V>
957 void ListHashSet<T, inlineCapacity, U, V>::prependNode(Node* node)
960 node->m_next = m_head;
963 m_head->m_prev = node;
970 template<typename T, size_t inlineCapacity, typename U, typename V>
971 void ListHashSet<T, inlineCapacity, U, V>::insertNodeBefore(Node* beforeNode, Node* newNode)
974 return appendNode(newNode);
976 newNode->m_next = beforeNode;
977 newNode->m_prev = beforeNode->m_prev;
978 if (beforeNode->m_prev)
979 beforeNode->m_prev->m_next = newNode;
980 beforeNode->m_prev = newNode;
982 if (!newNode->m_prev)
986 template<typename T, size_t inlineCapacity, typename U, typename V>
987 void ListHashSet<T, inlineCapacity, U, V>::deleteAllNodes()
992 for (Node* node = m_head, *next = m_head->next(); node; node = next, next = node ? node->next() : 0)
993 node->destroy(this->allocator());
996 template<typename T, size_t inlineCapacity, typename U, typename V>
997 void ListHashSet<T, inlineCapacity, U, V>::trace(typename Allocator::Visitor* visitor)
999 COMPILE_ASSERT(HashTraits<T>::weakHandlingFlag == NoWeakHandlingInCollections, ListHashSetDoesNotSupportWeakness);
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 */