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_LinkedHashSet_h
23 #define WTF_LinkedHashSet_h
25 #include "wtf/AddressSanitizer.h"
26 #include "wtf/DefaultAllocator.h"
27 #include "wtf/HashSet.h"
28 #include "wtf/OwnPtr.h"
29 #include "wtf/PassOwnPtr.h"
33 // LinkedHashSet: Just like HashSet, this class provides a Set
34 // interface - a collection of unique objects with O(1) insertion,
35 // removal and test for containership. However, it also has an
36 // order - iterating it will always give back values in the order
37 // in which they are added.
39 // Unlike ListHashSet, but like most WTF collections, iteration is NOT safe
40 // against mutation of the LinkedHashSet.
42 template<typename Value
, typename HashFunctions
, typename HashTraits
, typename Allocator
> class LinkedHashSet
;
44 template<typename LinkedHashSet
> class LinkedHashSetIterator
;
45 template<typename LinkedHashSet
> class LinkedHashSetConstIterator
;
46 template<typename LinkedHashSet
> class LinkedHashSetReverseIterator
;
47 template<typename LinkedHashSet
> class LinkedHashSetConstReverseIterator
;
49 template<typename Value
, typename HashFunctions
, typename Allocator
> struct LinkedHashSetTranslator
;
50 template<typename Value
, typename Allocator
> struct LinkedHashSetExtractor
;
51 template<typename Value
, typename ValueTraits
, typename Allocator
> struct LinkedHashSetTraits
;
53 class LinkedHashSetNodeBase
{
55 LinkedHashSetNodeBase() : m_prev(this), m_next(this) { }
57 NO_LAZY_SWEEP_SANITIZE_ADDRESS
63 ASSERT(m_next
->m_prev
== this);
64 ASSERT(m_prev
->m_next
== this);
65 m_next
->m_prev
= m_prev
;
66 m_prev
->m_next
= m_next
;
69 ~LinkedHashSetNodeBase()
74 void insertBefore(LinkedHashSetNodeBase
& other
)
77 other
.m_prev
= m_prev
;
78 m_prev
->m_next
= &other
;
86 void insertAfter(LinkedHashSetNodeBase
& other
)
89 other
.m_next
= m_next
;
90 m_next
->m_prev
= &other
;
98 LinkedHashSetNodeBase(LinkedHashSetNodeBase
* prev
, LinkedHashSetNodeBase
* next
)
102 ASSERT((prev
&& next
) || (!prev
&& !next
));
105 LinkedHashSetNodeBase
* m_prev
;
106 LinkedHashSetNodeBase
* m_next
;
109 // If we take a copy of a node we can't copy the next and prev pointers,
110 // since they point to something that does not point at us. This is used
111 // inside the shouldExpand() "if" in HashTable::add.
112 LinkedHashSetNodeBase(const LinkedHashSetNodeBase
& other
)
117 // Should not be used.
118 LinkedHashSetNodeBase
& operator=(const LinkedHashSetNodeBase
& other
);
121 template<typename ValueArg
, typename Allocator
>
122 class LinkedHashSetNode
: public LinkedHashSetNodeBase
{
124 LinkedHashSetNode(const ValueArg
& value
, LinkedHashSetNodeBase
* prev
, LinkedHashSetNodeBase
* next
)
125 : LinkedHashSetNodeBase(prev
, next
)
134 LinkedHashSetNode(const LinkedHashSetNode
&);
139 typename HashFunctions
= typename DefaultHash
<ValueArg
>::Hash
,
140 typename TraitsArg
= HashTraits
<ValueArg
>,
141 typename Allocator
= DefaultAllocator
>
142 class LinkedHashSet
{
143 WTF_USE_ALLOCATOR(LinkedHashSet
, Allocator
);
145 typedef ValueArg Value
;
146 typedef TraitsArg Traits
;
147 typedef LinkedHashSetNode
<Value
, Allocator
> Node
;
148 typedef LinkedHashSetNodeBase NodeBase
;
149 typedef LinkedHashSetTranslator
<Value
, HashFunctions
, Allocator
> NodeHashFunctions
;
150 typedef LinkedHashSetTraits
<Value
, Traits
, Allocator
> NodeHashTraits
;
152 typedef HashTable
<Node
, Node
, IdentityExtractor
,
153 NodeHashFunctions
, NodeHashTraits
, NodeHashTraits
, Allocator
> ImplType
;
156 typedef LinkedHashSetIterator
<LinkedHashSet
> iterator
;
157 friend class LinkedHashSetIterator
<LinkedHashSet
>;
158 typedef LinkedHashSetConstIterator
<LinkedHashSet
> const_iterator
;
159 friend class LinkedHashSetConstIterator
<LinkedHashSet
>;
161 typedef LinkedHashSetReverseIterator
<LinkedHashSet
> reverse_iterator
;
162 friend class LinkedHashSetReverseIterator
<LinkedHashSet
>;
163 typedef LinkedHashSetConstReverseIterator
<LinkedHashSet
> const_reverse_iterator
;
164 friend class LinkedHashSetConstReverseIterator
<LinkedHashSet
>;
167 AddResult(const typename
ImplType::AddResult
& hashTableAddResult
)
168 : storedValue(&hashTableAddResult
.storedValue
->m_value
)
169 , isNewEntry(hashTableAddResult
.isNewEntry
)
177 typedef typename HashTraits
<Value
>::PeekInType ValuePeekInType
;
180 LinkedHashSet(const LinkedHashSet
&);
181 LinkedHashSet
& operator=(const LinkedHashSet
&);
183 // Needs finalization. The anchor needs to unlink itself from the chain.
186 static void finalize(void* pointer
) { reinterpret_cast<LinkedHashSet
*>(pointer
)->~LinkedHashSet(); }
187 void finalizeGarbageCollectedObject() { finalize(this); }
189 void swap(LinkedHashSet
&);
191 unsigned size() const { return m_impl
.size(); }
192 unsigned capacity() const { return m_impl
.capacity(); }
193 bool isEmpty() const { return m_impl
.isEmpty(); }
195 iterator
begin() { return makeIterator(firstNode()); }
196 iterator
end() { return makeIterator(anchor()); }
197 const_iterator
begin() const { return makeConstIterator(firstNode()); }
198 const_iterator
end() const { return makeConstIterator(anchor()); }
200 reverse_iterator
rbegin() { return makeReverseIterator(lastNode()); }
201 reverse_iterator
rend() { return makeReverseIterator(anchor()); }
202 const_reverse_iterator
rbegin() const { return makeConstReverseIterator(lastNode()); }
203 const_reverse_iterator
rend() const { return makeConstReverseIterator(anchor()); }
206 const Value
& first() const;
210 const Value
& last() const;
213 iterator
find(ValuePeekInType
);
214 const_iterator
find(ValuePeekInType
) const;
215 bool contains(ValuePeekInType
) const;
217 // An alternate version of find() that finds the object by hashing and comparing
218 // with some other type, to avoid the cost of type conversion.
219 // The HashTranslator interface is defined in HashSet.
220 template<typename HashTranslator
, typename T
> iterator
find(const T
&);
221 template<typename HashTranslator
, typename T
> const_iterator
find(const T
&) const;
222 template<typename HashTranslator
, typename T
> bool contains(const T
&) const;
224 // The return value of add is a pair of a pointer to the stored value,
225 // and a bool that is true if an new entry was added.
226 AddResult
add(ValuePeekInType
);
228 // Same as add() except that the return value is an
229 // iterator. Useful in cases where it's needed to have the
230 // same return value as find() and where it's not possible to
231 // use a pointer to the storedValue.
232 iterator
addReturnIterator(ValuePeekInType
);
234 // Add the value to the end of the collection. If the value was already in
235 // the list, it is moved to the end.
236 AddResult
appendOrMoveToLast(ValuePeekInType
);
238 // Add the value to the beginning of the collection. If the value was already in
239 // the list, it is moved to the beginning.
240 AddResult
prependOrMoveToFirst(ValuePeekInType
);
242 AddResult
insertBefore(ValuePeekInType beforeValue
, ValuePeekInType newValue
);
243 AddResult
insertBefore(iterator it
, ValuePeekInType newValue
) { return m_impl
.template add
<NodeHashFunctions
>(newValue
, it
.node()); }
245 void remove(ValuePeekInType
);
246 void remove(iterator
);
247 void clear() { m_impl
.clear(); }
248 template<typename Collection
>
249 void removeAll(const Collection
& other
) { WTF::removeAll(*this, other
); }
251 template<typename VisitorDispatcher
>
252 void trace(VisitorDispatcher visitor
) { m_impl
.trace(visitor
); }
254 int64_t modifications() const { return m_impl
.modifications(); }
255 void checkModifications(int64_t mods
) const { m_impl
.checkModifications(mods
); }
258 Node
* anchor() { return reinterpret_cast<Node
*>(&m_anchor
); }
259 const Node
* anchor() const { return reinterpret_cast<const Node
*>(&m_anchor
); }
260 Node
* firstNode() { return reinterpret_cast<Node
*>(m_anchor
.m_next
); }
261 const Node
* firstNode() const { return reinterpret_cast<const Node
*>(m_anchor
.m_next
); }
262 Node
* lastNode() { return reinterpret_cast<Node
*>(m_anchor
.m_prev
); }
263 const Node
* lastNode() const { return reinterpret_cast<const Node
*>(m_anchor
.m_prev
); }
265 iterator
makeIterator(const Node
* position
) { return iterator(position
, this); }
266 const_iterator
makeConstIterator(const Node
* position
) const { return const_iterator(position
, this); }
267 reverse_iterator
makeReverseIterator(const Node
* position
) { return reverse_iterator(position
, this); }
268 const_reverse_iterator
makeConstReverseIterator(const Node
* position
) const { return const_reverse_iterator(position
, this); }
274 template<typename Value
, typename HashFunctions
, typename Allocator
>
275 struct LinkedHashSetTranslator
{
276 typedef LinkedHashSetNode
<Value
, Allocator
> Node
;
277 typedef LinkedHashSetNodeBase NodeBase
;
278 typedef typename HashTraits
<Value
>::PeekInType ValuePeekInType
;
279 static unsigned hash(const Node
& node
) { return HashFunctions::hash(node
.m_value
); }
280 static unsigned hash(const ValuePeekInType
& key
) { return HashFunctions::hash(key
); }
281 static bool equal(const Node
& a
, const ValuePeekInType
& b
) { return HashFunctions::equal(a
.m_value
, b
); }
282 static bool equal(const Node
& a
, const Node
& b
) { return HashFunctions::equal(a
.m_value
, b
.m_value
); }
283 static void translate(Node
& location
, ValuePeekInType key
, NodeBase
* anchor
)
285 anchor
->insertBefore(location
);
286 location
.m_value
= key
;
289 // Empty (or deleted) slots have the m_next pointer set to null, but we
290 // don't do anything to the other fields, which may contain junk.
291 // Therefore you can't compare a newly constructed empty value with a
292 // slot and get the right answer.
293 static const bool safeToCompareToEmptyOrDeleted
= false;
296 template<typename Value
, typename Allocator
>
297 struct LinkedHashSetExtractor
{
298 static const Value
& extract(const LinkedHashSetNode
<Value
, Allocator
>& node
) { return node
.m_value
; }
301 template<typename Value
, typename ValueTraitsArg
, typename Allocator
>
302 struct LinkedHashSetTraits
: public SimpleClassHashTraits
<LinkedHashSetNode
<Value
, Allocator
>> {
303 typedef LinkedHashSetNode
<Value
, Allocator
> Node
;
304 typedef ValueTraitsArg ValueTraits
;
306 // The slot is empty when the m_next field is zero so it's safe to zero
308 static const bool emptyValueIsZero
= true;
310 static const bool hasIsEmptyValueFunction
= true;
311 static bool isEmptyValue(const Node
& node
) { return !node
.m_next
; }
313 static const int deletedValue
= -1;
315 static void constructDeletedValue(Node
& slot
, bool) { slot
.m_next
= reinterpret_cast<Node
*>(deletedValue
); }
316 static bool isDeletedValue(const Node
& slot
) { return slot
.m_next
== reinterpret_cast<Node
*>(deletedValue
); }
318 // Whether we need to trace and do weak processing depends on the traits of
319 // the type inside the node.
320 template<typename U
= void>
321 struct NeedsTracingLazily
{
322 static const bool value
= ValueTraits::template NeedsTracingLazily
<>::value
;
324 static const WeakHandlingFlag weakHandlingFlag
= ValueTraits::weakHandlingFlag
;
327 template<typename LinkedHashSetType
>
328 class LinkedHashSetIterator
{
330 typedef typename
LinkedHashSetType::Node Node
;
331 typedef typename
LinkedHashSetType::Traits Traits
;
333 typedef typename
LinkedHashSetType::Value
& ReferenceType
;
334 typedef typename
LinkedHashSetType::Value
* PointerType
;
336 typedef LinkedHashSetConstIterator
<LinkedHashSetType
> const_iterator
;
338 Node
* node() { return const_cast<Node
*>(m_iterator
.node()); }
341 LinkedHashSetIterator(const Node
* position
, LinkedHashSetType
* m_container
)
342 : m_iterator(position
, m_container
)
347 // Default copy, assignment and destructor are OK.
349 PointerType
get() const { return const_cast<PointerType
>(m_iterator
.get()); }
350 ReferenceType
operator*() const { return *get(); }
351 PointerType
operator->() const { return get(); }
353 LinkedHashSetIterator
& operator++() { ++m_iterator
; return *this; }
354 LinkedHashSetIterator
& operator--() { --m_iterator
; return *this; }
356 // Postfix ++ and -- intentionally omitted.
359 bool operator==(const LinkedHashSetIterator
& other
) const { return m_iterator
== other
.m_iterator
; }
360 bool operator!=(const LinkedHashSetIterator
& other
) const { return m_iterator
!= other
.m_iterator
; }
362 operator const_iterator() const { return m_iterator
; }
365 const_iterator m_iterator
;
366 template<typename T
, typename U
, typename V
, typename W
> friend class LinkedHashSet
;
369 template<typename LinkedHashSetType
>
370 class LinkedHashSetConstIterator
{
372 typedef typename
LinkedHashSetType::Node Node
;
373 typedef typename
LinkedHashSetType::Traits Traits
;
375 typedef const typename
LinkedHashSetType::Value
& ReferenceType
;
376 typedef const typename
LinkedHashSetType::Value
* PointerType
;
378 const Node
* node() const { return static_cast<const Node
*>(m_position
); }
381 LinkedHashSetConstIterator(const LinkedHashSetNodeBase
* position
, const LinkedHashSetType
* container
)
382 : m_position(position
)
384 , m_container(container
)
385 , m_containerModifications(container
->modifications())
391 PointerType
get() const
393 checkModifications();
394 return &static_cast<const Node
*>(m_position
)->m_value
;
396 ReferenceType
operator*() const { return *get(); }
397 PointerType
operator->() const { return get(); }
399 LinkedHashSetConstIterator
& operator++()
402 checkModifications();
403 m_position
= m_position
->m_next
;
407 LinkedHashSetConstIterator
& operator--()
410 checkModifications();
411 m_position
= m_position
->m_prev
;
415 // Postfix ++ and -- intentionally omitted.
418 bool operator==(const LinkedHashSetConstIterator
& other
) const
420 return m_position
== other
.m_position
;
422 bool operator!=(const LinkedHashSetConstIterator
& other
) const
424 return m_position
!= other
.m_position
;
428 const LinkedHashSetNodeBase
* m_position
;
430 void checkModifications() const { m_container
->checkModifications(m_containerModifications
); }
431 const LinkedHashSetType
* m_container
;
432 int64_t m_containerModifications
;
434 void checkModifications() const { }
436 template<typename T
, typename U
, typename V
, typename W
> friend class LinkedHashSet
;
437 friend class LinkedHashSetIterator
<LinkedHashSetType
>;
440 template<typename LinkedHashSetType
>
441 class LinkedHashSetReverseIterator
: public LinkedHashSetIterator
<LinkedHashSetType
> {
442 typedef LinkedHashSetIterator
<LinkedHashSetType
> Superclass
;
443 typedef LinkedHashSetConstReverseIterator
<LinkedHashSetType
> const_reverse_iterator
;
444 typedef typename
LinkedHashSetType::Node Node
;
447 LinkedHashSetReverseIterator(const Node
* position
, LinkedHashSetType
* container
)
448 : Superclass(position
, container
) { }
451 LinkedHashSetReverseIterator
& operator++() { Superclass::operator--(); return *this; }
452 LinkedHashSetReverseIterator
& operator--() { Superclass::operator++(); return *this; }
454 // Postfix ++ and -- intentionally omitted.
456 operator const_reverse_iterator() const { return *reinterpret_cast<const_reverse_iterator
*>(this); }
458 template<typename T
, typename U
, typename V
, typename W
> friend class LinkedHashSet
;
461 template<typename LinkedHashSetType
>
462 class LinkedHashSetConstReverseIterator
: public LinkedHashSetConstIterator
<LinkedHashSetType
> {
463 typedef LinkedHashSetConstIterator
<LinkedHashSetType
> Superclass
;
464 typedef typename
LinkedHashSetType::Node Node
;
467 LinkedHashSetConstReverseIterator(const Node
* position
, const LinkedHashSetType
* container
)
468 : Superclass(position
, container
) { }
470 LinkedHashSetConstReverseIterator
& operator++() { Superclass::operator--(); return *this; }
471 LinkedHashSetConstReverseIterator
& operator--() { Superclass::operator++(); return *this; }
473 // Postfix ++ and -- intentionally omitted.
475 template<typename T
, typename U
, typename V
, typename W
> friend class LinkedHashSet
;
478 template<typename T
, typename U
, typename V
, typename W
>
479 inline LinkedHashSet
<T
, U
, V
, W
>::LinkedHashSet() { }
481 template<typename T
, typename U
, typename V
, typename W
>
482 inline LinkedHashSet
<T
, U
, V
, W
>::LinkedHashSet(const LinkedHashSet
& other
)
485 const_iterator end
= other
.end();
486 for (const_iterator it
= other
.begin(); it
!= end
; ++it
)
490 template<typename T
, typename U
, typename V
, typename W
>
491 inline LinkedHashSet
<T
, U
, V
, W
>& LinkedHashSet
<T
, U
, V
, W
>::operator=(const LinkedHashSet
& other
)
493 LinkedHashSet
tmp(other
);
498 template<typename T
, typename U
, typename V
, typename W
>
499 inline void LinkedHashSet
<T
, U
, V
, W
>::swap(LinkedHashSet
& other
)
501 m_impl
.swap(other
.m_impl
);
502 swapAnchor(m_anchor
, other
.m_anchor
);
505 template<typename T
, typename U
, typename V
, typename Allocator
>
506 inline LinkedHashSet
<T
, U
, V
, Allocator
>::~LinkedHashSet()
508 // The destructor of m_anchor will implicitly be called here, which will
509 // unlink the anchor from the collection.
512 template<typename T
, typename U
, typename V
, typename W
>
513 inline T
& LinkedHashSet
<T
, U
, V
, W
>::first()
516 return firstNode()->m_value
;
519 template<typename T
, typename U
, typename V
, typename W
>
520 inline const T
& LinkedHashSet
<T
, U
, V
, W
>::first() const
523 return firstNode()->m_value
;
526 template<typename T
, typename U
, typename V
, typename W
>
527 inline void LinkedHashSet
<T
, U
, V
, W
>::removeFirst()
530 m_impl
.remove(static_cast<Node
*>(m_anchor
.m_next
));
533 template<typename T
, typename U
, typename V
, typename W
>
534 inline T
& LinkedHashSet
<T
, U
, V
, W
>::last()
537 return lastNode()->m_value
;
540 template<typename T
, typename U
, typename V
, typename W
>
541 inline const T
& LinkedHashSet
<T
, U
, V
, W
>::last() const
544 return lastNode()->m_value
;
547 template<typename T
, typename U
, typename V
, typename W
>
548 inline void LinkedHashSet
<T
, U
, V
, W
>::removeLast()
551 m_impl
.remove(static_cast<Node
*>(m_anchor
.m_prev
));
554 template<typename T
, typename U
, typename V
, typename W
>
555 inline typename LinkedHashSet
<T
, U
, V
, W
>::iterator LinkedHashSet
<T
, U
, V
, W
>::find(ValuePeekInType value
)
557 LinkedHashSet::Node
* node
= m_impl
.template lookup
<LinkedHashSet::NodeHashFunctions
, ValuePeekInType
>(value
);
560 return makeIterator(node
);
563 template<typename T
, typename U
, typename V
, typename W
>
564 inline typename LinkedHashSet
<T
, U
, V
, W
>::const_iterator LinkedHashSet
<T
, U
, V
, W
>::find(ValuePeekInType value
) const
566 const LinkedHashSet::Node
* node
= m_impl
.template lookup
<LinkedHashSet::NodeHashFunctions
, ValuePeekInType
>(value
);
569 return makeConstIterator(node
);
572 template<typename Translator
>
573 struct LinkedHashSetTranslatorAdapter
{
574 template<typename T
> static unsigned hash(const T
& key
) { return Translator::hash(key
); }
575 template<typename T
, typename U
> static bool equal(const T
& a
, const U
& b
) { return Translator::equal(a
.m_value
, b
); }
578 template<typename Value
, typename U
, typename V
, typename W
>
579 template<typename HashTranslator
, typename T
>
580 inline typename LinkedHashSet
<Value
, U
, V
, W
>::iterator LinkedHashSet
<Value
, U
, V
, W
>::find(const T
& value
)
582 typedef LinkedHashSetTranslatorAdapter
<HashTranslator
> TranslatedFunctions
;
583 const LinkedHashSet::Node
* node
= m_impl
.template lookup
<TranslatedFunctions
, const T
&>(value
);
586 return makeIterator(node
);
589 template<typename Value
, typename U
, typename V
, typename W
>
590 template<typename HashTranslator
, typename T
>
591 inline typename LinkedHashSet
<Value
, U
, V
, W
>::const_iterator LinkedHashSet
<Value
, U
, V
, W
>::find(const T
& value
) const
593 typedef LinkedHashSetTranslatorAdapter
<HashTranslator
> TranslatedFunctions
;
594 const LinkedHashSet::Node
* node
= m_impl
.template lookup
<TranslatedFunctions
, const T
&>(value
);
597 return makeConstIterator(node
);
600 template<typename Value
, typename U
, typename V
, typename W
>
601 template<typename HashTranslator
, typename T
>
602 inline bool LinkedHashSet
<Value
, U
, V
, W
>::contains(const T
& value
) const
604 return m_impl
.template contains
<LinkedHashSetTranslatorAdapter
<HashTranslator
>>(value
);
607 template<typename T
, typename U
, typename V
, typename W
>
608 inline bool LinkedHashSet
<T
, U
, V
, W
>::contains(ValuePeekInType value
) const
610 return m_impl
.template contains
<NodeHashFunctions
>(value
);
613 template<typename Value
, typename HashFunctions
, typename Traits
, typename Allocator
>
614 typename LinkedHashSet
<Value
, HashFunctions
, Traits
, Allocator
>::AddResult LinkedHashSet
<Value
, HashFunctions
, Traits
, Allocator
>::add(ValuePeekInType value
)
616 return m_impl
.template add
<NodeHashFunctions
>(value
, &m_anchor
);
619 template<typename T
, typename U
, typename V
, typename W
>
620 typename LinkedHashSet
<T
, U
, V
, W
>::iterator LinkedHashSet
<T
, U
, V
, W
>::addReturnIterator(ValuePeekInType value
)
622 typename
ImplType::AddResult result
= m_impl
.template add
<NodeHashFunctions
>(value
, &m_anchor
);
623 return makeIterator(result
.storedValue
);
626 template<typename T
, typename U
, typename V
, typename W
>
627 typename LinkedHashSet
<T
, U
, V
, W
>::AddResult LinkedHashSet
<T
, U
, V
, W
>::appendOrMoveToLast(ValuePeekInType value
)
629 typename
ImplType::AddResult result
= m_impl
.template add
<NodeHashFunctions
>(value
, &m_anchor
);
630 Node
* node
= result
.storedValue
;
631 if (!result
.isNewEntry
) {
633 m_anchor
.insertBefore(*node
);
638 template<typename T
, typename U
, typename V
, typename W
>
639 typename LinkedHashSet
<T
, U
, V
, W
>::AddResult LinkedHashSet
<T
, U
, V
, W
>::prependOrMoveToFirst(ValuePeekInType value
)
641 typename
ImplType::AddResult result
= m_impl
.template add
<NodeHashFunctions
>(value
, m_anchor
.m_next
);
642 Node
* node
= result
.storedValue
;
643 if (!result
.isNewEntry
) {
645 m_anchor
.insertAfter(*node
);
650 template<typename T
, typename U
, typename V
, typename W
>
651 typename LinkedHashSet
<T
, U
, V
, W
>::AddResult LinkedHashSet
<T
, U
, V
, W
>::insertBefore(ValuePeekInType beforeValue
, ValuePeekInType newValue
)
653 return insertBefore(find(beforeValue
), newValue
);
656 template<typename T
, typename U
, typename V
, typename W
>
657 inline void LinkedHashSet
<T
, U
, V
, W
>::remove(iterator it
)
661 m_impl
.remove(it
.node());
664 template<typename T
, typename U
, typename V
, typename W
>
665 inline void LinkedHashSet
<T
, U
, V
, W
>::remove(ValuePeekInType value
)
670 inline void swapAnchor(LinkedHashSetNodeBase
& a
, LinkedHashSetNodeBase
& b
)
672 ASSERT(a
.m_prev
&& a
.m_next
&& b
.m_prev
&& b
.m_next
);
673 swap(a
.m_prev
, b
.m_prev
);
674 swap(a
.m_next
, b
.m_next
);
675 if (b
.m_next
== &a
) {
676 ASSERT(b
.m_prev
== &a
);
680 b
.m_next
->m_prev
= &b
;
681 b
.m_prev
->m_next
= &b
;
683 if (a
.m_next
== &b
) {
684 ASSERT(a
.m_prev
== &b
);
688 a
.m_next
->m_prev
= &a
;
689 a
.m_prev
->m_next
= &a
;
693 inline void swap(LinkedHashSetNodeBase
& a
, LinkedHashSetNodeBase
& b
)
695 ASSERT(a
.m_next
!= &a
&& b
.m_next
!= &b
);
696 swap(a
.m_prev
, b
.m_prev
);
697 swap(a
.m_next
, b
.m_next
);
699 b
.m_next
->m_prev
= &b
;
700 b
.m_prev
->m_next
= &b
;
703 a
.m_next
->m_prev
= &a
;
704 a
.m_prev
->m_next
= &a
;
708 template<typename T
, typename Allocator
>
709 inline void swap(LinkedHashSetNode
<T
, Allocator
>& a
, LinkedHashSetNode
<T
, Allocator
>& b
)
711 typedef LinkedHashSetNodeBase Base
;
712 // The key and value cannot be swapped atomically, and it would be
713 // wrong to have a GC when only one was swapped and the other still
714 // contained garbage (eg. from a previous use of the same slot).
715 // Therefore we forbid a GC until both the key and the value are
717 Allocator::enterGCForbiddenScope();
718 swap(static_cast<Base
&>(a
), static_cast<Base
&>(b
));
719 swap(a
.m_value
, b
.m_value
);
720 Allocator::leaveGCForbiddenScope();
724 template<typename T
, typename U
, typename V
>
725 struct NeedsTracing
<LinkedHashSet
<T
, U
, V
>> {
726 static const bool value
= false;
732 using WTF::LinkedHashSet
;
734 #endif /* WTF_LinkedHashSet_h */