mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
[util] Fix node_map growth
When node_map grew, it was not properly applying the fixup routine to non-moved elements. This fixes the grow algorithm to: 1. Realloc the array and set all new slots to empty/invalid 2. Check each old slot and remove/reinsert the item if it exists and its optimal slot is later in the array than its current slot 3. Reverse-iterate the original slots and call fixup() on empty slots to keep items from being located after a more-optimal empty slot Also fixed the fixup() function to not need to be called in a loop anymore, as it's only used the one way - on a given empty slot, looping until it hits an empty slot or optimally-placed item.
This commit is contained in:
@@ -42,7 +42,7 @@ public:
|
|||||||
using node_type = V;
|
using node_type = V;
|
||||||
|
|
||||||
static constexpr size_t max_load = 90;
|
static constexpr size_t max_load = 90;
|
||||||
static constexpr size_t min_capacity = 8;
|
static constexpr size_t min_capacity = 16;
|
||||||
|
|
||||||
inline size_t count() const { return m_count; }
|
inline size_t count() const { return m_count; }
|
||||||
inline size_t capacity() const { return m_capacity; }
|
inline size_t capacity() const { return m_capacity; }
|
||||||
@@ -100,7 +100,7 @@ public:
|
|||||||
const node_type * find(const key_type &key) const {
|
const node_type * find(const key_type &key) const {
|
||||||
size_t slot;
|
size_t slot;
|
||||||
if (!lookup(key, slot))
|
if (!lookup(key, slot))
|
||||||
return false;
|
return nullptr;
|
||||||
return &m_nodes[slot];
|
return &m_nodes[slot];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,17 +111,26 @@ public:
|
|||||||
size_t slot = mod(hash(key));
|
size_t slot = mod(hash(key));
|
||||||
size_t dist = 0;
|
size_t dist = 0;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
size_t inserted_at;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
node_type &node_at_slot = m_nodes[slot];
|
node_type &node_at_slot = m_nodes[slot];
|
||||||
key_type &key_at_slot = get_map_key(node_at_slot);
|
key_type &key_at_slot = get_map_key(node_at_slot);
|
||||||
|
|
||||||
if (open(key_at_slot)) {
|
if (open(key_at_slot)) {
|
||||||
node_at_slot = node;
|
node_at_slot = node;
|
||||||
return node_at_slot;
|
if (!found)
|
||||||
|
inserted_at = slot;
|
||||||
|
return m_nodes[inserted_at];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t psl_at_slot = psl(key_at_slot, slot);
|
size_t psl_at_slot = psl(key_at_slot, slot);
|
||||||
if (dist > psl_at_slot) {
|
if (dist > psl_at_slot) {
|
||||||
|
if (!found) {
|
||||||
|
found = true;
|
||||||
|
inserted_at = slot;
|
||||||
|
}
|
||||||
std::swap(node, node_at_slot);
|
std::swap(node, node_at_slot);
|
||||||
dist = psl_at_slot;
|
dist = psl_at_slot;
|
||||||
}
|
}
|
||||||
@@ -141,7 +150,7 @@ public:
|
|||||||
get_map_key(node) = invalid_id;
|
get_map_key(node) = invalid_id;
|
||||||
--m_count;
|
--m_count;
|
||||||
|
|
||||||
while (fixup(slot++));
|
fixup(slot);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,31 +162,33 @@ protected:
|
|||||||
return mod(slot + m_capacity - mod(hash(key)));
|
return mod(slot + m_capacity - mod(hash(key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fixup(size_t slot) {
|
void fixup(size_t slot) {
|
||||||
|
while (true) {
|
||||||
size_t next_slot = mod(slot+1);
|
size_t next_slot = mod(slot+1);
|
||||||
node_type &next = m_nodes[next_slot];
|
node_type &next = m_nodes[next_slot];
|
||||||
key_type &next_key = get_map_key(next);
|
key_type &next_key = get_map_key(next);
|
||||||
|
|
||||||
if (open(next_key) || psl(next_key, next_slot) == 0)
|
if (open(next_key) || psl(next_key, next_slot) == 0)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
m_nodes[slot] = std::move(next);
|
m_nodes[slot] = std::move(next);
|
||||||
next.~node_type();
|
next.~node_type();
|
||||||
next_key = invalid_id;
|
next_key = invalid_id;
|
||||||
return true;
|
++slot;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void grow() {
|
void grow() {
|
||||||
node_type *old_nodes = m_nodes;
|
|
||||||
size_t old_capacity = m_capacity;
|
size_t old_capacity = m_capacity;
|
||||||
size_t new_capacity = m_capacity * 2;
|
size_t new_capacity = m_capacity * 2;
|
||||||
|
|
||||||
if (new_capacity < min_capacity)
|
if (new_capacity < min_capacity)
|
||||||
new_capacity = min_capacity;
|
new_capacity = min_capacity;
|
||||||
|
|
||||||
m_nodes = reinterpret_cast<node_type*>(
|
void *grown = alloc::realloc(m_nodes,
|
||||||
realloc(m_nodes, old_capacity * sizeof(node_type),
|
old_capacity * sizeof(node_type),
|
||||||
new_capacity * sizeof(node_type)));
|
new_capacity * sizeof(node_type));
|
||||||
|
m_nodes = reinterpret_cast<node_type*>(grown);
|
||||||
|
|
||||||
for (size_t i = old_capacity; i < new_capacity; ++i)
|
for (size_t i = old_capacity; i < new_capacity; ++i)
|
||||||
get_map_key(m_nodes[i]) = invalid_id;
|
get_map_key(m_nodes[i]) = invalid_id;
|
||||||
@@ -187,19 +198,21 @@ protected:
|
|||||||
for (size_t slot = 0; slot < old_capacity; ++slot) {
|
for (size_t slot = 0; slot < old_capacity; ++slot) {
|
||||||
node_type &node = m_nodes[slot];
|
node_type &node = m_nodes[slot];
|
||||||
key_type &key = get_map_key(node);
|
key_type &key = get_map_key(node);
|
||||||
|
|
||||||
size_t target = mod(hash(key));
|
size_t target = mod(hash(key));
|
||||||
|
|
||||||
if (open(key) || target < old_capacity)
|
if (open(key) || target <= slot)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
--m_count;
|
--m_count;
|
||||||
insert(std::move(node));
|
insert(std::move(node));
|
||||||
node.~node_type();
|
node.~node_type();
|
||||||
key = invalid_id;
|
key = invalid_id;
|
||||||
|
|
||||||
size_t fixer = slot;
|
|
||||||
while (fixup(fixer++) && fixer < old_capacity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t slot = old_capacity - 1; slot < old_capacity; --slot)
|
||||||
|
if (open(get_map_key(m_nodes[slot])))
|
||||||
|
fixup(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool lookup(const key_type &key, size_t &slot) const {
|
const bool lookup(const key_type &key, size_t &slot) const {
|
||||||
|
|||||||
Reference in New Issue
Block a user