📄 hashtable.h
字号:
/* * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008 David Levin <levin@chromium.org> * * 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_HashTable_h#define WTF_HashTable_h#include "FastMalloc.h"#include "HashTraits.h"#include <wtf/Assertions.h>#include <wtf/Threading.h>namespace WTF {#define DUMP_HASHTABLE_STATS 0#define CHECK_HASHTABLE_CONSISTENCY 0#ifdef NDEBUG#define CHECK_HASHTABLE_ITERATORS 0#define CHECK_HASHTABLE_USE_AFTER_DESTRUCTION 0#else#define CHECK_HASHTABLE_ITERATORS 1#define CHECK_HASHTABLE_USE_AFTER_DESTRUCTION 1#endif#if DUMP_HASHTABLE_STATS struct HashTableStats { ~HashTableStats(); // All of the variables are accessed in ~HashTableStats when the static struct is destroyed. // The following variables are all atomically incremented when modified. static int numAccesses; static int numRehashes; static int numRemoves; static int numReinserts; // The following variables are only modified in the recordCollisionAtCount method within a mutex. static int maxCollisions; static int numCollisions; static int collisionGraph[4096]; static void recordCollisionAtCount(int count); };#endif template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> class HashTable; template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> class HashTableIterator; template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> class HashTableConstIterator; template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> void addIterator(const HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*, HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*); template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> void removeIterator(HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*);#if !CHECK_HASHTABLE_ITERATORS template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> inline void addIterator(const HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*, HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*) { } template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> inline void removeIterator(HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*) { }#endif typedef enum { HashItemKnownGood } HashItemKnownGoodTag; template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> class HashTableConstIterator { private: typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> HashTableType; typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator; typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator; typedef Value ValueType; typedef const ValueType& ReferenceType; typedef const ValueType* PointerType; friend class HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>; friend class HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>; void skipEmptyBuckets() { while (m_position != m_endPosition && HashTableType::isEmptyOrDeletedBucket(*m_position)) ++m_position; } HashTableConstIterator(const HashTableType* table, PointerType position, PointerType endPosition) : m_position(position), m_endPosition(endPosition) { addIterator(table, this); skipEmptyBuckets(); } HashTableConstIterator(const HashTableType* table, PointerType position, PointerType endPosition, HashItemKnownGoodTag) : m_position(position), m_endPosition(endPosition) { addIterator(table, this); } public: HashTableConstIterator() { addIterator(0, this); } // default copy, assignment and destructor are OK if CHECK_HASHTABLE_ITERATORS is 0#if CHECK_HASHTABLE_ITERATORS ~HashTableConstIterator() { removeIterator(this); } HashTableConstIterator(const const_iterator& other) : m_position(other.m_position), m_endPosition(other.m_endPosition) { addIterator(other.m_table, this); } const_iterator& operator=(const const_iterator& other) { m_position = other.m_position; m_endPosition = other.m_endPosition; removeIterator(this); addIterator(other.m_table, this); return *this; }#endif PointerType get() const { checkValidity(); return m_position; } ReferenceType operator*() const { return *get(); } PointerType operator->() const { return get(); } const_iterator& operator++() { checkValidity(); ASSERT(m_position != m_endPosition); ++m_position; skipEmptyBuckets(); return *this; } // postfix ++ intentionally omitted // Comparison. bool operator==(const const_iterator& other) const { checkValidity(other); return m_position == other.m_position; } bool operator!=(const const_iterator& other) const { checkValidity(other); return m_position != other.m_position; } private: void checkValidity() const {#if CHECK_HASHTABLE_ITERATORS ASSERT(m_table);#endif }#if CHECK_HASHTABLE_ITERATORS void checkValidity(const const_iterator& other) const { ASSERT(m_table); ASSERT(other.m_table); ASSERT(m_table == other.m_table); }#else void checkValidity(const const_iterator&) const { }#endif PointerType m_position; PointerType m_endPosition;#if CHECK_HASHTABLE_ITERATORS public: // Any modifications of the m_next or m_previous of an iterator that is in a linked list of a HashTable::m_iterator, // should be guarded with m_table->m_mutex. mutable const HashTableType* m_table; mutable const_iterator* m_next; mutable const_iterator* m_previous;#endif }; template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> class HashTableIterator { private: typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> HashTableType; typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator; typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator; typedef Value ValueType; typedef ValueType& ReferenceType; typedef ValueType* PointerType; friend class HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>; HashTableIterator(HashTableType* table, PointerType pos, PointerType end) : m_iterator(table, pos, end) { } HashTableIterator(HashTableType* table, PointerType pos, PointerType end, HashItemKnownGoodTag tag) : m_iterator(table, pos, end, tag) { } public: HashTableIterator() { } // 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 // 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: const_iterator m_iterator; }; using std::swap;#if !COMPILER(MSVC) // Visual C++ has a swap for pairs defined. // swap pairs by component, in case of pair members that specialize swap template<typename T, typename U> inline void swap(pair<T, U>& a, pair<T, U>& b) { swap(a.first, b.first); swap(a.second, b.second); }#endif template<typename T, bool useSwap> struct Mover; template<typename T> struct Mover<T, true> { static void move(T& from, T& to) { swap(from, to); } }; template<typename T> struct Mover<T, false> { static void move(T& from, T& to) { to = from; } }; template<typename Key, typename Value, typename HashFunctions> class IdentityHashTranslator { public: static unsigned hash(const Key& key) { return HashFunctions::hash(key); } static bool equal(const Key& a, const Key& b) { return HashFunctions::equal(a, b); } static void translate(Value& location, const Key&, const Value& value) { location = value; } }; template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> class HashTable { public: typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator; typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator; typedef Traits ValueTraits; typedef Key KeyType; typedef Value ValueType; typedef IdentityHashTranslator<Key, Value, HashFunctions> IdentityTranslatorType; HashTable(); ~HashTable() { invalidateIterators(); deallocateTable(m_table, m_tableSize); #if CHECK_HASHTABLE_USE_AFTER_DESTRUCTION m_table = (ValueType*)(uintptr_t)0xbbadbeef;#endif } HashTable(const HashTable&); void swap(HashTable&); HashTable& operator=(const HashTable&); iterator begin() { return makeIterator(m_table); } iterator end() { return makeKnownGoodIterator(m_table + m_tableSize); } const_iterator begin() const { return makeConstIterator(m_table); } const_iterator end() const { return makeKnownGoodConstIterator(m_table + m_tableSize); } int size() const { return m_keyCount; } int capacity() const { return m_tableSize; } bool isEmpty() const { return !m_keyCount; } pair<iterator, bool> add(const ValueType& value) { return add<KeyType, ValueType, IdentityTranslatorType>(Extractor::extract(value), value); } // A special version of add() that finds the object by hashing and comparing // with some other type, to avoid the cost of type conversion if the object is already // in the table. template<typename T, typename Extra, typename HashTranslator> pair<iterator, bool> add(const T& key, const Extra&); template<typename T, typename Extra, typename HashTranslator> pair<iterator, bool> addPassingHashCode(const T& key, const Extra&); iterator find(const KeyType& key) { return find<KeyType, IdentityTranslatorType>(key); } const_iterator find(const KeyType& key) const { return find<KeyType, IdentityTranslatorType>(key); } bool contains(const KeyType& key) const { return contains<KeyType, IdentityTranslatorType>(key); } 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; void remove(const KeyType&); void remove(iterator); void removeWithoutEntryConsistencyCheck(iterator); void clear(); static bool isEmptyBucket(const ValueType& value) { return Extractor::extract(value) == KeyTraits::emptyValue(); } static bool isDeletedBucket(const ValueType& value) { return KeyTraits::isDeletedValue(Extractor::extract(value)); } static bool isEmptyOrDeletedBucket(const ValueType& value) { return isEmptyBucket(value) || isDeletedBucket(value); } ValueType* lookup(const Key& key) { return lookup<Key, IdentityTranslatorType>(key); } template<typename T, typename HashTranslator> ValueType* lookup(const T&);#if CHECK_HASHTABLE_CONSISTENCY void checkTableConsistency() const;#else static void checkTableConsistency() { }#endif private: static ValueType* allocateTable(int size); static void deallocateTable(ValueType* table, int size); typedef pair<ValueType*, bool> LookupType; typedef pair<LookupType, unsigned> FullLookupType; LookupType lookupForWriting(const Key& key) { return lookupForWriting<Key, IdentityTranslatorType>(key); }; template<typename T, typename HashTranslator> FullLookupType fullLookupForWriting(const T&); template<typename T, typename HashTranslator> LookupType lookupForWriting(const T&); template<typename T, typename HashTranslator> void checkKey(const T&); void removeAndInvalidateWithoutEntryConsistencyCheck(ValueType*); void removeAndInvalidate(ValueType*); void remove(ValueType*); bool shouldExpand() const { return (m_keyCount + m_deletedCount) * m_maxLoad >= m_tableSize; } bool mustRehashInPlace() const { return m_keyCount * m_minLoad < m_tableSize * 2; } bool shouldShrink() const { return m_keyCount * m_minLoad < m_tableSize && m_tableSize > m_minTableSize; } void expand(); void shrink() { rehash(m_tableSize / 2); } void rehash(int newTableSize); void reinsert(ValueType&); static void initializeBucket(ValueType& bucket) { new (&bucket) ValueType(Traits::emptyValue()); } static void deleteBucket(ValueType& bucket) { bucket.~ValueType(); Traits::constructDeletedValue(bucket); } FullLookupType makeLookupResult(ValueType* position, bool found, unsigned hash) { return FullLookupType(LookupType(position, found), hash); } iterator makeIterator(ValueType* pos) { return iterator(this, pos, m_table + m_tableSize); } const_iterator makeConstIterator(ValueType* pos) const { return const_iterator(this, pos, m_table + m_tableSize); } iterator makeKnownGoodIterator(ValueType* pos) { return iterator(this, pos, m_table + m_tableSize, HashItemKnownGood); } const_iterator makeKnownGoodConstIterator(ValueType* pos) const { return const_iterator(this, pos, m_table + m_tableSize, HashItemKnownGood); }#if CHECK_HASHTABLE_CONSISTENCY void checkTableConsistencyExceptSize() const;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -