mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Hash maps now copy keys if keys are copyable.
This commit is contained in:
@@ -8,6 +8,7 @@ const uint DEFAULT_INITIAL_CAPACITY = 16;
|
||||
const uint MAXIMUM_CAPACITY = 1u << 31;
|
||||
const float DEFAULT_LOAD_FACTOR = 0.75;
|
||||
const VALUE_IS_EQUATABLE = types::is_equatable(Value);
|
||||
const bool COPY_KEYS = types::implements_copy(Key);
|
||||
|
||||
struct HashMap
|
||||
{
|
||||
@@ -164,7 +165,14 @@ fn void HashMap.clear(&map)
|
||||
{
|
||||
Entry* entry = *entry_ref;
|
||||
if (!entry) continue;
|
||||
map.free_internal(entry);
|
||||
Entry *next = entry.next;
|
||||
while (next)
|
||||
{
|
||||
Entry *to_delete = next;
|
||||
next = next.next;
|
||||
map.free_entry(to_delete);
|
||||
}
|
||||
map.free_entry(entry);
|
||||
*entry_ref = null;
|
||||
}
|
||||
map.count = 0;
|
||||
@@ -255,6 +263,9 @@ fn bool HashMap.has_value(&map, Value v) @if(VALUE_IS_EQUATABLE)
|
||||
fn void HashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private
|
||||
{
|
||||
Entry* entry = malloc(Entry, .using = map.allocator);
|
||||
$if COPY_KEYS:
|
||||
key = key.copy(map.allocator);
|
||||
$endif
|
||||
*entry = { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] };
|
||||
map.table[bucket_index] = entry;
|
||||
if (map.count++ >= map.threshold)
|
||||
@@ -359,7 +370,7 @@ fn bool HashMap.remove_entry_for_key(&map, Key key) @private
|
||||
{
|
||||
prev.next = next;
|
||||
}
|
||||
map.free_internal(e);
|
||||
map.free_entry(e);
|
||||
return true;
|
||||
}
|
||||
prev = e;
|
||||
@@ -372,15 +383,26 @@ fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_i
|
||||
{
|
||||
Entry *e = map.table[bucket_index];
|
||||
Entry* entry = malloc(Entry, .using = map.allocator);
|
||||
$if COPY_KEYS:
|
||||
key = key.copy(map.allocator);
|
||||
$endif
|
||||
*entry = { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] };
|
||||
map.table[bucket_index] = entry;
|
||||
map.count++;
|
||||
}
|
||||
|
||||
fn void HashMap.free_entry(&self, Entry *entry) @local
|
||||
{
|
||||
$if COPY_KEYS:
|
||||
entry.key.free(self.allocator);
|
||||
$endif
|
||||
self.free_internal(entry);
|
||||
}
|
||||
|
||||
struct Entry
|
||||
{
|
||||
uint hash;
|
||||
Key key;
|
||||
Value value;
|
||||
Entry* next;
|
||||
}
|
||||
}
|
||||
@@ -177,19 +177,14 @@ macro bool equals(a, b, isz len = -1, usz $align = 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
macro @clone(&value) @builtin
|
||||
macro @clone(&value, Allocator *using = mem::heap()) @builtin
|
||||
{
|
||||
$typeof(value)* x = malloc($typeof(value));
|
||||
$typeof(value)* x = malloc($typeof(value), .using = using);
|
||||
*x = value;
|
||||
return x;
|
||||
}
|
||||
|
||||
macro @tclone(&value) @builtin
|
||||
{
|
||||
$typeof(value)* x = talloc($typeof(value));
|
||||
*x = value;
|
||||
return x;
|
||||
}
|
||||
macro @tclone(&value) @builtin => @clone(value, mem::temp());
|
||||
|
||||
macro type_alloc_must_be_aligned($Type)
|
||||
{
|
||||
|
||||
@@ -346,6 +346,12 @@ fn String String.copy(s, Allocator* using = mem::heap())
|
||||
str[len] = 0;
|
||||
return (String)str[:len];
|
||||
}
|
||||
fn void String.free(&s, Allocator* using = mem::heap())
|
||||
{
|
||||
if (!s.len) return;
|
||||
mem::free(s.ptr, .using = using);
|
||||
*s = "";
|
||||
}
|
||||
|
||||
fn String String.tcopy(s) => s.copy(mem::temp()) @inline;
|
||||
|
||||
|
||||
@@ -229,6 +229,14 @@ macro bool is_equatable_type($Type)
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a type implements the copy protocol.
|
||||
**/
|
||||
macro bool implements_copy($Type)
|
||||
{
|
||||
return $checks(Allocator *a, $Type x, $Type y = x.copy(a), $Type z = x.copy(), z.free(a), z.free());
|
||||
}
|
||||
|
||||
macro bool is_equatable_value(value)
|
||||
{
|
||||
return is_equatable_type($typeof(value));
|
||||
|
||||
Reference in New Issue
Block a user