| /* |
| * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserved. |
| * Copyright (C) 2011, Benjamin Poulain <ikipou@gmail.com> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| * |
| */ |
| |
| #ifndef WTF_ListHashSet_h |
| #define WTF_ListHashSet_h |
| |
| #include <wtf/HashSet.h> |
| #include <wtf/OwnPtr.h> |
| #include <wtf/PassOwnPtr.h> |
| |
| namespace WTF { |
| |
| // ListHashSet: Just like HashSet, this class provides a Set |
| // interface - a collection of unique objects with O(1) insertion, |
| // removal and test for containership. However, it also has an |
| // order - iterating it will always give back values in the order |
| // in which they are added. |
| |
| // Unlike iteration of most WTF Hash data structures, iteration is |
| // guaranteed safe against mutation of the ListHashSet, except for |
| // removal of the item currently pointed to by a given iterator. |
| |
| template<typename Value, size_t inlineCapacity, typename HashFunctions> class ListHashSet; |
| |
| template<typename Value, size_t inlineCapacity, typename HashFunctions> |
| void deleteAllValues(const ListHashSet<Value, inlineCapacity, HashFunctions>&); |
| |
| template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetIterator; |
| template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstIterator; |
| template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetReverseIterator; |
| template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstReverseIterator; |
| |
| template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNode; |
| template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNodeAllocator; |
| |
| template<typename HashArg> struct ListHashSetNodeHashFunctions; |
| template<typename HashArg> struct ListHashSetTranslator; |
| |
| template<typename ValueArg, size_t inlineCapacity = 256, typename HashArg = typename DefaultHash<ValueArg>::Hash> class ListHashSet { |
| WTF_MAKE_FAST_ALLOCATED; |
| private: |
| typedef ListHashSetNode<ValueArg, inlineCapacity> Node; |
| typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator; |
| |
| typedef HashTraits<Node*> NodeTraits; |
| typedef ListHashSetNodeHashFunctions<HashArg> NodeHash; |
| typedef ListHashSetTranslator<HashArg> BaseTranslator; |
| |
| typedef HashTable<Node*, Node*, IdentityExtractor, NodeHash, NodeTraits, NodeTraits> ImplType; |
| typedef HashTableIterator<Node*, Node*, IdentityExtractor, NodeHash, NodeTraits, NodeTraits> ImplTypeIterator; |
| typedef HashTableConstIterator<Node*, Node*, IdentityExtractor, NodeHash, NodeTraits, NodeTraits> ImplTypeConstIterator; |
| |
| typedef HashArg HashFunctions; |
| |
| public: |
| typedef ValueArg ValueType; |
| |
| typedef ListHashSetIterator<ValueType, inlineCapacity, HashArg> iterator; |
| typedef ListHashSetConstIterator<ValueType, inlineCapacity, HashArg> const_iterator; |
| friend class ListHashSetConstIterator<ValueType, inlineCapacity, HashArg>; |
| |
| typedef ListHashSetReverseIterator<ValueType, inlineCapacity, HashArg> reverse_iterator; |
| typedef ListHashSetConstReverseIterator<ValueType, inlineCapacity, HashArg> const_reverse_iterator; |
| friend class ListHashSetConstReverseIterator<ValueType, inlineCapacity, HashArg>; |
| |
| typedef HashTableAddResult<iterator> AddResult; |
| |
| ListHashSet(); |
| ListHashSet(const ListHashSet&); |
| ListHashSet& operator=(const ListHashSet&); |
| ~ListHashSet(); |
| |
| void swap(ListHashSet&); |
| |
| int size() const; |
| int capacity() const; |
| bool isEmpty() const; |
| |
| size_t sizeInBytes() const; |
| |
| iterator begin(); |
| iterator end(); |
| const_iterator begin() const; |
| const_iterator end() const; |
| |
| reverse_iterator rbegin(); |
| reverse_iterator rend(); |
| const_reverse_iterator rbegin() const; |
| const_reverse_iterator rend() const; |
| |
| ValueType& first(); |
| const ValueType& first() const; |
| void removeFirst(); |
| |
| ValueType& last(); |
| const ValueType& last() const; |
| void removeLast(); |
| |
| iterator find(const ValueType&); |
| const_iterator find(const ValueType&) const; |
| bool contains(const ValueType&) const; |
| |
| // An alternate version of find() that finds the object by hashing and comparing |
| // with some other type, to avoid the cost of type conversion. |
| // The HashTranslator interface is defined in HashSet. |
| // FIXME: We should reverse the order of the template arguments so that callers |
| // can just pass the translator let the compiler deduce T. |
| template<typename T, typename HashTranslator> iterator find(const T&); |
| template<typename T, typename HashTranslator> const_iterator find(const T&) const; |
| template<typename T, typename HashTranslator> bool contains(const T&) const; |
| |
| // The return value of add is a pair of an iterator to the new value's location, |
| // and a bool that is true if an new entry was added. |
| AddResult add(const ValueType&); |
| |
| // Add the value to the end of the collection. If the value was already in |
| // the list, it is moved to the end. |
| AddResult appendOrMoveToLast(const ValueType&); |
| |
| // Add the value to the beginning of the collection. If the value was already in |
| // the list, it is moved to the beginning. |
| AddResult prependOrMoveToFirst(const ValueType&); |
| |
| AddResult insertBefore(const ValueType& beforeValue, const ValueType& newValue); |
| AddResult insertBefore(iterator, const ValueType&); |
| |
| void remove(const ValueType&); |
| void remove(iterator); |
| void clear(); |
| |
| private: |
| void unlink(Node*); |
| void unlinkAndDelete(Node*); |
| void appendNode(Node*); |
| void prependNode(Node*); |
| void insertNodeBefore(Node* beforeNode, Node* newNode); |
| void deleteAllNodes(); |
| |
| iterator makeIterator(Node*); |
| const_iterator makeConstIterator(Node*) const; |
| reverse_iterator makeReverseIterator(Node*); |
| const_reverse_iterator makeConstReverseIterator(Node*) const; |
| |
| friend void deleteAllValues<>(const ListHashSet&); |
| |
| ImplType m_impl; |
| Node* m_head; |
| Node* m_tail; |
| OwnPtr<NodeAllocator> m_allocator; |
| }; |
| |
| template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNodeAllocator { |
| typedef ListHashSetNode<ValueArg, inlineCapacity> Node; |
| typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator; |
| |
| ListHashSetNodeAllocator() |
| : m_freeList(pool()) |
| , m_isDoneWithInitialFreeList(false) |
| { |
| memset(m_pool.pool, 0, sizeof(m_pool.pool)); |
| } |
| |
| Node* allocate() |
| { |
| Node* result = m_freeList; |
| |
| if (!result) |
| return static_cast<Node*>(fastMalloc(sizeof(Node))); |
| |
| ASSERT(!result->m_isAllocated); |
| |
| Node* next = result->m_next; |
| ASSERT(!next || !next->m_isAllocated); |
| if (!next && !m_isDoneWithInitialFreeList) { |
| next = result + 1; |
| if (next == pastPool()) { |
| m_isDoneWithInitialFreeList = true; |
| next = 0; |
| } else { |
| ASSERT(inPool(next)); |
| ASSERT(!next->m_isAllocated); |
| } |
| } |
| m_freeList = next; |
| |
| return result; |
| } |
| |
| void deallocate(Node* node) |
| { |
| if (inPool(node)) { |
| #ifndef NDEBUG |
| node->m_isAllocated = false; |
| #endif |
| node->m_next = m_freeList; |
| m_freeList = node; |
| return; |
| } |
| |
| fastFree(node); |
| } |
| |
| bool inPool(Node* node) |
| { |
| return node >= pool() && node < pastPool(); |
| } |
| |
| private: |
| Node* pool() { return reinterpret_cast_ptr<Node*>(m_pool.pool); } |
| Node* pastPool() { return pool() + m_poolSize; } |
| |
| Node* m_freeList; |
| bool m_isDoneWithInitialFreeList; |
| static const size_t m_poolSize = inlineCapacity; |
| union { |
| char pool[sizeof(Node) * m_poolSize]; |
| double forAlignment; |
| } m_pool; |
| }; |
| |
| template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNode { |
| typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator; |
| |
| ListHashSetNode(ValueArg value) |
| : m_value(value) |
| , m_prev(0) |
| , m_next(0) |
| #ifndef NDEBUG |
| , m_isAllocated(true) |
| #endif |
| { |
| } |
| |
| void* operator new(size_t, NodeAllocator* allocator) |
| { |
| return allocator->allocate(); |
| } |
| void destroy(NodeAllocator* allocator) |
| { |
| this->~ListHashSetNode(); |
| allocator->deallocate(this); |
| } |
| |
| ValueArg m_value; |
| ListHashSetNode* m_prev; |
| ListHashSetNode* m_next; |
| |
| #ifndef NDEBUG |
| bool m_isAllocated; |
| #endif |
| }; |
| |
| template<typename HashArg> struct ListHashSetNodeHashFunctions { |
| template<typename T> static unsigned hash(const T& key) { return HashArg::hash(key->m_value); } |
| template<typename T> static bool equal(const T& a, const T& b) { return HashArg::equal(a->m_value, b->m_value); } |
| static const bool safeToCompareToEmptyOrDeleted = false; |
| }; |
| |
| template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetIterator { |
| private: |
| typedef ListHashSet<ValueArg, inlineCapacity, HashArg> ListHashSetType; |
| typedef ListHashSetIterator<ValueArg, inlineCapacity, HashArg> iterator; |
| typedef ListHashSetConstIterator<ValueArg, inlineCapacity, HashArg> const_iterator; |
| typedef ListHashSetNode<ValueArg, inlineCapacity> Node; |
| typedef ValueArg ValueType; |
| typedef ValueType& ReferenceType; |
| typedef ValueType* PointerType; |
| |
| friend class ListHashSet<ValueArg, inlineCapacity, HashArg>; |
| |
| ListHashSetIterator(const ListHashSetType* set, Node* position) : m_iterator(set, position) { } |
| |
| public: |
| ListHashSetIterator() { } |
| |
| // default copy, assignment and destructor are OK |
| |
| PointerType get() const { return const_cast<PointerType>(m_iterator.get()); } |
| ReferenceType operator*() const { return *get(); } |
| PointerType operator->() const { return get(); } |
| |
| iterator& operator++() { ++m_iterator; return *this; } |
| |
| // postfix ++ intentionally omitted |
| |
| iterator& operator--() { --m_iterator; return *this; } |
| |
| // postfix -- intentionally omitted |
| |
| // Comparison. |
| bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; } |
| bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; } |
| |
| operator const_iterator() const { return m_iterator; } |
| |
| private: |
| Node* node() { return m_iterator.node(); } |
| |
| const_iterator m_iterator; |
| }; |
| |
| template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstIterator { |
| private: |
| typedef ListHashSet<ValueArg, inlineCapacity, HashArg> ListHashSetType; |
| typedef ListHashSetIterator<ValueArg, inlineCapacity, HashArg> iterator; |
| typedef ListHashSetConstIterator<ValueArg, inlineCapacity, HashArg> const_iterator; |
| typedef ListHashSetNode<ValueArg, inlineCapacity> Node; |
| typedef ValueArg ValueType; |
| typedef const ValueType& ReferenceType; |
| typedef const ValueType* PointerType; |
| |
| friend class ListHashSet<ValueArg, inlineCapacity, HashArg>; |
| friend class ListHashSetIterator<ValueArg, inlineCapacity, HashArg>; |
| |
| ListHashSetConstIterator(const ListHashSetType* set, Node* position) |
| : m_set(set) |
| , m_position(position) |
| { |
| } |
| |
| public: |
| ListHashSetConstIterator() |
| { |
| } |
| |
| PointerType get() const |
| { |
| return &m_position->m_value; |
| } |
| ReferenceType operator*() const { return *get(); } |
| PointerType operator->() const { return get(); } |
| |
| const_iterator& operator++() |
| { |
| ASSERT(m_position != 0); |
| m_position = m_position->m_next; |
| return *this; |
| } |
| |
| // postfix ++ intentionally omitted |
| |
| const_iterator& operator--() |
| { |
| ASSERT(m_position != m_set->m_head); |
| if (!m_position) |
| m_position = m_set->m_tail; |
| else |
| m_position = m_position->m_prev; |
| return *this; |
| } |
| |
| // postfix -- intentionally omitted |
| |
| // Comparison. |
| bool operator==(const const_iterator& other) const |
| { |
| return m_position == other.m_position; |
| } |
| bool operator!=(const const_iterator& other) const |
| { |
| return m_position != other.m_position; |
| } |
| |
| private: |
| Node* node() { return m_position; } |
| |
| const ListHashSetType* m_set; |
| Node* m_position; |
| }; |
| |
| template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetReverseIterator { |
| private: |
| typedef ListHashSet<ValueArg, inlineCapacity, HashArg> ListHashSetType; |
| typedef ListHashSetReverseIterator<ValueArg, inlineCapacity, HashArg> reverse_iterator; |
| typedef ListHashSetConstReverseIterator<ValueArg, inlineCapacity, HashArg> const_reverse_iterator; |
| typedef ListHashSetNode<ValueArg, inlineCapacity> Node; |
| typedef ValueArg ValueType; |
| typedef ValueType& ReferenceType; |
| typedef ValueType* PointerType; |
| |
| friend class ListHashSet<ValueArg, inlineCapacity, HashArg>; |
| |
| ListHashSetReverseIterator(const ListHashSetType* set, Node* position) : m_iterator(set, position) { } |
| |
| public: |
| ListHashSetReverseIterator() { } |
| |
| // default copy, assignment and destructor are OK |
| |
| PointerType get() const { return const_cast<PointerType>(m_iterator.get()); } |
| ReferenceType operator*() const { return *get(); } |
| PointerType operator->() const { return get(); } |
| |
| reverse_iterator& operator++() { ++m_iterator; return *this; } |
| |
| // postfix ++ intentionally omitted |
| |
| reverse_iterator& operator--() { --m_iterator; return *this; } |
| |
| // postfix -- intentionally omitted |
| |
| // Comparison. |
| bool operator==(const reverse_iterator& other) const { return m_iterator == other.m_iterator; } |
| bool operator!=(const reverse_iterator& other) const { return m_iterator != other.m_iterator; } |
| |
| operator const_reverse_iterator() const { return m_iterator; } |
| |
| private: |
| Node* node() { return m_iterator.node(); } |
| |
| const_reverse_iterator m_iterator; |
| }; |
| |
| template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstReverseIterator { |
| private: |
| typedef ListHashSet<ValueArg, inlineCapacity, HashArg> ListHashSetType; |
| typedef ListHashSetReverseIterator<ValueArg, inlineCapacity, HashArg> reverse_iterator; |
| typedef ListHashSetConstReverseIterator<ValueArg, inlineCapacity, HashArg> const_reverse_iterator; |
| typedef ListHashSetNode<ValueArg, inlineCapacity> Node; |
| typedef ValueArg ValueType; |
| typedef const ValueType& ReferenceType; |
| typedef const ValueType* PointerType; |
| |
| friend class ListHashSet<ValueArg, inlineCapacity, HashArg>; |
| friend class ListHashSetReverseIterator<ValueArg, inlineCapacity, HashArg>; |
| |
| ListHashSetConstReverseIterator(const ListHashSetType* set, Node* position) |
| : m_set(set) |
| , m_position(position) |
| { |
| } |
| |
| public: |
| ListHashSetConstReverseIterator() |
| { |
| } |
| |
| PointerType get() const |
| { |
| return &m_position->m_value; |
| } |
| ReferenceType operator*() const { return *get(); } |
| PointerType operator->() const { return get(); } |
| |
| const_reverse_iterator& operator++() |
| { |
| ASSERT(m_position != 0); |
| m_position = m_position->m_prev; |
| return *this; |
| } |
| |
| // postfix ++ intentionally omitted |
| |
| const_reverse_iterator& operator--() |
| { |
| ASSERT(m_position != m_set->m_tail); |
| if (!m_position) |
| m_position = m_set->m_head; |
| else |
| m_position = m_position->m_next; |
| return *this; |
| } |
| |
| // postfix -- intentionally omitted |
| |
| // Comparison. |
| bool operator==(const const_reverse_iterator& other) const |
| { |
| return m_position == other.m_position; |
| } |
| bool operator!=(const const_reverse_iterator& other) const |
| { |
| return m_position != other.m_position; |
| } |
| |
| private: |
| Node* node() { return m_position; } |
| |
| const ListHashSetType* m_set; |
| Node* m_position; |
| }; |
| |
| template<typename HashFunctions> |
| struct ListHashSetTranslator { |
| template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); } |
| template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a->m_value, b); } |
| template<typename T, typename U, typename V> static void translate(T*& location, const U& key, const V& allocator) |
| { |
| location = new (allocator) T(key); |
| } |
| }; |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline ListHashSet<T, inlineCapacity, U>::ListHashSet() |
| : m_head(0) |
| , m_tail(0) |
| , m_allocator(adoptPtr(new NodeAllocator)) |
| { |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline ListHashSet<T, inlineCapacity, U>::ListHashSet(const ListHashSet& other) |
| : m_head(0) |
| , m_tail(0) |
| , m_allocator(adoptPtr(new NodeAllocator)) |
| { |
| const_iterator end = other.end(); |
| for (const_iterator it = other.begin(); it != end; ++it) |
| add(*it); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline ListHashSet<T, inlineCapacity, U>& ListHashSet<T, inlineCapacity, U>::operator=(const ListHashSet& other) |
| { |
| ListHashSet tmp(other); |
| swap(tmp); |
| return *this; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline void ListHashSet<T, inlineCapacity, U>::swap(ListHashSet& other) |
| { |
| m_impl.swap(other.m_impl); |
| std::swap(m_head, other.m_head); |
| std::swap(m_tail, other.m_tail); |
| m_allocator.swap(other.m_allocator); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline ListHashSet<T, inlineCapacity, U>::~ListHashSet() |
| { |
| deleteAllNodes(); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline int ListHashSet<T, inlineCapacity, U>::size() const |
| { |
| return m_impl.size(); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline int ListHashSet<T, inlineCapacity, U>::capacity() const |
| { |
| return m_impl.capacity(); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline bool ListHashSet<T, inlineCapacity, U>::isEmpty() const |
| { |
| return m_impl.isEmpty(); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| size_t ListHashSet<T, inlineCapacity, U>::sizeInBytes() const |
| { |
| size_t result = sizeof(*this) + sizeof(*m_allocator); |
| result += sizeof(typename ImplType::ValueType) * m_impl.capacity(); |
| for (Node* node = m_head; node; node = node->m_next) { |
| if (!m_allocator->inPool(node)) |
| result += sizeof(Node); |
| } |
| return result; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::begin() |
| { |
| return makeIterator(m_head); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::end() |
| { |
| return makeIterator(0); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline typename ListHashSet<T, inlineCapacity, U>::const_iterator ListHashSet<T, inlineCapacity, U>::begin() const |
| { |
| return makeConstIterator(m_head); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline typename ListHashSet<T, inlineCapacity, U>::const_iterator ListHashSet<T, inlineCapacity, U>::end() const |
| { |
| return makeConstIterator(0); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline typename ListHashSet<T, inlineCapacity, U>::reverse_iterator ListHashSet<T, inlineCapacity, U>::rbegin() |
| { |
| return makeReverseIterator(m_tail); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline typename ListHashSet<T, inlineCapacity, U>::reverse_iterator ListHashSet<T, inlineCapacity, U>::rend() |
| { |
| return makeReverseIterator(0); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline typename ListHashSet<T, inlineCapacity, U>::const_reverse_iterator ListHashSet<T, inlineCapacity, U>::rbegin() const |
| { |
| return makeConstReverseIterator(m_tail); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline typename ListHashSet<T, inlineCapacity, U>::const_reverse_iterator ListHashSet<T, inlineCapacity, U>::rend() const |
| { |
| return makeConstReverseIterator(0); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline T& ListHashSet<T, inlineCapacity, U>::first() |
| { |
| ASSERT(!isEmpty()); |
| return m_head->m_value; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline void ListHashSet<T, inlineCapacity, U>::removeFirst() |
| { |
| ASSERT(!isEmpty()); |
| m_impl.remove(m_head); |
| unlinkAndDelete(m_head); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline const T& ListHashSet<T, inlineCapacity, U>::first() const |
| { |
| ASSERT(!isEmpty()); |
| return m_head->m_value; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline T& ListHashSet<T, inlineCapacity, U>::last() |
| { |
| ASSERT(!isEmpty()); |
| return m_tail->m_value; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline const T& ListHashSet<T, inlineCapacity, U>::last() const |
| { |
| ASSERT(!isEmpty()); |
| return m_tail->m_value; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline void ListHashSet<T, inlineCapacity, U>::removeLast() |
| { |
| ASSERT(!isEmpty()); |
| m_impl.remove(m_tail); |
| unlinkAndDelete(m_tail); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::find(const ValueType& value) |
| { |
| ImplTypeIterator it = m_impl.template find<BaseTranslator>(value); |
| if (it == m_impl.end()) |
| return end(); |
| return makeIterator(*it); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline typename ListHashSet<T, inlineCapacity, U>::const_iterator ListHashSet<T, inlineCapacity, U>::find(const ValueType& value) const |
| { |
| ImplTypeConstIterator it = m_impl.template find<BaseTranslator>(value); |
| if (it == m_impl.end()) |
| return end(); |
| return makeConstIterator(*it); |
| } |
| |
| template<typename Translator> |
| struct ListHashSetTranslatorAdapter { |
| template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); } |
| template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a->m_value, b); } |
| }; |
| |
| template<typename ValueType, size_t inlineCapacity, typename U> |
| template<typename T, typename HashTranslator> |
| inline typename ListHashSet<ValueType, inlineCapacity, U>::iterator ListHashSet<ValueType, inlineCapacity, U>::find(const T& value) |
| { |
| ImplTypeConstIterator it = m_impl.template find<ListHashSetTranslatorAdapter<HashTranslator> >(value); |
| if (it == m_impl.end()) |
| return end(); |
| return makeIterator(*it); |
| } |
| |
| template<typename ValueType, size_t inlineCapacity, typename U> |
| template<typename T, typename HashTranslator> |
| inline typename ListHashSet<ValueType, inlineCapacity, U>::const_iterator ListHashSet<ValueType, inlineCapacity, U>::find(const T& value) const |
| { |
| ImplTypeConstIterator it = m_impl.template find<ListHashSetTranslatorAdapter<HashTranslator> >(value); |
| if (it == m_impl.end()) |
| return end(); |
| return makeConstIterator(*it); |
| } |
| |
| template<typename ValueType, size_t inlineCapacity, typename U> |
| template<typename T, typename HashTranslator> |
| inline bool ListHashSet<ValueType, inlineCapacity, U>::contains(const T& value) const |
| { |
| return m_impl.template contains<ListHashSetTranslatorAdapter<HashTranslator> >(value); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline bool ListHashSet<T, inlineCapacity, U>::contains(const ValueType& value) const |
| { |
| return m_impl.template contains<BaseTranslator>(value); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| typename ListHashSet<T, inlineCapacity, U>::AddResult ListHashSet<T, inlineCapacity, U>::add(const ValueType &value) |
| { |
| typename ImplType::AddResult result = m_impl.template add<BaseTranslator>(value, m_allocator.get()); |
| if (result.isNewEntry) |
| appendNode(*result.iterator); |
| return AddResult(makeIterator(*result.iterator), result.isNewEntry); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| typename ListHashSet<T, inlineCapacity, U>::AddResult ListHashSet<T, inlineCapacity, U>::appendOrMoveToLast(const ValueType &value) |
| { |
| typename ImplType::AddResult result = m_impl.template add<BaseTranslator>(value, m_allocator.get()); |
| Node* node = *result.iterator; |
| if (!result.isNewEntry) |
| unlink(node); |
| appendNode(node); |
| return AddResult(makeIterator(*result.iterator), result.isNewEntry); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| typename ListHashSet<T, inlineCapacity, U>::AddResult ListHashSet<T, inlineCapacity, U>::prependOrMoveToFirst(const ValueType &value) |
| { |
| typename ImplType::AddResult result = m_impl.template add<BaseTranslator>(value, m_allocator.get()); |
| Node* node = *result.iterator; |
| if (!result.isNewEntry) |
| unlink(node); |
| prependNode(node); |
| return AddResult(makeIterator(*result.iterator), result.isNewEntry); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| typename ListHashSet<T, inlineCapacity, U>::AddResult ListHashSet<T, inlineCapacity, U>::insertBefore(iterator it, const ValueType& newValue) |
| { |
| typename ImplType::AddResult result = m_impl.template add<BaseTranslator>(newValue, m_allocator.get()); |
| if (result.isNewEntry) |
| insertNodeBefore(it.node(), *result.iterator); |
| return AddResult(makeIterator(*result.iterator), result.isNewEntry); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| typename ListHashSet<T, inlineCapacity, U>::AddResult ListHashSet<T, inlineCapacity, U>::insertBefore(const ValueType& beforeValue, const ValueType& newValue) |
| { |
| return insertBefore(find(beforeValue), newValue); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline void ListHashSet<T, inlineCapacity, U>::remove(iterator it) |
| { |
| if (it == end()) |
| return; |
| m_impl.remove(it.node()); |
| unlinkAndDelete(it.node()); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline void ListHashSet<T, inlineCapacity, U>::remove(const ValueType& value) |
| { |
| remove(find(value)); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline void ListHashSet<T, inlineCapacity, U>::clear() |
| { |
| deleteAllNodes(); |
| m_impl.clear(); |
| m_head = 0; |
| m_tail = 0; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| void ListHashSet<T, inlineCapacity, U>::unlink(Node* node) |
| { |
| if (!node->m_prev) { |
| ASSERT(node == m_head); |
| m_head = node->m_next; |
| } else { |
| ASSERT(node != m_head); |
| node->m_prev->m_next = node->m_next; |
| } |
| |
| if (!node->m_next) { |
| ASSERT(node == m_tail); |
| m_tail = node->m_prev; |
| } else { |
| ASSERT(node != m_tail); |
| node->m_next->m_prev = node->m_prev; |
| } |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| void ListHashSet<T, inlineCapacity, U>::unlinkAndDelete(Node* node) |
| { |
| unlink(node); |
| node->destroy(m_allocator.get()); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| void ListHashSet<T, inlineCapacity, U>::appendNode(Node* node) |
| { |
| node->m_prev = m_tail; |
| node->m_next = 0; |
| |
| if (m_tail) { |
| ASSERT(m_head); |
| m_tail->m_next = node; |
| } else { |
| ASSERT(!m_head); |
| m_head = node; |
| } |
| |
| m_tail = node; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| void ListHashSet<T, inlineCapacity, U>::prependNode(Node* node) |
| { |
| node->m_prev = 0; |
| node->m_next = m_head; |
| |
| if (m_head) |
| m_head->m_prev = node; |
| else |
| m_tail = node; |
| |
| m_head = node; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| void ListHashSet<T, inlineCapacity, U>::insertNodeBefore(Node* beforeNode, Node* newNode) |
| { |
| if (!beforeNode) |
| return appendNode(newNode); |
| |
| newNode->m_next = beforeNode; |
| newNode->m_prev = beforeNode->m_prev; |
| if (beforeNode->m_prev) |
| beforeNode->m_prev->m_next = newNode; |
| beforeNode->m_prev = newNode; |
| |
| if (!newNode->m_prev) |
| m_head = newNode; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| void ListHashSet<T, inlineCapacity, U>::deleteAllNodes() |
| { |
| if (!m_head) |
| return; |
| |
| for (Node* node = m_head, *next = m_head->m_next; node; node = next, next = node ? node->m_next : 0) |
| node->destroy(m_allocator.get()); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline ListHashSetReverseIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeReverseIterator(Node* position) |
| { |
| return ListHashSetReverseIterator<T, inlineCapacity, U>(this, position); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline ListHashSetConstReverseIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeConstReverseIterator(Node* position) const |
| { |
| return ListHashSetConstReverseIterator<T, inlineCapacity, U>(this, position); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline ListHashSetIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeIterator(Node* position) |
| { |
| return ListHashSetIterator<T, inlineCapacity, U>(this, position); |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline ListHashSetConstIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeConstIterator(Node* position) const |
| { |
| return ListHashSetConstIterator<T, inlineCapacity, U>(this, position); |
| } |
| template<bool, typename ValueType, typename HashTableType> |
| void deleteAllValues(HashTableType& collection) |
| { |
| typedef typename HashTableType::const_iterator iterator; |
| iterator end = collection.end(); |
| for (iterator it = collection.begin(); it != end; ++it) |
| delete (*it)->m_value; |
| } |
| |
| template<typename T, size_t inlineCapacity, typename U> |
| inline void deleteAllValues(const ListHashSet<T, inlineCapacity, U>& collection) |
| { |
| deleteAllValues<true, typename ListHashSet<T, inlineCapacity, U>::ValueType>(collection.m_impl); |
| } |
| |
| } // namespace WTF |
| |
| using WTF::ListHashSet; |
| |
| #endif /* WTF_ListHashSet_h */ |