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

Side by Side Diff: third_party/WebKit/Source/wtf/ListHashSet.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
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_ListHashSet_h 5 #include "platform/wtf/ListHashSet.h"
24 #define WTF_ListHashSet_h
25 6
26 #include "wtf/HashSet.h" 7 // The contents of this header was moved to platform/wtf as part of
27 #include "wtf/allocator/PartitionAllocator.h" 8 // WTF migration project. See the following post for details:
28 #include <memory> 9 // https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gY CAAJ
29
30 namespace WTF {
31
32 // ListHashSet: Just like HashSet, this class provides a Set interface - a
33 // collection of unique objects with O(1) insertion, removal and test for
34 // containership. However, it also has an order - iterating it will always give
35 // back values in the order in which they are added.
36
37 // Unlike iteration of most WTF Hash data structures, iteration is guaranteed
38 // safe against mutation of the ListHashSet, except for removal of the item
39 // currently pointed to by a given iterator.
40
41 template <typename Value,
42 size_t inlineCapacity,
43 typename HashFunctions,
44 typename Allocator>
45 class ListHashSet;
46
47 template <typename Set>
48 class ListHashSetIterator;
49 template <typename Set>
50 class ListHashSetConstIterator;
51 template <typename Set>
52 class ListHashSetReverseIterator;
53 template <typename Set>
54 class ListHashSetConstReverseIterator;
55
56 template <typename ValueArg>
57 class ListHashSetNodeBase;
58 template <typename ValueArg, typename Allocator>
59 class ListHashSetNode;
60 template <typename ValueArg, size_t inlineCapacity>
61 struct ListHashSetAllocator;
62
63 template <typename HashArg>
64 struct ListHashSetNodeHashFunctions;
65 template <typename HashArg>
66 struct ListHashSetTranslator;
67
68 // Note that for a ListHashSet you cannot specify the HashTraits as a template
69 // argument. It uses the default hash traits for the ValueArg type.
70 template <typename ValueArg,
71 size_t inlineCapacity = 256,
72 typename HashArg = typename DefaultHash<ValueArg>::Hash,
73 typename AllocatorArg =
74 ListHashSetAllocator<ValueArg, inlineCapacity>>
75 class ListHashSet
76 : public ConditionalDestructor<
77 ListHashSet<ValueArg, inlineCapacity, HashArg, AllocatorArg>,
78 AllocatorArg::isGarbageCollected> {
79 typedef AllocatorArg Allocator;
80 USE_ALLOCATOR(ListHashSet, Allocator);
81
82 typedef ListHashSetNode<ValueArg, Allocator> Node;
83 typedef HashTraits<Node*> NodeTraits;
84 typedef ListHashSetNodeHashFunctions<HashArg> NodeHash;
85 typedef ListHashSetTranslator<HashArg> BaseTranslator;
86
87 typedef HashTable<Node*,
88 Node*,
89 IdentityExtractor,
90 NodeHash,
91 NodeTraits,
92 NodeTraits,
93 typename Allocator::TableAllocator>
94 ImplType;
95 typedef HashTableIterator<Node*,
96 Node*,
97 IdentityExtractor,
98 NodeHash,
99 NodeTraits,
100 NodeTraits,
101 typename Allocator::TableAllocator>
102 ImplTypeIterator;
103 typedef HashTableConstIterator<Node*,
104 Node*,
105 IdentityExtractor,
106 NodeHash,
107 NodeTraits,
108 NodeTraits,
109 typename Allocator::TableAllocator>
110 ImplTypeConstIterator;
111
112 typedef HashArg HashFunctions;
113
114 public:
115 typedef ValueArg ValueType;
116 typedef HashTraits<ValueType> ValueTraits;
117 typedef typename ValueTraits::PeekInType ValuePeekInType;
118
119 typedef ListHashSetIterator<ListHashSet> iterator;
120 typedef ListHashSetConstIterator<ListHashSet> const_iterator;
121 friend class ListHashSetIterator<ListHashSet>;
122 friend class ListHashSetConstIterator<ListHashSet>;
123
124 typedef ListHashSetReverseIterator<ListHashSet> reverse_iterator;
125 typedef ListHashSetConstReverseIterator<ListHashSet> const_reverse_iterator;
126 friend class ListHashSetReverseIterator<ListHashSet>;
127 friend class ListHashSetConstReverseIterator<ListHashSet>;
128
129 struct AddResult final {
130 STACK_ALLOCATED();
131 friend class ListHashSet<ValueArg, inlineCapacity, HashArg, AllocatorArg>;
132 AddResult(Node* node, bool isNewEntry)
133 : storedValue(&node->m_value), isNewEntry(isNewEntry), m_node(node) {}
134 ValueType* storedValue;
135 bool isNewEntry;
136
137 private:
138 Node* m_node;
139 };
140
141 ListHashSet();
142 ListHashSet(const ListHashSet&);
143 ListHashSet(ListHashSet&&);
144 ListHashSet& operator=(const ListHashSet&);
145 ListHashSet& operator=(ListHashSet&&);
146 void finalize();
147
148 void swap(ListHashSet&);
149
150 unsigned size() const { return m_impl.size(); }
151 unsigned capacity() const { return m_impl.capacity(); }
152 bool isEmpty() const { return m_impl.isEmpty(); }
153
154 iterator begin() { return makeIterator(m_head); }
155 iterator end() { return makeIterator(0); }
156 const_iterator begin() const { return makeConstIterator(m_head); }
157 const_iterator end() const { return makeConstIterator(0); }
158
159 reverse_iterator rbegin() { return makeReverseIterator(m_tail); }
160 reverse_iterator rend() { return makeReverseIterator(0); }
161 const_reverse_iterator rbegin() const {
162 return makeConstReverseIterator(m_tail);
163 }
164 const_reverse_iterator rend() const { return makeConstReverseIterator(0); }
165
166 ValueType& front();
167 const ValueType& front() const;
168 void removeFirst();
169
170 ValueType& back();
171 const ValueType& back() const;
172 void pop_back();
173
174 iterator find(ValuePeekInType);
175 const_iterator find(ValuePeekInType) const;
176 bool contains(ValuePeekInType) const;
177
178 // An alternate version of find() that finds the object by hashing and
179 // comparing with some other type, to avoid the cost of type conversion.
180 // The HashTranslator interface is defined in HashSet.
181 template <typename HashTranslator, typename T>
182 iterator find(const T&);
183 template <typename HashTranslator, typename T>
184 const_iterator find(const T&) const;
185 template <typename HashTranslator, typename T>
186 bool contains(const T&) const;
187
188 // The return value of insert is a pair of a pointer to the stored value, and
189 // a bool that is true if an new entry was added.
190 template <typename IncomingValueType>
191 AddResult insert(IncomingValueType&&);
192
193 // Same as insert() except that the return value is an iterator. Useful in
194 // cases where it's needed to have the same return value as find() and where
195 // it's not possible to use a pointer to the storedValue.
196 template <typename IncomingValueType>
197 iterator addReturnIterator(IncomingValueType&&);
198
199 // Add the value to the end of the collection. If the value was already in
200 // the list, it is moved to the end.
201 template <typename IncomingValueType>
202 AddResult appendOrMoveToLast(IncomingValueType&&);
203
204 // Add the value to the beginning of the collection. If the value was
205 // already in the list, it is moved to the beginning.
206 template <typename IncomingValueType>
207 AddResult prependOrMoveToFirst(IncomingValueType&&);
208
209 template <typename IncomingValueType>
210 AddResult insertBefore(ValuePeekInType beforeValue,
211 IncomingValueType&& newValue);
212 template <typename IncomingValueType>
213 AddResult insertBefore(iterator, IncomingValueType&&);
214
215 void erase(ValuePeekInType value) { return erase(find(value)); }
216 void erase(iterator);
217 void clear();
218 template <typename Collection>
219 void removeAll(const Collection& other) {
220 WTF::removeAll(*this, other);
221 }
222
223 ValueType take(iterator);
224 ValueType take(ValuePeekInType);
225 ValueType takeFirst();
226
227 template <typename VisitorDispatcher>
228 void trace(VisitorDispatcher);
229
230 private:
231 void unlink(Node*);
232 void unlinkAndDelete(Node*);
233 void appendNode(Node*);
234 void prependNode(Node*);
235 void insertNodeBefore(Node* beforeNode, Node* newNode);
236 void deleteAllNodes();
237 Allocator* getAllocator() const { return m_allocatorProvider.get(); }
238 void createAllocatorIfNeeded() {
239 m_allocatorProvider.createAllocatorIfNeeded();
240 }
241 void deallocate(Node* node) const { m_allocatorProvider.deallocate(node); }
242
243 iterator makeIterator(Node* position) { return iterator(this, position); }
244 const_iterator makeConstIterator(Node* position) const {
245 return const_iterator(this, position);
246 }
247 reverse_iterator makeReverseIterator(Node* position) {
248 return reverse_iterator(this, position);
249 }
250 const_reverse_iterator makeConstReverseIterator(Node* position) const {
251 return const_reverse_iterator(this, position);
252 }
253
254 ImplType m_impl;
255 Node* m_head;
256 Node* m_tail;
257 typename Allocator::AllocatorProvider m_allocatorProvider;
258 };
259
260 // ListHashSetNode has this base class to hold the members because the MSVC
261 // compiler otherwise gets into circular template dependencies when trying to do
262 // sizeof on a node.
263 template <typename ValueArg>
264 class ListHashSetNodeBase {
265 DISALLOW_NEW();
266
267 protected:
268 template <typename U>
269 explicit ListHashSetNodeBase(U&& value) : m_value(std::forward<U>(value)) {}
270
271 public:
272 ValueArg m_value;
273 ListHashSetNodeBase* m_prev = nullptr;
274 ListHashSetNodeBase* m_next = nullptr;
275 #if DCHECK_IS_ON()
276 bool m_isAllocated = true;
277 #endif
278 };
279
280 // This allocator is only used for non-Heap ListHashSets.
281 template <typename ValueArg, size_t inlineCapacity>
282 struct ListHashSetAllocator : public PartitionAllocator {
283 typedef PartitionAllocator TableAllocator;
284 typedef ListHashSetNode<ValueArg, ListHashSetAllocator> Node;
285 typedef ListHashSetNodeBase<ValueArg> NodeBase;
286
287 class AllocatorProvider {
288 DISALLOW_NEW();
289
290 public:
291 AllocatorProvider() : m_allocator(nullptr) {}
292 void createAllocatorIfNeeded() {
293 if (!m_allocator)
294 m_allocator = new ListHashSetAllocator;
295 }
296
297 void releaseAllocator() {
298 delete m_allocator;
299 m_allocator = nullptr;
300 }
301
302 void swap(AllocatorProvider& other) {
303 std::swap(m_allocator, other.m_allocator);
304 }
305
306 void deallocate(Node* node) const {
307 DCHECK(m_allocator);
308 m_allocator->deallocate(node);
309 }
310
311 ListHashSetAllocator* get() const {
312 DCHECK(m_allocator);
313 return m_allocator;
314 }
315
316 private:
317 // Not using std::unique_ptr as this pointer should be deleted at
318 // releaseAllocator() method rather than at destructor.
319 ListHashSetAllocator* m_allocator;
320 };
321
322 ListHashSetAllocator()
323 : m_freeList(pool()), m_isDoneWithInitialFreeList(false) {
324 memset(m_pool.buffer, 0, sizeof(m_pool.buffer));
325 }
326
327 Node* allocateNode() {
328 Node* result = m_freeList;
329
330 if (!result)
331 return static_cast<Node*>(WTF::Partitions::fastMalloc(
332 sizeof(NodeBase), WTF_HEAP_PROFILER_TYPE_NAME(Node)));
333
334 #if DCHECK_IS_ON()
335 DCHECK(!result->m_isAllocated);
336 #endif
337
338 Node* next = result->next();
339 #if DCHECK_IS_ON()
340 DCHECK(!next || !next->m_isAllocated);
341 #endif
342 if (!next && !m_isDoneWithInitialFreeList) {
343 next = result + 1;
344 if (next == pastPool()) {
345 m_isDoneWithInitialFreeList = true;
346 next = nullptr;
347 } else {
348 DCHECK(inPool(next));
349 #if DCHECK_IS_ON()
350 DCHECK(!next->m_isAllocated);
351 #endif
352 }
353 }
354 m_freeList = next;
355
356 return result;
357 }
358
359 void deallocate(Node* node) {
360 if (inPool(node)) {
361 #if DCHECK_IS_ON()
362 node->m_isAllocated = false;
363 #endif
364 node->m_next = m_freeList;
365 m_freeList = node;
366 return;
367 }
368
369 WTF::Partitions::fastFree(node);
370 }
371
372 bool inPool(Node* node) { return node >= pool() && node < pastPool(); }
373
374 static void traceValue(typename PartitionAllocator::Visitor* visitor,
375 Node* node) {}
376
377 private:
378 Node* pool() { return reinterpret_cast_ptr<Node*>(m_pool.buffer); }
379 Node* pastPool() { return pool() + m_poolSize; }
380
381 Node* m_freeList;
382 bool m_isDoneWithInitialFreeList;
383 #if defined(MEMORY_SANITIZER_INITIAL_SIZE)
384 // The allocation pool for nodes is one big chunk that ASAN has no insight
385 // into, so it can cloak errors. Make it as small as possible to force nodes
386 // to be allocated individually where ASAN can see them.
387 static const size_t m_poolSize = 1;
388 #else
389 static const size_t m_poolSize = inlineCapacity;
390 #endif
391 AlignedBuffer<sizeof(NodeBase) * m_poolSize, WTF_ALIGN_OF(NodeBase)> m_pool;
392 };
393
394 template <typename ValueArg, typename AllocatorArg>
395 class ListHashSetNode : public ListHashSetNodeBase<ValueArg> {
396 public:
397 typedef AllocatorArg NodeAllocator;
398 typedef ValueArg Value;
399
400 template <typename U>
401 ListHashSetNode(U&& value)
402 : ListHashSetNodeBase<ValueArg>(std::forward<U>(value)) {}
403
404 void* operator new(size_t, NodeAllocator* allocator) {
405 static_assert(
406 sizeof(ListHashSetNode) == sizeof(ListHashSetNodeBase<ValueArg>),
407 "please add any fields to the base");
408 return allocator->allocateNode();
409 }
410
411 void setWasAlreadyDestructed() {
412 if (NodeAllocator::isGarbageCollected &&
413 !IsTriviallyDestructible<ValueArg>::value)
414 this->m_prev = unlinkedNodePointer();
415 }
416
417 bool wasAlreadyDestructed() const {
418 DCHECK(NodeAllocator::isGarbageCollected);
419 return this->m_prev == unlinkedNodePointer();
420 }
421
422 static void finalize(void* pointer) {
423 // No need to waste time calling finalize if it's not needed.
424 DCHECK(!IsTriviallyDestructible<ValueArg>::value);
425 ListHashSetNode* self = reinterpret_cast_ptr<ListHashSetNode*>(pointer);
426
427 // Check whether this node was already destructed before being unlinked
428 // from the collection.
429 if (self->wasAlreadyDestructed())
430 return;
431
432 self->m_value.~ValueArg();
433 }
434 void finalizeGarbageCollectedObject() { finalize(this); }
435
436 void destroy(NodeAllocator* allocator) {
437 this->~ListHashSetNode();
438 setWasAlreadyDestructed();
439 allocator->deallocate(this);
440 }
441
442 // This is not called in normal tracing, but it is called if we find a
443 // pointer to a node on the stack using conservative scanning. Since the
444 // original ListHashSet may no longer exist we make sure to mark the
445 // neighbours in the chain too.
446 template <typename VisitorDispatcher>
447 void trace(VisitorDispatcher visitor) {
448 // The conservative stack scan can find nodes that have been removed
449 // from the set and destructed. We don't need to trace these, and it
450 // would be wrong to do so, because the class will not expect the trace
451 // method to be called after the destructor. It's an error to remove a
452 // node from the ListHashSet while an iterator is positioned at that
453 // node, so there should be no valid pointers from the stack to a
454 // destructed node.
455 if (wasAlreadyDestructed())
456 return;
457 NodeAllocator::traceValue(visitor, this);
458 visitor->mark(next());
459 visitor->mark(prev());
460 }
461
462 ListHashSetNode* next() const {
463 return reinterpret_cast<ListHashSetNode*>(this->m_next);
464 }
465 ListHashSetNode* prev() const {
466 return reinterpret_cast<ListHashSetNode*>(this->m_prev);
467 }
468
469 // Don't add fields here, the ListHashSetNodeBase and this should have the
470 // same size.
471
472 static ListHashSetNode* unlinkedNodePointer() {
473 return reinterpret_cast<ListHashSetNode*>(-1);
474 }
475
476 template <typename HashArg>
477 friend struct ListHashSetNodeHashFunctions;
478 };
479
480 template <typename HashArg>
481 struct ListHashSetNodeHashFunctions {
482 STATIC_ONLY(ListHashSetNodeHashFunctions);
483 template <typename T>
484 static unsigned hash(const T& key) {
485 return HashArg::hash(key->m_value);
486 }
487 template <typename T>
488 static bool equal(const T& a, const T& b) {
489 return HashArg::equal(a->m_value, b->m_value);
490 }
491 static const bool safeToCompareToEmptyOrDeleted = false;
492 };
493
494 template <typename Set>
495 class ListHashSetIterator {
496 DISALLOW_NEW();
497
498 private:
499 typedef typename Set::const_iterator const_iterator;
500 typedef typename Set::Node Node;
501 typedef typename Set::ValueType ValueType;
502 typedef ValueType& ReferenceType;
503 typedef ValueType* PointerType;
504
505 ListHashSetIterator(const Set* set, Node* position)
506 : m_iterator(set, position) {}
507
508 public:
509 ListHashSetIterator() {}
510
511 // default copy, assignment and destructor are OK
512
513 PointerType get() const { return const_cast<PointerType>(m_iterator.get()); }
514 ReferenceType operator*() const { return *get(); }
515 PointerType operator->() const { return get(); }
516
517 ListHashSetIterator& operator++() {
518 ++m_iterator;
519 return *this;
520 }
521 ListHashSetIterator& operator--() {
522 --m_iterator;
523 return *this;
524 }
525
526 // Postfix ++ and -- intentionally omitted.
527
528 // Comparison.
529 bool operator==(const ListHashSetIterator& other) const {
530 return m_iterator == other.m_iterator;
531 }
532 bool operator!=(const ListHashSetIterator& other) const {
533 return m_iterator != other.m_iterator;
534 }
535
536 operator const_iterator() const { return m_iterator; }
537
538 template <typename VisitorDispatcher>
539 void trace(VisitorDispatcher visitor) {
540 m_iterator.trace(visitor);
541 }
542
543 private:
544 Node* getNode() { return m_iterator.getNode(); }
545
546 const_iterator m_iterator;
547
548 template <typename T, size_t inlineCapacity, typename U, typename V>
549 friend class ListHashSet;
550 };
551
552 template <typename Set>
553 class ListHashSetConstIterator {
554 DISALLOW_NEW();
555
556 private:
557 typedef typename Set::const_iterator const_iterator;
558 typedef typename Set::Node Node;
559 typedef typename Set::ValueType ValueType;
560 typedef const ValueType& ReferenceType;
561 typedef const ValueType* PointerType;
562
563 friend class ListHashSetIterator<Set>;
564
565 ListHashSetConstIterator(const Set* set, Node* position)
566 : m_set(set), m_position(position) {}
567
568 public:
569 ListHashSetConstIterator() {}
570
571 PointerType get() const { return &m_position->m_value; }
572 ReferenceType operator*() const { return *get(); }
573 PointerType operator->() const { return get(); }
574
575 ListHashSetConstIterator& operator++() {
576 DCHECK(m_position);
577 m_position = m_position->next();
578 return *this;
579 }
580
581 ListHashSetConstIterator& operator--() {
582 DCHECK_NE(m_position, m_set->m_head);
583 if (!m_position)
584 m_position = m_set->m_tail;
585 else
586 m_position = m_position->prev();
587 return *this;
588 }
589
590 // Postfix ++ and -- intentionally omitted.
591
592 // Comparison.
593 bool operator==(const ListHashSetConstIterator& other) const {
594 return m_position == other.m_position;
595 }
596 bool operator!=(const ListHashSetConstIterator& other) const {
597 return m_position != other.m_position;
598 }
599
600 template <typename VisitorDispatcher>
601 void trace(VisitorDispatcher visitor) {
602 visitor->trace(*m_set);
603 visitor->trace(m_position);
604 }
605
606 private:
607 Node* getNode() { return m_position; }
608
609 const Set* m_set;
610 Node* m_position;
611
612 template <typename T, size_t inlineCapacity, typename U, typename V>
613 friend class ListHashSet;
614 };
615
616 template <typename Set>
617 class ListHashSetReverseIterator {
618 DISALLOW_NEW();
619
620 private:
621 typedef typename Set::const_reverse_iterator const_reverse_iterator;
622 typedef typename Set::Node Node;
623 typedef typename Set::ValueType ValueType;
624 typedef ValueType& ReferenceType;
625 typedef ValueType* PointerType;
626
627 ListHashSetReverseIterator(const Set* set, Node* position)
628 : m_iterator(set, position) {}
629
630 public:
631 ListHashSetReverseIterator() {}
632
633 // default copy, assignment and destructor are OK
634
635 PointerType get() const { return const_cast<PointerType>(m_iterator.get()); }
636 ReferenceType operator*() const { return *get(); }
637 PointerType operator->() const { return get(); }
638
639 ListHashSetReverseIterator& operator++() {
640 ++m_iterator;
641 return *this;
642 }
643 ListHashSetReverseIterator& operator--() {
644 --m_iterator;
645 return *this;
646 }
647
648 // Postfix ++ and -- intentionally omitted.
649
650 // Comparison.
651 bool operator==(const ListHashSetReverseIterator& other) const {
652 return m_iterator == other.m_iterator;
653 }
654 bool operator!=(const ListHashSetReverseIterator& other) const {
655 return m_iterator != other.m_iterator;
656 }
657
658 operator const_reverse_iterator() const { return m_iterator; }
659
660 template <typename VisitorDispatcher>
661 void trace(VisitorDispatcher visitor) {
662 m_iterator.trace(visitor);
663 }
664
665 private:
666 Node* getNode() { return m_iterator.node(); }
667
668 const_reverse_iterator m_iterator;
669
670 template <typename T, size_t inlineCapacity, typename U, typename V>
671 friend class ListHashSet;
672 };
673
674 template <typename Set>
675 class ListHashSetConstReverseIterator {
676 DISALLOW_NEW();
677
678 private:
679 typedef typename Set::reverse_iterator reverse_iterator;
680 typedef typename Set::Node Node;
681 typedef typename Set::ValueType ValueType;
682 typedef const ValueType& ReferenceType;
683 typedef const ValueType* PointerType;
684
685 friend class ListHashSetReverseIterator<Set>;
686
687 ListHashSetConstReverseIterator(const Set* set, Node* position)
688 : m_set(set), m_position(position) {}
689
690 public:
691 ListHashSetConstReverseIterator() {}
692
693 PointerType get() const { return &m_position->m_value; }
694 ReferenceType operator*() const { return *get(); }
695 PointerType operator->() const { return get(); }
696
697 ListHashSetConstReverseIterator& operator++() {
698 DCHECK(m_position);
699 m_position = m_position->prev();
700 return *this;
701 }
702
703 ListHashSetConstReverseIterator& operator--() {
704 DCHECK_NE(m_position, m_set->m_tail);
705 if (!m_position)
706 m_position = m_set->m_head;
707 else
708 m_position = m_position->next();
709 return *this;
710 }
711
712 // Postfix ++ and -- intentionally omitted.
713
714 // Comparison.
715 bool operator==(const ListHashSetConstReverseIterator& other) const {
716 return m_position == other.m_position;
717 }
718 bool operator!=(const ListHashSetConstReverseIterator& other) const {
719 return m_position != other.m_position;
720 }
721
722 template <typename VisitorDispatcher>
723 void trace(VisitorDispatcher visitor) {
724 visitor->trace(*m_set);
725 visitor->trace(m_position);
726 }
727
728 private:
729 Node* getNode() { return m_position; }
730
731 const Set* m_set;
732 Node* m_position;
733
734 template <typename T, size_t inlineCapacity, typename U, typename V>
735 friend class ListHashSet;
736 };
737
738 template <typename HashFunctions>
739 struct ListHashSetTranslator {
740 STATIC_ONLY(ListHashSetTranslator);
741 template <typename T>
742 static unsigned hash(const T& key) {
743 return HashFunctions::hash(key);
744 }
745 template <typename T, typename U>
746 static bool equal(const T& a, const U& b) {
747 return HashFunctions::equal(a->m_value, b);
748 }
749 template <typename T, typename U, typename V>
750 static void translate(T*& location, U&& key, const V& allocator) {
751 location = new (const_cast<V*>(&allocator)) T(std::forward<U>(key));
752 }
753 };
754
755 template <typename T, size_t inlineCapacity, typename U, typename Allocator>
756 inline ListHashSet<T, inlineCapacity, U, Allocator>::ListHashSet()
757 : m_head(nullptr), m_tail(nullptr) {
758 static_assert(
759 Allocator::isGarbageCollected ||
760 !IsPointerToGarbageCollectedType<T>::value,
761 "Cannot put raw pointers to garbage-collected classes into "
762 "an off-heap ListHashSet. Use HeapListHashSet<Member<T>> instead.");
763 }
764
765 template <typename T, size_t inlineCapacity, typename U, typename V>
766 inline ListHashSet<T, inlineCapacity, U, V>::ListHashSet(
767 const ListHashSet& other)
768 : m_head(nullptr), m_tail(nullptr) {
769 const_iterator end = other.end();
770 for (const_iterator it = other.begin(); it != end; ++it)
771 insert(*it);
772 }
773
774 template <typename T, size_t inlineCapacity, typename U, typename V>
775 inline ListHashSet<T, inlineCapacity, U, V>::ListHashSet(ListHashSet&& other)
776 : m_head(nullptr), m_tail(nullptr) {
777 swap(other);
778 }
779
780 template <typename T, size_t inlineCapacity, typename U, typename V>
781 inline ListHashSet<T, inlineCapacity, U, V>&
782 ListHashSet<T, inlineCapacity, U, V>::operator=(const ListHashSet& other) {
783 ListHashSet tmp(other);
784 swap(tmp);
785 return *this;
786 }
787
788 template <typename T, size_t inlineCapacity, typename U, typename V>
789 inline ListHashSet<T, inlineCapacity, U, V>&
790 ListHashSet<T, inlineCapacity, U, V>::operator=(ListHashSet&& other) {
791 swap(other);
792 return *this;
793 }
794
795 template <typename T, size_t inlineCapacity, typename U, typename V>
796 inline void ListHashSet<T, inlineCapacity, U, V>::swap(ListHashSet& other) {
797 m_impl.swap(other.m_impl);
798 std::swap(m_head, other.m_head);
799 std::swap(m_tail, other.m_tail);
800 m_allocatorProvider.swap(other.m_allocatorProvider);
801 }
802
803 template <typename T, size_t inlineCapacity, typename U, typename V>
804 inline void ListHashSet<T, inlineCapacity, U, V>::finalize() {
805 static_assert(!Allocator::isGarbageCollected,
806 "heap allocated ListHashSet should never call finalize()");
807 deleteAllNodes();
808 m_allocatorProvider.releaseAllocator();
809 }
810
811 template <typename T, size_t inlineCapacity, typename U, typename V>
812 inline T& ListHashSet<T, inlineCapacity, U, V>::front() {
813 DCHECK(!isEmpty());
814 return m_head->m_value;
815 }
816
817 template <typename T, size_t inlineCapacity, typename U, typename V>
818 inline void ListHashSet<T, inlineCapacity, U, V>::removeFirst() {
819 DCHECK(!isEmpty());
820 m_impl.remove(m_head);
821 unlinkAndDelete(m_head);
822 }
823
824 template <typename T, size_t inlineCapacity, typename U, typename V>
825 inline const T& ListHashSet<T, inlineCapacity, U, V>::front() const {
826 DCHECK(!isEmpty());
827 return m_head->m_value;
828 }
829
830 template <typename T, size_t inlineCapacity, typename U, typename V>
831 inline T& ListHashSet<T, inlineCapacity, U, V>::back() {
832 DCHECK(!isEmpty());
833 return m_tail->m_value;
834 }
835
836 template <typename T, size_t inlineCapacity, typename U, typename V>
837 inline const T& ListHashSet<T, inlineCapacity, U, V>::back() const {
838 DCHECK(!isEmpty());
839 return m_tail->m_value;
840 }
841
842 template <typename T, size_t inlineCapacity, typename U, typename V>
843 inline void ListHashSet<T, inlineCapacity, U, V>::pop_back() {
844 DCHECK(!isEmpty());
845 m_impl.remove(m_tail);
846 unlinkAndDelete(m_tail);
847 }
848
849 template <typename T, size_t inlineCapacity, typename U, typename V>
850 inline typename ListHashSet<T, inlineCapacity, U, V>::iterator
851 ListHashSet<T, inlineCapacity, U, V>::find(ValuePeekInType value) {
852 ImplTypeIterator it = m_impl.template find<BaseTranslator>(value);
853 if (it == m_impl.end())
854 return end();
855 return makeIterator(*it);
856 }
857
858 template <typename T, size_t inlineCapacity, typename U, typename V>
859 inline typename ListHashSet<T, inlineCapacity, U, V>::const_iterator
860 ListHashSet<T, inlineCapacity, U, V>::find(ValuePeekInType value) const {
861 ImplTypeConstIterator it = m_impl.template find<BaseTranslator>(value);
862 if (it == m_impl.end())
863 return end();
864 return makeConstIterator(*it);
865 }
866
867 template <typename Translator>
868 struct ListHashSetTranslatorAdapter {
869 STATIC_ONLY(ListHashSetTranslatorAdapter);
870 template <typename T>
871 static unsigned hash(const T& key) {
872 return Translator::hash(key);
873 }
874 template <typename T, typename U>
875 static bool equal(const T& a, const U& b) {
876 return Translator::equal(a->m_value, b);
877 }
878 };
879
880 template <typename ValueType, size_t inlineCapacity, typename U, typename V>
881 template <typename HashTranslator, typename T>
882 inline typename ListHashSet<ValueType, inlineCapacity, U, V>::iterator
883 ListHashSet<ValueType, inlineCapacity, U, V>::find(const T& value) {
884 ImplTypeConstIterator it =
885 m_impl.template find<ListHashSetTranslatorAdapter<HashTranslator>>(value);
886 if (it == m_impl.end())
887 return end();
888 return makeIterator(*it);
889 }
890
891 template <typename ValueType, size_t inlineCapacity, typename U, typename V>
892 template <typename HashTranslator, typename T>
893 inline typename ListHashSet<ValueType, inlineCapacity, U, V>::const_iterator
894 ListHashSet<ValueType, inlineCapacity, U, V>::find(const T& value) const {
895 ImplTypeConstIterator it =
896 m_impl.template find<ListHashSetTranslatorAdapter<HashTranslator>>(value);
897 if (it == m_impl.end())
898 return end();
899 return makeConstIterator(*it);
900 }
901
902 template <typename ValueType, size_t inlineCapacity, typename U, typename V>
903 template <typename HashTranslator, typename T>
904 inline bool ListHashSet<ValueType, inlineCapacity, U, V>::contains(
905 const T& value) const {
906 return m_impl.template contains<ListHashSetTranslatorAdapter<HashTranslator>>(
907 value);
908 }
909
910 template <typename T, size_t inlineCapacity, typename U, typename V>
911 inline bool ListHashSet<T, inlineCapacity, U, V>::contains(
912 ValuePeekInType value) const {
913 return m_impl.template contains<BaseTranslator>(value);
914 }
915
916 template <typename T, size_t inlineCapacity, typename U, typename V>
917 template <typename IncomingValueType>
918 typename ListHashSet<T, inlineCapacity, U, V>::AddResult
919 ListHashSet<T, inlineCapacity, U, V>::insert(IncomingValueType&& value) {
920 createAllocatorIfNeeded();
921 // The second argument is a const ref. This is useful for the HashTable
922 // because it lets it take lvalues by reference, but for our purposes it's
923 // inconvenient, since it constrains us to be const, whereas the allocator
924 // actually changes when it does allocations.
925 auto result = m_impl.template add<BaseTranslator>(
926 std::forward<IncomingValueType>(value), *this->getAllocator());
927 if (result.isNewEntry)
928 appendNode(*result.storedValue);
929 return AddResult(*result.storedValue, result.isNewEntry);
930 }
931
932 template <typename T, size_t inlineCapacity, typename U, typename V>
933 template <typename IncomingValueType>
934 typename ListHashSet<T, inlineCapacity, U, V>::iterator
935 ListHashSet<T, inlineCapacity, U, V>::addReturnIterator(
936 IncomingValueType&& value) {
937 return makeIterator(insert(std::forward<IncomingValueType>(value)).m_node);
938 }
939
940 template <typename T, size_t inlineCapacity, typename U, typename V>
941 template <typename IncomingValueType>
942 typename ListHashSet<T, inlineCapacity, U, V>::AddResult
943 ListHashSet<T, inlineCapacity, U, V>::appendOrMoveToLast(
944 IncomingValueType&& value) {
945 createAllocatorIfNeeded();
946 auto result = m_impl.template add<BaseTranslator>(
947 std::forward<IncomingValueType>(value), *this->getAllocator());
948 Node* node = *result.storedValue;
949 if (!result.isNewEntry)
950 unlink(node);
951 appendNode(node);
952 return AddResult(*result.storedValue, result.isNewEntry);
953 }
954
955 template <typename T, size_t inlineCapacity, typename U, typename V>
956 template <typename IncomingValueType>
957 typename ListHashSet<T, inlineCapacity, U, V>::AddResult
958 ListHashSet<T, inlineCapacity, U, V>::prependOrMoveToFirst(
959 IncomingValueType&& value) {
960 createAllocatorIfNeeded();
961 auto result = m_impl.template add<BaseTranslator>(
962 std::forward<IncomingValueType>(value), *this->getAllocator());
963 Node* node = *result.storedValue;
964 if (!result.isNewEntry)
965 unlink(node);
966 prependNode(node);
967 return AddResult(*result.storedValue, result.isNewEntry);
968 }
969
970 template <typename T, size_t inlineCapacity, typename U, typename V>
971 template <typename IncomingValueType>
972 typename ListHashSet<T, inlineCapacity, U, V>::AddResult
973 ListHashSet<T, inlineCapacity, U, V>::insertBefore(
974 iterator it,
975 IncomingValueType&& newValue) {
976 createAllocatorIfNeeded();
977 auto result = m_impl.template add<BaseTranslator>(
978 std::forward<IncomingValueType>(newValue), *this->getAllocator());
979 if (result.isNewEntry)
980 insertNodeBefore(it.getNode(), *result.storedValue);
981 return AddResult(*result.storedValue, result.isNewEntry);
982 }
983
984 template <typename T, size_t inlineCapacity, typename U, typename V>
985 template <typename IncomingValueType>
986 typename ListHashSet<T, inlineCapacity, U, V>::AddResult
987 ListHashSet<T, inlineCapacity, U, V>::insertBefore(
988 ValuePeekInType beforeValue,
989 IncomingValueType&& newValue) {
990 createAllocatorIfNeeded();
991 return insertBefore(find(beforeValue),
992 std::forward<IncomingValueType>(newValue));
993 }
994
995 template <typename T, size_t inlineCapacity, typename U, typename V>
996 inline void ListHashSet<T, inlineCapacity, U, V>::erase(iterator it) {
997 if (it == end())
998 return;
999 m_impl.remove(it.getNode());
1000 unlinkAndDelete(it.getNode());
1001 }
1002
1003 template <typename T, size_t inlineCapacity, typename U, typename V>
1004 inline void ListHashSet<T, inlineCapacity, U, V>::clear() {
1005 deleteAllNodes();
1006 m_impl.clear();
1007 m_head = nullptr;
1008 m_tail = nullptr;
1009 }
1010
1011 template <typename T, size_t inlineCapacity, typename U, typename V>
1012 auto ListHashSet<T, inlineCapacity, U, V>::take(iterator it) -> ValueType {
1013 if (it == end())
1014 return ValueTraits::emptyValue();
1015
1016 m_impl.remove(it.getNode());
1017 ValueType result = std::move(it.getNode()->m_value);
1018 unlinkAndDelete(it.getNode());
1019
1020 return result;
1021 }
1022
1023 template <typename T, size_t inlineCapacity, typename U, typename V>
1024 auto ListHashSet<T, inlineCapacity, U, V>::take(ValuePeekInType value)
1025 -> ValueType {
1026 return take(find(value));
1027 }
1028
1029 template <typename T, size_t inlineCapacity, typename U, typename V>
1030 auto ListHashSet<T, inlineCapacity, U, V>::takeFirst() -> ValueType {
1031 DCHECK(!isEmpty());
1032 m_impl.remove(m_head);
1033 ValueType result = std::move(m_head->m_value);
1034 unlinkAndDelete(m_head);
1035
1036 return result;
1037 }
1038
1039 template <typename T, size_t inlineCapacity, typename U, typename Allocator>
1040 void ListHashSet<T, inlineCapacity, U, Allocator>::unlink(Node* node) {
1041 if (!node->m_prev) {
1042 DCHECK_EQ(node, m_head);
1043 m_head = node->next();
1044 } else {
1045 DCHECK_NE(node, m_head);
1046 node->m_prev->m_next = node->m_next;
1047 }
1048
1049 if (!node->m_next) {
1050 DCHECK_EQ(node, m_tail);
1051 m_tail = node->prev();
1052 } else {
1053 DCHECK_NE(node, m_tail);
1054 node->m_next->m_prev = node->m_prev;
1055 }
1056 }
1057
1058 template <typename T, size_t inlineCapacity, typename U, typename V>
1059 void ListHashSet<T, inlineCapacity, U, V>::unlinkAndDelete(Node* node) {
1060 unlink(node);
1061 node->destroy(this->getAllocator());
1062 }
1063
1064 template <typename T, size_t inlineCapacity, typename U, typename V>
1065 void ListHashSet<T, inlineCapacity, U, V>::appendNode(Node* node) {
1066 node->m_prev = m_tail;
1067 node->m_next = nullptr;
1068
1069 if (m_tail) {
1070 DCHECK(m_head);
1071 m_tail->m_next = node;
1072 } else {
1073 DCHECK(!m_head);
1074 m_head = node;
1075 }
1076
1077 m_tail = node;
1078 }
1079
1080 template <typename T, size_t inlineCapacity, typename U, typename V>
1081 void ListHashSet<T, inlineCapacity, U, V>::prependNode(Node* node) {
1082 node->m_prev = nullptr;
1083 node->m_next = m_head;
1084
1085 if (m_head)
1086 m_head->m_prev = node;
1087 else
1088 m_tail = node;
1089
1090 m_head = node;
1091 }
1092
1093 template <typename T, size_t inlineCapacity, typename U, typename V>
1094 void ListHashSet<T, inlineCapacity, U, V>::insertNodeBefore(Node* beforeNode,
1095 Node* newNode) {
1096 if (!beforeNode)
1097 return appendNode(newNode);
1098
1099 newNode->m_next = beforeNode;
1100 newNode->m_prev = beforeNode->m_prev;
1101 if (beforeNode->m_prev)
1102 beforeNode->m_prev->m_next = newNode;
1103 beforeNode->m_prev = newNode;
1104
1105 if (!newNode->m_prev)
1106 m_head = newNode;
1107 }
1108
1109 template <typename T, size_t inlineCapacity, typename U, typename V>
1110 void ListHashSet<T, inlineCapacity, U, V>::deleteAllNodes() {
1111 if (!m_head)
1112 return;
1113
1114 for (Node *node = m_head, *next = m_head->next(); node;
1115 node = next, next = node ? node->next() : 0)
1116 node->destroy(this->getAllocator());
1117 }
1118
1119 template <typename T, size_t inlineCapacity, typename U, typename V>
1120 template <typename VisitorDispatcher>
1121 void ListHashSet<T, inlineCapacity, U, V>::trace(VisitorDispatcher visitor) {
1122 static_assert(HashTraits<T>::weakHandlingFlag == NoWeakHandlingInCollections,
1123 "HeapListHashSet does not support weakness, consider using "
1124 "HeapLinkedHashSet instead.");
1125 // This marks all the nodes and their contents live that can be accessed
1126 // through the HashTable. That includes m_head and m_tail so we do not have
1127 // to explicitly trace them here.
1128 m_impl.trace(visitor);
1129 }
1130
1131 } // namespace WTF
1132
1133 using WTF::ListHashSet;
1134
1135 #endif // WTF_ListHashSet_h
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/wtf/LinkedHashSet.h ('k') | third_party/WebKit/Source/wtf/PrintStream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698