map is internally backed by a pointer (i.e. a "reference type")

This commit is contained in:
gingerBill
2017-12-17 19:25:35 +00:00
parent 30530d058c
commit a69ea58388
7 changed files with 161 additions and 98 deletions
+36 -9
View File
@@ -487,9 +487,13 @@ free_slice :: proc(array: $T/[]$E, loc := #caller_location) {
free_ptr(raw.data(array), loc);
}
free_map :: proc(m: $T/map[$K]$V, loc := #caller_location) {
raw := cast(^raw.Map)&m;
free_dynamic_array(raw.hashes, loc);
free_ptr(raw.entries.data, loc);
raw := transmute(raw.Map)m;
if raw.internal != nil {
free_dynamic_array(raw.hashes, loc);
free_ptr(raw.entries.data, loc);
free_ptr(raw.internal, loc);
raw.internal = nil;
}
}
free :: proc[
@@ -911,14 +915,22 @@ __default_hash :: proc(data: []byte) -> u128 {
}
__default_hash_string :: proc(s: string) -> u128 do return __default_hash(cast([]byte)s);
__dynamic_map_check_init :: proc(h: __Map_Header) {
if h.m.internal == nil {
h.m.internal = new(raw.Map_Internal);
}
}
__dynamic_map_reserve :: proc(using header: __Map_Header, cap: int, loc := #caller_location) {
__dynamic_map_check_init(header);
__dynamic_array_reserve(&m.hashes, size_of(int), align_of(int), cap, loc);
__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc);
}
__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int, loc := #caller_location) {
__dynamic_map_check_init(header);
new_header: __Map_Header = header;
nm: raw.Map;
nm.internal = new(raw.Map_Internal);
new_header.m = &nm;
header_hashes := cast(^raw.Dynamic_Array)&header.m.hashes;
@@ -956,6 +968,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int, loc :=
}
__dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr {
__dynamic_map_check_init(h);
index := __dynamic_map_find(h, key).entry_index;
if index >= 0 {
data := cast(^byte)__dynamic_map_get_entry(h, index);
@@ -964,11 +977,13 @@ __dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr {
return nil;
}
__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr, loc := #caller_location) {
__dynamic_map_set :: proc(h: __Map_Header, key: __Map_Key, value: rawptr, loc := #caller_location) {
__dynamic_map_check_init(h);
index: int;
assert(value != nil);
if len(m.hashes) == 0 {
if len(h.m.hashes) == 0 {
__dynamic_map_reserve(h, __INITIAL_MAP_CAP, loc);
__dynamic_map_grow(h, loc);
}
@@ -982,14 +997,14 @@ __dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr,
entry := __dynamic_map_get_entry(h, fr.entry_prev);
entry.next = index;
} else {
m.hashes[fr.hash_index] = index;
h.m.hashes[fr.hash_index] = index;
}
}
{
e := __dynamic_map_get_entry(h, index);
e.key = key;
val := cast(^byte)e + value_offset;
__mem_copy(val, value, value_size);
val := cast(^byte)(uintptr(e) + h.value_offset);
__mem_copy(val, value, h.value_size);
}
if __dynamic_map_full(h) {
@@ -999,11 +1014,13 @@ __dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr,
__dynamic_map_grow :: proc(using h: __Map_Header, loc := #caller_location) {
__dynamic_map_check_init(h);
new_count := max(2*m.entries.cap + 8, __INITIAL_MAP_CAP);
__dynamic_map_rehash(h, new_count, loc);
}
__dynamic_map_full :: inline proc(using h: __Map_Header) -> bool {
__dynamic_map_check_init(h);
return int(0.75 * f64(len(m.hashes))) <= m.entries.cap;
}
@@ -1017,6 +1034,7 @@ __dynamic_map_hash_equal :: proc(h: __Map_Header, a, b: __Map_Key) -> bool {
}
__dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_Result {
__dynamic_map_check_init(h);
fr := __Map_Find_Result{-1, -1, -1};
if len(m.hashes) > 0 {
fr.hash_index = int(key.hash % u128(len(m.hashes)));
@@ -1032,6 +1050,7 @@ __dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_
}
__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key, loc := #caller_location) -> int {
__dynamic_map_check_init(h);
prev := m.entries.len;
c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc);
if c != prev {
@@ -1043,6 +1062,7 @@ __dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key, loc := #c
}
__dynamic_map_delete :: proc(using h: __Map_Header, key: __Map_Key) {
__dynamic_map_check_init(h);
fr := __dynamic_map_find(h, key);
if fr.entry_index >= 0 {
__dynamic_map_erase(h, fr);
@@ -1050,10 +1070,13 @@ __dynamic_map_delete :: proc(using h: __Map_Header, key: __Map_Key) {
}
__dynamic_map_get_entry :: proc(using h: __Map_Header, index: int) -> ^__Map_Entry_Header {
__dynamic_map_check_init(h);
assert(0 <= index && index < m.entries.len);
return cast(^__Map_Entry_Header)(cast(^byte)m.entries.data + index*entry_size);
}
__dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
__dynamic_map_check_init(h);
if fr.entry_prev < 0 {
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next;
} else {
@@ -1071,3 +1094,7 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
m.hashes[last.hash_index] = fr.entry_index;
}
}
__map_for_test :: proc "c" (s: string) {
fmt.printf("__map_for_test '%s'\n", s);
}
+21 -21
View File
@@ -815,33 +815,33 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
write_string(fi.buf, "map[");
defer write_byte(fi.buf, ']');
entries := &(^raw.Map)(v.data).entries;
gs := type_info_base(info.generated_struct).variant.(Type_Info_Struct);
ed := type_info_base(gs.types[1]).variant.(Type_Info_Dynamic_Array);
entry_type := ed.elem.variant.(Type_Info_Struct);
entry_size := ed.elem_size;
if (^raw.Map)(v.data).internal != nil {
entries := &(^raw.Map)(v.data).entries;
gs := type_info_base(info.generated_struct).variant.(Type_Info_Struct);
ed := type_info_base(gs.types[1]).variant.(Type_Info_Dynamic_Array);
entry_type := ed.elem.variant.(Type_Info_Struct);
entry_size := ed.elem_size;
for i in 0..entries.len {
if i > 0 do write_string(fi.buf, ", ");
for i in 0..entries.len {
if i > 0 do write_string(fi.buf, ", ");
data := uintptr(entries.data) + uintptr(i*entry_size);
header := cast(^__Map_Entry_Header)data;
data := uintptr(entries.data) + uintptr(i*entry_size);
header := cast(^__Map_Entry_Header)data;
if types.is_string(info.key) {
write_string(fi.buf, header.key.str);
} else {
fi := Fmt_Info{buf = fi.buf};
fmt_arg(&fi, any{rawptr(&header.key.hash), info.key}, 'v');
if types.is_string(info.key) {
write_string(fi.buf, header.key.str);
} else {
fi := Fmt_Info{buf = fi.buf};
fmt_arg(&fi, any{rawptr(&header.key.hash), info.key}, 'v');
}
write_string(fi.buf, "=");
value := data + entry_type.offsets[2];
fmt_arg(fi, any{rawptr(value), info.value}, 'v');
}
write_string(fi.buf, "=");
value := data + entry_type.offsets[2];
fmt_arg(fi, any{rawptr(value), info.value}, 'v');
}
case Type_Info_Struct:
if info.is_raw_union {
write_string(fi.buf, "(raw_union)");
+5 -1
View File
@@ -20,11 +20,15 @@ Dynamic_Array :: struct {
allocator: Allocator,
}
Map :: struct {
Map_Internal :: struct {
hashes: [dynamic]int,
entries: Dynamic_Array,
}
Map :: struct {
using internal: ^Map_Internal,
}
make_any :: inline proc(data: rawptr, type_info: ^Type_Info) -> any {
return transmute(any)Any{data, type_info};
}