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) 2008 David Levin <levin@chromium.org> | 3 * Copyright (C) 2008 David Levin <levin@chromium.org> |
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 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 class HashTable; | 96 class HashTable; |
97 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 97 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
98 class HashTableIterator; | 98 class HashTableIterator; |
99 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 99 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
100 class HashTableConstIterator; | 100 class HashTableConstIterator; |
101 template <typename Value, typename HashFunctions, typename HashTraits, typename
Allocator> | 101 template <typename Value, typename HashFunctions, typename HashTraits, typename
Allocator> |
102 class LinkedHashSet; | 102 class LinkedHashSet; |
103 template <WeakHandlingFlag x, typename T, typename U, typename V, typename W, ty
pename X, typename Y, typename Z> | 103 template <WeakHandlingFlag x, typename T, typename U, typename V, typename W, ty
pename X, typename Y, typename Z> |
104 struct WeakProcessingHashTableHelper; | 104 struct WeakProcessingHashTableHelper; |
105 | 105 |
| 106 #if ENABLE(ASSERT) |
| 107 // HashTable and collections that build on it do not support modifications |
| 108 // while there is an iterator or HashTableAddResult on the stack. |
| 109 // The exception is ListHashSet, which has its own iterators that tolerate modif
ication |
| 110 // of the underlying set. |
| 111 // |
| 112 // Constraint enforced by this scope object. |
| 113 template <typename HashTableType> |
| 114 class HashTableModificationForbiddenScope { |
| 115 public: |
| 116 HashTableModificationForbiddenScope(); |
| 117 explicit HashTableModificationForbiddenScope(const HashTableType*); |
| 118 HashTableModificationForbiddenScope(const HashTableModificationForbiddenScop
e&); |
| 119 |
| 120 ~HashTableModificationForbiddenScope(); |
| 121 |
| 122 void leaveScope(); |
| 123 |
| 124 private: |
| 125 HashTableType* m_container; |
| 126 }; |
| 127 #endif |
| 128 |
106 typedef enum { HashItemKnownGood } HashItemKnownGoodTag; | 129 typedef enum { HashItemKnownGood } HashItemKnownGoodTag; |
107 | 130 |
108 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 131 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
109 class HashTableConstIterator final { | 132 class HashTableConstIterator final { |
110 DISALLOW_NEW(); | 133 DISALLOW_NEW(); |
111 private: | 134 private: |
112 typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, A
llocator> HashTableType; | 135 typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, A
llocator> HashTableType; |
113 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyT
raits, Allocator> iterator; | 136 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyT
raits, Allocator> iterator; |
114 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits,
KeyTraits, Allocator> const_iterator; | 137 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits,
KeyTraits, Allocator> const_iterator; |
115 typedef Value ValueType; | 138 typedef Value ValueType; |
116 typedef typename Traits::IteratorConstGetType GetType; | 139 typedef typename Traits::IteratorConstGetType GetType; |
117 typedef const ValueType* PointerType; | 140 typedef const ValueType* PointerType; |
118 | 141 |
119 friend class HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrai
ts, Allocator>; | 142 friend class HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrai
ts, Allocator>; |
120 friend class HashTableIterator<Key, Value, Extractor, HashFunctions, Traits,
KeyTraits, Allocator>; | 143 friend class HashTableIterator<Key, Value, Extractor, HashFunctions, Traits,
KeyTraits, Allocator>; |
121 | 144 |
122 void skipEmptyBuckets() | 145 void skipEmptyBuckets() |
123 { | 146 { |
124 while (m_position != m_endPosition && HashTableType::isEmptyOrDeletedBuc
ket(*m_position)) | 147 while (m_position != m_endPosition && HashTableType::isEmptyOrDeletedBuc
ket(*m_position)) |
125 ++m_position; | 148 ++m_position; |
126 } | 149 } |
127 | 150 |
128 HashTableConstIterator(PointerType position, PointerType endPosition, const
HashTableType* container) | 151 HashTableConstIterator(PointerType position, PointerType endPosition, const
HashTableType* container) |
129 : m_position(position) | 152 : m_position(position) |
130 , m_endPosition(endPosition) | 153 , m_endPosition(endPosition) |
131 #if ENABLE(ASSERT) | 154 #if ENABLE(ASSERT) |
132 , m_container(container) | 155 , m_modificationForbiddenScope(position != endPosition ? container : nul
lptr) |
133 , m_containerModifications(container->modifications()) | |
134 #endif | 156 #endif |
135 { | 157 { |
136 skipEmptyBuckets(); | 158 skipEmptyBuckets(); |
137 } | 159 } |
138 | 160 |
139 HashTableConstIterator(PointerType position, PointerType endPosition, const
HashTableType* container, HashItemKnownGoodTag) | 161 HashTableConstIterator(PointerType position, PointerType endPosition, const
HashTableType* container, HashItemKnownGoodTag) |
140 : m_position(position) | 162 : m_position(position) |
141 , m_endPosition(endPosition) | 163 , m_endPosition(endPosition) |
142 #if ENABLE(ASSERT) | 164 #if ENABLE(ASSERT) |
143 , m_container(container) | 165 , m_modificationForbiddenScope(position != endPosition ? container : nul
lptr) |
144 , m_containerModifications(container->modifications()) | |
145 #endif | 166 #endif |
146 { | 167 { |
147 ASSERT(m_containerModifications == m_container->modifications()); | |
148 } | |
149 | |
150 void checkModifications() const | |
151 { | |
152 // HashTable and collections that build on it do not support | |
153 // modifications while there is an iterator in use. The exception is | |
154 // ListHashSet, which has its own iterators that tolerate modification | |
155 // of the underlying set. | |
156 ASSERT(m_containerModifications == m_container->modifications()); | |
157 ASSERT(!m_container->accessForbidden()); | |
158 } | 168 } |
159 | 169 |
160 public: | 170 public: |
161 HashTableConstIterator() {} | 171 HashTableConstIterator() {} |
162 | 172 |
163 GetType get() const | 173 GetType get() const |
164 { | 174 { |
165 checkModifications(); | |
166 return m_position; | 175 return m_position; |
167 } | 176 } |
168 typename Traits::IteratorConstReferenceType operator*() const { return Trait
s::getToReferenceConstConversion(get()); } | 177 typename Traits::IteratorConstReferenceType operator*() const { return Trait
s::getToReferenceConstConversion(get()); } |
169 GetType operator->() const { return get(); } | 178 GetType operator->() const { return get(); } |
170 | 179 |
171 const_iterator& operator++() | 180 const_iterator& operator++() |
172 { | 181 { |
173 ASSERT(m_position != m_endPosition); | 182 ASSERT(m_position != m_endPosition); |
174 checkModifications(); | |
175 ++m_position; | 183 ++m_position; |
176 skipEmptyBuckets(); | 184 skipEmptyBuckets(); |
| 185 #if ENABLE(ASSERT) |
| 186 // If now at the end, leave the forbidden scope. Waiting until |
| 187 // the iterator goes out of (stack) scope disallows perfectly valid |
| 188 // code idioms. |
| 189 if (m_position == m_endPosition) |
| 190 m_modificationForbiddenScope.leaveScope(); |
| 191 #endif |
177 return *this; | 192 return *this; |
178 } | 193 } |
179 | 194 |
180 // postfix ++ intentionally omitted | 195 // postfix ++ intentionally omitted |
181 | 196 |
182 // Comparison. | 197 // Comparison. |
183 bool operator==(const const_iterator& other) const | 198 bool operator==(const const_iterator& other) const |
184 { | 199 { |
185 return m_position == other.m_position; | 200 return m_position == other.m_position; |
186 } | 201 } |
187 bool operator!=(const const_iterator& other) const | 202 bool operator!=(const const_iterator& other) const |
188 { | 203 { |
189 return m_position != other.m_position; | 204 return m_position != other.m_position; |
190 } | 205 } |
191 bool operator==(const iterator& other) const | 206 bool operator==(const iterator& other) const |
192 { | 207 { |
193 return *this == static_cast<const_iterator>(other); | 208 return *this == static_cast<const_iterator>(other); |
194 } | 209 } |
195 bool operator!=(const iterator& other) const | 210 bool operator!=(const iterator& other) const |
196 { | 211 { |
197 return *this != static_cast<const_iterator>(other); | 212 return *this != static_cast<const_iterator>(other); |
198 } | 213 } |
199 | 214 |
200 private: | 215 private: |
201 PointerType m_position; | 216 PointerType m_position; |
202 PointerType m_endPosition; | 217 PointerType m_endPosition; |
203 #if ENABLE(ASSERT) | 218 #if ENABLE(ASSERT) |
204 const HashTableType* m_container; | 219 HashTableModificationForbiddenScope<HashTableType> m_modificationForbiddenSc
ope; |
205 int64_t m_containerModifications; | |
206 #endif | 220 #endif |
207 }; | 221 }; |
208 | 222 |
209 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 223 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
210 class HashTableIterator final { | 224 class HashTableIterator final { |
211 DISALLOW_NEW(); | 225 DISALLOW_NEW(); |
212 private: | 226 private: |
213 typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, A
llocator> HashTableType; | 227 typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, A
llocator> HashTableType; |
214 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyT
raits, Allocator> iterator; | 228 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyT
raits, Allocator> iterator; |
215 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits,
KeyTraits, Allocator> const_iterator; | 229 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits,
KeyTraits, Allocator> const_iterator; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 }; | 284 }; |
271 | 285 |
272 template <typename HashFunctions> class IdentityHashTranslator { | 286 template <typename HashFunctions> class IdentityHashTranslator { |
273 STATIC_ONLY(IdentityHashTranslator); | 287 STATIC_ONLY(IdentityHashTranslator); |
274 public: | 288 public: |
275 template <typename T> static unsigned hash(const T& key) { return HashFuncti
ons::hash(key); } | 289 template <typename T> static unsigned hash(const T& key) { return HashFuncti
ons::hash(key); } |
276 template <typename T, typename U> static bool equal(const T& a, const U& b)
{ return HashFunctions::equal(a, b); } | 290 template <typename T, typename U> static bool equal(const T& a, const U& b)
{ return HashFunctions::equal(a, b); } |
277 template <typename T, typename U, typename V> static void translate(T& locat
ion, U&&, V&& value) { location = std::forward<V>(value); } | 291 template <typename T, typename U, typename V> static void translate(T& locat
ion, U&&, V&& value) { location = std::forward<V>(value); } |
278 }; | 292 }; |
279 | 293 |
280 template <typename HashTableType, typename ValueType> struct HashTableAddResult
final { | 294 template <typename HashTableType, typename ValueType> |
| 295 struct HashTableAddResult final { |
281 STACK_ALLOCATED(); | 296 STACK_ALLOCATED(); |
282 HashTableAddResult(const HashTableType* container, ValueType* storedValue, b
ool isNewEntry) | 297 HashTableAddResult(const HashTableType* container, ValueType* storedValue, b
ool isNewEntry) |
283 : storedValue(storedValue) | 298 : storedValue(storedValue) |
284 , isNewEntry(isNewEntry) | 299 , isNewEntry(isNewEntry) |
285 #if ENABLE(SECURITY_ASSERT) | 300 #if ENABLE(SECURITY_ASSERT) |
286 , m_container(container) | 301 , m_modificationForbiddenScope(container) |
287 , m_containerModifications(container->modifications()) | |
288 #endif | 302 #endif |
289 { | 303 { |
290 ALLOW_UNUSED_LOCAL(container); | 304 ALLOW_UNUSED_LOCAL(container); |
291 DCHECK(container); | 305 DCHECK(container); |
292 } | 306 } |
293 | 307 |
294 ValueType* storedValue; | 308 ValueType* storedValue; |
295 bool isNewEntry; | 309 bool isNewEntry; |
296 | 310 |
297 #if ENABLE(SECURITY_ASSERT) | 311 #if ENABLE(SECURITY_ASSERT) |
298 ~HashTableAddResult() | 312 ~HashTableAddResult() |
299 { | 313 { |
300 // If rehash happened before accessing storedValue, it's | 314 // If rehash happened before accessing storedValue, it's |
301 // use-after-free. Any modification may cause a rehash, so we check for | 315 // use-after-free. Any modification may cause a rehash, so we enter |
302 // modifications here. | 316 // a modification forbidden scope for the lifetime of this value. |
303 | |
304 // Rehash after accessing storedValue is harmless but will assert if the | |
305 // AddResult destructor takes place after a modification. You may need | |
306 // to limit the scope of the AddResult. | |
307 ASSERT_WITH_SECURITY_IMPLICATION(m_containerModifications == m_container
->modifications()); | |
308 } | 317 } |
309 | 318 |
310 private: | 319 private: |
311 const HashTableType* m_container; | 320 HashTableModificationForbiddenScope<HashTableType> m_modificationForbiddenSc
ope; |
312 const int64_t m_containerModifications; | |
313 #endif | 321 #endif |
314 }; | 322 }; |
315 | 323 |
316 template <typename Value, typename Extractor, typename KeyTraits> | 324 template <typename Value, typename Extractor, typename KeyTraits> |
317 struct HashTableHelper { | 325 struct HashTableHelper { |
318 STATIC_ONLY(HashTableHelper); | 326 STATIC_ONLY(HashTableHelper); |
319 static bool isEmptyBucket(const Value& value) { return isHashTraitsEmptyValu
e<KeyTraits>(Extractor::extract(value)); } | 327 static bool isEmptyBucket(const Value& value) { return isHashTraitsEmptyValu
e<KeyTraits>(Extractor::extract(value)); } |
320 static bool isDeletedBucket(const Value& value) { return KeyTraits::isDelete
dValue(Extractor::extract(value)); } | 328 static bool isDeletedBucket(const Value& value) { return KeyTraits::isDelete
dValue(Extractor::extract(value)); } |
321 static bool isEmptyOrDeletedBucket(const Value& value) { return isEmptyBucke
t(value) || isDeletedBucket(value); } | 329 static bool isEmptyOrDeletedBucket(const Value& value) { return isEmptyBucke
t(value) || isDeletedBucket(value); } |
322 }; | 330 }; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 } | 414 } |
407 }; | 415 }; |
408 #endif | 416 #endif |
409 | 417 |
410 HashTable(); | 418 HashTable(); |
411 void finalize() | 419 void finalize() |
412 { | 420 { |
413 ASSERT(!Allocator::isGarbageCollected); | 421 ASSERT(!Allocator::isGarbageCollected); |
414 if (LIKELY(!m_table)) | 422 if (LIKELY(!m_table)) |
415 return; | 423 return; |
416 ASSERT(!m_accessForbidden); | |
417 #if ENABLE(ASSERT) | |
418 m_accessForbidden = true; | |
419 #endif | |
420 deleteAllBucketsAndDeallocate(m_table, m_tableSize); | 424 deleteAllBucketsAndDeallocate(m_table, m_tableSize); |
421 #if ENABLE(ASSERT) | |
422 m_accessForbidden = false; | |
423 #endif | |
424 m_table = nullptr; | 425 m_table = nullptr; |
425 } | 426 } |
426 | 427 |
427 HashTable(const HashTable&); | 428 HashTable(const HashTable&); |
428 HashTable(HashTable&&); | 429 HashTable(HashTable&&); |
429 void swap(HashTable&); | 430 void swap(HashTable&); |
430 HashTable& operator=(const HashTable&); | 431 HashTable& operator=(const HashTable&); |
431 HashTable& operator=(HashTable&&); | 432 HashTable& operator=(HashTable&&); |
432 | 433 |
433 // When the hash table is empty, just return the same iterator for end as | 434 // When the hash table is empty, just return the same iterator for end as |
434 // for begin. This is more efficient because we don't have to skip all the | 435 // for begin. This is more efficient because we don't have to skip all the |
435 // empty and deleted buckets, and iterating an empty table is a common case | 436 // empty and deleted buckets, and iterating an empty table is a common case |
436 // that's worth optimizing. | 437 // that's worth optimizing. |
437 iterator begin() { return isEmpty() ? end() : makeIterator(m_table); } | 438 iterator begin() { return isEmpty() ? end() : makeIterator(m_table); } |
438 iterator end() { return makeKnownGoodIterator(m_table + m_tableSize); } | 439 iterator end() { return makeKnownGoodIterator(m_table + m_tableSize); } |
439 const_iterator begin() const { return isEmpty() ? end() : makeConstIterator(
m_table); } | 440 const_iterator begin() const { return isEmpty() ? end() : makeConstIterator(
m_table); } |
440 const_iterator end() const { return makeKnownGoodConstIterator(m_table + m_t
ableSize); } | 441 const_iterator end() const { return makeKnownGoodConstIterator(m_table + m_t
ableSize); } |
441 | 442 |
442 unsigned size() const | 443 unsigned size() const |
443 { | 444 { |
444 ASSERT(!m_accessForbidden); | |
445 return m_keyCount; | 445 return m_keyCount; |
446 } | 446 } |
447 unsigned capacity() const | 447 unsigned capacity() const |
448 { | 448 { |
449 ASSERT(!m_accessForbidden); | |
450 return m_tableSize; | 449 return m_tableSize; |
451 } | 450 } |
452 bool isEmpty() const | 451 bool isEmpty() const |
453 { | 452 { |
454 ASSERT(!m_accessForbidden); | |
455 return !m_keyCount; | 453 return !m_keyCount; |
456 } | 454 } |
457 | 455 |
458 void reserveCapacityForSize(unsigned size); | 456 void reserveCapacityForSize(unsigned size); |
459 | 457 |
460 template <typename IncomingValueType> | 458 template <typename IncomingValueType> |
461 AddResult add(IncomingValueType&& value) | 459 AddResult add(IncomingValueType&& value) |
462 { | 460 { |
463 return add<IdentityTranslatorType>(Extractor::extract(value), std::forwa
rd<IncomingValueType>(value)); | 461 return add<IdentityTranslatorType>(Extractor::extract(value), std::forwa
rd<IncomingValueType>(value)); |
464 } | 462 } |
(...skipping 21 matching lines...) Expand all Loading... |
486 static bool isDeletedBucket(const ValueType& value) { return KeyTraits::isDe
letedValue(Extractor::extract(value)); } | 484 static bool isDeletedBucket(const ValueType& value) { return KeyTraits::isDe
letedValue(Extractor::extract(value)); } |
487 static bool isEmptyOrDeletedBucket(const ValueType& value) { return HashTabl
eHelper<ValueType, Extractor, KeyTraits>:: isEmptyOrDeletedBucket(value); } | 485 static bool isEmptyOrDeletedBucket(const ValueType& value) { return HashTabl
eHelper<ValueType, Extractor, KeyTraits>:: isEmptyOrDeletedBucket(value); } |
488 | 486 |
489 ValueType* lookup(KeyPeekInType key) { return lookup<IdentityTranslatorType,
KeyPeekInType>(key); } | 487 ValueType* lookup(KeyPeekInType key) { return lookup<IdentityTranslatorType,
KeyPeekInType>(key); } |
490 template <typename HashTranslator, typename T> ValueType* lookup(const T&); | 488 template <typename HashTranslator, typename T> ValueType* lookup(const T&); |
491 template <typename HashTranslator, typename T> const ValueType* lookup(const
T&) const; | 489 template <typename HashTranslator, typename T> const ValueType* lookup(const
T&) const; |
492 | 490 |
493 template <typename VisitorDispatcher> void trace(VisitorDispatcher); | 491 template <typename VisitorDispatcher> void trace(VisitorDispatcher); |
494 | 492 |
495 #if ENABLE(ASSERT) | 493 #if ENABLE(ASSERT) |
496 bool accessForbidden() const { return m_accessForbidden; } | 494 void enterModificationForbiddenScope() { m_modificationForbidden++; } |
497 int64_t modifications() const { return m_modifications; } | 495 void leaveModificationForbiddenScope() |
498 void registerModification() { m_modifications++; } | 496 { |
499 // HashTable and collections that build on it do not support modifications | 497 ASSERT(m_modificationForbidden > 0); |
500 // while there is an iterator in use. The exception is ListHashSet, which | 498 m_modificationForbidden--; |
501 // has its own iterators that tolerate modification of the underlying set. | 499 } |
502 void checkModifications(int64_t mods) const { ASSERT(mods == m_modifications
); } | 500 |
| 501 void registerModification() |
| 502 { |
| 503 ASSERT(!m_modificationForbidden); |
| 504 } |
503 #else | 505 #else |
504 int64_t modifications() const { return 0; } | 506 void registerModification() { } |
505 void registerModification() {} | |
506 void checkModifications(int64_t mods) const {} | |
507 #endif | 507 #endif |
508 | 508 |
509 private: | 509 private: |
510 static ValueType* allocateTable(unsigned size); | 510 static ValueType* allocateTable(unsigned size); |
511 static void deleteAllBucketsAndDeallocate(ValueType* table, unsigned size); | 511 static void deleteAllBucketsAndDeallocate(ValueType* table, unsigned size); |
512 | 512 |
513 typedef std::pair<ValueType*, bool> LookupType; | 513 typedef std::pair<ValueType*, bool> LookupType; |
514 typedef std::pair<LookupType, unsigned> FullLookupType; | 514 typedef std::pair<LookupType, unsigned> FullLookupType; |
515 | 515 |
516 LookupType lookupForWriting(const Key& key) { return lookupForWriting<Identi
tyTranslatorType>(key); } | 516 LookupType lookupForWriting(const Key& key) { return lookupForWriting<Identi
tyTranslatorType>(key); } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
562 return mask; | 562 return mask; |
563 } | 563 } |
564 | 564 |
565 void setEnqueued() { m_queueFlag = true; } | 565 void setEnqueued() { m_queueFlag = true; } |
566 void clearEnqueued() { m_queueFlag = false; } | 566 void clearEnqueued() { m_queueFlag = false; } |
567 bool enqueued() { return m_queueFlag; } | 567 bool enqueued() { return m_queueFlag; } |
568 | 568 |
569 ValueType* m_table; | 569 ValueType* m_table; |
570 unsigned m_tableSize; | 570 unsigned m_tableSize; |
571 unsigned m_keyCount; | 571 unsigned m_keyCount; |
572 #if ENABLE(ASSERT) | |
573 unsigned m_deletedCount:30; | |
574 unsigned m_queueFlag:1; | |
575 unsigned m_accessForbidden:1; | |
576 unsigned m_modifications; | |
577 #else | |
578 unsigned m_deletedCount:31; | 572 unsigned m_deletedCount:31; |
579 unsigned m_queueFlag:1; | 573 unsigned m_queueFlag:1; |
| 574 #if ENABLE(ASSERT) |
| 575 unsigned m_modificationForbidden; |
580 #endif | 576 #endif |
581 | 577 |
582 #if DUMP_HASHTABLE_STATS_PER_TABLE | 578 #if DUMP_HASHTABLE_STATS_PER_TABLE |
583 public: | 579 public: |
584 mutable OwnPtr<Stats> m_stats; | 580 mutable OwnPtr<Stats> m_stats; |
585 #endif | 581 #endif |
586 | 582 |
587 template <WeakHandlingFlag x, typename T, typename U, typename V, typename W
, typename X, typename Y, typename Z> friend struct WeakProcessingHashTableHelpe
r; | 583 template <WeakHandlingFlag x, typename T, typename U, typename V, typename W
, typename X, typename Y, typename Z> friend struct WeakProcessingHashTableHelpe
r; |
588 template <typename T, typename U, typename V, typename W> friend class Linke
dHashSet; | 584 template <typename T, typename U, typename V, typename W> friend class Linke
dHashSet; |
589 }; | 585 }; |
590 | 586 |
591 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 587 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
592 inline HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Alloca
tor>::HashTable() | 588 inline HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Alloca
tor>::HashTable() |
593 : m_table(nullptr) | 589 : m_table(nullptr) |
594 , m_tableSize(0) | 590 , m_tableSize(0) |
595 , m_keyCount(0) | 591 , m_keyCount(0) |
596 , m_deletedCount(0) | 592 , m_deletedCount(0) |
597 , m_queueFlag(false) | 593 , m_queueFlag(false) |
598 #if ENABLE(ASSERT) | 594 #if ENABLE(ASSERT) |
599 , m_accessForbidden(false) | 595 , m_modificationForbidden(0) |
600 , m_modifications(0) | |
601 #endif | 596 #endif |
602 #if DUMP_HASHTABLE_STATS_PER_TABLE | 597 #if DUMP_HASHTABLE_STATS_PER_TABLE |
603 , m_stats(adoptPtr(new Stats)) | 598 , m_stats(adoptPtr(new Stats)) |
604 #endif | 599 #endif |
605 { | 600 { |
606 static_assert(Allocator::isGarbageCollected || (!IsPointerToGarbageCollected
Type<Key>::value && !IsPointerToGarbageCollectedType<Value>::value), "Cannot put
raw pointers to garbage-collected classes into an off-heap collection."); | 601 static_assert(Allocator::isGarbageCollected || (!IsPointerToGarbageCollected
Type<Key>::value && !IsPointerToGarbageCollectedType<Value>::value), "Cannot put
raw pointers to garbage-collected classes into an off-heap collection."); |
607 } | 602 } |
608 | 603 |
609 inline unsigned doubleHash(unsigned key) | 604 inline unsigned doubleHash(unsigned key) |
610 { | 605 { |
(...skipping 29 matching lines...) Expand all Loading... |
640 template <typename HashTranslator, typename T> | 635 template <typename HashTranslator, typename T> |
641 inline Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits,
Allocator>::lookup(const T& key) | 636 inline Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits,
Allocator>::lookup(const T& key) |
642 { | 637 { |
643 return const_cast<Value*>(const_cast<const HashTable*>(this)->lookup<HashTra
nslator>(key)); | 638 return const_cast<Value*>(const_cast<const HashTable*>(this)->lookup<HashTra
nslator>(key)); |
644 } | 639 } |
645 | 640 |
646 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 641 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
647 template <typename HashTranslator, typename T> | 642 template <typename HashTranslator, typename T> |
648 inline const Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyT
raits, Allocator>::lookup(const T& key) const | 643 inline const Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyT
raits, Allocator>::lookup(const T& key) const |
649 { | 644 { |
650 ASSERT(!m_accessForbidden); | |
651 ASSERT((HashTableKeyChecker<HashTranslator, KeyTraits, HashFunctions::safeTo
CompareToEmptyOrDeleted>::checkKey(key))); | 645 ASSERT((HashTableKeyChecker<HashTranslator, KeyTraits, HashFunctions::safeTo
CompareToEmptyOrDeleted>::checkKey(key))); |
652 const ValueType* table = m_table; | 646 const ValueType* table = m_table; |
653 if (!table) | 647 if (!table) |
654 return nullptr; | 648 return nullptr; |
655 | 649 |
656 size_t k = 0; | 650 size_t k = 0; |
657 size_t sizeMask = tableSizeMask(); | 651 size_t sizeMask = tableSizeMask(); |
658 unsigned h = HashTranslator::hash(key); | 652 unsigned h = HashTranslator::hash(key); |
659 size_t i = h & sizeMask; | 653 size_t i = h & sizeMask; |
660 | 654 |
(...skipping 19 matching lines...) Expand all Loading... |
680 if (!k) | 674 if (!k) |
681 k = 1 | doubleHash(h); | 675 k = 1 | doubleHash(h); |
682 i = (i + k) & sizeMask; | 676 i = (i + k) & sizeMask; |
683 } | 677 } |
684 } | 678 } |
685 | 679 |
686 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 680 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
687 template <typename HashTranslator, typename T> | 681 template <typename HashTranslator, typename T> |
688 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrait
s, Allocator>::LookupType HashTable<Key, Value, Extractor, HashFunctions, Traits
, KeyTraits, Allocator>::lookupForWriting(const T& key) | 682 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrait
s, Allocator>::LookupType HashTable<Key, Value, Extractor, HashFunctions, Traits
, KeyTraits, Allocator>::lookupForWriting(const T& key) |
689 { | 683 { |
690 ASSERT(!m_accessForbidden); | |
691 ASSERT(m_table); | 684 ASSERT(m_table); |
692 registerModification(); | 685 registerModification(); |
693 | 686 |
694 ValueType* table = m_table; | 687 ValueType* table = m_table; |
695 size_t k = 0; | 688 size_t k = 0; |
696 size_t sizeMask = tableSizeMask(); | 689 size_t sizeMask = tableSizeMask(); |
697 unsigned h = HashTranslator::hash(key); | 690 unsigned h = HashTranslator::hash(key); |
698 size_t i = h & sizeMask; | 691 size_t i = h & sizeMask; |
699 | 692 |
700 UPDATE_ACCESS_COUNTS(); | 693 UPDATE_ACCESS_COUNTS(); |
(...skipping 22 matching lines...) Expand all Loading... |
723 if (!k) | 716 if (!k) |
724 k = 1 | doubleHash(h); | 717 k = 1 | doubleHash(h); |
725 i = (i + k) & sizeMask; | 718 i = (i + k) & sizeMask; |
726 } | 719 } |
727 } | 720 } |
728 | 721 |
729 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 722 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
730 template <typename HashTranslator, typename T> | 723 template <typename HashTranslator, typename T> |
731 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrait
s, Allocator>::FullLookupType HashTable<Key, Value, Extractor, HashFunctions, Tr
aits, KeyTraits, Allocator>::fullLookupForWriting(const T& key) | 724 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrait
s, Allocator>::FullLookupType HashTable<Key, Value, Extractor, HashFunctions, Tr
aits, KeyTraits, Allocator>::fullLookupForWriting(const T& key) |
732 { | 725 { |
733 ASSERT(!m_accessForbidden); | |
734 ASSERT(m_table); | 726 ASSERT(m_table); |
735 registerModification(); | 727 registerModification(); |
736 | 728 |
737 ValueType* table = m_table; | 729 ValueType* table = m_table; |
738 size_t k = 0; | 730 size_t k = 0; |
739 size_t sizeMask = tableSizeMask(); | 731 size_t sizeMask = tableSizeMask(); |
740 unsigned h = HashTranslator::hash(key); | 732 unsigned h = HashTranslator::hash(key); |
741 size_t i = h & sizeMask; | 733 size_t i = h & sizeMask; |
742 | 734 |
743 UPDATE_ACCESS_COUNTS(); | 735 UPDATE_ACCESS_COUNTS(); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
794 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 786 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
795 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, A
llocator>::initializeBucket(ValueType& bucket) | 787 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, A
llocator>::initializeBucket(ValueType& bucket) |
796 { | 788 { |
797 HashTableBucketInitializer<Traits::emptyValueIsZero>::template initialize<Tr
aits>(bucket); | 789 HashTableBucketInitializer<Traits::emptyValueIsZero>::template initialize<Tr
aits>(bucket); |
798 } | 790 } |
799 | 791 |
800 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 792 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
801 template <typename HashTranslator, typename T, typename Extra> | 793 template <typename HashTranslator, typename T, typename Extra> |
802 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allo
cator>::AddResult HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTra
its, Allocator>::add(T&& key, Extra&& extra) | 794 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allo
cator>::AddResult HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTra
its, Allocator>::add(T&& key, Extra&& extra) |
803 { | 795 { |
804 ASSERT(!m_accessForbidden); | |
805 ASSERT(Allocator::isAllocationAllowed()); | 796 ASSERT(Allocator::isAllocationAllowed()); |
806 if (!m_table) | 797 if (!m_table) |
807 expand(); | 798 expand(); |
808 | 799 |
809 ASSERT(m_table); | 800 ASSERT(m_table); |
810 | 801 |
811 ValueType* table = m_table; | 802 ValueType* table = m_table; |
812 size_t k = 0; | 803 size_t k = 0; |
813 size_t sizeMask = tableSizeMask(); | 804 size_t sizeMask = tableSizeMask(); |
814 unsigned h = HashTranslator::hash(key); | 805 unsigned h = HashTranslator::hash(key); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
860 if (shouldExpand()) | 851 if (shouldExpand()) |
861 entry = expand(entry); | 852 entry = expand(entry); |
862 | 853 |
863 return AddResult(this, entry, true); | 854 return AddResult(this, entry, true); |
864 } | 855 } |
865 | 856 |
866 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 857 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
867 template <typename HashTranslator, typename T, typename Extra> | 858 template <typename HashTranslator, typename T, typename Extra> |
868 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allo
cator>::AddResult HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTra
its, Allocator>::addPassingHashCode(T&& key, Extra&& extra) | 859 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allo
cator>::AddResult HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTra
its, Allocator>::addPassingHashCode(T&& key, Extra&& extra) |
869 { | 860 { |
870 ASSERT(!m_accessForbidden); | |
871 ASSERT(Allocator::isAllocationAllowed()); | 861 ASSERT(Allocator::isAllocationAllowed()); |
872 if (!m_table) | 862 if (!m_table) |
873 expand(); | 863 expand(); |
874 | 864 |
875 FullLookupType lookupResult = fullLookupForWriting<HashTranslator>(key); | 865 FullLookupType lookupResult = fullLookupForWriting<HashTranslator>(key); |
876 | 866 |
877 ValueType* entry = lookupResult.first.first; | 867 ValueType* entry = lookupResult.first.first; |
878 bool found = lookupResult.first.second; | 868 bool found = lookupResult.first.second; |
879 unsigned h = lookupResult.second; | 869 unsigned h = lookupResult.second; |
880 | 870 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
950 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocato
r>::remove(ValueType* pos) | 940 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocato
r>::remove(ValueType* pos) |
951 { | 941 { |
952 registerModification(); | 942 registerModification(); |
953 #if DUMP_HASHTABLE_STATS | 943 #if DUMP_HASHTABLE_STATS |
954 atomicIncrement(&HashTableStats::numRemoves); | 944 atomicIncrement(&HashTableStats::numRemoves); |
955 #endif | 945 #endif |
956 #if DUMP_HASHTABLE_STATS_PER_TABLE | 946 #if DUMP_HASHTABLE_STATS_PER_TABLE |
957 ++m_stats->numRemoves; | 947 ++m_stats->numRemoves; |
958 #endif | 948 #endif |
959 | 949 |
960 ASSERT(!m_accessForbidden); | |
961 #if ENABLE(ASSERT) | |
962 m_accessForbidden = true; | |
963 #endif | |
964 deleteBucket(*pos); | 950 deleteBucket(*pos); |
965 #if ENABLE(ASSERT) | |
966 m_accessForbidden = false; | |
967 #endif | |
968 ++m_deletedCount; | 951 ++m_deletedCount; |
969 --m_keyCount; | 952 --m_keyCount; |
970 | 953 |
971 if (shouldShrink()) | 954 if (shouldShrink()) |
972 shrink(); | 955 shrink(); |
973 } | 956 } |
974 | 957 |
975 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 958 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
976 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, A
llocator>::remove(iterator it) | 959 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, A
llocator>::remove(iterator it) |
977 { | 960 { |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1093 m_table = temporaryTable; | 1076 m_table = temporaryTable; |
1094 | 1077 |
1095 if (Traits::emptyValueIsZero) { | 1078 if (Traits::emptyValueIsZero) { |
1096 memset(originalTable, 0, newTableSize * sizeof(ValueType)); | 1079 memset(originalTable, 0, newTableSize * sizeof(ValueType)); |
1097 } else { | 1080 } else { |
1098 for (unsigned i = 0; i < newTableSize; i++) | 1081 for (unsigned i = 0; i < newTableSize; i++) |
1099 initializeBucket(originalTable[i]); | 1082 initializeBucket(originalTable[i]); |
1100 } | 1083 } |
1101 newEntry = rehashTo(originalTable, newTableSize, newEntry); | 1084 newEntry = rehashTo(originalTable, newTableSize, newEntry); |
1102 | 1085 |
1103 ASSERT(!m_accessForbidden); | |
1104 #if ENABLE(ASSERT) | |
1105 m_accessForbidden = true; | |
1106 #endif | |
1107 deleteAllBucketsAndDeallocate(temporaryTable, oldTableSize); | 1086 deleteAllBucketsAndDeallocate(temporaryTable, oldTableSize); |
1108 #if ENABLE(ASSERT) | |
1109 m_accessForbidden = false; | |
1110 #endif | |
1111 | |
1112 return newEntry; | 1087 return newEntry; |
1113 } | 1088 } |
1114 | 1089 |
1115 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 1090 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
1116 Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Alloca
tor>::rehashTo(ValueType* newTable, unsigned newTableSize, Value* entry) | 1091 Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Alloca
tor>::rehashTo(ValueType* newTable, unsigned newTableSize, Value* entry) |
1117 { | 1092 { |
1118 unsigned oldTableSize = m_tableSize; | 1093 unsigned oldTableSize = m_tableSize; |
1119 ValueType* oldTable = m_table; | 1094 ValueType* oldTable = m_table; |
1120 | 1095 |
1121 #if DUMP_HASHTABLE_STATS | 1096 #if DUMP_HASHTABLE_STATS |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1171 if (Allocator::isGarbageCollected && newTableSize > oldTableSize) { | 1146 if (Allocator::isGarbageCollected && newTableSize > oldTableSize) { |
1172 bool success; | 1147 bool success; |
1173 Value* newEntry = expandBuffer(newTableSize, entry, success); | 1148 Value* newEntry = expandBuffer(newTableSize, entry, success); |
1174 if (success) | 1149 if (success) |
1175 return newEntry; | 1150 return newEntry; |
1176 } | 1151 } |
1177 | 1152 |
1178 ValueType* newTable = allocateTable(newTableSize); | 1153 ValueType* newTable = allocateTable(newTableSize); |
1179 Value* newEntry = rehashTo(newTable, newTableSize, entry); | 1154 Value* newEntry = rehashTo(newTable, newTableSize, entry); |
1180 | 1155 |
1181 ASSERT(!m_accessForbidden); | |
1182 #if ENABLE(ASSERT) | |
1183 m_accessForbidden = true; | |
1184 #endif | |
1185 deleteAllBucketsAndDeallocate(oldTable, oldTableSize); | 1156 deleteAllBucketsAndDeallocate(oldTable, oldTableSize); |
1186 #if ENABLE(ASSERT) | |
1187 m_accessForbidden = false; | |
1188 #endif | |
1189 | |
1190 return newEntry; | 1157 return newEntry; |
1191 } | 1158 } |
1192 | 1159 |
1193 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 1160 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
1194 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocato
r>::clear() | 1161 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocato
r>::clear() |
1195 { | 1162 { |
1196 registerModification(); | 1163 registerModification(); |
1197 if (!m_table) | 1164 if (!m_table) |
1198 return; | 1165 return; |
1199 | 1166 |
1200 ASSERT(!m_accessForbidden); | |
1201 #if ENABLE(ASSERT) | |
1202 m_accessForbidden = true; | |
1203 #endif | |
1204 deleteAllBucketsAndDeallocate(m_table, m_tableSize); | 1167 deleteAllBucketsAndDeallocate(m_table, m_tableSize); |
1205 #if ENABLE(ASSERT) | |
1206 m_accessForbidden = false; | |
1207 #endif | |
1208 m_table = nullptr; | 1168 m_table = nullptr; |
1209 m_tableSize = 0; | 1169 m_tableSize = 0; |
1210 m_keyCount = 0; | 1170 m_keyCount = 0; |
1211 } | 1171 } |
1212 | 1172 |
1213 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 1173 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
1214 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::H
ashTable(const HashTable& other) | 1174 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::H
ashTable(const HashTable& other) |
1215 : m_table(nullptr) | 1175 : m_table(nullptr) |
1216 , m_tableSize(0) | 1176 , m_tableSize(0) |
1217 , m_keyCount(0) | 1177 , m_keyCount(0) |
1218 , m_deletedCount(0) | 1178 , m_deletedCount(0) |
1219 , m_queueFlag(false) | 1179 , m_queueFlag(false) |
1220 #if ENABLE(ASSERT) | 1180 #if ENABLE(ASSERT) |
1221 , m_accessForbidden(false) | 1181 , m_modificationForbidden(0) |
1222 , m_modifications(0) | |
1223 #endif | 1182 #endif |
1224 #if DUMP_HASHTABLE_STATS_PER_TABLE | 1183 #if DUMP_HASHTABLE_STATS_PER_TABLE |
1225 , m_stats(adoptPtr(new Stats(*other.m_stats))) | 1184 , m_stats(adoptPtr(new Stats(*other.m_stats))) |
1226 #endif | 1185 #endif |
1227 { | 1186 { |
1228 // Copy the hash table the dumb way, by adding each element to the new | 1187 // Copy the hash table the dumb way, by adding each element to the new |
1229 // table. It might be more efficient to copy the table slots, but it's not | 1188 // table. It might be more efficient to copy the table slots, but it's not |
1230 // clear that efficiency is needed. | 1189 // clear that efficiency is needed. |
1231 const_iterator end = other.end(); | 1190 const_iterator end = other.end(); |
1232 for (const_iterator it = other.begin(); it != end; ++it) | 1191 for (const_iterator it = other.begin(); it != end; ++it) |
1233 add(*it); | 1192 add(*it); |
1234 } | 1193 } |
1235 | 1194 |
1236 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 1195 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
1237 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::H
ashTable(HashTable&& other) | 1196 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::H
ashTable(HashTable&& other) |
1238 : m_table(nullptr) | 1197 : m_table(nullptr) |
1239 , m_tableSize(0) | 1198 , m_tableSize(0) |
1240 , m_keyCount(0) | 1199 , m_keyCount(0) |
1241 , m_deletedCount(0) | 1200 , m_deletedCount(0) |
1242 , m_queueFlag(false) | 1201 , m_queueFlag(false) |
1243 #if ENABLE(ASSERT) | 1202 #if ENABLE(ASSERT) |
1244 , m_accessForbidden(false) | 1203 , m_modificationForbidden(0) |
1245 , m_modifications(0) | |
1246 #endif | 1204 #endif |
1247 #if DUMP_HASHTABLE_STATS_PER_TABLE | 1205 #if DUMP_HASHTABLE_STATS_PER_TABLE |
1248 , m_stats(adoptPtr(new Stats(*other.m_stats))) | 1206 , m_stats(adoptPtr(new Stats(*other.m_stats))) |
1249 #endif | 1207 #endif |
1250 { | 1208 { |
1251 swap(other); | 1209 swap(other); |
1252 } | 1210 } |
1253 | 1211 |
1254 | 1212 |
1255 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 1213 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
1256 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocato
r>::swap(HashTable& other) | 1214 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocato
r>::swap(HashTable& other) |
1257 { | 1215 { |
1258 ASSERT(!m_accessForbidden); | 1216 registerModification(); |
1259 std::swap(m_table, other.m_table); | 1217 std::swap(m_table, other.m_table); |
1260 std::swap(m_tableSize, other.m_tableSize); | 1218 std::swap(m_tableSize, other.m_tableSize); |
1261 std::swap(m_keyCount, other.m_keyCount); | 1219 std::swap(m_keyCount, other.m_keyCount); |
1262 // std::swap does not work for bit fields. | 1220 // std::swap does not work for bit fields. |
1263 unsigned deleted = m_deletedCount; | 1221 unsigned deleted = m_deletedCount; |
1264 m_deletedCount = other.m_deletedCount; | 1222 m_deletedCount = other.m_deletedCount; |
1265 other.m_deletedCount = deleted; | 1223 other.m_deletedCount = deleted; |
1266 ASSERT(!m_queueFlag); | 1224 ASSERT(!m_queueFlag); |
1267 ASSERT(!other.m_queueFlag); | 1225 ASSERT(!other.m_queueFlag); |
1268 | 1226 |
1269 #if ENABLE(ASSERT) | 1227 #if ENABLE(ASSERT) |
1270 std::swap(m_modifications, other.m_modifications); | 1228 std::swap(m_modificationForbidden, other.m_modificationForbidden); |
1271 #endif | 1229 #endif |
1272 | 1230 |
1273 #if DUMP_HASHTABLE_STATS_PER_TABLE | 1231 #if DUMP_HASHTABLE_STATS_PER_TABLE |
1274 m_stats.swap(other.m_stats); | 1232 m_stats.swap(other.m_stats); |
1275 #endif | 1233 #endif |
1276 } | 1234 } |
1277 | 1235 |
1278 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 1236 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
1279 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>& H
ashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::op
erator=(const HashTable& other) | 1237 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>& H
ashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::op
erator=(const HashTable& other) |
1280 { | 1238 { |
1281 HashTable tmp(other); | 1239 HashTable tmp(other); |
1282 swap(tmp); | 1240 swap(tmp); |
1283 return *this; | 1241 return *this; |
1284 } | 1242 } |
1285 | 1243 |
1286 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 1244 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
1287 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>& H
ashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::op
erator=(HashTable&& other) | 1245 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>& H
ashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::op
erator=(HashTable&& other) |
1288 { | 1246 { |
1289 swap(other); | 1247 swap(other); |
1290 return *this; | 1248 return *this; |
1291 } | 1249 } |
1292 | 1250 |
| 1251 #if ENABLE(ASSERT) |
| 1252 template <typename HashTableType> |
| 1253 HashTableModificationForbiddenScope<HashTableType>::HashTableModificationForbidd
enScope() |
| 1254 : m_container(nullptr) |
| 1255 { |
| 1256 } |
| 1257 |
| 1258 template <typename HashTableType> |
| 1259 HashTableModificationForbiddenScope<HashTableType>::HashTableModificationForbidd
enScope(const HashTableType* container) |
| 1260 : m_container(const_cast<HashTableType*>(container)) |
| 1261 { |
| 1262 if (m_container) |
| 1263 m_container->enterModificationForbiddenScope(); |
| 1264 } |
| 1265 |
| 1266 template <typename HashTableType> |
| 1267 HashTableModificationForbiddenScope<HashTableType>::HashTableModificationForbidd
enScope(const HashTableModificationForbiddenScope& other) |
| 1268 : m_container(other.m_container) |
| 1269 { |
| 1270 if (m_container) |
| 1271 m_container->enterModificationForbiddenScope(); |
| 1272 } |
| 1273 |
| 1274 template <typename HashTableType> |
| 1275 HashTableModificationForbiddenScope<HashTableType>::~HashTableModificationForbid
denScope() |
| 1276 { |
| 1277 leaveScope(); |
| 1278 } |
| 1279 |
| 1280 template <typename HashTableType> |
| 1281 void HashTableModificationForbiddenScope<HashTableType>::leaveScope() |
| 1282 { |
| 1283 if (!m_container) |
| 1284 return; |
| 1285 m_container->leaveModificationForbiddenScope(); |
| 1286 m_container = nullptr; |
| 1287 } |
| 1288 #endif |
| 1289 |
1293 template <WeakHandlingFlag weakHandlingFlag, typename Key, typename Value, typen
ame Extractor, typename HashFunctions, typename Traits, typename KeyTraits, type
name Allocator> | 1290 template <WeakHandlingFlag weakHandlingFlag, typename Key, typename Value, typen
ame Extractor, typename HashFunctions, typename Traits, typename KeyTraits, type
name Allocator> |
1294 struct WeakProcessingHashTableHelper; | 1291 struct WeakProcessingHashTableHelper; |
1295 | 1292 |
1296 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> | 1293 template <typename Key, typename Value, typename Extractor, typename HashFunctio
ns, typename Traits, typename KeyTraits, typename Allocator> |
1297 struct WeakProcessingHashTableHelper<NoWeakHandlingInCollections, Key, Value, Ex
tractor, HashFunctions, Traits, KeyTraits, Allocator> { | 1294 struct WeakProcessingHashTableHelper<NoWeakHandlingInCollections, Key, Value, Ex
tractor, HashFunctions, Traits, KeyTraits, Allocator> { |
1298 STATIC_ONLY(WeakProcessingHashTableHelper); | 1295 STATIC_ONLY(WeakProcessingHashTableHelper); |
1299 static void process(typename Allocator::Visitor* visitor, void* closure) {} | 1296 static void process(typename Allocator::Visitor* visitor, void* closure) {} |
1300 static void ephemeronIteration(typename Allocator::Visitor* visitor, void* c
losure) {} | 1297 static void ephemeronIteration(typename Allocator::Visitor* visitor, void* c
losure) {} |
1301 static void ephemeronIterationDone(typename Allocator::Visitor* visitor, voi
d* closure) {} | 1298 static void ephemeronIterationDone(typename Allocator::Visitor* visitor, voi
d* closure) {} |
1302 }; | 1299 }; |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1522 CollectionIterator end(toBeRemoved.end()); | 1519 CollectionIterator end(toBeRemoved.end()); |
1523 for (CollectionIterator it(toBeRemoved.begin()); it != end; ++it) | 1520 for (CollectionIterator it(toBeRemoved.begin()); it != end; ++it) |
1524 collection.remove(*it); | 1521 collection.remove(*it); |
1525 } | 1522 } |
1526 | 1523 |
1527 } // namespace WTF | 1524 } // namespace WTF |
1528 | 1525 |
1529 #include "wtf/HashIterators.h" | 1526 #include "wtf/HashIterators.h" |
1530 | 1527 |
1531 #endif // WTF_HashTable_h | 1528 #endif // WTF_HashTable_h |
OLD | NEW |