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