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