ListHashSet.h revision ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb
1/* 2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21#ifndef WTF_ListHashSet_h 22#define WTF_ListHashSet_h 23 24#include "Assertions.h" 25#include "HashSet.h" 26#include "OwnPtr.h" 27#include "StdLibExtras.h" 28 29namespace WTF { 30 31 // ListHashSet: Just like HashSet, this class provides a Set 32 // interface - a collection of unique objects with O(1) insertion, 33 // removal and test for containership. However, it also has an 34 // order - iterating it will always give back values in the order 35 // in which they are added. 36 37 // In theory it would be possible to add prepend, insertAfter 38 // and an append that moves the element to the end even if already present, 39 // but unclear yet if these are needed. 40 41 template<typename Value, size_t inlineCapacity, typename HashFunctions> class ListHashSet; 42 43 template<typename T> struct IdentityExtractor; 44 45 template<typename Value, size_t inlineCapacity, typename HashFunctions> 46 void deleteAllValues(const ListHashSet<Value, inlineCapacity, HashFunctions>&); 47 48 template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetIterator; 49 template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstIterator; 50 51 template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNode; 52 template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNodeAllocator; 53 template<typename ValueArg, size_t inlineCapacity, typename HashArg> struct ListHashSetNodeHashFunctions; 54 55 template<typename ValueArg, size_t inlineCapacity = 256, typename HashArg = typename DefaultHash<ValueArg>::Hash> class ListHashSet { 56 WTF_MAKE_FAST_ALLOCATED; 57 private: 58 typedef ListHashSetNode<ValueArg, inlineCapacity> Node; 59 typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator; 60 61 typedef HashTraits<Node*> NodeTraits; 62 typedef ListHashSetNodeHashFunctions<ValueArg, inlineCapacity, HashArg> NodeHash; 63 64 typedef HashTable<Node*, Node*, IdentityExtractor<Node*>, NodeHash, NodeTraits, NodeTraits> ImplType; 65 typedef HashTableIterator<Node*, Node*, IdentityExtractor<Node*>, NodeHash, NodeTraits, NodeTraits> ImplTypeIterator; 66 typedef HashTableConstIterator<Node*, Node*, IdentityExtractor<Node*>, NodeHash, NodeTraits, NodeTraits> ImplTypeConstIterator; 67 68 typedef HashArg HashFunctions; 69 70 public: 71 typedef ValueArg ValueType; 72 typedef ListHashSetIterator<ValueType, inlineCapacity, HashArg> iterator; 73 typedef ListHashSetConstIterator<ValueType, inlineCapacity, HashArg> const_iterator; 74 75 friend class ListHashSetConstIterator<ValueType, inlineCapacity, HashArg>; 76 77 ListHashSet(); 78 ListHashSet(const ListHashSet&); 79 ListHashSet& operator=(const ListHashSet&); 80 ~ListHashSet(); 81 82 void swap(ListHashSet&); 83 84 int size() const; 85 int capacity() const; 86 bool isEmpty() const; 87 88 iterator begin(); 89 iterator end(); 90 const_iterator begin() const; 91 const_iterator end() const; 92 93 iterator find(const ValueType&); 94 const_iterator find(const ValueType&) const; 95 bool contains(const ValueType&) const; 96 97 // the return value is a pair of an iterator to the new value's location, 98 // and a bool that is true if an new entry was added 99 pair<iterator, bool> add(const ValueType&); 100 101 pair<iterator, bool> insertBefore(const ValueType& beforeValue, const ValueType& newValue); 102 pair<iterator, bool> insertBefore(iterator it, const ValueType&); 103 104 void remove(const ValueType&); 105 void remove(iterator); 106 void clear(); 107 108 private: 109 void unlinkAndDelete(Node*); 110 void appendNode(Node*); 111 void insertNodeBefore(Node* beforeNode, Node* newNode); 112 void deleteAllNodes(); 113 iterator makeIterator(Node*); 114 const_iterator makeConstIterator(Node*) const; 115 116 friend void deleteAllValues<>(const ListHashSet&); 117 118 ImplType m_impl; 119 Node* m_head; 120 Node* m_tail; 121 OwnPtr<NodeAllocator> m_allocator; 122 }; 123 124 template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNodeAllocator { 125 typedef ListHashSetNode<ValueArg, inlineCapacity> Node; 126 typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator; 127 128 ListHashSetNodeAllocator() 129 : m_freeList(pool()) 130 , m_isDoneWithInitialFreeList(false) 131 { 132 memset(m_pool.pool, 0, sizeof(m_pool.pool)); 133 } 134 135 Node* allocate() 136 { 137 Node* result = m_freeList; 138 139 if (!result) 140 return static_cast<Node*>(fastMalloc(sizeof(Node))); 141 142 ASSERT(!result->m_isAllocated); 143 144 Node* next = result->m_next; 145 ASSERT(!next || !next->m_isAllocated); 146 if (!next && !m_isDoneWithInitialFreeList) { 147 next = result + 1; 148 if (next == pastPool()) { 149 m_isDoneWithInitialFreeList = true; 150 next = 0; 151 } else { 152 ASSERT(inPool(next)); 153 ASSERT(!next->m_isAllocated); 154 } 155 } 156 m_freeList = next; 157 158 return result; 159 } 160 161 void deallocate(Node* node) 162 { 163 if (inPool(node)) { 164#ifndef NDEBUG 165 node->m_isAllocated = false; 166#endif 167 node->m_next = m_freeList; 168 m_freeList = node; 169 return; 170 } 171 172 fastFree(node); 173 } 174 175 private: 176 Node* pool() { return reinterpret_cast_ptr<Node*>(m_pool.pool); } 177 Node* pastPool() { return pool() + m_poolSize; } 178 179 bool inPool(Node* node) 180 { 181 return node >= pool() && node < pastPool(); 182 } 183 184 Node* m_freeList; 185 bool m_isDoneWithInitialFreeList; 186 static const size_t m_poolSize = inlineCapacity; 187 union { 188 char pool[sizeof(Node) * m_poolSize]; 189 double forAlignment; 190 } m_pool; 191 }; 192 193 template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNode { 194 typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator; 195 196 ListHashSetNode(ValueArg value) 197 : m_value(value) 198 , m_prev(0) 199 , m_next(0) 200#ifndef NDEBUG 201 , m_isAllocated(true) 202#endif 203 { 204 } 205 206 void* operator new(size_t, NodeAllocator* allocator) 207 { 208 return allocator->allocate(); 209 } 210 void destroy(NodeAllocator* allocator) 211 { 212 this->~ListHashSetNode(); 213 allocator->deallocate(this); 214 } 215 216 ValueArg m_value; 217 ListHashSetNode* m_prev; 218 ListHashSetNode* m_next; 219 220#ifndef NDEBUG 221 bool m_isAllocated; 222#endif 223 }; 224 225 template<typename ValueArg, size_t inlineCapacity, typename HashArg> struct ListHashSetNodeHashFunctions { 226 typedef ListHashSetNode<ValueArg, inlineCapacity> Node; 227 228 static unsigned hash(Node* const& key) { return HashArg::hash(key->m_value); } 229 static bool equal(Node* const& a, Node* const& b) { return HashArg::equal(a->m_value, b->m_value); } 230 static const bool safeToCompareToEmptyOrDeleted = false; 231 }; 232 233 template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetIterator { 234 private: 235 typedef ListHashSet<ValueArg, inlineCapacity, HashArg> ListHashSetType; 236 typedef ListHashSetIterator<ValueArg, inlineCapacity, HashArg> iterator; 237 typedef ListHashSetConstIterator<ValueArg, inlineCapacity, HashArg> const_iterator; 238 typedef ListHashSetNode<ValueArg, inlineCapacity> Node; 239 typedef ValueArg ValueType; 240 typedef ValueType& ReferenceType; 241 typedef ValueType* PointerType; 242 243 friend class ListHashSet<ValueArg, inlineCapacity, HashArg>; 244 245 ListHashSetIterator(const ListHashSetType* set, Node* position) : m_iterator(set, position) { } 246 247 public: 248 ListHashSetIterator() { } 249 250 // default copy, assignment and destructor are OK 251 252 PointerType get() const { return const_cast<PointerType>(m_iterator.get()); } 253 ReferenceType operator*() const { return *get(); } 254 PointerType operator->() const { return get(); } 255 256 iterator& operator++() { ++m_iterator; return *this; } 257 258 // postfix ++ intentionally omitted 259 260 iterator& operator--() { --m_iterator; return *this; } 261 262 // postfix -- intentionally omitted 263 264 // Comparison. 265 bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; } 266 bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; } 267 268 operator const_iterator() const { return m_iterator; } 269 270 private: 271 Node* node() { return m_iterator.node(); } 272 273 const_iterator m_iterator; 274 }; 275 276 template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstIterator { 277 private: 278 typedef ListHashSet<ValueArg, inlineCapacity, HashArg> ListHashSetType; 279 typedef ListHashSetIterator<ValueArg, inlineCapacity, HashArg> iterator; 280 typedef ListHashSetConstIterator<ValueArg, inlineCapacity, HashArg> const_iterator; 281 typedef ListHashSetNode<ValueArg, inlineCapacity> Node; 282 typedef ValueArg ValueType; 283 typedef const ValueType& ReferenceType; 284 typedef const ValueType* PointerType; 285 286 friend class ListHashSet<ValueArg, inlineCapacity, HashArg>; 287 friend class ListHashSetIterator<ValueArg, inlineCapacity, HashArg>; 288 289 ListHashSetConstIterator(const ListHashSetType* set, Node* position) 290 : m_set(set) 291 , m_position(position) 292 { 293 } 294 295 public: 296 ListHashSetConstIterator() 297 { 298 } 299 300 PointerType get() const 301 { 302 return &m_position->m_value; 303 } 304 ReferenceType operator*() const { return *get(); } 305 PointerType operator->() const { return get(); } 306 307 const_iterator& operator++() 308 { 309 ASSERT(m_position != 0); 310 m_position = m_position->m_next; 311 return *this; 312 } 313 314 // postfix ++ intentionally omitted 315 316 const_iterator& operator--() 317 { 318 ASSERT(m_position != m_set->m_head); 319 if (!m_position) 320 m_position = m_set->m_tail; 321 else 322 m_position = m_position->m_prev; 323 return *this; 324 } 325 326 // postfix -- intentionally omitted 327 328 // Comparison. 329 bool operator==(const const_iterator& other) const 330 { 331 return m_position == other.m_position; 332 } 333 bool operator!=(const const_iterator& other) const 334 { 335 return m_position != other.m_position; 336 } 337 338 private: 339 Node* node() { return m_position; } 340 341 const ListHashSetType* m_set; 342 Node* m_position; 343 }; 344 345 346 template<typename ValueType, size_t inlineCapacity, typename HashFunctions> 347 struct ListHashSetTranslator { 348 private: 349 typedef ListHashSetNode<ValueType, inlineCapacity> Node; 350 typedef ListHashSetNodeAllocator<ValueType, inlineCapacity> NodeAllocator; 351 public: 352 static unsigned hash(const ValueType& key) { return HashFunctions::hash(key); } 353 static bool equal(Node* const& a, const ValueType& b) { return HashFunctions::equal(a->m_value, b); } 354 static void translate(Node*& location, const ValueType& key, NodeAllocator* allocator) 355 { 356 location = new (allocator) Node(key); 357 } 358 }; 359 360 template<typename T, size_t inlineCapacity, typename U> 361 inline ListHashSet<T, inlineCapacity, U>::ListHashSet() 362 : m_head(0) 363 , m_tail(0) 364 , m_allocator(new NodeAllocator) 365 { 366 } 367 368 template<typename T, size_t inlineCapacity, typename U> 369 inline ListHashSet<T, inlineCapacity, U>::ListHashSet(const ListHashSet& other) 370 : m_head(0) 371 , m_tail(0) 372 , m_allocator(new NodeAllocator) 373 { 374 const_iterator end = other.end(); 375 for (const_iterator it = other.begin(); it != end; ++it) 376 add(*it); 377 } 378 379 template<typename T, size_t inlineCapacity, typename U> 380 inline ListHashSet<T, inlineCapacity, U>& ListHashSet<T, inlineCapacity, U>::operator=(const ListHashSet& other) 381 { 382 ListHashSet tmp(other); 383 swap(tmp); 384 return *this; 385 } 386 387 template<typename T, size_t inlineCapacity, typename U> 388 inline void ListHashSet<T, inlineCapacity, U>::swap(ListHashSet& other) 389 { 390 m_impl.swap(other.m_impl); 391 std::swap(m_head, other.m_head); 392 std::swap(m_tail, other.m_tail); 393 m_allocator.swap(other.m_allocator); 394 } 395 396 template<typename T, size_t inlineCapacity, typename U> 397 inline ListHashSet<T, inlineCapacity, U>::~ListHashSet() 398 { 399 deleteAllNodes(); 400 } 401 402 template<typename T, size_t inlineCapacity, typename U> 403 inline int ListHashSet<T, inlineCapacity, U>::size() const 404 { 405 return m_impl.size(); 406 } 407 408 template<typename T, size_t inlineCapacity, typename U> 409 inline int ListHashSet<T, inlineCapacity, U>::capacity() const 410 { 411 return m_impl.capacity(); 412 } 413 414 template<typename T, size_t inlineCapacity, typename U> 415 inline bool ListHashSet<T, inlineCapacity, U>::isEmpty() const 416 { 417 return m_impl.isEmpty(); 418 } 419 420 template<typename T, size_t inlineCapacity, typename U> 421 inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::begin() 422 { 423 return makeIterator(m_head); 424 } 425 426 template<typename T, size_t inlineCapacity, typename U> 427 inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::end() 428 { 429 return makeIterator(0); 430 } 431 432 template<typename T, size_t inlineCapacity, typename U> 433 inline typename ListHashSet<T, inlineCapacity, U>::const_iterator ListHashSet<T, inlineCapacity, U>::begin() const 434 { 435 return makeConstIterator(m_head); 436 } 437 438 template<typename T, size_t inlineCapacity, typename U> 439 inline typename ListHashSet<T, inlineCapacity, U>::const_iterator ListHashSet<T, inlineCapacity, U>::end() const 440 { 441 return makeConstIterator(0); 442 } 443 444 template<typename T, size_t inlineCapacity, typename U> 445 inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::find(const ValueType& value) 446 { 447 typedef ListHashSetTranslator<ValueType, inlineCapacity, HashFunctions> Translator; 448 ImplTypeIterator it = m_impl.template find<ValueType, Translator>(value); 449 if (it == m_impl.end()) 450 return end(); 451 return makeIterator(*it); 452 } 453 454 template<typename T, size_t inlineCapacity, typename U> 455 inline typename ListHashSet<T, inlineCapacity, U>::const_iterator ListHashSet<T, inlineCapacity, U>::find(const ValueType& value) const 456 { 457 typedef ListHashSetTranslator<ValueType, inlineCapacity, HashFunctions> Translator; 458 ImplTypeConstIterator it = m_impl.template find<ValueType, Translator>(value); 459 if (it == m_impl.end()) 460 return end(); 461 return makeConstIterator(*it); 462 } 463 464 template<typename T, size_t inlineCapacity, typename U> 465 inline bool ListHashSet<T, inlineCapacity, U>::contains(const ValueType& value) const 466 { 467 typedef ListHashSetTranslator<ValueType, inlineCapacity, HashFunctions> Translator; 468 return m_impl.template contains<ValueType, Translator>(value); 469 } 470 471 template<typename T, size_t inlineCapacity, typename U> 472 pair<typename ListHashSet<T, inlineCapacity, U>::iterator, bool> ListHashSet<T, inlineCapacity, U>::add(const ValueType &value) 473 { 474 typedef ListHashSetTranslator<ValueType, inlineCapacity, HashFunctions> Translator; 475 pair<typename ImplType::iterator, bool> result = m_impl.template add<ValueType, NodeAllocator*, Translator>(value, m_allocator.get()); 476 if (result.second) 477 appendNode(*result.first); 478 return std::make_pair(makeIterator(*result.first), result.second); 479 } 480 481 template<typename T, size_t inlineCapacity, typename U> 482 pair<typename ListHashSet<T, inlineCapacity, U>::iterator, bool> ListHashSet<T, inlineCapacity, U>::insertBefore(iterator it, const ValueType& newValue) 483 { 484 typedef ListHashSetTranslator<ValueType, inlineCapacity, HashFunctions> Translator; 485 pair<typename ImplType::iterator, bool> result = m_impl.template add<ValueType, NodeAllocator*, Translator>(newValue, m_allocator.get()); 486 if (result.second) 487 insertNodeBefore(it.node(), *result.first); 488 return std::make_pair(makeIterator(*result.first), result.second); 489 490 } 491 492 template<typename T, size_t inlineCapacity, typename U> 493 pair<typename ListHashSet<T, inlineCapacity, U>::iterator, bool> ListHashSet<T, inlineCapacity, U>::insertBefore(const ValueType& beforeValue, const ValueType& newValue) 494 { 495 return insertBefore(find(beforeValue), newValue); 496 } 497 498 template<typename T, size_t inlineCapacity, typename U> 499 inline void ListHashSet<T, inlineCapacity, U>::remove(iterator it) 500 { 501 if (it == end()) 502 return; 503 m_impl.remove(it.node()); 504 unlinkAndDelete(it.node()); 505 } 506 507 template<typename T, size_t inlineCapacity, typename U> 508 inline void ListHashSet<T, inlineCapacity, U>::remove(const ValueType& value) 509 { 510 remove(find(value)); 511 } 512 513 template<typename T, size_t inlineCapacity, typename U> 514 inline void ListHashSet<T, inlineCapacity, U>::clear() 515 { 516 deleteAllNodes(); 517 m_impl.clear(); 518 m_head = 0; 519 m_tail = 0; 520 } 521 522 template<typename T, size_t inlineCapacity, typename U> 523 void ListHashSet<T, inlineCapacity, U>::unlinkAndDelete(Node* node) 524 { 525 if (!node->m_prev) { 526 ASSERT(node == m_head); 527 m_head = node->m_next; 528 } else { 529 ASSERT(node != m_head); 530 node->m_prev->m_next = node->m_next; 531 } 532 533 if (!node->m_next) { 534 ASSERT(node == m_tail); 535 m_tail = node->m_prev; 536 } else { 537 ASSERT(node != m_tail); 538 node->m_next->m_prev = node->m_prev; 539 } 540 541 node->destroy(m_allocator.get()); 542 } 543 544 template<typename T, size_t inlineCapacity, typename U> 545 void ListHashSet<T, inlineCapacity, U>::appendNode(Node* node) 546 { 547 node->m_prev = m_tail; 548 node->m_next = 0; 549 550 if (m_tail) { 551 ASSERT(m_head); 552 m_tail->m_next = node; 553 } else { 554 ASSERT(!m_head); 555 m_head = node; 556 } 557 558 m_tail = node; 559 } 560 561 template<typename T, size_t inlineCapacity, typename U> 562 void ListHashSet<T, inlineCapacity, U>::insertNodeBefore(Node* beforeNode, Node* newNode) 563 { 564 if (!beforeNode) 565 return appendNode(newNode); 566 567 newNode->m_next = beforeNode; 568 newNode->m_prev = beforeNode->m_prev; 569 if (beforeNode->m_prev) 570 beforeNode->m_prev->m_next = newNode; 571 beforeNode->m_prev = newNode; 572 573 if (!newNode->m_prev) 574 m_head = newNode; 575 } 576 577 template<typename T, size_t inlineCapacity, typename U> 578 void ListHashSet<T, inlineCapacity, U>::deleteAllNodes() 579 { 580 if (!m_head) 581 return; 582 583 for (Node* node = m_head, *next = m_head->m_next; node; node = next, next = node ? node->m_next : 0) 584 node->destroy(m_allocator.get()); 585 } 586 587 template<typename T, size_t inlineCapacity, typename U> 588 inline ListHashSetIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeIterator(Node* position) 589 { 590 return ListHashSetIterator<T, inlineCapacity, U>(this, position); 591 } 592 593 template<typename T, size_t inlineCapacity, typename U> 594 inline ListHashSetConstIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeConstIterator(Node* position) const 595 { 596 return ListHashSetConstIterator<T, inlineCapacity, U>(this, position); 597 } 598 599 template<bool, typename ValueType, typename HashTableType> 600 void deleteAllValues(HashTableType& collection) 601 { 602 typedef typename HashTableType::const_iterator iterator; 603 iterator end = collection.end(); 604 for (iterator it = collection.begin(); it != end; ++it) 605 delete (*it)->m_value; 606 } 607 608 template<typename T, size_t inlineCapacity, typename U> 609 inline void deleteAllValues(const ListHashSet<T, inlineCapacity, U>& collection) 610 { 611 deleteAllValues<true, typename ListHashSet<T, inlineCapacity, U>::ValueType>(collection.m_impl); 612 } 613 614} // namespace WTF 615 616using WTF::ListHashSet; 617 618#endif /* WTF_ListHashSet_h */ 619