Begin work on implementing the new map internals

This commit is contained in:
gingerBill
2022-11-07 23:02:21 +00:00
parent f1c24f434b
commit c96e0afbf1
13 changed files with 832 additions and 492 deletions
+2
View File
@@ -2072,6 +2072,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
if info.generated_struct == nil {
return
}
/*
entries := &m.entries
gs := runtime.type_info_base(info.generated_struct).variant.(runtime.Type_Info_Struct)
ed := runtime.type_info_base(gs.types[1]).variant.(runtime.Type_Info_Dynamic_Array)
@@ -2106,6 +2107,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
value := data + entry_type.offsets[3] // value: Value
fmt_arg(fi, any{rawptr(value), info.value.id}, 'v')
}
*/
}
case runtime.Type_Info_Struct:
+10 -11
View File
@@ -112,22 +112,21 @@ query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_locatio
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) {
free(raw_data(str), allocator, loc)
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return free(raw_data(str), allocator, loc)
}
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) {
free((^byte)(str), allocator, loc)
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return free((^byte)(str), allocator, loc)
}
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) {
free(raw_data(array), array.allocator, loc)
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
return free(raw_data(array), array.allocator, loc)
}
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) {
free(raw_data(array), allocator, loc)
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return free(raw_data(array), allocator, loc)
}
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) {
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
raw := transmute(Raw_Map)m
delete_slice(raw.hashes, raw.entries.allocator, loc)
free(raw.entries.data, raw.entries.allocator, loc)
return runtime.map_free(raw, loc)
}
+2 -2
View File
@@ -273,7 +273,7 @@ length :: proc(val: any) -> int {
return (^runtime.Raw_Dynamic_Array)(val.data).len
case Type_Info_Map:
return (^runtime.Raw_Map)(val.data).entries.len
return runtime.map_len((^runtime.Raw_Map)(val.data)^)
case Type_Info_String:
if a.is_cstring {
@@ -305,7 +305,7 @@ capacity :: proc(val: any) -> int {
return (^runtime.Raw_Dynamic_Array)(val.data).cap
case Type_Info_Map:
return (^runtime.Raw_Map)(val.data).entries.cap
return runtime.map_cap((^runtime.Raw_Map)(val.data)^)
}
return 0
}
+25 -2
View File
@@ -394,9 +394,32 @@ Raw_Dynamic_Array :: struct {
allocator: Allocator,
}
// The raw, type-erased representation of a map.
//
// 32-bytes on 64-bit
// 16-bytes on 32-bit
Raw_Map :: struct {
hashes: []Map_Index,
entries: Raw_Dynamic_Array,
// A single allocation spanning all keys, values, and hashes.
// {
// k: Map_Cell(K) * (capacity / ks_per_cell)
// v: Map_Cell(V) * (capacity / vs_per_cell)
// h: Map_Cell(H) * (capacity / hs_per_cell)
// }
//
// The data is allocated assuming 64-byte alignment, meaning the address is
// always a multiple of 64. This means we have 6 bits of zeros in the pointer
// to store the capacity. We can store a value as large as 2^6-1 or 63 in
// there. This conveniently is the maximum log2 capacity we can have for a map
// as Odin uses signed integers to represent capacity.
//
// Since the hashes are backed by Map_Hash, which is just a 64-bit unsigned
// integer, the cell structure for hashes is unnecessary because 64/8 is 8 and
// requires no padding, meaning it can be indexed as a regular array of
// Map_Hash directly, though for consistency sake it's written as if it were
// an array of Map_Cell(Map_Hash).
data: uintptr, // 8-bytes on 64-bits, 4-bytes on 32-bits
len: uintptr, // 8-bytes on 64-bits, 4-bytes on 32-bits
allocator: Allocator, // 16-bytes on 64-bits, 8-bytes on 32-bits
}
Raw_Any :: struct {
+6 -31
View File
@@ -159,20 +159,7 @@ delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #cal
}
@builtin
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
Entry :: struct {
hash: uintptr,
next: int,
key: K,
value: V,
}
raw := transmute(Raw_Map)m
err := delete_slice(raw.hashes, raw.entries.allocator, loc)
err1 := mem_free_with_size(raw.entries.data, raw.entries.cap*size_of(Entry), raw.entries.allocator, loc)
if err == nil {
err = err1
}
return err
return map_free(transmute(Raw_Map)m, loc)
}
@@ -285,19 +272,13 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
if m == nil {
return
}
raw_map := (^Raw_Map)(m)
entries := (^Raw_Dynamic_Array)(&raw_map.entries)
entries.len = 0
for _, i in raw_map.hashes {
raw_map.hashes[i] = MAP_SENTINEL
}
map_clear_dynamic((^Raw_Map)(m), map_info(K, V))
}
@builtin
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) {
if m != nil {
h := __get_map_header_table(T)
__dynamic_map_reserve(m, h, uint(capacity), loc)
__dynamic_map_reserve((^Raw_Map)(m), map_info(K, V), uint(capacity), loc)
}
}
@@ -325,15 +306,9 @@ shrink_map :: proc(m: ^$T/map[$K]$V, new_cap := -1, loc := #caller_location) ->
delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value: V) {
if m != nil {
key := key
h := __get_map_header(m)
fr := __map_find(h, &key)
if fr.entry_index != MAP_SENTINEL {
entry := __dynamic_map_get_entry(h, fr.entry_index)
deleted_key = (^K)(uintptr(entry)+h.key_offset)^
deleted_value = (^V)(uintptr(entry)+h.value_offset)^
__dynamic_map_erase(h, fr)
}
info := map_info(K, V)
_ = map_erase_dynamic((^Raw_Map)(m), info, uintptr(&key))
// TODO(bill) old key and value
}
return
}
File diff suppressed because it is too large Load Diff