Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: Source/wtf/LinkedHashSet.h

Issue 223373002: Create HeapLinkedHashSet and LinkedHashSet, ordered heap-friendly hash sets. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Remove inadvertent changes Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« Source/wtf/HashTable.h ('K') | « Source/wtf/HashTable.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 */
OLDNEW
« Source/wtf/HashTable.h ('K') | « Source/wtf/HashTable.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698