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