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

Unified Diff: src/base/hashmap.h

Issue 2343123002: [base] Template hashmap on key and value (Closed)
Patch Set: Update gyp/gn build files Created 4 years, 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « BUILD.gn ('k') | src/base/hashmap-entry.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/base/hashmap.h
diff --git a/src/base/hashmap.h b/src/base/hashmap.h
index e3c47de6d7d8af647d6baa6b5069e4290a5ede2b..852d7d125c28dfafd3f2279aa4513c39ba8ce6d7 100644
--- a/src/base/hashmap.h
+++ b/src/base/hashmap.h
@@ -12,6 +12,7 @@
#include <stdlib.h>
#include "src/base/bits.h"
+#include "src/base/hashmap-entry.h"
#include "src/base/logging.h"
namespace v8 {
@@ -23,10 +24,16 @@ class DefaultAllocationPolicy {
V8_INLINE static void Delete(void* p) { free(p); }
};
-template <class AllocationPolicy>
+// Metaprogramming helper to allow pointer keys to be passed by value and
+// non-pointer keys by const reference.
+template <typename Key>
+struct MatchFunHelper;
+
+template <typename Key, typename Value, class AllocationPolicy>
class TemplateHashMapImpl {
public:
- typedef bool (*MatchFun)(void* key1, void* key2);
+ typedef typename MatchFunHelper<Key>::Fun MatchFun;
+ typedef TemplateHashMapEntry<Key, Value> Entry;
// The default capacity. This is used by the call sites which want
// to pass in a non-default AllocationPolicy but want to use the
@@ -41,32 +48,23 @@ class TemplateHashMapImpl {
~TemplateHashMapImpl();
- // HashMap entries are (key, value, hash) triplets.
- // Some clients may not need to use the value slot
- // (e.g. implementers of sets, where the key is the value).
- struct Entry {
- void* key;
- void* value;
- uint32_t hash; // The full hash value for key
- };
-
// If an entry with matching key is found, returns that entry.
- // Otherwise, NULL is returned.
- Entry* Lookup(void* key, uint32_t hash) const;
+ // Otherwise, nullptr is returned.
+ Entry* Lookup(const Key& key, uint32_t hash) const;
// If an entry with matching key is found, returns that entry.
// If no matching entry is found, a new entry is inserted with
- // corresponding key, key hash, and NULL value.
- Entry* LookupOrInsert(void* key, uint32_t hash,
+ // corresponding key, key hash, and default initialized value.
+ Entry* LookupOrInsert(const Key& key, uint32_t hash,
AllocationPolicy allocator = AllocationPolicy());
- Entry* InsertNew(void* key, uint32_t hash,
+ Entry* InsertNew(const Key& key, uint32_t hash,
AllocationPolicy allocator = AllocationPolicy());
// Removes the entry with matching key.
// It returns the value of the deleted entry
// or null if there is no value for such key.
- void* Remove(void* key, uint32_t hash);
+ Value Remove(const Key& key, uint32_t hash);
// Empties the hash map (occupancy() == 0).
void Clear();
@@ -81,7 +79,7 @@ class TemplateHashMapImpl {
// Iteration
//
- // for (Entry* p = map.Start(); p != NULL; p = map.Next(p)) {
+ // for (Entry* p = map.Start(); p != nullptr; p = map.Next(p)) {
// ...
// }
//
@@ -91,7 +89,13 @@ class TemplateHashMapImpl {
Entry* Next(Entry* p) const;
// Some match functions defined for convenience.
- static bool PointersMatch(void* key1, void* key2) { return key1 == key2; }
+ // TODO(leszeks): This isn't really matching pointers, so the name doesn't
+ // really make sense, but we should remove this entirely and template the map
+ // on the matching function.
+ static bool PointersMatch(typename MatchFunHelper<Key>::KeyRef key1,
+ typename MatchFunHelper<Key>::KeyRef key2) {
+ return key1 == key2;
+ }
private:
MatchFun match_;
@@ -100,57 +104,69 @@ class TemplateHashMapImpl {
uint32_t occupancy_;
Entry* map_end() const { return map_ + capacity_; }
- Entry* Probe(void* key, uint32_t hash) const;
+ Entry* Probe(const Key& key, uint32_t hash) const;
void Initialize(uint32_t capacity, AllocationPolicy allocator);
void Resize(AllocationPolicy allocator);
};
-typedef TemplateHashMapImpl<DefaultAllocationPolicy> HashMap;
+template <typename Key>
+struct MatchFunHelper {
+ typedef const Key& KeyRef;
+ typedef bool (*Fun)(KeyRef key1, KeyRef key2);
+};
-template <class AllocationPolicy>
-TemplateHashMapImpl<AllocationPolicy>::TemplateHashMapImpl(
+template <typename Key>
+struct MatchFunHelper<Key*> {
+ typedef Key* KeyRef;
+ typedef bool (*Fun)(KeyRef key1, KeyRef key2);
+};
+
+typedef TemplateHashMapImpl<void*, void*, DefaultAllocationPolicy> HashMap;
+
+template <typename Key, typename Value, class AllocationPolicy>
+TemplateHashMapImpl<Key, Value, AllocationPolicy>::TemplateHashMapImpl(
MatchFun match, uint32_t initial_capacity, AllocationPolicy allocator) {
match_ = match;
Initialize(initial_capacity, allocator);
}
-template <class AllocationPolicy>
-TemplateHashMapImpl<AllocationPolicy>::~TemplateHashMapImpl() {
+template <typename Key, typename Value, class AllocationPolicy>
+TemplateHashMapImpl<Key, Value, AllocationPolicy>::~TemplateHashMapImpl() {
AllocationPolicy::Delete(map_);
}
-template <class AllocationPolicy>
-typename TemplateHashMapImpl<AllocationPolicy>::Entry*
-TemplateHashMapImpl<AllocationPolicy>::Lookup(void* key, uint32_t hash) const {
+template <typename Key, typename Value, class AllocationPolicy>
+typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry*
+TemplateHashMapImpl<Key, Value, AllocationPolicy>::Lookup(const Key& key,
+ uint32_t hash) const {
Entry* p = Probe(key, hash);
- return p->key != NULL ? p : NULL;
+ return p->exists() ? p : nullptr;
}
-template <class AllocationPolicy>
-typename TemplateHashMapImpl<AllocationPolicy>::Entry*
-TemplateHashMapImpl<AllocationPolicy>::LookupOrInsert(
- void* key, uint32_t hash, AllocationPolicy allocator) {
+template <typename Key, typename Value, class AllocationPolicy>
+typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry*
+TemplateHashMapImpl<Key, Value, AllocationPolicy>::LookupOrInsert(
+ const Key& key, uint32_t hash, AllocationPolicy allocator) {
// Find a matching entry.
Entry* p = Probe(key, hash);
- if (p->key != NULL) {
+ if (p->exists()) {
return p;
}
return InsertNew(key, hash, allocator);
}
-template <class AllocationPolicy>
-typename TemplateHashMapImpl<AllocationPolicy>::Entry*
-TemplateHashMapImpl<AllocationPolicy>::InsertNew(void* key, uint32_t hash,
- AllocationPolicy allocator) {
+template <typename Key, typename Value, class AllocationPolicy>
+typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry*
+TemplateHashMapImpl<Key, Value, AllocationPolicy>::InsertNew(
+ const Key& key, uint32_t hash, AllocationPolicy allocator) {
// Find a matching entry.
Entry* p = Probe(key, hash);
- DCHECK(p->key == NULL);
+ DCHECK(!p->exists());
- // No entry found; insert one.
- p->key = key;
- p->value = NULL;
- p->hash = hash;
+ // No entry found; construct one in-place in the empty slot using placement
+ // new.
+ new (p) Entry(key, Value(), hash);
occupancy_++;
// Grow the map if we reached >= 80% occupancy.
@@ -162,16 +178,17 @@ TemplateHashMapImpl<AllocationPolicy>::InsertNew(void* key, uint32_t hash,
return p;
}
-template <class AllocationPolicy>
-void* TemplateHashMapImpl<AllocationPolicy>::Remove(void* key, uint32_t hash) {
+template <typename Key, typename Value, class AllocationPolicy>
+Value TemplateHashMapImpl<Key, Value, AllocationPolicy>::Remove(const Key& key,
+ uint32_t hash) {
// Lookup the entry for the key to remove.
Entry* p = Probe(key, hash);
- if (p->key == NULL) {
+ if (!p->exists()) {
// Key not found nothing to remove.
- return NULL;
+ return nullptr;
}
- void* value = p->value;
+ Value value = p->value;
// To remove an entry we need to ensure that it does not create an empty
// entry that will cause the search for another entry to stop too soon. If all
// the entries between the entry to remove and the next empty slot have their
@@ -200,7 +217,7 @@ void* TemplateHashMapImpl<AllocationPolicy>::Remove(void* key, uint32_t hash) {
// All entries between p and q have their initial position between p and q
// and the entry p can be cleared without breaking the search for these
// entries.
- if (q->key == NULL) {
+ if (!q->exists()) {
break;
}
@@ -217,52 +234,51 @@ void* TemplateHashMapImpl<AllocationPolicy>::Remove(void* key, uint32_t hash) {
}
// Clear the entry which is allowed to en emptied.
- p->key = NULL;
+ p->clear();
occupancy_--;
return value;
}
-template <class AllocationPolicy>
-void TemplateHashMapImpl<AllocationPolicy>::Clear() {
+template <typename Key, typename Value, class AllocationPolicy>
+void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Clear() {
// Mark all entries as empty.
const Entry* end = map_end();
for (Entry* p = map_; p < end; p++) {
- p->key = NULL;
+ p->clear();
}
occupancy_ = 0;
}
-template <class AllocationPolicy>
-typename TemplateHashMapImpl<AllocationPolicy>::Entry*
-TemplateHashMapImpl<AllocationPolicy>::Start() const {
+template <typename Key, typename Value, class AllocationPolicy>
+typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry*
+TemplateHashMapImpl<Key, Value, AllocationPolicy>::Start() const {
return Next(map_ - 1);
}
-template <class AllocationPolicy>
-typename TemplateHashMapImpl<AllocationPolicy>::Entry*
-TemplateHashMapImpl<AllocationPolicy>::Next(Entry* p) const {
+template <typename Key, typename Value, class AllocationPolicy>
+typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry*
+TemplateHashMapImpl<Key, Value, AllocationPolicy>::Next(Entry* p) const {
const Entry* end = map_end();
DCHECK(map_ - 1 <= p && p < end);
for (p++; p < end; p++) {
- if (p->key != NULL) {
+ if (p->exists()) {
return p;
}
}
- return NULL;
+ return nullptr;
}
-template <class AllocationPolicy>
-typename TemplateHashMapImpl<AllocationPolicy>::Entry*
-TemplateHashMapImpl<AllocationPolicy>::Probe(void* key, uint32_t hash) const {
- DCHECK(key != NULL);
-
+template <typename Key, typename Value, class AllocationPolicy>
+typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry*
+TemplateHashMapImpl<Key, Value, AllocationPolicy>::Probe(const Key& key,
+ uint32_t hash) const {
DCHECK(base::bits::IsPowerOfTwo32(capacity_));
Entry* p = map_ + (hash & (capacity_ - 1));
const Entry* end = map_end();
DCHECK(map_ <= p && p < end);
DCHECK(occupancy_ < capacity_); // Guarantees loop termination.
- while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) {
+ while (p->exists() && (hash != p->hash || !match_(key, p->key))) {
p++;
if (p >= end) {
p = map_;
@@ -272,12 +288,12 @@ TemplateHashMapImpl<AllocationPolicy>::Probe(void* key, uint32_t hash) const {
return p;
}
-template <class AllocationPolicy>
-void TemplateHashMapImpl<AllocationPolicy>::Initialize(
+template <typename Key, typename Value, class AllocationPolicy>
+void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Initialize(
uint32_t capacity, AllocationPolicy allocator) {
DCHECK(base::bits::IsPowerOfTwo32(capacity));
map_ = reinterpret_cast<Entry*>(allocator.New(capacity * sizeof(Entry)));
- if (map_ == NULL) {
+ if (map_ == nullptr) {
FATAL("Out of memory: HashMap::Initialize");
return;
}
@@ -285,8 +301,9 @@ void TemplateHashMapImpl<AllocationPolicy>::Initialize(
Clear();
}
-template <class AllocationPolicy>
-void TemplateHashMapImpl<AllocationPolicy>::Resize(AllocationPolicy allocator) {
+template <typename Key, typename Value, class AllocationPolicy>
+void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Resize(
+ AllocationPolicy allocator) {
Entry* map = map_;
uint32_t n = occupancy_;
@@ -295,7 +312,7 @@ void TemplateHashMapImpl<AllocationPolicy>::Resize(AllocationPolicy allocator) {
// Rehash all current entries.
for (Entry* p = map; n > 0; p++) {
- if (p->key != NULL) {
+ if (p->exists()) {
Entry* entry = LookupOrInsert(p->key, p->hash, allocator);
entry->value = p->value;
n--;
@@ -308,7 +325,8 @@ void TemplateHashMapImpl<AllocationPolicy>::Resize(AllocationPolicy allocator) {
// A hash map for pointer keys and values with an STL-like interface.
template <class Key, class Value, class AllocationPolicy>
-class TemplateHashMap : private TemplateHashMapImpl<AllocationPolicy> {
+class TemplateHashMap
+ : private TemplateHashMapImpl<void*, void*, AllocationPolicy> {
public:
STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT
STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT
@@ -328,26 +346,28 @@ class TemplateHashMap : private TemplateHashMapImpl<AllocationPolicy> {
bool operator!=(const Iterator& other) { return entry_ != other.entry_; }
private:
- Iterator(const TemplateHashMapImpl<AllocationPolicy>* map,
- typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry)
+ Iterator(const TemplateHashMapImpl<void*, void*, AllocationPolicy>* map,
+ typename TemplateHashMapImpl<void*, void*,
+ AllocationPolicy>::Entry* entry)
: map_(map), entry_(entry) {}
- const TemplateHashMapImpl<AllocationPolicy>* map_;
- typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry_;
+ const TemplateHashMapImpl<void*, void*, AllocationPolicy>* map_;
+ typename TemplateHashMapImpl<void*, void*, AllocationPolicy>::Entry* entry_;
friend class TemplateHashMap;
};
- TemplateHashMap(
- typename TemplateHashMapImpl<AllocationPolicy>::MatchFun match,
- AllocationPolicy allocator = AllocationPolicy())
- : TemplateHashMapImpl<AllocationPolicy>(
+ TemplateHashMap(typename TemplateHashMapImpl<
+ void*, void*, AllocationPolicy>::MatchFun match,
+ AllocationPolicy allocator = AllocationPolicy())
+ : TemplateHashMapImpl<void*, void*, AllocationPolicy>(
match,
- TemplateHashMapImpl<AllocationPolicy>::kDefaultHashMapCapacity,
+ TemplateHashMapImpl<void*, void*,
+ AllocationPolicy>::kDefaultHashMapCapacity,
allocator) {}
Iterator begin() const { return Iterator(this, this->Start()); }
- Iterator end() const { return Iterator(this, NULL); }
+ Iterator end() const { return Iterator(this, nullptr); }
Iterator find(Key* key, bool insert = false,
AllocationPolicy allocator = AllocationPolicy()) {
if (insert) {
« no previous file with comments | « BUILD.gn ('k') | src/base/hashmap-entry.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698