Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserv ed. | |
|
Mads Ager (chromium)
2014/04/03 09:24:35
Ehm, no.
You should use the short copyright notic
| |
| 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 struct LinkedHashSetNodeBase { | |
|
Mikhail
2014/04/03 09:32:18
this actually better to be class (since it's not a
Mads Ager (chromium)
2014/04/03 09:44:58
Why not class?
Erik Corry
2014/04/10 10:47:37
Done.
Erik Corry
2014/04/10 10:47:37
Done.
| |
| 53 ~LinkedHashSetNodeBase() | |
|
Mikhail
2014/04/03 09:32:18
Can nodes be deleted via base interface? should th
Erik Corry
2014/04/10 10:47:37
There's no virtualness here and we don't want to b
| |
| 54 { | |
| 55 if (!m_next) | |
| 56 return; | |
| 57 ASSERT(m_prev); | |
| 58 ASSERT(m_next->m_prev == this); | |
| 59 ASSERT(m_prev->m_next == this); | |
| 60 m_next->m_prev = m_prev; | |
| 61 m_prev->m_next = m_next; | |
| 62 } | |
| 63 | |
| 64 LinkedHashSetNodeBase() : m_prev(this), m_next(this) { } | |
| 65 | |
| 66 void insertBefore(LinkedHashSetNodeBase& other) | |
| 67 { | |
| 68 ASSERT(!other.m_next); | |
| 69 ASSERT(!other.m_prev); | |
| 70 other.m_next = this; | |
| 71 other.m_prev = m_prev; | |
| 72 m_prev->m_next = &other; | |
| 73 m_prev = &other; | |
| 74 ASSERT(other.m_next); | |
| 75 ASSERT(other.m_prev); | |
| 76 ASSERT(m_next); | |
| 77 ASSERT(m_prev); | |
| 78 } | |
| 79 | |
| 80 LinkedHashSetNodeBase(LinkedHashSetNodeBase* prev, LinkedHashSetNodeBase* ne xt) | |
| 81 : m_prev(prev) | |
| 82 , m_next(next) | |
| 83 { | |
| 84 ASSERT((prev && next) || (!prev && !next)); | |
| 85 } | |
| 86 | |
| 87 LinkedHashSetNodeBase* m_prev; | |
| 88 LinkedHashSetNodeBase* m_next; | |
| 89 | |
| 90 protected: | |
| 91 // If we take a copy of a node we can't copy the next and prev pointers, | |
| 92 // since they point to something that does not point at us. This is used | |
| 93 // inside the shouldExpand() "if" in HashTable::add. | |
| 94 LinkedHashSetNodeBase(const LinkedHashSetNodeBase& other) | |
|
Mikhail
2014/04/03 09:32:18
Do we have cases when nodes are copied?
Erik Corry
2014/04/10 10:47:37
Yes, as explained in the comment.
| |
| 95 : m_prev(0) | |
| 96 , m_next(0) { } | |
| 97 | |
| 98 private: | |
| 99 // Should not be used. | |
| 100 LinkedHashSetNodeBase& operator=(const LinkedHashSetNodeBase& other); | |
| 101 }; | |
| 102 | |
| 103 template<typename ValueArg> | |
| 104 struct LinkedHashSetNode : public LinkedHashSetNodeBase { | |
|
Mads Ager (chromium)
2014/04/03 09:44:58
class?
Erik Corry
2014/04/10 10:47:37
Done.
| |
| 105 LinkedHashSetNode(const ValueArg& value, LinkedHashSetNodeBase* prev, Linked HashSetNodeBase* next) | |
| 106 : LinkedHashSetNodeBase(prev, next) | |
| 107 , m_value(value) | |
| 108 { | |
| 109 } | |
|
Mikhail
2014/04/03 09:32:18
If you want 'LinkedHashSetNodeBase' copy construct
Erik Corry
2014/04/10 10:47:37
I made the copy constructor for this class undefin
| |
| 110 | |
| 111 ValueArg m_value; | |
| 112 }; | |
| 113 | |
| 114 template< | |
| 115 typename ValueArg, | |
| 116 typename HashFunctions = typename DefaultHash<ValueArg>::Hash, | |
| 117 typename TraitsArg = HashTraits<ValueArg>, | |
| 118 typename Allocator = DefaultAllocator> | |
| 119 class LinkedHashSet { | |
|
Mads Ager (chromium)
2014/04/03 09:44:58
Indentation
Erik Corry
2014/04/10 10:47:37
Done.
| |
| 120 private: | |
| 121 typedef ValueArg Value; | |
| 122 typedef TraitsArg Traits; | |
| 123 typedef LinkedHashSetNode<Value> Node; | |
| 124 typedef LinkedHashSetNodeBase NodeBase; | |
| 125 typedef LinkedHashSetTranslator<Value, HashFunctions> NodeHashFunctions; | |
| 126 typedef LinkedHashSetTraits<Value, Traits> NodeHashTraits; | |
| 127 | |
| 128 typedef HashTable<Node, Node, IdentityExtractor, | |
|
Mikhail
2014/04/03 09:32:18
Why not "HashTable<Node*, Node*" ?
Erik Corry
2014/04/10 10:47:37
Then we would have to allocate lots of small Node
| |
| 129 NodeHashFunctions, NodeHashTraits, NodeHashTraits, Allocator> ImplType; | |
| 130 | |
| 131 public: | |
| 132 typedef LinkedHashSetIterator<LinkedHashSet> iterator; | |
| 133 friend class LinkedHashSetIterator<LinkedHashSet>; | |
| 134 typedef LinkedHashSetConstIterator<LinkedHashSet> const_iterator; | |
| 135 friend class LinkedHashSetConstIterator<LinkedHashSet>; | |
| 136 | |
| 137 typedef LinkedHashSetReverseIterator<LinkedHashSet> reverse_iterator; | |
| 138 friend class LinkedHashSetReverseIterator<LinkedHashSet>; | |
| 139 typedef LinkedHashSetConstReverseIterator<LinkedHashSet> const_reverse_itera tor; | |
| 140 friend class LinkedHashSetConstReverseIterator<LinkedHashSet>; | |
| 141 | |
| 142 struct AddResult { | |
| 143 AddResult(const typename ImplType::AddResult& hashTableAddResult) | |
| 144 : storedValue(&hashTableAddResult.storedValue->m_value) | |
| 145 , isNewEntry(hashTableAddResult.isNewEntry) { } | |
|
Mads Ager (chromium)
2014/04/03 09:44:58
When you are using multiple lines you should have
Erik Corry
2014/04/10 10:47:37
Done.
| |
| 146 | |
| 147 Value* storedValue; | |
| 148 bool isNewEntry; | |
| 149 }; | |
| 150 | |
| 151 void* operator new(size_t size) | |
| 152 { | |
| 153 return Allocator::template malloc<void*, LinkedHashSet>(size); | |
| 154 } | |
| 155 void operator delete(void* p) { Allocator::free(p); } | |
| 156 void* operator new[](size_t size) { return Allocator::template newArray<Link edHashSet>(size); } | |
| 157 void operator delete[](void* p) { Allocator::deleteArray(p); } | |
| 158 void* operator new(size_t, NotNullTag, void* location) | |
| 159 { | |
| 160 COMPILE_ASSERT(!Allocator::isGarbageCollected, Garbage_collector_must_be _disabled); | |
| 161 ASSERT(location); | |
| 162 return location; | |
| 163 } | |
| 164 | |
| 165 LinkedHashSet(); | |
| 166 LinkedHashSet(const LinkedHashSet&); | |
| 167 LinkedHashSet& operator=(const LinkedHashSet&); | |
| 168 ~LinkedHashSet(); | |
| 169 | |
| 170 static void finalize(void* pointer) { reinterpret_cast<LinkedHashSet*>(point er)->~LinkedHashSet(); } | |
| 171 | |
| 172 void swap(LinkedHashSet&); | |
| 173 | |
| 174 unsigned size() const { return m_impl.size(); } | |
| 175 unsigned capacity() const { return m_impl.capacity(); } | |
| 176 bool isEmpty() const { return m_impl.isEmpty(); } | |
| 177 | |
| 178 iterator begin() { return makeIterator(firstNode()); } | |
| 179 iterator end() { return makeIterator(anchor()); } | |
| 180 const_iterator begin() const { return makeConstIterator(firstNode()); } | |
| 181 const_iterator end() const { return makeConstIterator(anchor()); } | |
| 182 | |
| 183 reverse_iterator rbegin() { return makeReverseIterator(lastNode()); } | |
| 184 reverse_iterator rend() { return makeReverseIterator(anchor()); } | |
| 185 const_reverse_iterator rbegin() const { return makeConstReverseIterator(last Node()); } | |
| 186 const_reverse_iterator rend() const { return makeConstReverseIterator(anchor ()); } | |
| 187 | |
| 188 Value& first(); | |
| 189 const Value& first() const; | |
| 190 void removeFirst(); | |
| 191 | |
| 192 Value& last(); | |
| 193 const Value& last() const; | |
| 194 void removeLast(); | |
| 195 | |
| 196 iterator find(const Value&); | |
|
Mikhail
2014/04/03 09:32:18
maybe 'ValuePeekInType' is worth using here?
Erik Corry
2014/04/10 10:47:37
Good idea. Done.
To do this I had to change the
| |
| 197 const_iterator find(const Value&) const; | |
| 198 bool contains(const Value&) const; | |
| 199 | |
| 200 // An alternate version of find() that finds the object by hashing and compa ring | |
| 201 // with some other type, to avoid the cost of type conversion. | |
| 202 // The HashTranslator interface is defined in HashSet. | |
| 203 template<typename HashTranslator, typename T> iterator find(const T&); | |
| 204 template<typename HashTranslator, typename T> const_iterator find(const T&) const; | |
| 205 template<typename HashTranslator, typename T> bool contains(const T&) const; | |
| 206 | |
| 207 // The return value of add is a pair of a pointer to the stored value, | |
| 208 // and a bool that is true if an new entry was added. | |
| 209 AddResult add(const Value&); | |
| 210 | |
| 211 // Same as add() except that the return value is an | |
| 212 // iterator. Useful in cases where it's needed to have the | |
| 213 // same return value as find() and where it's not possible to | |
| 214 // use a pointer to the storedValue. | |
| 215 iterator addReturnIterator(const Value&); | |
| 216 | |
| 217 // Add the value to the end of the collection. If the value was already in | |
| 218 // the list, it is moved to the end. | |
| 219 AddResult appendOrMoveToLast(const Value&); | |
| 220 | |
| 221 // Add the value to the beginning of the collection. If the value was alread y in | |
| 222 // the list, it is moved to the beginning. | |
| 223 AddResult prependOrMoveToFirst(const Value&); | |
| 224 | |
| 225 AddResult insertBefore(const Value& beforeValue, const Value& newValue); | |
| 226 AddResult insertBefore(iterator, const Value&); | |
| 227 | |
| 228 void remove(const Value&); | |
| 229 void remove(iterator); | |
| 230 void clear() { m_impl.clear(); } | |
| 231 | |
| 232 void trace(typename Allocator::Visitor* visitor) { m_impl.trace(visitor); } | |
| 233 | |
| 234 int64_t modifications() const { return m_impl.modifications(); } | |
| 235 void checkModifications(int64_t mods) const { m_impl.checkModifications(mods ); } | |
| 236 | |
| 237 private: | |
| 238 void unlink(Node*); | |
| 239 void insertNodeBefore(Node* beforeNode, Node* newNode); | |
| 240 | |
| 241 Node* anchor() { return reinterpret_cast<Node*>(&m_anchor); } | |
| 242 const Node* anchor() const { return reinterpret_cast<const Node*>(&m_anchor) ; } | |
| 243 Node* firstNode() { return reinterpret_cast<Node*>(m_anchor.m_next); } | |
| 244 const Node* firstNode() const { return reinterpret_cast<const Node*>(m_ancho r.m_next); } | |
| 245 Node* lastNode() { return reinterpret_cast<Node*>(m_anchor.m_prev); } | |
| 246 const Node* lastNode() const { return reinterpret_cast<const Node*>(m_anchor .m_prev); } | |
| 247 | |
| 248 iterator makeIterator(const Node* position) { return iterator(position, this ); } | |
| 249 const_iterator makeConstIterator(const Node* position) const { return const_ iterator(position, this); } | |
| 250 reverse_iterator makeReverseIterator(const Node* position) { return reverse_ iterator(position, this); } | |
| 251 const_reverse_iterator makeConstReverseIterator(const Node* position) const { return const_reverse_iterator(position, this); } | |
| 252 | |
| 253 ImplType m_impl; | |
| 254 NodeBase m_anchor; | |
|
Mikhail
2014/04/03 09:32:18
Could you pls explain why not working with pointer
Erik Corry
2014/04/10 10:47:37
Locality of reference, pressure on the allocator,
| |
| 255 #ifndef NDEBUG | |
| 256 uint64_t m_modifications; | |
| 257 #endif | |
| 258 }; | |
| 259 | |
| 260 template<typename Value, typename HashFunctions> | |
| 261 struct LinkedHashSetTranslator { | |
| 262 typedef LinkedHashSetNode<Value> Node; | |
| 263 typedef LinkedHashSetNodeBase NodeBase; | |
| 264 static unsigned hash(const Node& node) { return HashFunctions::hash(node.m_v alue); } | |
| 265 static unsigned hash(const Value& key) { return HashFunctions::hash(key); } | |
| 266 static bool equal(const Value& a, const Value& b) { return HashFunctions::eq ual(a, b); } | |
| 267 static bool equal(const Node& a, const Value& b) { return HashFunctions::equ al(a.m_value, b); } | |
| 268 static bool equal(const Value& a, const Node& b) { return HashFunctions::equ al(a, b.m_value); } | |
| 269 static bool equal(const Node& a, const Node& b) { return HashFunctions::equa l(a.m_value, b.m_value); } | |
| 270 static void translate(Node& location, const Value& key, NodeBase* anchor) | |
| 271 { | |
| 272 location.m_value = key; | |
| 273 anchor->insertBefore(location); | |
| 274 } | |
| 275 | |
| 276 // Empty (or deleted) slots have the m_next pointer set to null, but we | |
| 277 // don't do anything to the other fields, which may contain junk. | |
| 278 // Therefore you can't compare a newly constructed empty value with a | |
| 279 // slot and get the right answer. | |
| 280 static const bool safeToCompareToEmptyOrDeleted = false; | |
| 281 }; | |
| 282 | |
| 283 template<typename Value> | |
| 284 struct LinkedHashSetExtractor { | |
| 285 static const Value& extract(const LinkedHashSetNode<Value>& node) { return n ode.m_value; } | |
| 286 }; | |
| 287 | |
| 288 template<typename Value, typename ValueTraitsArg> | |
| 289 struct LinkedHashSetTraits : public SimpleClassHashTraits<LinkedHashSetNode<Valu e> > { | |
| 290 typedef LinkedHashSetNode<Value> Node; | |
| 291 typedef ValueTraitsArg ValueTraits; | |
| 292 | |
| 293 // The slot is empty when the m_next field is zero so it's safe to zero | |
| 294 // the backing. | |
| 295 static const bool emptyValueIsZero = true; | |
| 296 | |
| 297 static const bool hasIsEmptyValueFunction = true; | |
| 298 static bool isEmptyValue(const Node& value) { return !value.m_next; } | |
| 299 | |
| 300 static const int deletedValue = -1; | |
| 301 | |
| 302 static void constructDeletedValue(Node& slot) { slot.m_next = reinterpret_ca st<Node*>(deletedValue); } | |
| 303 static bool isDeletedValue(const Node& slot) { return slot.m_next == reinter pret_cast<Node*>(deletedValue); } | |
| 304 | |
| 305 // We always need to call destructors, that's how we get linked and | |
| 306 // unlinked from the chain. | |
| 307 static const bool needsDestruction = true; | |
| 308 | |
| 309 // Whether we need to trace and do weak processing depends on the traits of | |
| 310 // the type inside the node. | |
| 311 template<typename U = void> | |
| 312 struct NeedsTracingLazily { | |
| 313 static const bool value = ValueTraits::template NeedsTracingLazily<>::va lue; | |
| 314 }; | |
| 315 static const bool isWeak = ValueTraits::isWeak; | |
| 316 }; | |
| 317 | |
| 318 template<typename LinkedHashSetType> | |
| 319 class LinkedHashSetIterator { | |
| 320 private: | |
| 321 typedef typename LinkedHashSetType::Node Node; | |
| 322 typedef typename LinkedHashSetType::Traits Traits; | |
| 323 | |
| 324 typedef typename LinkedHashSetType::Value& ReferenceType; | |
| 325 typedef typename LinkedHashSetType::Value* PointerType; | |
| 326 | |
| 327 typedef LinkedHashSetConstIterator<LinkedHashSetType> const_iterator; | |
| 328 | |
| 329 Node* node() const { return const_cast<Node*>(m_iterator.node()); } | |
| 330 | |
| 331 protected: | |
| 332 LinkedHashSetIterator(const Node* position, LinkedHashSetType* m_container) | |
| 333 : m_iterator(position , m_container) | |
| 334 { | |
| 335 } | |
| 336 | |
| 337 public: | |
| 338 // default copy, assignment and destructor are OK | |
|
Mads Ager (chromium)
2014/04/03 09:44:58
Begin comment with capital letter and end with per
Erik Corry
2014/04/10 10:47:37
Done.
| |
| 339 | |
| 340 PointerType get() const { return const_cast<PointerType>(m_iterator.get()); } | |
| 341 ReferenceType operator*() const { return *get(); } | |
| 342 PointerType operator->() const { return get(); } | |
| 343 | |
| 344 LinkedHashSetIterator& operator++() { ++m_iterator; return *this; } | |
| 345 LinkedHashSetIterator& operator--() { --m_iterator; return *this; } | |
| 346 | |
| 347 // Postfix ++ and -- intentionally omitted. | |
| 348 | |
| 349 // Comparison. | |
| 350 bool operator==(const LinkedHashSetIterator& other) const { return m_iterato r == other.m_iterator; } | |
| 351 bool operator!=(const LinkedHashSetIterator& other) const { return m_iterato r != other.m_iterator; } | |
| 352 | |
| 353 operator const_iterator() const { return m_iterator; } | |
| 354 | |
| 355 protected: | |
| 356 const_iterator m_iterator; | |
| 357 template<typename T, typename U, typename V, typename W> friend class Linked HashSet; | |
| 358 }; | |
| 359 | |
| 360 template<typename LinkedHashSetType> | |
| 361 class LinkedHashSetConstIterator { | |
| 362 private: | |
| 363 typedef typename LinkedHashSetType::Node Node; | |
| 364 typedef typename LinkedHashSetType::Traits Traits; | |
| 365 | |
| 366 typedef const typename LinkedHashSetType::Value& ReferenceType; | |
| 367 typedef const typename LinkedHashSetType::Value* PointerType; | |
| 368 | |
| 369 const Node* node() const { return static_cast<const Node*>(m_position); } | |
| 370 | |
| 371 protected: | |
| 372 LinkedHashSetConstIterator( | |
| 373 const LinkedHashSetNodeBase* position, | |
|
Mads Ager (chromium)
2014/04/03 09:44:58
Very strange indentation. Just put this on one lin
Erik Corry
2014/04/10 10:47:37
Done (I had some ifdefs here, but I got rid of the
| |
| 374 const LinkedHashSetType* container | |
| 375 ) | |
| 376 : m_position(position) | |
| 377 #ifndef NDEBUG | |
|
Mikhail
2014/04/03 09:32:18
#ifdef ASSERT_ENABLED ? (same in other similar pla
Erik Corry
2014/04/10 10:47:37
Done.
| |
| 378 , m_container(container) | |
| 379 , m_containerModifications(container->modifications()) | |
| 380 #endif | |
| 381 { | |
| 382 } | |
| 383 | |
| 384 public: | |
| 385 PointerType get() const | |
| 386 { | |
| 387 checkModifications(); | |
| 388 return &static_cast<const Node*>(m_position)->m_value; | |
| 389 } | |
| 390 ReferenceType operator*() const { return *get(); } | |
| 391 PointerType operator->() const { return get(); } | |
| 392 | |
| 393 LinkedHashSetConstIterator& operator++() | |
| 394 { | |
| 395 ASSERT(m_position); | |
| 396 checkModifications(); | |
| 397 m_position = m_position->m_next; | |
| 398 return *this; | |
| 399 } | |
| 400 | |
| 401 LinkedHashSetConstIterator& operator--() | |
| 402 { | |
| 403 ASSERT(m_position); | |
| 404 checkModifications(); | |
| 405 m_position = m_position->m_prev; | |
| 406 return *this; | |
| 407 } | |
| 408 | |
| 409 // Postfix ++ and -- intentionally omitted. | |
| 410 | |
| 411 // Comparison. | |
| 412 bool operator==(const LinkedHashSetConstIterator& other) const | |
| 413 { | |
| 414 return m_position == other.m_position; | |
| 415 } | |
| 416 bool operator!=(const LinkedHashSetConstIterator& other) const | |
| 417 { | |
| 418 return m_position != other.m_position; | |
| 419 } | |
| 420 | |
| 421 private: | |
| 422 const LinkedHashSetNodeBase* m_position; | |
| 423 #ifdef NDEBUG | |
|
Mads Ager (chromium)
2014/04/03 09:44:58
These were guarded by ASSERT_ENABLED or something
Erik Corry
2014/04/10 10:47:37
Done.
| |
| 424 void checkModifications() const { } | |
| 425 #else | |
| 426 void checkModifications() const { m_container->checkModifications(m_containe rModifications); } | |
| 427 const LinkedHashSetType* m_container; | |
|
Mikhail
2014/04/03 09:32:18
I guess m_container can be const pointer: const Li
Erik Corry
2014/04/10 10:47:37
It turns out if you do this then you can't overwri
| |
| 428 const int64_t m_containerModifications; | |
| 429 #endif | |
| 430 template<typename T, typename U, typename V, typename W> friend class Linked HashSet; | |
| 431 friend class LinkedHashSetIterator<LinkedHashSetType>; | |
| 432 }; | |
| 433 | |
| 434 template<typename LinkedHashSetType> | |
| 435 class LinkedHashSetReverseIterator : public LinkedHashSetIterator<LinkedHashSetT ype> { | |
| 436 typedef LinkedHashSetIterator<LinkedHashSetType> Superclass; | |
| 437 typedef LinkedHashSetConstReverseIterator<LinkedHashSetType> const_reverse_i terator; | |
| 438 typedef typename LinkedHashSetType::Node Node; | |
| 439 | |
| 440 protected: | |
| 441 LinkedHashSetReverseIterator(const Node* position, LinkedHashSetType* contai ner) | |
| 442 : Superclass(position, container) { } | |
| 443 | |
| 444 public: | |
| 445 LinkedHashSetReverseIterator& operator++() { Superclass::operator--(); retur n *this; } | |
| 446 LinkedHashSetReverseIterator& operator--() { Superclass::operator++(); retur n *this; } | |
| 447 | |
| 448 // Postfix ++ and -- intentionally omitted. | |
| 449 | |
| 450 operator const_reverse_iterator() const { return *reinterpret_cast<const_rev erse_iterator*>(this); } | |
| 451 | |
| 452 template<typename T, typename U, typename V, typename W> friend class Linked HashSet; | |
| 453 }; | |
| 454 | |
| 455 template<typename LinkedHashSetType> | |
| 456 class LinkedHashSetConstReverseIterator : public LinkedHashSetConstIterator<Link edHashSetType> { | |
| 457 typedef LinkedHashSetConstIterator<LinkedHashSetType> Superclass; | |
| 458 typedef typename LinkedHashSetType::Node Node; | |
| 459 | |
| 460 public: | |
| 461 LinkedHashSetConstReverseIterator(const Node* position, const LinkedHashSetT ype* container) | |
| 462 : Superclass(position, container) { } | |
| 463 | |
| 464 LinkedHashSetConstReverseIterator& operator++() { Superclass::operator--(); return *this; } | |
| 465 LinkedHashSetConstReverseIterator& operator--() { Superclass::operator++(); return *this; } | |
| 466 | |
| 467 // Postfix ++ and -- intentionally omitted. | |
| 468 | |
| 469 template<typename T, typename U, typename V, typename W> friend class Linked HashSet; | |
| 470 }; | |
| 471 | |
| 472 template<typename T, typename U, typename V, typename W> | |
| 473 inline LinkedHashSet<T, U, V, W>::LinkedHashSet() : m_anchor() { } | |
|
Mikhail
2014/04/03 09:32:18
well if m_anchor is a class instance, the default
Erik Corry
2014/04/10 10:47:37
Done.
| |
| 474 | |
| 475 template<typename T, typename U, typename V, typename W> | |
| 476 inline LinkedHashSet<T, U, V, W>::LinkedHashSet(const LinkedHashSet& other) | |
| 477 : m_anchor() | |
| 478 { | |
| 479 const_iterator end = other.end(); | |
| 480 for (const_iterator it = other.begin(); it != end; ++it) | |
| 481 add(*it); | |
| 482 } | |
| 483 | |
| 484 template<typename T, typename U, typename V, typename W> | |
| 485 inline LinkedHashSet<T, U, V, W>& LinkedHashSet<T, U, V, W>::operator=(const Lin kedHashSet& other) | |
| 486 { | |
| 487 LinkedHashSet tmp(other); | |
| 488 swap(tmp); | |
| 489 return *this; | |
| 490 } | |
| 491 | |
| 492 template<typename T, typename U, typename V, typename W> | |
| 493 inline void LinkedHashSet<T, U, V, W>::swap(LinkedHashSet& other) | |
| 494 { | |
| 495 m_impl.swap(other.m_impl); | |
| 496 using namespace std; | |
|
Mikhail
2014/04/03 09:32:18
"using std::swap;" is better to use IMHO, so that
Mads Ager (chromium)
2014/04/03 09:44:58
We decided to not do this style of swap, right. Ju
Erik Corry
2014/04/10 10:47:37
I removed the using std instead, because in this c
Erik Corry
2014/04/10 10:47:37
Fixed.
| |
| 497 swap(m_anchor, other.m_anchor); | |
| 498 } | |
| 499 | |
| 500 template<typename T, typename U, typename V, typename Allocator> | |
| 501 inline LinkedHashSet<T, U, V, Allocator>::~LinkedHashSet() | |
| 502 { | |
| 503 // The destructor of m_anchor will implicitly be called here, which will | |
| 504 // unlink the anchor from the collection. | |
| 505 } | |
| 506 | |
| 507 template<typename T, typename U, typename V, typename W> | |
| 508 inline T& LinkedHashSet<T, U, V, W>::first() | |
| 509 { | |
| 510 ASSERT(!isEmpty()); | |
| 511 return firstNode()->m_value; | |
| 512 } | |
| 513 | |
| 514 template<typename T, typename U, typename V, typename W> | |
| 515 inline const T& LinkedHashSet<T, U, V, W>::first() const | |
| 516 { | |
| 517 ASSERT(!isEmpty()); | |
| 518 return firstNode()->m_value; | |
| 519 } | |
| 520 | |
| 521 template<typename T, typename U, typename V, typename W> | |
| 522 inline void LinkedHashSet<T, U, V, W>::removeFirst() | |
| 523 { | |
| 524 ASSERT(!isEmpty()); | |
| 525 m_impl.remove(*m_anchor.m_next); | |
| 526 } | |
| 527 | |
| 528 template<typename T, typename U, typename V, typename W> | |
| 529 inline T& LinkedHashSet<T, U, V, W>::last() | |
| 530 { | |
| 531 ASSERT(!isEmpty()); | |
| 532 return lastNode()->m_value; | |
| 533 } | |
| 534 | |
| 535 template<typename T, typename U, typename V, typename W> | |
| 536 inline const T& LinkedHashSet<T, U, V, W>::last() const | |
| 537 { | |
| 538 ASSERT(!isEmpty()); | |
| 539 return lastNode()->m_value; | |
| 540 } | |
| 541 | |
| 542 template<typename T, typename U, typename V, typename W> | |
| 543 inline void LinkedHashSet<T, U, V, W>::removeLast() | |
| 544 { | |
| 545 ASSERT(!isEmpty()); | |
| 546 m_impl.remove(m_anchor.m_prev); | |
|
Mikhail
2014/04/03 09:32:18
shoudl it be m_impl.remove(*m_anchor.m_prev); ?
Mads Ager (chromium)
2014/04/03 09:44:58
Do you have tests for all of these methods? This l
Erik Corry
2014/04/10 10:47:37
Actually it should be m_impl.remove(static_cast<No
Erik Corry
2014/04/10 10:47:37
No, I didn't test this and it didn't work (of cour
| |
| 547 } | |
| 548 | |
| 549 template<typename T, typename U, typename V, typename W> | |
| 550 inline typename LinkedHashSet<T, U, V, W>::iterator LinkedHashSet<T, U, V, W>::f ind(const T& value) | |
| 551 { | |
| 552 LinkedHashSet::Node* node = m_impl.template lookup<LinkedHashSet::NodeHashFu nctions, T>(value); | |
| 553 if (!node) | |
| 554 return end(); | |
| 555 return makeIterator(node); | |
| 556 } | |
| 557 | |
| 558 template<typename T, typename U, typename V, typename W> | |
| 559 inline typename LinkedHashSet<T, U, V, W>::const_iterator LinkedHashSet<T, U, V, W>::find(const T& value) const | |
| 560 { | |
| 561 const_iterator it = begin(); | |
|
Mikhail
2014/04/03 09:32:18
I did not get why this method is so different from
Erik Corry
2014/04/10 10:47:37
This was accidentally left in. My first thought w
| |
| 562 const_iterator endIterator = end(); | |
| 563 while (it != endIterator && !HashTraits<T>::equal(it->m_value, value)) | |
| 564 ++it; | |
| 565 return it; | |
| 566 } | |
| 567 | |
| 568 template<typename Value, typename U, typename V, typename W> | |
| 569 template<typename HashTranslator, typename T> | |
| 570 inline typename LinkedHashSet<Value, U, V, W>::iterator LinkedHashSet<Value, U, V, W>::find(const T& value) | |
| 571 { | |
| 572 iterator it = begin(); | |
| 573 iterator endIterator = end(); | |
| 574 while (it != endIterator && !HashTranslator::template equal<Value, T>(it->m_ value, value)) | |
| 575 ++it; | |
| 576 return it; | |
| 577 } | |
| 578 | |
| 579 template<typename Value, typename U, typename V, typename W> | |
| 580 template<typename HashTranslator, typename T> | |
| 581 inline typename LinkedHashSet<Value, U, V, W>::const_iterator LinkedHashSet<Valu e, U, V, W>::find(const T& value) const | |
| 582 { | |
| 583 const_iterator it = begin(); | |
| 584 const_iterator endIterator = end(); | |
| 585 while (it != endIterator && !HashTranslator::template equal<Value, T>(it->m_ value, value)) | |
| 586 ++it; | |
| 587 return it; | |
| 588 } | |
| 589 | |
| 590 template<typename Translator> | |
| 591 struct LinkedHashSetTranslatorAdapter { | |
| 592 template<typename T> static unsigned hash(const T& key) { return Translator: :hash(key); } | |
| 593 template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a->m_value, b); } | |
| 594 }; | |
| 595 | |
| 596 template<typename Value, typename U, typename V, typename W> | |
| 597 template<typename HashTranslator, typename T> | |
| 598 inline bool LinkedHashSet<Value, U, V, W>::contains(const T& value) const | |
| 599 { | |
| 600 return m_impl.template contains<LinkedHashSetTranslatorAdapter<HashTranslato r> >(value); | |
| 601 } | |
| 602 | |
| 603 template<typename T, typename U, typename V, typename W> | |
| 604 inline bool LinkedHashSet<T, U, V, W>::contains(const T& value) const | |
| 605 { | |
| 606 return m_impl.template contains<NodeHashFunctions>(value); | |
| 607 } | |
| 608 | |
| 609 template<typename Value, typename HashFunctions, typename Traits, typename Alloc ator> | |
| 610 typename LinkedHashSet<Value, HashFunctions, Traits, Allocator>::AddResult Linke dHashSet<Value, HashFunctions, Traits, Allocator>::add(const Value &value) | |
| 611 { | |
| 612 return m_impl.template add<LinkedHashSetTranslator<Value, HashFunctions> >(v alue, &m_anchor); | |
| 613 } | |
| 614 | |
| 615 template<typename T, typename U, typename V, typename W> | |
| 616 typename LinkedHashSet<T, U, V, W>::iterator LinkedHashSet<T, U, V, W>::addRetur nIterator(const T &value) | |
| 617 { | |
| 618 return m_impl.template addReturnIterator<NodeHashFunctions>(value); | |
| 619 } | |
| 620 | |
| 621 template<typename T, typename U, typename V, typename W> | |
| 622 typename LinkedHashSet<T, U, V, W>::AddResult LinkedHashSet<T, U, V, W>::appendO rMoveToLast(const T &value) | |
| 623 { | |
| 624 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions> (value); | |
| 625 Node* node = *result.storedValue; | |
| 626 if (!result.isNewEntry) | |
| 627 unlink(node); | |
| 628 appendNode(node); | |
| 629 return AddResult(*result.storedValue, result.isNewEntry); | |
| 630 } | |
| 631 | |
| 632 template<typename T, typename U, typename V, typename W> | |
| 633 typename LinkedHashSet<T, U, V, W>::AddResult LinkedHashSet<T, U, V, W>::prepend OrMoveToFirst(const T &value) | |
| 634 { | |
| 635 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions> (value); | |
| 636 Node* node = *result.storedValue; | |
| 637 if (!result.isNewEntry) | |
| 638 unlink(node); | |
| 639 prependNode(node); | |
| 640 return AddResult(*result.storedValue, result.isNewEntry); | |
| 641 } | |
| 642 | |
| 643 template<typename T, typename U, typename V, typename W> | |
| 644 typename LinkedHashSet<T, U, V, W>::AddResult LinkedHashSet<T, U, V, W>::insertB efore(iterator it, const T& newValue) | |
| 645 { | |
| 646 typename ImplType::AddResult result = m_impl.template add<NodeHashFunctions> (newValue); | |
| 647 if (result.isNewEntry) | |
| 648 insertNodeBefore(it.node(), *result.storedValue); | |
| 649 return AddResult(*result.storedValue, result.isNewEntry); | |
| 650 } | |
| 651 | |
| 652 template<typename T, typename U, typename V, typename W> | |
| 653 typename LinkedHashSet<T, U, V, W>::AddResult LinkedHashSet<T, U, V, W>::insertB efore(const T& beforeValue, const T& newValue) | |
| 654 { | |
| 655 return insertBefore(find(beforeValue), newValue); | |
| 656 } | |
| 657 | |
| 658 template<typename T, typename U, typename V, typename W> | |
| 659 inline void LinkedHashSet<T, U, V, W>::remove(iterator it) | |
| 660 { | |
| 661 if (it == end()) | |
| 662 return; | |
| 663 m_impl.remove(it.node()); | |
| 664 } | |
| 665 | |
| 666 template<typename T, typename U, typename V, typename W> | |
| 667 inline void LinkedHashSet<T, U, V, W>::remove(const T& value) | |
| 668 { | |
| 669 remove(find(value)); | |
| 670 } | |
| 671 | |
| 672 template<typename T> | |
| 673 struct IsWeak<LinkedHashSetNode<T> > { | |
| 674 static const bool value = IsWeak<T>::value; | |
| 675 }; | |
| 676 | |
| 677 inline void swap(LinkedHashSetNodeBase& a, LinkedHashSetNodeBase& b) | |
| 678 { | |
| 679 typedef LinkedHashSetNodeBase Base; | |
| 680 Base* aNext = a.m_next; | |
| 681 Base* aPrev = a.m_prev; | |
| 682 Base* bNext = b.m_next; | |
| 683 Base* bPrev = b.m_prev; | |
| 684 b.m_next = aNext; | |
|
Mikhail
2014/04/03 09:32:18
swap(a.m_next, b.m_next) ?
Mads Ager (chromium)
2014/04/03 09:44:58
Can you just use std::swap(a.m_next, b.m_next) for
Erik Corry
2014/04/10 10:47:37
swap gets us part of the way, so I refactored to u
| |
| 685 b.m_prev = aPrev; | |
| 686 a.m_next = bNext; | |
| 687 a.m_prev = bPrev; | |
| 688 if (aNext) { | |
| 689 aNext->m_prev = &b; | |
| 690 aPrev->m_next = &b; | |
| 691 } | |
| 692 if (bNext) { | |
| 693 bNext->m_prev = &a; | |
| 694 bPrev->m_next = &a; | |
| 695 } | |
| 696 } | |
| 697 | |
| 698 template<typename T> | |
| 699 inline void swap(LinkedHashSetNode<T>& a, LinkedHashSetNode<T>& b) | |
| 700 { | |
| 701 typedef LinkedHashSetNodeBase Base; | |
| 702 | |
| 703 using namespace std; | |
| 704 | |
| 705 swap(static_cast<Base&>(a), static_cast<Base&>(b)); | |
| 706 swap(a.m_value, b.m_value); | |
| 707 } | |
| 708 | |
| 709 } | |
| 710 | |
| 711 using WTF::LinkedHashSet; | |
| 712 | |
| 713 #endif /* WTF_LinkedHashSet_h */ | |
| OLD | NEW |