Skip to content

Commit

Permalink
Merge pull request #1 from vibe-d/fix_remove_cow
Browse files Browse the repository at this point in the history
Fix copy-on-write semantics of HashMap for remove/clear
  • Loading branch information
s-ludwig authored Nov 27, 2023
2 parents 53d9a24 + e3f0e79 commit b076ff0
Showing 1 changed file with 27 additions and 17 deletions.
44 changes: 27 additions & 17 deletions source/vibe/container/hashmap.d
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ struct HashMap(TKey, TValue, Traits = DefaultHashMapTraits!TKey, Allocator = IAl
{
import std.algorithm.mutation : move;

makeUnique();

auto idx = findIndex(key);
assert (idx != size_t.max, "Removing non-existent element.");
auto i = idx;
Expand Down Expand Up @@ -198,6 +200,7 @@ struct HashMap(TKey, TValue, Traits = DefaultHashMapTraits!TKey, Allocator = IAl

void clear()
{
makeUnique();
foreach (i; 0 .. m_table.length)
if (!Traits.equals(m_table[i].key, Traits.clearValue)) {
m_table[i].key = Traits.clearValue;
Expand Down Expand Up @@ -305,32 +308,39 @@ struct HashMap(TKey, TValue, Traits = DefaultHashMapTraits!TKey, Allocator = IAl
}

private void grow(size_t amount)
@trusted {
@safe {
auto newsize = m_length + amount;
if (newsize < (m_table.length*2)/3) {
int rc;
try rc = allocator.prefix(m_table);
catch (Exception e) assert(false, e.msg);
if (rc > 1) {
// enforce copy-on-write
auto oldtable = m_table;
try {
m_table = allocator.makeArray!TableEntry(m_table.length);
m_table[] = oldtable;
allocator.prefix(oldtable)--;
assert(allocator.prefix(oldtable) > 0);
allocator.prefix(m_table) = 1;
} catch (Exception e) {
assert(false, e.msg);
}
}
makeUnique();
return;
}
auto newcap = m_table.length ? m_table.length : 16;
while (newsize >= (newcap*2)/3) newcap *= 2;
resize(newcap);
}

private void makeUnique()
@trusted {
if (m_table is null) return;

int rc;
try rc = allocator.prefix(m_table);
catch (Exception e) assert(false, e.msg);
if (rc > 1) {
// enforce copy-on-write
auto oldtable = m_table;
try {
m_table = allocator.makeArray!TableEntry(m_table.length);
m_table[] = oldtable;
allocator.prefix(oldtable)--;
assert(allocator.prefix(oldtable) > 0);
allocator.prefix(m_table) = 1;
} catch (Exception e) {
assert(false, e.msg);
}
}
}

private void resize(size_t new_size)
@trusted {
assert(!m_resizing);
Expand Down

0 comments on commit b076ff0

Please sign in to comment.