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 |