Commit bedde181 authored by leszeks's avatar leszeks Committed by Commit bot

[base] Decrease probing in hashmap

Removes some unnecessary probing in TemplateHashMapImpl, in
particular probing a second time in LookupOrInsert after the
first probe came up with an empty value.

Review-Url: https://codereview.chromium.org/2349163002
Cr-Commit-Position: refs/heads/master@{#39545}
parent 72456950
......@@ -84,7 +84,7 @@ class TemplateHashMapImpl {
// If entries are inserted during iteration, the effect of
// calling Next() is undefined.
Entry* Start() const;
Entry* Next(Entry* p) const;
Entry* Next(Entry* entry) const;
// Some match functions defined for convenience.
// TODO(leszeks): This isn't really matching pointers, so the name doesn't
......@@ -104,6 +104,8 @@ class TemplateHashMapImpl {
Entry* map_end() const { return map_ + capacity_; }
Entry* Probe(const Key& key, uint32_t hash) const;
Entry* FillEmptyEntry(Entry* entry, const Key& key, const Value& value,
uint32_t hash);
void Initialize(uint32_t capacity);
void Resize();
};
......@@ -139,8 +141,8 @@ 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->exists() ? p : nullptr;
Entry* entry = Probe(key, hash);
return entry->exists() ? entry : nullptr;
}
template <typename Key, typename Value, class AllocationPolicy>
......@@ -148,34 +150,20 @@ typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry*
TemplateHashMapImpl<Key, Value, AllocationPolicy>::LookupOrInsert(
const Key& key, uint32_t hash) {
// Find a matching entry.
Entry* p = Probe(key, hash);
if (p->exists()) {
return p;
Entry* entry = Probe(key, hash);
if (entry->exists()) {
return entry;
}
return InsertNew(key, hash);
return FillEmptyEntry(entry, key, Value(), hash);
}
template <typename Key, typename Value, class AllocationPolicy>
typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry*
TemplateHashMapImpl<Key, Value, AllocationPolicy>::InsertNew(const Key& key,
uint32_t hash) {
// Find a matching entry.
Entry* p = Probe(key, hash);
DCHECK(!p->exists());
// 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.
if (occupancy_ + occupancy_ / 4 >= capacity_) {
Resize();
p = Probe(key, hash);
}
return p;
Entry* entry = Probe(key, hash);
return FillEmptyEntry(entry, key, Value(), hash);
}
template <typename Key, typename Value, class AllocationPolicy>
......@@ -243,8 +231,8 @@ 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->clear();
for (Entry* entry = map_; entry < end; entry++) {
entry->clear();
}
occupancy_ = 0;
}
......@@ -257,12 +245,12 @@ TemplateHashMapImpl<Key, Value, AllocationPolicy>::Start() const {
template <typename Key, typename Value, class AllocationPolicy>
typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry*
TemplateHashMapImpl<Key, Value, AllocationPolicy>::Next(Entry* p) const {
TemplateHashMapImpl<Key, Value, AllocationPolicy>::Next(Entry* entry) const {
const Entry* end = map_end();
DCHECK(map_ - 1 <= p && p < end);
for (p++; p < end; p++) {
if (p->exists()) {
return p;
DCHECK(map_ - 1 <= entry && entry < end);
for (entry++; entry < end; entry++) {
if (entry->exists()) {
return entry;
}
}
return nullptr;
......@@ -273,19 +261,37 @@ 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));
Entry* entry = map_ + (hash & (capacity_ - 1));
const Entry* end = map_end();
DCHECK(map_ <= p && p < end);
DCHECK(map_ <= entry && entry < end);
DCHECK(occupancy_ < capacity_); // Guarantees loop termination.
while (p->exists() && (hash != p->hash || !match_(key, p->key))) {
p++;
if (p >= end) {
p = map_;
while (entry->exists() && (hash != entry->hash || !match_(key, entry->key))) {
entry++;
if (entry >= end) {
entry = map_;
}
}
return p;
return entry;
}
template <typename Key, typename Value, class AllocationPolicy>
typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry*
TemplateHashMapImpl<Key, Value, AllocationPolicy>::FillEmptyEntry(
Entry* entry, const Key& key, const Value& value, uint32_t hash) {
DCHECK(!entry->exists());
new (entry) Entry(key, value, hash);
occupancy_++;
// Grow the map if we reached >= 80% occupancy.
if (occupancy_ + occupancy_ / 4 >= capacity_) {
Resize();
entry = Probe(key, hash);
}
return entry;
}
template <typename Key, typename Value, class AllocationPolicy>
......@@ -310,10 +316,11 @@ void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Resize() {
Initialize(capacity_ * 2);
// Rehash all current entries.
for (Entry* p = map; n > 0; p++) {
if (p->exists()) {
Entry* entry = LookupOrInsert(p->key, p->hash);
entry->value = p->value;
for (Entry* entry = map; n > 0; entry++) {
if (entry->exists()) {
Entry* new_entry = Probe(entry->key, entry->hash);
new_entry =
FillEmptyEntry(new_entry, entry->key, entry->value, entry->hash);
n--;
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment