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&); |
| 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 WTF_USE_ALLOCATOR(LinkedHashSet); |
| 142 private: |
| 143 typedef ValueArg Value; |
| 144 typedef TraitsArg Traits; |
| 145 typedef LinkedHashSetNode<Value> Node; |
| 146 typedef LinkedHashSetNodeBase NodeBase; |
| 147 typedef LinkedHashSetTranslator<Value, HashFunctions> NodeHashFunctions; |
| 148 typedef LinkedHashSetTraits<Value, Traits> NodeHashTraits; |
| 149 |
| 150 typedef HashTable<Node, Node, IdentityExtractor, |
| 151 NodeHashFunctions, NodeHashTraits, NodeHashTraits, Allocator> ImplType; |
| 152 |
| 153 public: |
| 154 typedef LinkedHashSetIterator<LinkedHashSet> iterator; |
| 155 friend class LinkedHashSetIterator<LinkedHashSet>; |
| 156 typedef LinkedHashSetConstIterator<LinkedHashSet> const_iterator; |
| 157 friend class LinkedHashSetConstIterator<LinkedHashSet>; |
| 158 |
| 159 typedef LinkedHashSetReverseIterator<LinkedHashSet> reverse_iterator; |
| 160 friend class LinkedHashSetReverseIterator<LinkedHashSet>; |
| 161 typedef LinkedHashSetConstReverseIterator<LinkedHashSet> const_reverse_itera
tor; |
| 162 friend class LinkedHashSetConstReverseIterator<LinkedHashSet>; |
| 163 |
| 164 struct AddResult { |
| 165 AddResult(const typename ImplType::AddResult& hashTableAddResult) |
| 166 : storedValue(&hashTableAddResult.storedValue->m_value) |
| 167 , isNewEntry(hashTableAddResult.isNewEntry) |
| 168 { |
| 169 } |
| 170 |
| 171 Value* storedValue; |
| 172 bool isNewEntry; |
| 173 }; |
| 174 |
| 175 typedef typename HashTraits<Value>::PeekInType ValuePeekInType; |
| 176 |
| 177 LinkedHashSet(); |
| 178 LinkedHashSet(const LinkedHashSet&); |
| 179 LinkedHashSet& operator=(const LinkedHashSet&); |
| 180 ~LinkedHashSet(); |
| 181 |
| 182 static void finalize(void* pointer) { reinterpret_cast<LinkedHashSet*>(point
er)->~LinkedHashSet(); } |
| 183 |
| 184 void swap(LinkedHashSet&); |
| 185 |
| 186 unsigned size() const { return m_impl.size(); } |
| 187 unsigned capacity() const { return m_impl.capacity(); } |
| 188 bool isEmpty() const { return m_impl.isEmpty(); } |
| 189 |
| 190 iterator begin() { return makeIterator(firstNode()); } |
| 191 iterator end() { return makeIterator(anchor()); } |
| 192 const_iterator begin() const { return makeConstIterator(firstNode()); } |
| 193 const_iterator end() const { return makeConstIterator(anchor()); } |
| 194 |
| 195 reverse_iterator rbegin() { return makeReverseIterator(lastNode()); } |
| 196 reverse_iterator rend() { return makeReverseIterator(anchor()); } |
| 197 const_reverse_iterator rbegin() const { return makeConstReverseIterator(last
Node()); } |
| 198 const_reverse_iterator rend() const { return makeConstReverseIterator(anchor
()); } |
| 199 |
| 200 Value& first(); |
| 201 const Value& first() const; |
| 202 void removeFirst(); |
| 203 |
| 204 Value& last(); |
| 205 const Value& last() const; |
| 206 void removeLast(); |
| 207 |
| 208 iterator find(ValuePeekInType); |
| 209 const_iterator find(ValuePeekInType) const; |
| 210 bool contains(ValuePeekInType) const; |
| 211 |
| 212 // An alternate version of find() that finds the object by hashing and compa
ring |
| 213 // with some other type, to avoid the cost of type conversion. |
| 214 // The HashTranslator interface is defined in HashSet. |
| 215 template<typename HashTranslator, typename T> iterator find(const T&); |
| 216 template<typename HashTranslator, typename T> const_iterator find(const T&)
const; |
| 217 template<typename HashTranslator, typename T> bool contains(const T&) const; |
| 218 |
| 219 // The return value of add is a pair of a pointer to the stored value, |
| 220 // and a bool that is true if an new entry was added. |
| 221 AddResult add(ValuePeekInType); |
| 222 |
| 223 // Same as add() except that the return value is an |
| 224 // iterator. Useful in cases where it's needed to have the |
| 225 // same return value as find() and where it's not possible to |
| 226 // use a pointer to the storedValue. |
| 227 iterator addReturnIterator(ValuePeekInType); |
| 228 |
| 229 // Add the value to the end of the collection. If the value was already in |
| 230 // the list, it is moved to the end. |
| 231 AddResult appendOrMoveToLast(ValuePeekInType); |
| 232 |
| 233 // Add the value to the beginning of the collection. If the value was alread
y in |
| 234 // the list, it is moved to the beginning. |
| 235 AddResult prependOrMoveToFirst(ValuePeekInType); |
| 236 |
| 237 AddResult insertBefore(ValuePeekInType beforeValue, ValuePeekInType newValue
); |
| 238 AddResult insertBefore(iterator it, ValuePeekInType newValue) { return m_imp
l.template add<NodeHashFunctions>(newValue, it.node()); } |
| 239 |
| 240 void remove(ValuePeekInType); |
| 241 void remove(iterator); |
| 242 void clear() { m_impl.clear(); } |
| 243 |
| 244 void trace(typename Allocator::Visitor* visitor) { m_impl.trace(visitor); } |
| 245 |
| 246 int64_t modifications() const { return m_impl.modifications(); } |
| 247 void checkModifications(int64_t mods) const { m_impl.checkModifications(mods
); } |
| 248 |
| 249 private: |
| 250 Node* anchor() { return reinterpret_cast<Node*>(&m_anchor); } |
| 251 const Node* anchor() const { return reinterpret_cast<const Node*>(&m_anchor)
; } |
| 252 Node* firstNode() { return reinterpret_cast<Node*>(m_anchor.m_next); } |
| 253 const Node* firstNode() const { return reinterpret_cast<const Node*>(m_ancho
r.m_next); } |
| 254 Node* lastNode() { return reinterpret_cast<Node*>(m_anchor.m_prev); } |
| 255 const Node* lastNode() const { return reinterpret_cast<const Node*>(m_anchor
.m_prev); } |
| 256 |
| 257 iterator makeIterator(const Node* position) { return iterator(position, this
); } |
| 258 const_iterator makeConstIterator(const Node* position) const { return const_
iterator(position, this); } |
| 259 reverse_iterator makeReverseIterator(const Node* position) { return reverse_
iterator(position, this); } |
| 260 const_reverse_iterator makeConstReverseIterator(const Node* position) const
{ return const_reverse_iterator(position, this); } |
| 261 |
| 262 ImplType m_impl; |
| 263 NodeBase m_anchor; |
| 264 #ifndef ASSERT_ENABLED |
| 265 uint64_t m_modifications; |
| 266 #endif |
| 267 }; |
| 268 |
| 269 template<typename Value, typename HashFunctions> |
| 270 struct LinkedHashSetTranslator { |
| 271 typedef LinkedHashSetNode<Value> Node; |
| 272 typedef LinkedHashSetNodeBase NodeBase; |
| 273 typedef typename HashTraits<Value>::PeekInType ValuePeekInType; |
| 274 static unsigned hash(const Node& node) { return HashFunctions::hash(node.m_v
alue); } |
| 275 static unsigned hash(const ValuePeekInType& key) { return HashFunctions::has
h(key); } |
| 276 static bool equal(const Node& a, const ValuePeekInType& b) { return HashFunc
tions::equal(a.m_value, b); } |
| 277 static bool equal(const Node& a, const Node& b) { return HashFunctions::equa
l(a.m_value, b.m_value); } |
| 278 static void translate(Node& location, ValuePeekInType key, NodeBase* anchor) |
| 279 { |
| 280 location.m_value = key; |
| 281 anchor->insertBefore(location); |
| 282 } |
| 283 |
| 284 // Empty (or deleted) slots have the m_next pointer set to null, but we |
| 285 // don't do anything to the other fields, which may contain junk. |
| 286 // Therefore you can't compare a newly constructed empty value with a |
| 287 // slot and get the right answer. |
| 288 static const bool safeToCompareToEmptyOrDeleted = false; |
| 289 }; |
| 290 |
| 291 template<typename Value> |
| 292 struct LinkedHashSetExtractor { |
| 293 static const Value& extract(const LinkedHashSetNode<Value>& node) { return n
ode.m_value; } |
| 294 }; |
| 295 |
| 296 template<typename Value, typename ValueTraitsArg> |
| 297 struct LinkedHashSetTraits : public SimpleClassHashTraits<LinkedHashSetNode<Valu
e> > { |
| 298 typedef LinkedHashSetNode<Value> Node; |
| 299 typedef ValueTraitsArg ValueTraits; |
| 300 |
| 301 // The slot is empty when the m_next field is zero so it's safe to zero |
| 302 // the backing. |
| 303 static const bool emptyValueIsZero = true; |
| 304 |
| 305 static const bool hasIsEmptyValueFunction = true; |
| 306 static bool isEmptyValue(const Node& value) { return !value.m_next; } |
| 307 |
| 308 static const int deletedValue = -1; |
| 309 |
| 310 static void constructDeletedValue(Node& slot) { slot.m_next = reinterpret_ca
st<Node*>(deletedValue); } |
| 311 static bool isDeletedValue(const Node& slot) { return slot.m_next == reinter
pret_cast<Node*>(deletedValue); } |
| 312 |
| 313 // We always need to call destructors, that's how we get linked and |
| 314 // unlinked from the chain. |
| 315 static const bool needsDestruction = true; |
| 316 |
| 317 // Whether we need to trace and do weak processing depends on the traits of |
| 318 // the type inside the node. |
| 319 template<typename U = void> |
| 320 struct NeedsTracingLazily { |
| 321 static const bool value = ValueTraits::template NeedsTracingLazily<>::va
lue; |
| 322 }; |
| 323 static const bool isWeak = ValueTraits::isWeak; |
| 324 }; |
| 325 |
| 326 template<typename LinkedHashSetType> |
| 327 class LinkedHashSetIterator { |
| 328 private: |
| 329 typedef typename LinkedHashSetType::Node Node; |
| 330 typedef typename LinkedHashSetType::Traits Traits; |
| 331 |
| 332 typedef typename LinkedHashSetType::Value& ReferenceType; |
| 333 typedef typename LinkedHashSetType::Value* PointerType; |
| 334 |
| 335 typedef LinkedHashSetConstIterator<LinkedHashSetType> const_iterator; |
| 336 |
| 337 Node* node() { return const_cast<Node*>(m_iterator.node()); } |
| 338 |
| 339 protected: |
| 340 LinkedHashSetIterator(const Node* position, LinkedHashSetType* m_container) |
| 341 : m_iterator(position , m_container) |
| 342 { |
| 343 } |
| 344 |
| 345 public: |
| 346 // Default copy, assignment and destructor are OK. |
| 347 |
| 348 PointerType get() const { return const_cast<PointerType>(m_iterator.get());
} |
| 349 ReferenceType operator*() const { return *get(); } |
| 350 PointerType operator->() const { return get(); } |
| 351 |
| 352 LinkedHashSetIterator& operator++() { ++m_iterator; return *this; } |
| 353 LinkedHashSetIterator& operator--() { --m_iterator; return *this; } |
| 354 |
| 355 // Postfix ++ and -- intentionally omitted. |
| 356 |
| 357 // Comparison. |
| 358 bool operator==(const LinkedHashSetIterator& other) const { return m_iterato
r == other.m_iterator; } |
| 359 bool operator!=(const LinkedHashSetIterator& other) const { return m_iterato
r != other.m_iterator; } |
| 360 |
| 361 operator const_iterator() const { return m_iterator; } |
| 362 |
| 363 protected: |
| 364 const_iterator m_iterator; |
| 365 template<typename T, typename U, typename V, typename W> friend class Linked
HashSet; |
| 366 }; |
| 367 |
| 368 template<typename LinkedHashSetType> |
| 369 class LinkedHashSetConstIterator { |
| 370 private: |
| 371 typedef typename LinkedHashSetType::Node Node; |
| 372 typedef typename LinkedHashSetType::Traits Traits; |
| 373 |
| 374 typedef const typename LinkedHashSetType::Value& ReferenceType; |
| 375 typedef const typename LinkedHashSetType::Value* PointerType; |
| 376 |
| 377 const Node* node() const { return static_cast<const Node*>(m_position); } |
| 378 |
| 379 protected: |
| 380 LinkedHashSetConstIterator(const LinkedHashSetNodeBase* position, const Link
edHashSetType* container) |
| 381 : m_position(position) |
| 382 #ifdef ASSERT_ENABLED |
| 383 , m_container(container) |
| 384 , m_containerModifications(container->modifications()) |
| 385 #endif |
| 386 { |
| 387 } |
| 388 |
| 389 public: |
| 390 PointerType get() const |
| 391 { |
| 392 checkModifications(); |
| 393 return &static_cast<const Node*>(m_position)->m_value; |
| 394 } |
| 395 ReferenceType operator*() const { return *get(); } |
| 396 PointerType operator->() const { return get(); } |
| 397 |
| 398 LinkedHashSetConstIterator& operator++() |
| 399 { |
| 400 ASSERT(m_position); |
| 401 checkModifications(); |
| 402 m_position = m_position->m_next; |
| 403 return *this; |
| 404 } |
| 405 |
| 406 LinkedHashSetConstIterator& operator--() |
| 407 { |
| 408 ASSERT(m_position); |
| 409 checkModifications(); |
| 410 m_position = m_position->m_prev; |
| 411 return *this; |
| 412 } |
| 413 |
| 414 // Postfix ++ and -- intentionally omitted. |
| 415 |
| 416 // Comparison. |
| 417 bool operator==(const LinkedHashSetConstIterator& other) const |
| 418 { |
| 419 return m_position == other.m_position; |
| 420 } |
| 421 bool operator!=(const LinkedHashSetConstIterator& other) const |
| 422 { |
| 423 return m_position != other.m_position; |
| 424 } |
| 425 |
| 426 private: |
| 427 const LinkedHashSetNodeBase* m_position; |
| 428 #ifdef ASSERT_ENABLED |
| 429 void checkModifications() const { m_container->checkModifications(m_containe
rModifications); } |
| 430 const LinkedHashSetType* m_container; |
| 431 int64_t m_containerModifications; |
| 432 #else |
| 433 void checkModifications() const { } |
| 434 #endif |
| 435 template<typename T, typename U, typename V, typename W> friend class Linked
HashSet; |
| 436 friend class LinkedHashSetIterator<LinkedHashSetType>; |
| 437 }; |
| 438 |
| 439 template<typename LinkedHashSetType> |
| 440 class LinkedHashSetReverseIterator : public LinkedHashSetIterator<LinkedHashSetT
ype> { |
| 441 typedef LinkedHashSetIterator<LinkedHashSetType> Superclass; |
| 442 typedef LinkedHashSetConstReverseIterator<LinkedHashSetType> const_reverse_i
terator; |
| 443 typedef typename LinkedHashSetType::Node Node; |
| 444 |
| 445 protected: |
| 446 LinkedHashSetReverseIterator(const Node* position, LinkedHashSetType* contai
ner) |
| 447 : Superclass(position, container) { } |
| 448 |
| 449 public: |
| 450 LinkedHashSetReverseIterator& operator++() { Superclass::operator--(); retur
n *this; } |
| 451 LinkedHashSetReverseIterator& operator--() { Superclass::operator++(); retur
n *this; } |
| 452 |
| 453 // Postfix ++ and -- intentionally omitted. |
| 454 |
| 455 operator const_reverse_iterator() const { return *reinterpret_cast<const_rev
erse_iterator*>(this); } |
| 456 |
| 457 template<typename T, typename U, typename V, typename W> friend class Linked
HashSet; |
| 458 }; |
| 459 |
| 460 template<typename LinkedHashSetType> |
| 461 class LinkedHashSetConstReverseIterator : public LinkedHashSetConstIterator<Link
edHashSetType> { |
| 462 typedef LinkedHashSetConstIterator<LinkedHashSetType> Superclass; |
| 463 typedef typename LinkedHashSetType::Node Node; |
| 464 |
| 465 public: |
| 466 LinkedHashSetConstReverseIterator(const Node* position, const LinkedHashSetT
ype* container) |
| 467 : Superclass(position, container) { } |
| 468 |
| 469 LinkedHashSetConstReverseIterator& operator++() { Superclass::operator--();
return *this; } |
| 470 LinkedHashSetConstReverseIterator& operator--() { Superclass::operator++();
return *this; } |
| 471 |
| 472 // Postfix ++ and -- intentionally omitted. |
| 473 |
| 474 template<typename T, typename U, typename V, typename W> friend class Linked
HashSet; |
| 475 }; |
| 476 |
| 477 template<typename T, typename U, typename V, typename W> |
| 478 inline LinkedHashSet<T, U, V, W>::LinkedHashSet() { } |
| 479 |
| 480 template<typename T, typename U, typename V, typename W> |
| 481 inline LinkedHashSet<T, U, V, W>::LinkedHashSet(const LinkedHashSet& other) |
| 482 : m_anchor() |
| 483 { |
| 484 const_iterator end = other.end(); |
| 485 for (const_iterator it = other.begin(); it != end; ++it) |
| 486 add(*it); |
| 487 } |
| 488 |
| 489 template<typename T, typename U, typename V, typename W> |
| 490 inline LinkedHashSet<T, U, V, W>& LinkedHashSet<T, U, V, W>::operator=(const Lin
kedHashSet& other) |
| 491 { |
| 492 LinkedHashSet tmp(other); |
| 493 swap(tmp); |
| 494 return *this; |
| 495 } |
| 496 |
| 497 template<typename T, typename U, typename V, typename W> |
| 498 inline void LinkedHashSet<T, U, V, W>::swap(LinkedHashSet& other) |
| 499 { |
| 500 m_impl.swap(other.m_impl); |
| 501 swap(m_anchor, other.m_anchor); |
| 502 } |
| 503 |
| 504 template<typename T, typename U, typename V, typename Allocator> |
| 505 inline LinkedHashSet<T, U, V, Allocator>::~LinkedHashSet() |
| 506 { |
| 507 // The destructor of m_anchor will implicitly be called here, which will |
| 508 // unlink the anchor from the collection. |
| 509 } |
| 510 |
| 511 template<typename T, typename U, typename V, typename W> |
| 512 inline T& LinkedHashSet<T, U, V, W>::first() |
| 513 { |
| 514 ASSERT(!isEmpty()); |
| 515 return firstNode()->m_value; |
| 516 } |
| 517 |
| 518 template<typename T, typename U, typename V, typename W> |
| 519 inline const T& LinkedHashSet<T, U, V, W>::first() const |
| 520 { |
| 521 ASSERT(!isEmpty()); |
| 522 return firstNode()->m_value; |
| 523 } |
| 524 |
| 525 template<typename T, typename U, typename V, typename W> |
| 526 inline void LinkedHashSet<T, U, V, W>::removeFirst() |
| 527 { |
| 528 ASSERT(!isEmpty()); |
| 529 m_impl.remove(static_cast<Node*>(m_anchor.m_next)); |
| 530 } |
| 531 |
| 532 template<typename T, typename U, typename V, typename W> |
| 533 inline T& LinkedHashSet<T, U, V, W>::last() |
| 534 { |
| 535 ASSERT(!isEmpty()); |
| 536 return lastNode()->m_value; |
| 537 } |
| 538 |
| 539 template<typename T, typename U, typename V, typename W> |
| 540 inline const T& LinkedHashSet<T, U, V, W>::last() const |
| 541 { |
| 542 ASSERT(!isEmpty()); |
| 543 return lastNode()->m_value; |
| 544 } |
| 545 |
| 546 template<typename T, typename U, typename V, typename W> |
| 547 inline void LinkedHashSet<T, U, V, W>::removeLast() |
| 548 { |
| 549 ASSERT(!isEmpty()); |
| 550 m_impl.remove(static_cast<Node*>(m_anchor.m_prev)); |
| 551 } |
| 552 |
| 553 template<typename T, typename U, typename V, typename W> |
| 554 inline typename LinkedHashSet<T, U, V, W>::iterator LinkedHashSet<T, U, V, W>::f
ind(ValuePeekInType value) |
| 555 { |
| 556 LinkedHashSet::Node* node = m_impl.template lookup<LinkedHashSet::NodeHashFu
nctions, ValuePeekInType>(value); |
| 557 if (!node) |
| 558 return end(); |
| 559 return makeIterator(node); |
| 560 } |
| 561 |
| 562 template<typename T, typename U, typename V, typename W> |
| 563 inline typename LinkedHashSet<T, U, V, W>::const_iterator LinkedHashSet<T, U, V,
W>::find(ValuePeekInType value) const |
| 564 { |
| 565 const LinkedHashSet::Node* node = m_impl.template lookup<LinkedHashSet::Node
HashFunctions, ValuePeekInType>(value); |
| 566 if (!node) |
| 567 return end(); |
| 568 return makeConstIterator(node); |
| 569 } |
| 570 |
| 571 template<typename Translator> |
| 572 struct LinkedHashSetTranslatorAdapter { |
| 573 template<typename T> static unsigned hash(const T& key) { return Translator:
:hash(key); } |
| 574 template<typename T, typename U> static bool equal(const T& a, const U& b) {
return Translator::equal(a.m_value, b); } |
| 575 }; |
| 576 |
| 577 template<typename Value, typename U, typename V, typename W> |
| 578 template<typename HashTranslator, typename T> |
| 579 inline typename LinkedHashSet<Value, U, V, W>::iterator LinkedHashSet<Value, U,
V, W>::find(const T& value) |
| 580 { |
| 581 typedef LinkedHashSetTranslatorAdapter<HashTranslator> TranslatedFunctions; |
| 582 const LinkedHashSet::Node* node = m_impl.template lookup<TranslatedFunctions
, const T&>(value); |
| 583 if (!node) |
| 584 return end(); |
| 585 return makeIterator(node); |
| 586 } |
| 587 |
| 588 template<typename Value, typename U, typename V, typename W> |
| 589 template<typename HashTranslator, typename T> |
| 590 inline typename LinkedHashSet<Value, U, V, W>::const_iterator LinkedHashSet<Valu
e, U, V, W>::find(const T& value) const |
| 591 { |
| 592 typedef LinkedHashSetTranslatorAdapter<HashTranslator> TranslatedFunctions; |
| 593 const LinkedHashSet::Node* node = m_impl.template lookup<TranslatedFunctions
, const T&>(value); |
| 594 if (!node) |
| 595 return end(); |
| 596 return makeConstIterator(node); |
| 597 } |
| 598 |
| 599 template<typename Value, typename U, typename V, typename W> |
| 600 template<typename HashTranslator, typename T> |
| 601 inline bool LinkedHashSet<Value, U, V, W>::contains(const T& value) const |
| 602 { |
| 603 return m_impl.template contains<LinkedHashSetTranslatorAdapter<HashTranslato
r> >(value); |
| 604 } |
| 605 |
| 606 template<typename T, typename U, typename V, typename W> |
| 607 inline bool LinkedHashSet<T, U, V, W>::contains(ValuePeekInType value) const |
| 608 { |
| 609 return m_impl.template contains<NodeHashFunctions>(value); |
| 610 } |
| 611 |
| 612 template<typename Value, typename HashFunctions, typename Traits, typename Alloc
ator> |
| 613 typename LinkedHashSet<Value, HashFunctions, Traits, Allocator>::AddResult Linke
dHashSet<Value, HashFunctions, Traits, Allocator>::add(ValuePeekInType value) |
| 614 { |
| 615 return m_impl.template add<NodeHashFunctions>(value, &m_anchor); |
| 616 } |
| 617 |
| 618 template<typename T, typename U, typename V, typename W> |
| 619 typename LinkedHashSet<T, U, V, W>::iterator LinkedHashSet<T, U, V, W>::addRetur
nIterator(ValuePeekInType value) |
| 620 { |
| 621 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions>
(value, &m_anchor); |
| 622 return makeIterator(result.storedValue); |
| 623 } |
| 624 |
| 625 template<typename T, typename U, typename V, typename W> |
| 626 typename LinkedHashSet<T, U, V, W>::AddResult LinkedHashSet<T, U, V, W>::appendO
rMoveToLast(ValuePeekInType value) |
| 627 { |
| 628 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions>
(value, &m_anchor); |
| 629 Node* node = result.storedValue; |
| 630 if (!result.isNewEntry) { |
| 631 node->unlink(); |
| 632 m_anchor.insertBefore(*node); |
| 633 } |
| 634 return result; |
| 635 } |
| 636 |
| 637 template<typename T, typename U, typename V, typename W> |
| 638 typename LinkedHashSet<T, U, V, W>::AddResult LinkedHashSet<T, U, V, W>::prepend
OrMoveToFirst(ValuePeekInType value) |
| 639 { |
| 640 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions>
(value, m_anchor.m_next); |
| 641 Node* node = result.storedValue; |
| 642 if (!result.isNewEntry) { |
| 643 node->unlink(); |
| 644 m_anchor.insertAfter(*node); |
| 645 } |
| 646 return result; |
| 647 } |
| 648 |
| 649 template<typename T, typename U, typename V, typename W> |
| 650 typename LinkedHashSet<T, U, V, W>::AddResult LinkedHashSet<T, U, V, W>::insertB
efore(ValuePeekInType beforeValue, ValuePeekInType newValue) |
| 651 { |
| 652 return insertBefore(find(beforeValue), newValue); |
| 653 } |
| 654 |
| 655 template<typename T, typename U, typename V, typename W> |
| 656 inline void LinkedHashSet<T, U, V, W>::remove(iterator it) |
| 657 { |
| 658 if (it == end()) |
| 659 return; |
| 660 m_impl.remove(it.node()); |
| 661 } |
| 662 |
| 663 template<typename T, typename U, typename V, typename W> |
| 664 inline void LinkedHashSet<T, U, V, W>::remove(ValuePeekInType value) |
| 665 { |
| 666 remove(find(value)); |
| 667 } |
| 668 |
| 669 template<typename T> |
| 670 struct IsWeak<LinkedHashSetNode<T> > { |
| 671 static const bool value = IsWeak<T>::value; |
| 672 }; |
| 673 |
| 674 inline void swap(LinkedHashSetNodeBase& a, LinkedHashSetNodeBase& b) |
| 675 { |
| 676 typedef LinkedHashSetNodeBase Base; |
| 677 swap(a.m_next, b.m_next); |
| 678 swap(a.m_prev, b.m_prev); |
| 679 if (b.m_next) { |
| 680 b.m_next->m_prev = &b; |
| 681 b.m_prev->m_next = &b; |
| 682 } |
| 683 if (a.m_next) { |
| 684 a.m_next->m_prev = &a; |
| 685 a.m_prev->m_next = &a; |
| 686 } |
| 687 } |
| 688 |
| 689 template<typename T> |
| 690 inline void swap(LinkedHashSetNode<T>& a, LinkedHashSetNode<T>& b) |
| 691 { |
| 692 typedef LinkedHashSetNodeBase Base; |
| 693 |
| 694 swap(static_cast<Base&>(a), static_cast<Base&>(b)); |
| 695 swap(a.m_value, b.m_value); |
| 696 } |
| 697 |
| 698 // Warning: After and while calling this you have a collection with deleted |
| 699 // pointers. Consider using a smart pointer like OwnPtr and calling clear() |
| 700 // instead. |
| 701 template<typename ValueType, typename T, typename U> |
| 702 void deleteAllValues(const LinkedHashSet<ValueType, T, U>& set) |
| 703 { |
| 704 typedef typename LinkedHashSet<ValueType, T, U>::const_iterator iterator; |
| 705 iterator end = set.end(); |
| 706 for (iterator it = set.begin(); it != end; ++it) |
| 707 delete *it; |
| 708 } |
| 709 |
| 710 } |
| 711 |
| 712 using WTF::LinkedHashSet; |
| 713 |
| 714 #endif /* WTF_LinkedHashSet_h */ |
OLD | NEW |