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 |