Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(240)

Side by Side Diff: third_party/WebKit/Source/wtf/LinkedHashSet.h

Issue 2769603002: Move files in wtf/ to platform/wtf/ (Part 8). (Closed)
Patch Set: Rebase. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/wtf/HashTraits.h ('k') | third_party/WebKit/Source/wtf/ListHashSet.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights 2 // Use of this source code is governed by a BSD-style license that can be
3 * reserved. 3 // found in the LICENSE file.
4 * Copyright (C) 2011, Benjamin Poulain <ikipou@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22 4
23 #ifndef WTF_LinkedHashSet_h 5 #include "platform/wtf/LinkedHashSet.h"
24 #define WTF_LinkedHashSet_h
25 6
26 #include "wtf/AddressSanitizer.h" 7 // The contents of this header was moved to platform/wtf as part of
27 #include "wtf/HashSet.h" 8 // WTF migration project. See the following post for details:
28 #include "wtf/allocator/PartitionAllocator.h" 9 // https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gY CAAJ
29
30 namespace WTF {
31
32 // LinkedHashSet: 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.
37
38 // Unlike ListHashSet, but like most WTF collections, iteration is NOT safe
39 // against mutation of the LinkedHashSet.
40
41 template <typename Value,
42 typename HashFunctions,
43 typename HashTraits,
44 typename Allocator>
45 class LinkedHashSet;
46
47 template <typename LinkedHashSet>
48 class LinkedHashSetIterator;
49 template <typename LinkedHashSet>
50 class LinkedHashSetConstIterator;
51 template <typename LinkedHashSet>
52 class LinkedHashSetReverseIterator;
53 template <typename LinkedHashSet>
54 class LinkedHashSetConstReverseIterator;
55
56 template <typename Value, typename HashFunctions, typename Allocator>
57 struct LinkedHashSetTranslator;
58 template <typename Value, typename Allocator>
59 struct LinkedHashSetExtractor;
60 template <typename Value, typename ValueTraits, typename Allocator>
61 struct LinkedHashSetTraits;
62
63 class LinkedHashSetNodeBase {
64 DISALLOW_NEW();
65
66 public:
67 LinkedHashSetNodeBase() : m_prev(this), m_next(this) {}
68
69 NO_SANITIZE_ADDRESS
70 void unlink() {
71 if (!m_next)
72 return;
73 DCHECK(m_prev);
74 DCHECK(m_next->m_prev == this);
75 DCHECK(m_prev->m_next == this);
76 m_next->m_prev = m_prev;
77 m_prev->m_next = m_next;
78 }
79
80 ~LinkedHashSetNodeBase() { unlink(); }
81
82 void insertBefore(LinkedHashSetNodeBase& other) {
83 other.m_next = this;
84 other.m_prev = m_prev;
85 m_prev->m_next = &other;
86 m_prev = &other;
87 DCHECK(other.m_next);
88 DCHECK(other.m_prev);
89 DCHECK(m_next);
90 DCHECK(m_prev);
91 }
92
93 void insertAfter(LinkedHashSetNodeBase& other) {
94 other.m_prev = this;
95 other.m_next = m_next;
96 m_next->m_prev = &other;
97 m_next = &other;
98 DCHECK(other.m_next);
99 DCHECK(other.m_prev);
100 DCHECK(m_next);
101 DCHECK(m_prev);
102 }
103
104 LinkedHashSetNodeBase(LinkedHashSetNodeBase* prev,
105 LinkedHashSetNodeBase* next)
106 : m_prev(prev), m_next(next) {
107 DCHECK((prev && next) || (!prev && !next));
108 }
109
110 LinkedHashSetNodeBase* m_prev;
111 LinkedHashSetNodeBase* m_next;
112
113 protected:
114 // If we take a copy of a node we can't copy the next and prev pointers,
115 // since they point to something that does not point at us. This is used
116 // inside the shouldExpand() "if" in HashTable::add.
117 LinkedHashSetNodeBase(const LinkedHashSetNodeBase& other)
118 : m_prev(0), m_next(0) {}
119
120 LinkedHashSetNodeBase(LinkedHashSetNodeBase&& other)
121 : m_prev(other.m_prev), m_next(other.m_next) {
122 other.m_prev = nullptr;
123 other.m_next = nullptr;
124 if (m_next) {
125 m_prev->m_next = this;
126 m_next->m_prev = this;
127 }
128 }
129
130 private:
131 // Should not be used.
132 LinkedHashSetNodeBase& operator=(const LinkedHashSetNodeBase& other);
133 };
134
135 template <typename ValueArg, typename Allocator>
136 class LinkedHashSetNode : public LinkedHashSetNodeBase {
137 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
138
139 public:
140 LinkedHashSetNode(const ValueArg& value,
141 LinkedHashSetNodeBase* prev,
142 LinkedHashSetNodeBase* next)
143 : LinkedHashSetNodeBase(prev, next), m_value(value) {}
144
145 LinkedHashSetNode(LinkedHashSetNode&& other)
146 : LinkedHashSetNodeBase(std::move(other)),
147 m_value(std::move(other.m_value)) {}
148
149 ValueArg m_value;
150
151 private:
152 WTF_MAKE_NONCOPYABLE(LinkedHashSetNode);
153 };
154
155 template <typename ValueArg,
156 typename HashFunctions = typename DefaultHash<ValueArg>::Hash,
157 typename TraitsArg = HashTraits<ValueArg>,
158 typename Allocator = PartitionAllocator>
159 class LinkedHashSet {
160 USE_ALLOCATOR(LinkedHashSet, Allocator);
161
162 private:
163 typedef ValueArg Value;
164 typedef TraitsArg Traits;
165 typedef LinkedHashSetNode<Value, Allocator> Node;
166 typedef LinkedHashSetNodeBase NodeBase;
167 typedef LinkedHashSetTranslator<Value, HashFunctions, Allocator>
168 NodeHashFunctions;
169 typedef LinkedHashSetTraits<Value, Traits, Allocator> NodeHashTraits;
170
171 typedef HashTable<Node,
172 Node,
173 IdentityExtractor,
174 NodeHashFunctions,
175 NodeHashTraits,
176 NodeHashTraits,
177 Allocator>
178 ImplType;
179
180 public:
181 typedef LinkedHashSetIterator<LinkedHashSet> iterator;
182 friend class LinkedHashSetIterator<LinkedHashSet>;
183 typedef LinkedHashSetConstIterator<LinkedHashSet> const_iterator;
184 friend class LinkedHashSetConstIterator<LinkedHashSet>;
185
186 typedef LinkedHashSetReverseIterator<LinkedHashSet> reverse_iterator;
187 friend class LinkedHashSetReverseIterator<LinkedHashSet>;
188 typedef LinkedHashSetConstReverseIterator<LinkedHashSet>
189 const_reverse_iterator;
190 friend class LinkedHashSetConstReverseIterator<LinkedHashSet>;
191
192 struct AddResult final {
193 STACK_ALLOCATED();
194 AddResult(const typename ImplType::AddResult& hashTableAddResult)
195 : storedValue(&hashTableAddResult.storedValue->m_value),
196 isNewEntry(hashTableAddResult.isNewEntry) {}
197
198 Value* storedValue;
199 bool isNewEntry;
200 };
201
202 typedef typename HashTraits<Value>::PeekInType ValuePeekInType;
203
204 LinkedHashSet();
205 LinkedHashSet(const LinkedHashSet&);
206 LinkedHashSet(LinkedHashSet&&);
207 LinkedHashSet& operator=(const LinkedHashSet&);
208 LinkedHashSet& operator=(LinkedHashSet&&);
209
210 // Needs finalization. The anchor needs to unlink itself from the chain.
211 ~LinkedHashSet();
212
213 static void finalize(void* pointer) {
214 reinterpret_cast<LinkedHashSet*>(pointer)->~LinkedHashSet();
215 }
216 void finalizeGarbageCollectedObject() { finalize(this); }
217
218 void swap(LinkedHashSet&);
219
220 unsigned size() const { return m_impl.size(); }
221 unsigned capacity() const { return m_impl.capacity(); }
222 bool isEmpty() const { return m_impl.isEmpty(); }
223
224 iterator begin() { return makeIterator(firstNode()); }
225 iterator end() { return makeIterator(anchor()); }
226 const_iterator begin() const { return makeConstIterator(firstNode()); }
227 const_iterator end() const { return makeConstIterator(anchor()); }
228
229 reverse_iterator rbegin() { return makeReverseIterator(lastNode()); }
230 reverse_iterator rend() { return makeReverseIterator(anchor()); }
231 const_reverse_iterator rbegin() const {
232 return makeConstReverseIterator(lastNode());
233 }
234 const_reverse_iterator rend() const {
235 return makeConstReverseIterator(anchor());
236 }
237
238 Value& front();
239 const Value& front() const;
240 void removeFirst();
241
242 Value& back();
243 const Value& back() const;
244 void pop_back();
245
246 iterator find(ValuePeekInType);
247 const_iterator find(ValuePeekInType) const;
248 bool contains(ValuePeekInType) const;
249
250 // An alternate version of find() that finds the object by hashing and
251 // comparing with some other type, to avoid the cost of type conversion.
252 // The HashTranslator interface is defined in HashSet.
253 template <typename HashTranslator, typename T>
254 iterator find(const T&);
255 template <typename HashTranslator, typename T>
256 const_iterator find(const T&) const;
257 template <typename HashTranslator, typename T>
258 bool contains(const T&) const;
259
260 // The return value of insert is a pair of a pointer to the stored value,
261 // and a bool that is true if an new entry was added.
262 template <typename IncomingValueType>
263 AddResult insert(IncomingValueType&&);
264
265 // Same as insert() except that the return value is an
266 // iterator. Useful in cases where it's needed to have the
267 // same return value as find() and where it's not possible to
268 // use a pointer to the storedValue.
269 template <typename IncomingValueType>
270 iterator addReturnIterator(IncomingValueType&&);
271
272 // Add the value to the end of the collection. If the value was already in
273 // the list, it is moved to the end.
274 template <typename IncomingValueType>
275 AddResult appendOrMoveToLast(IncomingValueType&&);
276
277 // Add the value to the beginning of the collection. If the value was already
278 // in the list, it is moved to the beginning.
279 template <typename IncomingValueType>
280 AddResult prependOrMoveToFirst(IncomingValueType&&);
281
282 template <typename IncomingValueType>
283 AddResult insertBefore(ValuePeekInType beforeValue,
284 IncomingValueType&& newValue);
285 template <typename IncomingValueType>
286 AddResult insertBefore(iterator it, IncomingValueType&& newValue) {
287 return m_impl.template add<NodeHashFunctions>(
288 std::forward<IncomingValueType>(newValue), it.getNode());
289 }
290
291 void erase(ValuePeekInType);
292 void erase(iterator);
293 void clear() { m_impl.clear(); }
294 template <typename Collection>
295 void removeAll(const Collection& other) {
296 WTF::removeAll(*this, other);
297 }
298
299 template <typename VisitorDispatcher>
300 void trace(VisitorDispatcher visitor) {
301 m_impl.trace(visitor);
302 // Should the underlying table be moved by GC, register a callback
303 // that fixes up the interior pointers that the (Heap)LinkedHashSet keeps.
304 if (m_impl.m_table) {
305 Allocator::registerBackingStoreCallback(
306 visitor, m_impl.m_table, moveBackingCallback,
307 reinterpret_cast<void*>(&m_anchor));
308 }
309 }
310
311 int64_t modifications() const { return m_impl.modifications(); }
312 void checkModifications(int64_t mods) const {
313 m_impl.checkModifications(mods);
314 }
315
316 private:
317 Node* anchor() { return reinterpret_cast<Node*>(&m_anchor); }
318 const Node* anchor() const {
319 return reinterpret_cast<const Node*>(&m_anchor);
320 }
321 Node* firstNode() { return reinterpret_cast<Node*>(m_anchor.m_next); }
322 const Node* firstNode() const {
323 return reinterpret_cast<const Node*>(m_anchor.m_next);
324 }
325 Node* lastNode() { return reinterpret_cast<Node*>(m_anchor.m_prev); }
326 const Node* lastNode() const {
327 return reinterpret_cast<const Node*>(m_anchor.m_prev);
328 }
329
330 iterator makeIterator(const Node* position) {
331 return iterator(position, this);
332 }
333 const_iterator makeConstIterator(const Node* position) const {
334 return const_iterator(position, this);
335 }
336 reverse_iterator makeReverseIterator(const Node* position) {
337 return reverse_iterator(position, this);
338 }
339 const_reverse_iterator makeConstReverseIterator(const Node* position) const {
340 return const_reverse_iterator(position, this);
341 }
342
343 static void moveBackingCallback(void* anchor,
344 void* from,
345 void* to,
346 size_t size) {
347 // Note: the hash table move may have been overlapping; linearly scan the
348 // entire table and fixup interior pointers into the old region with
349 // correspondingly offset ones into the new.
350 size_t tableSize = size / sizeof(Node);
351 Node* table = reinterpret_cast<Node*>(to);
352 NodeBase* fromStart = reinterpret_cast<NodeBase*>(from);
353 NodeBase* fromEnd =
354 reinterpret_cast<NodeBase*>(reinterpret_cast<uintptr_t>(from) + size);
355 for (Node* element = table + tableSize - 1; element >= table; element--) {
356 Node& node = *element;
357 if (ImplType::isEmptyOrDeletedBucket(node))
358 continue;
359 if (node.m_next >= fromStart && node.m_next < fromEnd) {
360 size_t diff = reinterpret_cast<uintptr_t>(node.m_next) -
361 reinterpret_cast<uintptr_t>(from);
362 node.m_next =
363 reinterpret_cast<NodeBase*>(reinterpret_cast<uintptr_t>(to) + diff);
364 }
365 if (node.m_prev >= fromStart && node.m_prev < fromEnd) {
366 size_t diff = reinterpret_cast<uintptr_t>(node.m_prev) -
367 reinterpret_cast<uintptr_t>(from);
368 node.m_prev =
369 reinterpret_cast<NodeBase*>(reinterpret_cast<uintptr_t>(to) + diff);
370 }
371 }
372 NodeBase* anchorNode = reinterpret_cast<NodeBase*>(anchor);
373 if (anchorNode->m_next >= fromStart && anchorNode->m_next < fromEnd) {
374 size_t diff = reinterpret_cast<uintptr_t>(anchorNode->m_next) -
375 reinterpret_cast<uintptr_t>(from);
376 anchorNode->m_next =
377 reinterpret_cast<NodeBase*>(reinterpret_cast<uintptr_t>(to) + diff);
378 }
379 if (anchorNode->m_prev >= fromStart && anchorNode->m_prev < fromEnd) {
380 size_t diff = reinterpret_cast<uintptr_t>(anchorNode->m_prev) -
381 reinterpret_cast<uintptr_t>(from);
382 anchorNode->m_prev =
383 reinterpret_cast<NodeBase*>(reinterpret_cast<uintptr_t>(to) + diff);
384 }
385 }
386
387 ImplType m_impl;
388 NodeBase m_anchor;
389 };
390
391 template <typename Value, typename HashFunctions, typename Allocator>
392 struct LinkedHashSetTranslator {
393 STATIC_ONLY(LinkedHashSetTranslator);
394 typedef LinkedHashSetNode<Value, Allocator> Node;
395 typedef LinkedHashSetNodeBase NodeBase;
396 typedef typename HashTraits<Value>::PeekInType ValuePeekInType;
397 static unsigned hash(const Node& node) {
398 return HashFunctions::hash(node.m_value);
399 }
400 static unsigned hash(const ValuePeekInType& key) {
401 return HashFunctions::hash(key);
402 }
403 static bool equal(const Node& a, const ValuePeekInType& b) {
404 return HashFunctions::equal(a.m_value, b);
405 }
406 static bool equal(const Node& a, const Node& b) {
407 return HashFunctions::equal(a.m_value, b.m_value);
408 }
409 template <typename IncomingValueType>
410 static void translate(Node& location,
411 IncomingValueType&& key,
412 NodeBase* anchor) {
413 anchor->insertBefore(location);
414 location.m_value = std::forward<IncomingValueType>(key);
415 }
416
417 // Empty (or deleted) slots have the m_next pointer set to null, but we
418 // don't do anything to the other fields, which may contain junk.
419 // Therefore you can't compare a newly constructed empty value with a
420 // slot and get the right answer.
421 static const bool safeToCompareToEmptyOrDeleted = false;
422 };
423
424 template <typename Value, typename Allocator>
425 struct LinkedHashSetExtractor {
426 STATIC_ONLY(LinkedHashSetExtractor);
427 static const Value& extract(const LinkedHashSetNode<Value, Allocator>& node) {
428 return node.m_value;
429 }
430 };
431
432 template <typename Value, typename ValueTraitsArg, typename Allocator>
433 struct LinkedHashSetTraits
434 : public SimpleClassHashTraits<LinkedHashSetNode<Value, Allocator>> {
435 STATIC_ONLY(LinkedHashSetTraits);
436 typedef LinkedHashSetNode<Value, Allocator> Node;
437 typedef ValueTraitsArg ValueTraits;
438
439 // The slot is empty when the m_next field is zero so it's safe to zero
440 // the backing.
441 static const bool emptyValueIsZero = true;
442
443 static const bool hasIsEmptyValueFunction = true;
444 static bool isEmptyValue(const Node& node) { return !node.m_next; }
445
446 static const int deletedValue = -1;
447
448 static void constructDeletedValue(Node& slot, bool) {
449 slot.m_next = reinterpret_cast<Node*>(deletedValue);
450 }
451 static bool isDeletedValue(const Node& slot) {
452 return slot.m_next == reinterpret_cast<Node*>(deletedValue);
453 }
454
455 // Whether we need to trace and do weak processing depends on the traits of
456 // the type inside the node.
457 template <typename U = void>
458 struct IsTraceableInCollection {
459 STATIC_ONLY(IsTraceableInCollection);
460 static const bool value =
461 ValueTraits::template IsTraceableInCollection<>::value;
462 };
463 static const WeakHandlingFlag weakHandlingFlag =
464 ValueTraits::weakHandlingFlag;
465 };
466
467 template <typename LinkedHashSetType>
468 class LinkedHashSetIterator {
469 DISALLOW_NEW();
470
471 private:
472 typedef typename LinkedHashSetType::Node Node;
473 typedef typename LinkedHashSetType::Traits Traits;
474
475 typedef typename LinkedHashSetType::Value& ReferenceType;
476 typedef typename LinkedHashSetType::Value* PointerType;
477
478 typedef LinkedHashSetConstIterator<LinkedHashSetType> const_iterator;
479
480 Node* getNode() { return const_cast<Node*>(m_iterator.getNode()); }
481
482 protected:
483 LinkedHashSetIterator(const Node* position, LinkedHashSetType* m_container)
484 : m_iterator(position, m_container) {}
485
486 public:
487 // Default copy, assignment and destructor are OK.
488
489 PointerType get() const { return const_cast<PointerType>(m_iterator.get()); }
490 ReferenceType operator*() const { return *get(); }
491 PointerType operator->() const { return get(); }
492
493 LinkedHashSetIterator& operator++() {
494 ++m_iterator;
495 return *this;
496 }
497 LinkedHashSetIterator& operator--() {
498 --m_iterator;
499 return *this;
500 }
501
502 // Postfix ++ and -- intentionally omitted.
503
504 // Comparison.
505 bool operator==(const LinkedHashSetIterator& other) const {
506 return m_iterator == other.m_iterator;
507 }
508 bool operator!=(const LinkedHashSetIterator& other) const {
509 return m_iterator != other.m_iterator;
510 }
511
512 operator const_iterator() const { return m_iterator; }
513
514 protected:
515 const_iterator m_iterator;
516 template <typename T, typename U, typename V, typename W>
517 friend class LinkedHashSet;
518 };
519
520 template <typename LinkedHashSetType>
521 class LinkedHashSetConstIterator {
522 DISALLOW_NEW();
523
524 private:
525 typedef typename LinkedHashSetType::Node Node;
526 typedef typename LinkedHashSetType::Traits Traits;
527
528 typedef const typename LinkedHashSetType::Value& ReferenceType;
529 typedef const typename LinkedHashSetType::Value* PointerType;
530
531 const Node* getNode() const { return static_cast<const Node*>(m_position); }
532
533 protected:
534 LinkedHashSetConstIterator(const LinkedHashSetNodeBase* position,
535 const LinkedHashSetType* container)
536 : m_position(position)
537 #if DCHECK_IS_ON()
538 ,
539 m_container(container),
540 m_containerModifications(container->modifications())
541 #endif
542 {
543 }
544
545 public:
546 PointerType get() const {
547 checkModifications();
548 return &static_cast<const Node*>(m_position)->m_value;
549 }
550 ReferenceType operator*() const { return *get(); }
551 PointerType operator->() const { return get(); }
552
553 LinkedHashSetConstIterator& operator++() {
554 DCHECK(m_position);
555 checkModifications();
556 m_position = m_position->m_next;
557 return *this;
558 }
559
560 LinkedHashSetConstIterator& operator--() {
561 DCHECK(m_position);
562 checkModifications();
563 m_position = m_position->m_prev;
564 return *this;
565 }
566
567 // Postfix ++ and -- intentionally omitted.
568
569 // Comparison.
570 bool operator==(const LinkedHashSetConstIterator& other) const {
571 return m_position == other.m_position;
572 }
573 bool operator!=(const LinkedHashSetConstIterator& other) const {
574 return m_position != other.m_position;
575 }
576
577 private:
578 const LinkedHashSetNodeBase* m_position;
579 #if DCHECK_IS_ON()
580 void checkModifications() const {
581 m_container->checkModifications(m_containerModifications);
582 }
583 const LinkedHashSetType* m_container;
584 int64_t m_containerModifications;
585 #else
586 void checkModifications() const {}
587 #endif
588 template <typename T, typename U, typename V, typename W>
589 friend class LinkedHashSet;
590 friend class LinkedHashSetIterator<LinkedHashSetType>;
591 };
592
593 template <typename LinkedHashSetType>
594 class LinkedHashSetReverseIterator
595 : public LinkedHashSetIterator<LinkedHashSetType> {
596 typedef LinkedHashSetIterator<LinkedHashSetType> Superclass;
597 typedef LinkedHashSetConstReverseIterator<LinkedHashSetType>
598 const_reverse_iterator;
599 typedef typename LinkedHashSetType::Node Node;
600
601 protected:
602 LinkedHashSetReverseIterator(const Node* position,
603 LinkedHashSetType* container)
604 : Superclass(position, container) {}
605
606 public:
607 LinkedHashSetReverseIterator& operator++() {
608 Superclass::operator--();
609 return *this;
610 }
611 LinkedHashSetReverseIterator& operator--() {
612 Superclass::operator++();
613 return *this;
614 }
615
616 // Postfix ++ and -- intentionally omitted.
617
618 operator const_reverse_iterator() const {
619 return *reinterpret_cast<const_reverse_iterator*>(this);
620 }
621
622 template <typename T, typename U, typename V, typename W>
623 friend class LinkedHashSet;
624 };
625
626 template <typename LinkedHashSetType>
627 class LinkedHashSetConstReverseIterator
628 : public LinkedHashSetConstIterator<LinkedHashSetType> {
629 typedef LinkedHashSetConstIterator<LinkedHashSetType> Superclass;
630 typedef typename LinkedHashSetType::Node Node;
631
632 public:
633 LinkedHashSetConstReverseIterator(const Node* position,
634 const LinkedHashSetType* container)
635 : Superclass(position, container) {}
636
637 LinkedHashSetConstReverseIterator& operator++() {
638 Superclass::operator--();
639 return *this;
640 }
641 LinkedHashSetConstReverseIterator& operator--() {
642 Superclass::operator++();
643 return *this;
644 }
645
646 // Postfix ++ and -- intentionally omitted.
647
648 template <typename T, typename U, typename V, typename W>
649 friend class LinkedHashSet;
650 };
651
652 template <typename T, typename U, typename V, typename Allocator>
653 inline LinkedHashSet<T, U, V, Allocator>::LinkedHashSet() {
654 static_assert(
655 Allocator::isGarbageCollected ||
656 !IsPointerToGarbageCollectedType<T>::value,
657 "Cannot put raw pointers to garbage-collected classes into "
658 "an off-heap LinkedHashSet. Use HeapLinkedHashSet<Member<T>> instead.");
659 }
660
661 template <typename T, typename U, typename V, typename W>
662 inline LinkedHashSet<T, U, V, W>::LinkedHashSet(const LinkedHashSet& other)
663 : m_anchor() {
664 const_iterator end = other.end();
665 for (const_iterator it = other.begin(); it != end; ++it)
666 insert(*it);
667 }
668
669 template <typename T, typename U, typename V, typename W>
670 inline LinkedHashSet<T, U, V, W>::LinkedHashSet(LinkedHashSet&& other)
671 : m_anchor() {
672 swap(other);
673 }
674
675 template <typename T, typename U, typename V, typename W>
676 inline LinkedHashSet<T, U, V, W>& LinkedHashSet<T, U, V, W>::operator=(
677 const LinkedHashSet& other) {
678 LinkedHashSet tmp(other);
679 swap(tmp);
680 return *this;
681 }
682
683 template <typename T, typename U, typename V, typename W>
684 inline LinkedHashSet<T, U, V, W>& LinkedHashSet<T, U, V, W>::operator=(
685 LinkedHashSet&& other) {
686 swap(other);
687 return *this;
688 }
689
690 template <typename T, typename U, typename V, typename W>
691 inline void LinkedHashSet<T, U, V, W>::swap(LinkedHashSet& other) {
692 m_impl.swap(other.m_impl);
693 swapAnchor(m_anchor, other.m_anchor);
694 }
695
696 template <typename T, typename U, typename V, typename Allocator>
697 inline LinkedHashSet<T, U, V, Allocator>::~LinkedHashSet() {
698 // The destructor of m_anchor will implicitly be called here, which will
699 // unlink the anchor from the collection.
700 }
701
702 template <typename T, typename U, typename V, typename W>
703 inline T& LinkedHashSet<T, U, V, W>::front() {
704 DCHECK(!isEmpty());
705 return firstNode()->m_value;
706 }
707
708 template <typename T, typename U, typename V, typename W>
709 inline const T& LinkedHashSet<T, U, V, W>::front() const {
710 DCHECK(!isEmpty());
711 return firstNode()->m_value;
712 }
713
714 template <typename T, typename U, typename V, typename W>
715 inline void LinkedHashSet<T, U, V, W>::removeFirst() {
716 DCHECK(!isEmpty());
717 m_impl.remove(static_cast<Node*>(m_anchor.m_next));
718 }
719
720 template <typename T, typename U, typename V, typename W>
721 inline T& LinkedHashSet<T, U, V, W>::back() {
722 DCHECK(!isEmpty());
723 return lastNode()->m_value;
724 }
725
726 template <typename T, typename U, typename V, typename W>
727 inline const T& LinkedHashSet<T, U, V, W>::back() const {
728 DCHECK(!isEmpty());
729 return lastNode()->m_value;
730 }
731
732 template <typename T, typename U, typename V, typename W>
733 inline void LinkedHashSet<T, U, V, W>::pop_back() {
734 DCHECK(!isEmpty());
735 m_impl.remove(static_cast<Node*>(m_anchor.m_prev));
736 }
737
738 template <typename T, typename U, typename V, typename W>
739 inline typename LinkedHashSet<T, U, V, W>::iterator
740 LinkedHashSet<T, U, V, W>::find(ValuePeekInType value) {
741 LinkedHashSet::Node* node =
742 m_impl.template lookup<LinkedHashSet::NodeHashFunctions, ValuePeekInType>(
743 value);
744 if (!node)
745 return end();
746 return makeIterator(node);
747 }
748
749 template <typename T, typename U, typename V, typename W>
750 inline typename LinkedHashSet<T, U, V, W>::const_iterator
751 LinkedHashSet<T, U, V, W>::find(ValuePeekInType value) const {
752 const LinkedHashSet::Node* node =
753 m_impl.template lookup<LinkedHashSet::NodeHashFunctions, ValuePeekInType>(
754 value);
755 if (!node)
756 return end();
757 return makeConstIterator(node);
758 }
759
760 template <typename Translator>
761 struct LinkedHashSetTranslatorAdapter {
762 STATIC_ONLY(LinkedHashSetTranslatorAdapter);
763 template <typename T>
764 static unsigned hash(const T& key) {
765 return Translator::hash(key);
766 }
767 template <typename T, typename U>
768 static bool equal(const T& a, const U& b) {
769 return Translator::equal(a.m_value, b);
770 }
771 };
772
773 template <typename Value, typename U, typename V, typename W>
774 template <typename HashTranslator, typename T>
775 inline typename LinkedHashSet<Value, U, V, W>::iterator
776 LinkedHashSet<Value, U, V, W>::find(const T& value) {
777 typedef LinkedHashSetTranslatorAdapter<HashTranslator> TranslatedFunctions;
778 const LinkedHashSet::Node* node =
779 m_impl.template lookup<TranslatedFunctions, const T&>(value);
780 if (!node)
781 return end();
782 return makeIterator(node);
783 }
784
785 template <typename Value, typename U, typename V, typename W>
786 template <typename HashTranslator, typename T>
787 inline typename LinkedHashSet<Value, U, V, W>::const_iterator
788 LinkedHashSet<Value, U, V, W>::find(const T& value) const {
789 typedef LinkedHashSetTranslatorAdapter<HashTranslator> TranslatedFunctions;
790 const LinkedHashSet::Node* node =
791 m_impl.template lookup<TranslatedFunctions, const T&>(value);
792 if (!node)
793 return end();
794 return makeConstIterator(node);
795 }
796
797 template <typename Value, typename U, typename V, typename W>
798 template <typename HashTranslator, typename T>
799 inline bool LinkedHashSet<Value, U, V, W>::contains(const T& value) const {
800 return m_impl
801 .template contains<LinkedHashSetTranslatorAdapter<HashTranslator>>(value);
802 }
803
804 template <typename T, typename U, typename V, typename W>
805 inline bool LinkedHashSet<T, U, V, W>::contains(ValuePeekInType value) const {
806 return m_impl.template contains<NodeHashFunctions>(value);
807 }
808
809 template <typename Value,
810 typename HashFunctions,
811 typename Traits,
812 typename Allocator>
813 template <typename IncomingValueType>
814 typename LinkedHashSet<Value, HashFunctions, Traits, Allocator>::AddResult
815 LinkedHashSet<Value, HashFunctions, Traits, Allocator>::insert(
816 IncomingValueType&& value) {
817 return m_impl.template add<NodeHashFunctions>(
818 std::forward<IncomingValueType>(value), &m_anchor);
819 }
820
821 template <typename T, typename U, typename V, typename W>
822 template <typename IncomingValueType>
823 typename LinkedHashSet<T, U, V, W>::iterator
824 LinkedHashSet<T, U, V, W>::addReturnIterator(IncomingValueType&& value) {
825 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions>(
826 std::forward<IncomingValueType>(value), &m_anchor);
827 return makeIterator(result.storedValue);
828 }
829
830 template <typename T, typename U, typename V, typename W>
831 template <typename IncomingValueType>
832 typename LinkedHashSet<T, U, V, W>::AddResult
833 LinkedHashSet<T, U, V, W>::appendOrMoveToLast(IncomingValueType&& value) {
834 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions>(
835 std::forward<IncomingValueType>(value), &m_anchor);
836 Node* node = result.storedValue;
837 if (!result.isNewEntry) {
838 node->unlink();
839 m_anchor.insertBefore(*node);
840 }
841 return result;
842 }
843
844 template <typename T, typename U, typename V, typename W>
845 template <typename IncomingValueType>
846 typename LinkedHashSet<T, U, V, W>::AddResult
847 LinkedHashSet<T, U, V, W>::prependOrMoveToFirst(IncomingValueType&& value) {
848 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions>(
849 std::forward<IncomingValueType>(value), m_anchor.m_next);
850 Node* node = result.storedValue;
851 if (!result.isNewEntry) {
852 node->unlink();
853 m_anchor.insertAfter(*node);
854 }
855 return result;
856 }
857
858 template <typename T, typename U, typename V, typename W>
859 template <typename IncomingValueType>
860 typename LinkedHashSet<T, U, V, W>::AddResult
861 LinkedHashSet<T, U, V, W>::insertBefore(ValuePeekInType beforeValue,
862 IncomingValueType&& newValue) {
863 return insertBefore(find(beforeValue),
864 std::forward<IncomingValueType>(newValue));
865 }
866
867 template <typename T, typename U, typename V, typename W>
868 inline void LinkedHashSet<T, U, V, W>::erase(iterator it) {
869 if (it == end())
870 return;
871 m_impl.remove(it.getNode());
872 }
873
874 template <typename T, typename U, typename V, typename W>
875 inline void LinkedHashSet<T, U, V, W>::erase(ValuePeekInType value) {
876 erase(find(value));
877 }
878
879 inline void swapAnchor(LinkedHashSetNodeBase& a, LinkedHashSetNodeBase& b) {
880 DCHECK(a.m_prev);
881 DCHECK(a.m_next);
882 DCHECK(b.m_prev);
883 DCHECK(b.m_next);
884 swap(a.m_prev, b.m_prev);
885 swap(a.m_next, b.m_next);
886 if (b.m_next == &a) {
887 DCHECK_EQ(b.m_prev, &a);
888 b.m_next = &b;
889 b.m_prev = &b;
890 } else {
891 b.m_next->m_prev = &b;
892 b.m_prev->m_next = &b;
893 }
894 if (a.m_next == &b) {
895 DCHECK_EQ(a.m_prev, &b);
896 a.m_next = &a;
897 a.m_prev = &a;
898 } else {
899 a.m_next->m_prev = &a;
900 a.m_prev->m_next = &a;
901 }
902 }
903
904 inline void swap(LinkedHashSetNodeBase& a, LinkedHashSetNodeBase& b) {
905 DCHECK_NE(a.m_next, &a);
906 DCHECK_NE(b.m_next, &b);
907 swap(a.m_prev, b.m_prev);
908 swap(a.m_next, b.m_next);
909 if (b.m_next) {
910 b.m_next->m_prev = &b;
911 b.m_prev->m_next = &b;
912 }
913 if (a.m_next) {
914 a.m_next->m_prev = &a;
915 a.m_prev->m_next = &a;
916 }
917 }
918
919 template <typename T, typename Allocator>
920 inline void swap(LinkedHashSetNode<T, Allocator>& a,
921 LinkedHashSetNode<T, Allocator>& b) {
922 typedef LinkedHashSetNodeBase Base;
923 // The key and value cannot be swapped atomically, and it would be
924 // wrong to have a GC when only one was swapped and the other still
925 // contained garbage (eg. from a previous use of the same slot).
926 // Therefore we forbid a GC until both the key and the value are
927 // swapped.
928 Allocator::enterGCForbiddenScope();
929 swap(static_cast<Base&>(a), static_cast<Base&>(b));
930 swap(a.m_value, b.m_value);
931 Allocator::leaveGCForbiddenScope();
932 }
933
934 } // namespace WTF
935
936 using WTF::LinkedHashSet;
937
938 #endif /* WTF_LinkedHashSet_h */
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/wtf/HashTraits.h ('k') | third_party/WebKit/Source/wtf/ListHashSet.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698