Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserv ed. | |
| 3 * Copyright (C) 2011, Benjamin Poulain <ikipou@gmail.com> | |
| 4 * | |
| 5 * This library is free software; you can redistribute it and/or | |
| 6 * modify it under the terms of the GNU Library General Public | |
| 7 * License as published by the Free Software Foundation; either | |
| 8 * version 2 of the License, or (at your option) any later version. | |
| 9 * | |
| 10 * This library is distributed in the hope that it will be useful, | |
| 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 * Library General Public License for more details. | |
| 14 * | |
| 15 * You should have received a copy of the GNU Library General Public License | |
| 16 * along with this library; see the file COPYING.LIB. If not, write to | |
| 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 18 * Boston, MA 02110-1301, USA. | |
| 19 * | |
| 20 */ | |
| 21 | |
| 22 #ifndef WTF_LinkedHashSet_h | |
| 23 #define WTF_LinkedHashSet_h | |
| 24 | |
| 25 #include "wtf/DefaultAllocator.h" | |
| 26 #include "wtf/HashSet.h" | |
| 27 #include "wtf/OwnPtr.h" | |
| 28 #include "wtf/PassOwnPtr.h" | |
| 29 | |
| 30 namespace WTF { | |
| 31 | |
| 32 // LinkedHashSet: Just like HashSet, this class provides a Set | |
| 33 // interface - a collection of unique objects with O(1) insertion, | |
| 34 // removal and test for containership. However, it also has an | |
| 35 // order - iterating it will always give back values in the order | |
| 36 // in which they are added. | |
| 37 | |
| 38 // Unlike ListHashSet, but like most WTF collections, iteration is NOT safe | |
| 39 // against mutation of the LinkedHashSet. | |
| 40 | |
| 41 template<typename Value, typename HashFunctions, typename HashTraits, typename A llocator> class LinkedHashSet; | |
| 42 | |
| 43 template<typename LinkedHashSet> class LinkedHashSetIterator; | |
| 44 template<typename LinkedHashSet> class LinkedHashSetConstIterator; | |
| 45 template<typename LinkedHashSet> class LinkedHashSetReverseIterator; | |
| 46 template<typename LinkedHashSet> class LinkedHashSetConstReverseIterator; | |
| 47 | |
| 48 template<typename Value, typename HashFunctions> struct LinkedHashSetTranslator; | |
| 49 template<typename Value> struct LinkedHashSetExtractor; | |
| 50 template<typename Value, typename ValueTraits> struct LinkedHashSetTraits; | |
| 51 | |
| 52 class LinkedHashSetNodeBase { | |
| 53 public: | |
| 54 LinkedHashSetNodeBase() : m_prev(this), m_next(this) { } | |
| 55 | |
| 56 void unlink() | |
| 57 { | |
| 58 if (!m_next) | |
| 59 return; | |
| 60 ASSERT(m_prev); | |
| 61 ASSERT(m_next->m_prev == this); | |
| 62 ASSERT(m_prev->m_next == this); | |
| 63 m_next->m_prev = m_prev; | |
| 64 m_prev->m_next = m_next; | |
| 65 } | |
| 66 | |
| 67 ~LinkedHashSetNodeBase() | |
| 68 { | |
| 69 unlink(); | |
| 70 } | |
| 71 | |
| 72 void insertBefore(LinkedHashSetNodeBase& other) | |
| 73 { | |
| 74 other.m_next = this; | |
| 75 other.m_prev = m_prev; | |
| 76 m_prev->m_next = &other; | |
| 77 m_prev = &other; | |
| 78 ASSERT(other.m_next); | |
| 79 ASSERT(other.m_prev); | |
| 80 ASSERT(m_next); | |
| 81 ASSERT(m_prev); | |
| 82 } | |
| 83 | |
| 84 void insertAfter(LinkedHashSetNodeBase& other) | |
| 85 { | |
| 86 other.m_prev = this; | |
| 87 other.m_next = m_next; | |
| 88 m_next->m_prev = &other; | |
| 89 m_next = &other; | |
| 90 ASSERT(other.m_next); | |
| 91 ASSERT(other.m_prev); | |
| 92 ASSERT(m_next); | |
| 93 ASSERT(m_prev); | |
| 94 } | |
| 95 | |
| 96 LinkedHashSetNodeBase(LinkedHashSetNodeBase* prev, LinkedHashSetNodeBase* ne xt) | |
| 97 : m_prev(prev) | |
| 98 , m_next(next) | |
| 99 { | |
| 100 ASSERT((prev && next) || (!prev && !next)); | |
| 101 } | |
| 102 | |
| 103 LinkedHashSetNodeBase* m_prev; | |
| 104 LinkedHashSetNodeBase* m_next; | |
| 105 | |
| 106 protected: | |
| 107 // If we take a copy of a node we can't copy the next and prev pointers, | |
| 108 // since they point to something that does not point at us. This is used | |
| 109 // inside the shouldExpand() "if" in HashTable::add. | |
| 110 LinkedHashSetNodeBase(const LinkedHashSetNodeBase& other) | |
| 111 : m_prev(0) | |
| 112 , m_next(0) { } | |
| 113 | |
| 114 private: | |
| 115 // Should not be used. | |
| 116 LinkedHashSetNodeBase& operator=(const LinkedHashSetNodeBase& other); | |
| 117 }; | |
| 118 | |
| 119 template<typename ValueArg> | |
| 120 class LinkedHashSetNode : public LinkedHashSetNodeBase { | |
| 121 public: | |
| 122 LinkedHashSetNode(const ValueArg& value, LinkedHashSetNodeBase* prev, Linked HashSetNodeBase* next) | |
| 123 : LinkedHashSetNodeBase(prev, next) | |
| 124 , m_value(value) | |
| 125 { | |
| 126 } | |
| 127 | |
| 128 ValueArg m_value; | |
| 129 | |
| 130 private: | |
| 131 // Not used. | |
| 132 LinkedHashSetNode(const LinkedHashSetNode&); | |
|
Mikhail
2014/04/10 12:25:03
WTF_MAKE_NONCOPYABLE ?
Erik Corry
2014/04/10 13:47:29
Can't do that because it also overwrites the copy
| |
| 133 }; | |
| 134 | |
| 135 template< | |
| 136 typename ValueArg, | |
| 137 typename HashFunctions = typename DefaultHash<ValueArg>::Hash, | |
| 138 typename TraitsArg = HashTraits<ValueArg>, | |
| 139 typename Allocator = DefaultAllocator> | |
| 140 class LinkedHashSet { | |
| 141 private: | |
| 142 typedef ValueArg Value; | |
| 143 typedef TraitsArg Traits; | |
| 144 typedef LinkedHashSetNode<Value> Node; | |
| 145 typedef LinkedHashSetNodeBase NodeBase; | |
| 146 typedef LinkedHashSetTranslator<Value, HashFunctions> NodeHashFunctions; | |
| 147 typedef LinkedHashSetTraits<Value, Traits> NodeHashTraits; | |
| 148 | |
| 149 typedef HashTable<Node, Node, IdentityExtractor, | |
| 150 NodeHashFunctions, NodeHashTraits, NodeHashTraits, Allocator> ImplType; | |
| 151 | |
| 152 public: | |
| 153 typedef LinkedHashSetIterator<LinkedHashSet> iterator; | |
| 154 friend class LinkedHashSetIterator<LinkedHashSet>; | |
| 155 typedef LinkedHashSetConstIterator<LinkedHashSet> const_iterator; | |
| 156 friend class LinkedHashSetConstIterator<LinkedHashSet>; | |
| 157 | |
| 158 typedef LinkedHashSetReverseIterator<LinkedHashSet> reverse_iterator; | |
| 159 friend class LinkedHashSetReverseIterator<LinkedHashSet>; | |
| 160 typedef LinkedHashSetConstReverseIterator<LinkedHashSet> const_reverse_itera tor; | |
| 161 friend class LinkedHashSetConstReverseIterator<LinkedHashSet>; | |
| 162 | |
| 163 struct AddResult { | |
| 164 AddResult(const typename ImplType::AddResult& hashTableAddResult) | |
| 165 : storedValue(&hashTableAddResult.storedValue->m_value) | |
| 166 , isNewEntry(hashTableAddResult.isNewEntry) | |
| 167 { | |
| 168 } | |
| 169 | |
| 170 Value* storedValue; | |
| 171 bool isNewEntry; | |
| 172 }; | |
| 173 | |
| 174 typedef typename HashTraits<Value>::PeekInType ValuePeekInType; | |
| 175 | |
| 176 void* operator new(size_t size) | |
|
Mads Ager (chromium)
2014/04/10 11:12:25
Did we now have a macro for this?
Erik Corry
2014/04/10 13:47:29
Done.
| |
| 177 { | |
| 178 return Allocator::template malloc<void*, LinkedHashSet>(size); | |
| 179 } | |
| 180 void operator delete(void* p) { Allocator::free(p); } | |
| 181 void* operator new[](size_t size) { return Allocator::template newArray<Link edHashSet>(size); } | |
| 182 void operator delete[](void* p) { Allocator::deleteArray(p); } | |
| 183 void* operator new(size_t, NotNullTag, void* location) | |
| 184 { | |
| 185 COMPILE_ASSERT(!Allocator::isGarbageCollected, Garbage_collector_must_be _disabled); | |
| 186 ASSERT(location); | |
| 187 return location; | |
| 188 } | |
| 189 | |
| 190 LinkedHashSet(); | |
| 191 LinkedHashSet(const LinkedHashSet&); | |
| 192 LinkedHashSet& operator=(const LinkedHashSet&); | |
| 193 ~LinkedHashSet(); | |
| 194 | |
| 195 static void finalize(void* pointer) { reinterpret_cast<LinkedHashSet*>(point er)->~LinkedHashSet(); } | |
| 196 | |
| 197 void swap(LinkedHashSet&); | |
| 198 | |
| 199 unsigned size() const { return m_impl.size(); } | |
| 200 unsigned capacity() const { return m_impl.capacity(); } | |
| 201 bool isEmpty() const { return m_impl.isEmpty(); } | |
| 202 | |
| 203 iterator begin() { return makeIterator(firstNode()); } | |
| 204 iterator end() { return makeIterator(anchor()); } | |
| 205 const_iterator begin() const { return makeConstIterator(firstNode()); } | |
| 206 const_iterator end() const { return makeConstIterator(anchor()); } | |
| 207 | |
| 208 reverse_iterator rbegin() { return makeReverseIterator(lastNode()); } | |
| 209 reverse_iterator rend() { return makeReverseIterator(anchor()); } | |
| 210 const_reverse_iterator rbegin() const { return makeConstReverseIterator(last Node()); } | |
| 211 const_reverse_iterator rend() const { return makeConstReverseIterator(anchor ()); } | |
| 212 | |
| 213 Value& first(); | |
| 214 const Value& first() const; | |
| 215 void removeFirst(); | |
| 216 | |
| 217 Value& last(); | |
| 218 const Value& last() const; | |
| 219 void removeLast(); | |
| 220 | |
| 221 iterator find(ValuePeekInType); | |
| 222 const_iterator find(ValuePeekInType) const; | |
| 223 bool contains(ValuePeekInType) const; | |
| 224 | |
| 225 // An alternate version of find() that finds the object by hashing and compa ring | |
| 226 // with some other type, to avoid the cost of type conversion. | |
| 227 // The HashTranslator interface is defined in HashSet. | |
| 228 template<typename HashTranslator, typename T> iterator find(const T&); | |
| 229 template<typename HashTranslator, typename T> const_iterator find(const T&) const; | |
| 230 template<typename HashTranslator, typename T> bool contains(const T&) const; | |
| 231 | |
| 232 // The return value of add is a pair of a pointer to the stored value, | |
| 233 // and a bool that is true if an new entry was added. | |
| 234 AddResult add(ValuePeekInType); | |
| 235 | |
| 236 // Same as add() except that the return value is an | |
| 237 // iterator. Useful in cases where it's needed to have the | |
| 238 // same return value as find() and where it's not possible to | |
| 239 // use a pointer to the storedValue. | |
| 240 iterator addReturnIterator(ValuePeekInType); | |
| 241 | |
| 242 // Add the value to the end of the collection. If the value was already in | |
| 243 // the list, it is moved to the end. | |
| 244 AddResult appendOrMoveToLast(ValuePeekInType); | |
| 245 | |
| 246 // Add the value to the beginning of the collection. If the value was alread y in | |
| 247 // the list, it is moved to the beginning. | |
| 248 AddResult prependOrMoveToFirst(ValuePeekInType); | |
| 249 | |
| 250 AddResult insertBefore(ValuePeekInType beforeValue, ValuePeekInType newValue ); | |
| 251 AddResult insertBefore(iterator it, ValuePeekInType newValue) { return m_imp l.template add<NodeHashFunctions>(newValue, it.node()); } | |
| 252 | |
| 253 void remove(ValuePeekInType); | |
| 254 void remove(iterator); | |
| 255 void clear() { m_impl.clear(); } | |
| 256 | |
| 257 void trace(typename Allocator::Visitor* visitor) { m_impl.trace(visitor); } | |
| 258 | |
| 259 int64_t modifications() const { return m_impl.modifications(); } | |
| 260 void checkModifications(int64_t mods) const { m_impl.checkModifications(mods ); } | |
|
Mikhail
2014/04/10 12:25:03
do we need those in release mode (or you think the
Erik Corry
2014/04/10 13:47:29
This one is only called from an assert.
The one wi
| |
| 261 | |
| 262 private: | |
| 263 Node* anchor() { return reinterpret_cast<Node*>(&m_anchor); } | |
| 264 const Node* anchor() const { return reinterpret_cast<const Node*>(&m_anchor) ; } | |
| 265 Node* firstNode() { return reinterpret_cast<Node*>(m_anchor.m_next); } | |
| 266 const Node* firstNode() const { return reinterpret_cast<const Node*>(m_ancho r.m_next); } | |
| 267 Node* lastNode() { return reinterpret_cast<Node*>(m_anchor.m_prev); } | |
| 268 const Node* lastNode() const { return reinterpret_cast<const Node*>(m_anchor .m_prev); } | |
| 269 | |
| 270 iterator makeIterator(const Node* position) { return iterator(position, this ); } | |
| 271 const_iterator makeConstIterator(const Node* position) const { return const_ iterator(position, this); } | |
| 272 reverse_iterator makeReverseIterator(const Node* position) { return reverse_ iterator(position, this); } | |
| 273 const_reverse_iterator makeConstReverseIterator(const Node* position) const { return const_reverse_iterator(position, this); } | |
| 274 | |
| 275 ImplType m_impl; | |
| 276 NodeBase m_anchor; | |
| 277 #ifndef ASSERT_ENABLED | |
| 278 uint64_t m_modifications; | |
| 279 #endif | |
| 280 }; | |
| 281 | |
| 282 template<typename Value, typename HashFunctions> | |
| 283 struct LinkedHashSetTranslator { | |
| 284 typedef LinkedHashSetNode<Value> Node; | |
| 285 typedef LinkedHashSetNodeBase NodeBase; | |
| 286 typedef typename HashTraits<Value>::PeekInType ValuePeekInType; | |
| 287 static unsigned hash(const Node& node) { return HashFunctions::hash(node.m_v alue); } | |
| 288 static unsigned hash(const ValuePeekInType& key) { return HashFunctions::has h(key); } | |
| 289 static bool equal(const Node& a, const ValuePeekInType& b) { return HashFunc tions::equal(a.m_value, b); } | |
| 290 static bool equal(const Node& a, const Node& b) { return HashFunctions::equa l(a.m_value, b.m_value); } | |
| 291 static void translate(Node& location, ValuePeekInType key, NodeBase* anchor) | |
| 292 { | |
| 293 location.m_value = key; | |
| 294 anchor->insertBefore(location); | |
| 295 } | |
| 296 | |
| 297 // Empty (or deleted) slots have the m_next pointer set to null, but we | |
| 298 // don't do anything to the other fields, which may contain junk. | |
| 299 // Therefore you can't compare a newly constructed empty value with a | |
| 300 // slot and get the right answer. | |
| 301 static const bool safeToCompareToEmptyOrDeleted = false; | |
| 302 }; | |
| 303 | |
| 304 template<typename Value> | |
| 305 struct LinkedHashSetExtractor { | |
| 306 static const Value& extract(const LinkedHashSetNode<Value>& node) { return n ode.m_value; } | |
| 307 }; | |
| 308 | |
| 309 template<typename Value, typename ValueTraitsArg> | |
| 310 struct LinkedHashSetTraits : public SimpleClassHashTraits<LinkedHashSetNode<Valu e> > { | |
| 311 typedef LinkedHashSetNode<Value> Node; | |
| 312 typedef ValueTraitsArg ValueTraits; | |
| 313 | |
| 314 // The slot is empty when the m_next field is zero so it's safe to zero | |
| 315 // the backing. | |
| 316 static const bool emptyValueIsZero = true; | |
| 317 | |
| 318 static const bool hasIsEmptyValueFunction = true; | |
| 319 static bool isEmptyValue(const Node& value) { return !value.m_next; } | |
| 320 | |
| 321 static const int deletedValue = -1; | |
| 322 | |
| 323 static void constructDeletedValue(Node& slot) { slot.m_next = reinterpret_ca st<Node*>(deletedValue); } | |
| 324 static bool isDeletedValue(const Node& slot) { return slot.m_next == reinter pret_cast<Node*>(deletedValue); } | |
| 325 | |
| 326 // We always need to call destructors, that's how we get linked and | |
| 327 // unlinked from the chain. | |
| 328 static const bool needsDestruction = true; | |
| 329 | |
| 330 // Whether we need to trace and do weak processing depends on the traits of | |
| 331 // the type inside the node. | |
| 332 template<typename U = void> | |
| 333 struct NeedsTracingLazily { | |
| 334 static const bool value = ValueTraits::template NeedsTracingLazily<>::va lue; | |
| 335 }; | |
| 336 static const bool isWeak = ValueTraits::isWeak; | |
| 337 }; | |
| 338 | |
| 339 template<typename LinkedHashSetType> | |
| 340 class LinkedHashSetIterator { | |
| 341 private: | |
| 342 typedef typename LinkedHashSetType::Node Node; | |
| 343 typedef typename LinkedHashSetType::Traits Traits; | |
| 344 | |
| 345 typedef typename LinkedHashSetType::Value& ReferenceType; | |
| 346 typedef typename LinkedHashSetType::Value* PointerType; | |
| 347 | |
| 348 typedef LinkedHashSetConstIterator<LinkedHashSetType> const_iterator; | |
| 349 | |
| 350 Node* node() const { return const_cast<Node*>(m_iterator.node()); } | |
|
Mikhail
2014/04/10 12:25:03
looks like it should not be a const method
Erik Corry
2014/04/10 13:47:29
Done.
| |
| 351 | |
| 352 protected: | |
| 353 LinkedHashSetIterator(const Node* position, LinkedHashSetType* m_container) | |
| 354 : m_iterator(position , m_container) | |
| 355 { | |
| 356 } | |
| 357 | |
| 358 public: | |
| 359 // Default copy, assignment and destructor are OK. | |
| 360 | |
| 361 PointerType get() const { return const_cast<PointerType>(m_iterator.get()); } | |
| 362 ReferenceType operator*() const { return *get(); } | |
| 363 PointerType operator->() const { return get(); } | |
| 364 | |
| 365 LinkedHashSetIterator& operator++() { ++m_iterator; return *this; } | |
| 366 LinkedHashSetIterator& operator--() { --m_iterator; return *this; } | |
| 367 | |
| 368 // Postfix ++ and -- intentionally omitted. | |
| 369 | |
| 370 // Comparison. | |
| 371 bool operator==(const LinkedHashSetIterator& other) const { return m_iterato r == other.m_iterator; } | |
| 372 bool operator!=(const LinkedHashSetIterator& other) const { return m_iterato r != other.m_iterator; } | |
| 373 | |
| 374 operator const_iterator() const { return m_iterator; } | |
| 375 | |
| 376 protected: | |
| 377 const_iterator m_iterator; | |
| 378 template<typename T, typename U, typename V, typename W> friend class Linked HashSet; | |
| 379 }; | |
| 380 | |
| 381 template<typename LinkedHashSetType> | |
| 382 class LinkedHashSetConstIterator { | |
| 383 private: | |
| 384 typedef typename LinkedHashSetType::Node Node; | |
| 385 typedef typename LinkedHashSetType::Traits Traits; | |
| 386 | |
| 387 typedef const typename LinkedHashSetType::Value& ReferenceType; | |
| 388 typedef const typename LinkedHashSetType::Value* PointerType; | |
| 389 | |
| 390 const Node* node() const { return static_cast<const Node*>(m_position); } | |
| 391 | |
| 392 protected: | |
| 393 LinkedHashSetConstIterator(const LinkedHashSetNodeBase* position, const Link edHashSetType* container) | |
| 394 : m_position(position) | |
| 395 #ifdef ASSERT_ENABLED | |
| 396 , m_container(container) | |
| 397 , m_containerModifications(container->modifications()) | |
| 398 #endif | |
| 399 { | |
| 400 } | |
| 401 | |
| 402 public: | |
| 403 PointerType get() const | |
| 404 { | |
| 405 checkModifications(); | |
| 406 return &static_cast<const Node*>(m_position)->m_value; | |
| 407 } | |
| 408 ReferenceType operator*() const { return *get(); } | |
| 409 PointerType operator->() const { return get(); } | |
| 410 | |
| 411 LinkedHashSetConstIterator& operator++() | |
| 412 { | |
| 413 ASSERT(m_position); | |
| 414 checkModifications(); | |
| 415 m_position = m_position->m_next; | |
| 416 return *this; | |
| 417 } | |
| 418 | |
| 419 LinkedHashSetConstIterator& operator--() | |
| 420 { | |
| 421 ASSERT(m_position); | |
| 422 checkModifications(); | |
| 423 m_position = m_position->m_prev; | |
| 424 return *this; | |
| 425 } | |
| 426 | |
| 427 // Postfix ++ and -- intentionally omitted. | |
| 428 | |
| 429 // Comparison. | |
| 430 bool operator==(const LinkedHashSetConstIterator& other) const | |
| 431 { | |
| 432 return m_position == other.m_position; | |
| 433 } | |
| 434 bool operator!=(const LinkedHashSetConstIterator& other) const | |
| 435 { | |
| 436 return m_position != other.m_position; | |
| 437 } | |
| 438 | |
| 439 private: | |
| 440 const LinkedHashSetNodeBase* m_position; | |
| 441 #ifdef ASSERT_ENABLED | |
| 442 void checkModifications() const { m_container->checkModifications(m_containe rModifications); } | |
| 443 const LinkedHashSetType* m_container; | |
| 444 int64_t m_containerModifications; | |
| 445 #else | |
| 446 void checkModifications() const { } | |
| 447 #endif | |
| 448 template<typename T, typename U, typename V, typename W> friend class Linked HashSet; | |
| 449 friend class LinkedHashSetIterator<LinkedHashSetType>; | |
| 450 }; | |
| 451 | |
| 452 template<typename LinkedHashSetType> | |
| 453 class LinkedHashSetReverseIterator : public LinkedHashSetIterator<LinkedHashSetT ype> { | |
| 454 typedef LinkedHashSetIterator<LinkedHashSetType> Superclass; | |
| 455 typedef LinkedHashSetConstReverseIterator<LinkedHashSetType> const_reverse_i terator; | |
| 456 typedef typename LinkedHashSetType::Node Node; | |
| 457 | |
| 458 protected: | |
| 459 LinkedHashSetReverseIterator(const Node* position, LinkedHashSetType* contai ner) | |
| 460 : Superclass(position, container) { } | |
| 461 | |
| 462 public: | |
| 463 LinkedHashSetReverseIterator& operator++() { Superclass::operator--(); retur n *this; } | |
| 464 LinkedHashSetReverseIterator& operator--() { Superclass::operator++(); retur n *this; } | |
| 465 | |
| 466 // Postfix ++ and -- intentionally omitted. | |
| 467 | |
| 468 operator const_reverse_iterator() const { return *reinterpret_cast<const_rev erse_iterator*>(this); } | |
| 469 | |
| 470 template<typename T, typename U, typename V, typename W> friend class Linked HashSet; | |
| 471 }; | |
| 472 | |
| 473 template<typename LinkedHashSetType> | |
| 474 class LinkedHashSetConstReverseIterator : public LinkedHashSetConstIterator<Link edHashSetType> { | |
| 475 typedef LinkedHashSetConstIterator<LinkedHashSetType> Superclass; | |
| 476 typedef typename LinkedHashSetType::Node Node; | |
| 477 | |
| 478 public: | |
| 479 LinkedHashSetConstReverseIterator(const Node* position, const LinkedHashSetT ype* container) | |
| 480 : Superclass(position, container) { } | |
| 481 | |
| 482 LinkedHashSetConstReverseIterator& operator++() { Superclass::operator--(); return *this; } | |
| 483 LinkedHashSetConstReverseIterator& operator--() { Superclass::operator++(); return *this; } | |
| 484 | |
| 485 // Postfix ++ and -- intentionally omitted. | |
| 486 | |
| 487 template<typename T, typename U, typename V, typename W> friend class Linked HashSet; | |
| 488 }; | |
| 489 | |
| 490 template<typename T, typename U, typename V, typename W> | |
| 491 inline LinkedHashSet<T, U, V, W>::LinkedHashSet() { } | |
| 492 | |
| 493 template<typename T, typename U, typename V, typename W> | |
| 494 inline LinkedHashSet<T, U, V, W>::LinkedHashSet(const LinkedHashSet& other) | |
| 495 : m_anchor() | |
| 496 { | |
| 497 const_iterator end = other.end(); | |
| 498 for (const_iterator it = other.begin(); it != end; ++it) | |
| 499 add(*it); | |
| 500 } | |
| 501 | |
| 502 template<typename T, typename U, typename V, typename W> | |
| 503 inline LinkedHashSet<T, U, V, W>& LinkedHashSet<T, U, V, W>::operator=(const Lin kedHashSet& other) | |
| 504 { | |
| 505 LinkedHashSet tmp(other); | |
| 506 swap(tmp); | |
| 507 return *this; | |
| 508 } | |
| 509 | |
| 510 template<typename T, typename U, typename V, typename W> | |
| 511 inline void LinkedHashSet<T, U, V, W>::swap(LinkedHashSet& other) | |
| 512 { | |
| 513 m_impl.swap(other.m_impl); | |
| 514 swap(m_anchor, other.m_anchor); | |
| 515 } | |
| 516 | |
| 517 template<typename T, typename U, typename V, typename Allocator> | |
| 518 inline LinkedHashSet<T, U, V, Allocator>::~LinkedHashSet() | |
| 519 { | |
| 520 // The destructor of m_anchor will implicitly be called here, which will | |
| 521 // unlink the anchor from the collection. | |
| 522 } | |
| 523 | |
| 524 template<typename T, typename U, typename V, typename W> | |
| 525 inline T& LinkedHashSet<T, U, V, W>::first() | |
| 526 { | |
| 527 ASSERT(!isEmpty()); | |
| 528 return firstNode()->m_value; | |
| 529 } | |
| 530 | |
| 531 template<typename T, typename U, typename V, typename W> | |
| 532 inline const T& LinkedHashSet<T, U, V, W>::first() const | |
| 533 { | |
| 534 ASSERT(!isEmpty()); | |
| 535 return firstNode()->m_value; | |
| 536 } | |
| 537 | |
| 538 template<typename T, typename U, typename V, typename W> | |
| 539 inline void LinkedHashSet<T, U, V, W>::removeFirst() | |
| 540 { | |
| 541 ASSERT(!isEmpty()); | |
| 542 m_impl.remove(static_cast<Node*>(m_anchor.m_next)); | |
| 543 } | |
| 544 | |
| 545 template<typename T, typename U, typename V, typename W> | |
| 546 inline T& LinkedHashSet<T, U, V, W>::last() | |
| 547 { | |
| 548 ASSERT(!isEmpty()); | |
| 549 return lastNode()->m_value; | |
| 550 } | |
| 551 | |
| 552 template<typename T, typename U, typename V, typename W> | |
| 553 inline const T& LinkedHashSet<T, U, V, W>::last() const | |
| 554 { | |
| 555 ASSERT(!isEmpty()); | |
| 556 return lastNode()->m_value; | |
| 557 } | |
| 558 | |
| 559 template<typename T, typename U, typename V, typename W> | |
| 560 inline void LinkedHashSet<T, U, V, W>::removeLast() | |
| 561 { | |
| 562 ASSERT(!isEmpty()); | |
| 563 m_impl.remove(static_cast<Node*>(m_anchor.m_prev)); | |
| 564 } | |
| 565 | |
| 566 template<typename T, typename U, typename V, typename W> | |
| 567 inline typename LinkedHashSet<T, U, V, W>::iterator LinkedHashSet<T, U, V, W>::f ind(ValuePeekInType value) | |
| 568 { | |
| 569 LinkedHashSet::Node* node = m_impl.template lookup<LinkedHashSet::NodeHashFu nctions, ValuePeekInType>(value); | |
| 570 if (!node) | |
| 571 return end(); | |
| 572 return makeIterator(node); | |
| 573 } | |
| 574 | |
| 575 template<typename T, typename U, typename V, typename W> | |
| 576 inline typename LinkedHashSet<T, U, V, W>::const_iterator LinkedHashSet<T, U, V, W>::find(ValuePeekInType value) const | |
| 577 { | |
| 578 const LinkedHashSet::Node* node = m_impl.template lookup<LinkedHashSet::Node HashFunctions, ValuePeekInType>(value); | |
| 579 if (!node) | |
| 580 return end(); | |
| 581 return makeConstIterator(node); | |
| 582 } | |
| 583 | |
| 584 template<typename Value, typename U, typename V, typename W> | |
| 585 template<typename HashTranslator, typename T> | |
| 586 inline typename LinkedHashSet<Value, U, V, W>::iterator LinkedHashSet<Value, U, V, W>::find(const T& value) | |
| 587 { | |
| 588 iterator it = begin(); | |
| 589 iterator endIterator = end(); | |
|
Erik Corry
2014/04/10 10:53:06
I need to fix this implementation to not loop.
Erik Corry
2014/04/10 13:47:29
Done.
| |
| 590 while (it != endIterator && !HashTranslator::template equal<Value, T>(it->m_ value, value)) | |
| 591 ++it; | |
| 592 return it; | |
| 593 } | |
| 594 | |
| 595 template<typename Value, typename U, typename V, typename W> | |
| 596 template<typename HashTranslator, typename T> | |
| 597 inline typename LinkedHashSet<Value, U, V, W>::const_iterator LinkedHashSet<Valu e, U, V, W>::find(const T& value) const | |
| 598 { | |
| 599 const_iterator it = begin(); | |
| 600 const_iterator endIterator = end(); | |
| 601 while (it != endIterator && !HashTranslator::template equal<Value, T>(it->m_ value, value)) | |
| 602 ++it; | |
| 603 return it; | |
| 604 } | |
| 605 | |
| 606 template<typename Translator> | |
| 607 struct LinkedHashSetTranslatorAdapter { | |
| 608 template<typename T> static unsigned hash(const T& key) { return Translator: :hash(key); } | |
| 609 template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a->m_value, b); } | |
| 610 }; | |
| 611 | |
| 612 template<typename Value, typename U, typename V, typename W> | |
| 613 template<typename HashTranslator, typename T> | |
| 614 inline bool LinkedHashSet<Value, U, V, W>::contains(const T& value) const | |
| 615 { | |
| 616 return m_impl.template contains<LinkedHashSetTranslatorAdapter<HashTranslato r> >(value); | |
| 617 } | |
| 618 | |
| 619 template<typename T, typename U, typename V, typename W> | |
| 620 inline bool LinkedHashSet<T, U, V, W>::contains(ValuePeekInType value) const | |
| 621 { | |
| 622 return m_impl.template contains<NodeHashFunctions>(value); | |
| 623 } | |
| 624 | |
| 625 template<typename Value, typename HashFunctions, typename Traits, typename Alloc ator> | |
| 626 typename LinkedHashSet<Value, HashFunctions, Traits, Allocator>::AddResult Linke dHashSet<Value, HashFunctions, Traits, Allocator>::add(ValuePeekInType value) | |
| 627 { | |
| 628 return m_impl.template add<NodeHashFunctions>(value, &m_anchor); | |
| 629 } | |
| 630 | |
| 631 template<typename T, typename U, typename V, typename W> | |
| 632 typename LinkedHashSet<T, U, V, W>::iterator LinkedHashSet<T, U, V, W>::addRetur nIterator(ValuePeekInType value) | |
| 633 { | |
| 634 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions> (value, &m_anchor); | |
| 635 return makeIterator(result.storedValue); | |
| 636 } | |
| 637 | |
| 638 template<typename T, typename U, typename V, typename W> | |
| 639 typename LinkedHashSet<T, U, V, W>::AddResult LinkedHashSet<T, U, V, W>::appendO rMoveToLast(ValuePeekInType value) | |
| 640 { | |
| 641 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions> (value, &m_anchor); | |
| 642 Node* node = result.storedValue; | |
| 643 if (!result.isNewEntry) { | |
| 644 node->unlink(); | |
| 645 m_anchor.insertBefore(*node); | |
| 646 } | |
| 647 return result; | |
| 648 } | |
| 649 | |
| 650 template<typename T, typename U, typename V, typename W> | |
| 651 typename LinkedHashSet<T, U, V, W>::AddResult LinkedHashSet<T, U, V, W>::prepend OrMoveToFirst(ValuePeekInType value) | |
| 652 { | |
| 653 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions> (value, m_anchor.m_next); | |
| 654 Node* node = result.storedValue; | |
| 655 if (!result.isNewEntry) { | |
| 656 node->unlink(); | |
| 657 m_anchor.insertAfter(*node); | |
| 658 } | |
| 659 return result; | |
| 660 } | |
| 661 | |
| 662 template<typename T, typename U, typename V, typename W> | |
| 663 typename LinkedHashSet<T, U, V, W>::AddResult LinkedHashSet<T, U, V, W>::insertB efore(ValuePeekInType beforeValue, ValuePeekInType newValue) | |
| 664 { | |
| 665 return insertBefore(find(beforeValue), newValue); | |
| 666 } | |
| 667 | |
| 668 template<typename T, typename U, typename V, typename W> | |
| 669 inline void LinkedHashSet<T, U, V, W>::remove(iterator it) | |
| 670 { | |
| 671 if (it == end()) | |
| 672 return; | |
| 673 m_impl.remove(it.node()); | |
| 674 } | |
| 675 | |
| 676 template<typename T, typename U, typename V, typename W> | |
| 677 inline void LinkedHashSet<T, U, V, W>::remove(ValuePeekInType value) | |
| 678 { | |
| 679 remove(find(value)); | |
| 680 } | |
| 681 | |
| 682 template<typename T> | |
| 683 struct IsWeak<LinkedHashSetNode<T> > { | |
| 684 static const bool value = IsWeak<T>::value; | |
| 685 }; | |
| 686 | |
| 687 inline void swap(LinkedHashSetNodeBase& a, LinkedHashSetNodeBase& b) | |
| 688 { | |
| 689 typedef LinkedHashSetNodeBase Base; | |
| 690 swap(a.m_next, b.m_next); | |
| 691 swap(a.m_prev, b.m_prev); | |
| 692 if (b.m_next) { | |
| 693 b.m_next->m_prev = &b; | |
| 694 b.m_prev->m_next = &b; | |
| 695 } | |
| 696 if (a.m_next) { | |
| 697 a.m_next->m_prev = &a; | |
| 698 a.m_prev->m_next = &a; | |
| 699 } | |
| 700 } | |
| 701 | |
| 702 template<typename T> | |
| 703 inline void swap(LinkedHashSetNode<T>& a, LinkedHashSetNode<T>& b) | |
| 704 { | |
| 705 typedef LinkedHashSetNodeBase Base; | |
| 706 | |
| 707 swap(static_cast<Base&>(a), static_cast<Base&>(b)); | |
| 708 | |
| 709 using namespace std; | |
|
Mads Ager (chromium)
2014/04/10 11:12:25
I thought we were not doing this?
Erik Corry
2014/04/10 13:47:29
I was a bit confused too, but the check-webkit-sty
Erik Corry
2014/04/10 13:53:07
Or I could just remove the using directive complet
| |
| 710 swap(a.m_value, b.m_value); | |
| 711 } | |
| 712 | |
| 713 } | |
| 714 | |
| 715 using WTF::LinkedHashSet; | |
| 716 | |
| 717 #endif /* WTF_LinkedHashSet_h */ | |
| OLD | NEW |