mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Merge pull request #2055 from odin-lang/map-index-internal
Map Internals Improvements
This commit is contained in:
@@ -423,18 +423,16 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := runtime.Map_Hash {
|
key_hash := runtime.default_hasher_string(&key, 0)
|
||||||
hash = runtime.default_hasher_string(&key, 0),
|
key_ptr := rawptr(&key)
|
||||||
key_ptr = &key,
|
|
||||||
}
|
|
||||||
|
|
||||||
key_cstr: cstring
|
key_cstr: cstring
|
||||||
if reflect.is_cstring(t.key) {
|
if reflect.is_cstring(t.key) {
|
||||||
key_cstr = cstring(raw_data(key))
|
key_cstr = cstring(raw_data(key))
|
||||||
hash.key_ptr = &key_cstr
|
key_ptr = &key_cstr
|
||||||
}
|
}
|
||||||
|
|
||||||
set_ptr := runtime.__dynamic_map_set(header, hash, map_backing_value.data)
|
set_ptr := runtime.__dynamic_map_set(header, key_hash, key_ptr, map_backing_value.data)
|
||||||
if set_ptr == nil {
|
if set_ptr == nil {
|
||||||
delete(key, p.allocator)
|
delete(key, p.allocator)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -394,7 +394,7 @@ Raw_Dynamic_Array :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Raw_Map :: struct {
|
Raw_Map :: struct {
|
||||||
hashes: []int,
|
hashes: []Map_Index,
|
||||||
entries: Raw_Dynamic_Array,
|
entries: Raw_Dynamic_Array,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -289,14 +289,14 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
|
|||||||
entries := (^Raw_Dynamic_Array)(&raw_map.entries)
|
entries := (^Raw_Dynamic_Array)(&raw_map.entries)
|
||||||
entries.len = 0
|
entries.len = 0
|
||||||
for _, i in raw_map.hashes {
|
for _, i in raw_map.hashes {
|
||||||
raw_map.hashes[i] = -1
|
raw_map.hashes[i] = MAP_SENTINEL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) {
|
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
__dynamic_map_reserve(__get_map_header(m), capacity, loc)
|
__dynamic_map_reserve(__get_map_header(m), uint(capacity), loc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,9 +325,8 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
|
|||||||
if m != nil {
|
if m != nil {
|
||||||
key := key
|
key := key
|
||||||
h := __get_map_header(m)
|
h := __get_map_header(m)
|
||||||
hash := __get_map_hash(&key)
|
fr := __map_find(h, &key)
|
||||||
fr := __dynamic_map_find(h, hash)
|
if fr.entry_index != MAP_SENTINEL {
|
||||||
if fr.entry_index >= 0 {
|
|
||||||
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
||||||
deleted_key = (^K)(uintptr(entry)+h.key_offset)^
|
deleted_key = (^K)(uintptr(entry)+h.key_offset)^
|
||||||
deleted_value = (^V)(uintptr(entry)+h.value_offset)^
|
deleted_value = (^V)(uintptr(entry)+h.value_offset)^
|
||||||
@@ -335,7 +334,6 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
|
|||||||
__dynamic_map_erase(h, fr)
|
__dynamic_map_erase(h, fr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,9 +672,8 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
|
|||||||
map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
|
map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
|
||||||
key, value := key, value
|
key, value := key, value
|
||||||
h := __get_map_header(m)
|
h := __get_map_header(m)
|
||||||
hash := __get_map_hash(&key)
|
|
||||||
|
|
||||||
data := uintptr(__dynamic_map_set(h, hash, &value, loc))
|
data := uintptr(__dynamic_map_set(h, __get_map_key_hash(&key), &key, &value, loc))
|
||||||
return (^V)(data + h.value_offset)
|
return (^V)(data + h.value_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_c
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_cap := new_cap
|
||||||
|
new_cap = max(new_cap, 0)
|
||||||
old_size := array.cap * elem_size
|
old_size := array.cap * elem_size
|
||||||
new_size := new_cap * elem_size
|
new_size := new_cap * elem_size
|
||||||
allocator := array.allocator
|
allocator := array.allocator
|
||||||
|
|||||||
@@ -11,30 +11,27 @@ Map_Hash :: struct {
|
|||||||
key_ptr: rawptr, // address of Map_Entry_Header.key
|
key_ptr: rawptr, // address of Map_Entry_Header.key
|
||||||
}
|
}
|
||||||
|
|
||||||
__get_map_hash :: proc "contextless" (k: ^$K) -> (map_hash: Map_Hash) {
|
__get_map_key_hash :: #force_inline proc "contextless" (k: ^$K) -> uintptr {
|
||||||
hasher := intrinsics.type_hasher_proc(K)
|
hasher := intrinsics.type_hasher_proc(K)
|
||||||
map_hash.key_ptr = k
|
return hasher(k, 0)
|
||||||
map_hash.hash = hasher(k, 0)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__get_map_hash_from_entry :: proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> (hash: Map_Hash) {
|
__get_map_entry_key_ptr :: #force_inline proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> rawptr {
|
||||||
hash.hash = entry.hash
|
return rawptr(uintptr(entry) + h.key_offset)
|
||||||
hash.key_ptr = rawptr(uintptr(entry) + h.key_offset)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map_Index :: distinct uint
|
||||||
|
MAP_SENTINEL :: ~Map_Index(0)
|
||||||
|
|
||||||
Map_Find_Result :: struct {
|
Map_Find_Result :: struct {
|
||||||
hash_index: int,
|
hash_index: Map_Index,
|
||||||
entry_prev: int,
|
entry_prev: Map_Index,
|
||||||
entry_index: int,
|
entry_index: Map_Index,
|
||||||
}
|
}
|
||||||
|
|
||||||
Map_Entry_Header :: struct {
|
Map_Entry_Header :: struct {
|
||||||
hash: uintptr,
|
hash: uintptr,
|
||||||
next: int,
|
next: Map_Index,
|
||||||
/*
|
/*
|
||||||
key: Key_Value,
|
key: Key_Value,
|
||||||
value: Value_Type,
|
value: Value_Type,
|
||||||
@@ -183,7 +180,7 @@ __get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
|
__slice_resize :: proc "odin" (array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
|
||||||
array := (^Raw_Slice)(array_)
|
array := (^Raw_Slice)(array_)
|
||||||
|
|
||||||
if new_count < array.len {
|
if new_count < array.len {
|
||||||
@@ -205,86 +202,95 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) {
|
__dynamic_map_reset_entries :: proc "contextless" (h: Map_Header, loc := #caller_location) {
|
||||||
for i in 0..<len(m.hashes) {
|
for i in 0..<len(h.m.hashes) {
|
||||||
m.hashes[i] = -1
|
h.m.hashes[i] = MAP_SENTINEL
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..<m.entries.len {
|
for i in 0..<Map_Index(h.m.entries.len) {
|
||||||
entry_header := __dynamic_map_get_entry(header, i)
|
entry_header := __dynamic_map_get_entry(h, i)
|
||||||
entry_hash := __get_map_hash_from_entry(header, entry_header)
|
entry_header.next = MAP_SENTINEL
|
||||||
entry_header.next = -1
|
|
||||||
|
|
||||||
fr := __dynamic_map_find(header, entry_hash)
|
fr := __dynamic_map_find_from_entry(h, entry_header)
|
||||||
if fr.entry_prev < 0 {
|
if fr.entry_prev != MAP_SENTINEL {
|
||||||
m.hashes[fr.hash_index] = i
|
e := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||||
} else {
|
|
||||||
e := __dynamic_map_get_entry(header, fr.entry_prev)
|
|
||||||
e.next = i
|
e.next = i
|
||||||
|
} else {
|
||||||
|
h.m.hashes[fr.hash_index] = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller_location) {
|
__dynamic_map_reserve :: proc "odin" (h: Map_Header, cap: uint, loc := #caller_location) {
|
||||||
c := context
|
c := context
|
||||||
if m.entries.allocator.procedure != nil {
|
if h.m.entries.allocator.procedure != nil {
|
||||||
c.allocator = m.entries.allocator
|
c.allocator = h.m.entries.allocator
|
||||||
}
|
}
|
||||||
context = c
|
context = c
|
||||||
|
|
||||||
cap := cap
|
cap := cap
|
||||||
cap = ceil_to_pow2(cap)
|
cap = ceil_to_pow2(cap)
|
||||||
|
|
||||||
__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc)
|
__dynamic_array_reserve(&h.m.entries, h.entry_size, h.entry_align, int(cap), loc)
|
||||||
|
|
||||||
if m.entries.len*2 < len(m.hashes) {
|
if h.m.entries.len*2 < len(h.m.hashes) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if __slice_resize(&m.hashes, cap*2, m.entries.allocator, loc) {
|
if __slice_resize(&h.m.hashes, int(cap*2), h.m.entries.allocator, loc) {
|
||||||
__dynamic_map_reset_entries(header, loc)
|
__dynamic_map_reset_entries(h, loc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_shrink :: proc(using header: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) {
|
__dynamic_map_shrink :: proc "odin" (h: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) {
|
||||||
c := context
|
c := context
|
||||||
if m.entries.allocator.procedure != nil {
|
if h.m.entries.allocator.procedure != nil {
|
||||||
c.allocator = m.entries.allocator
|
c.allocator = h.m.entries.allocator
|
||||||
}
|
}
|
||||||
context = c
|
context = c
|
||||||
|
|
||||||
return __dynamic_array_shrink(&m.entries, entry_size, entry_align, cap, loc)
|
return __dynamic_array_shrink(&h.m.entries, h.entry_size, h.entry_align, cap, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) {
|
// USED INTERNALLY BY THE COMPILER
|
||||||
#force_inline __dynamic_map_reserve(header, new_count, loc)
|
__dynamic_map_get :: proc "contextless" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr) -> rawptr {
|
||||||
}
|
index := __dynamic_map_find(h, key_hash, key_ptr).entry_index
|
||||||
|
if index != MAP_SENTINEL {
|
||||||
__dynamic_map_get :: proc(h: Map_Header, hash: Map_Hash) -> rawptr {
|
|
||||||
index := __dynamic_map_find(h, hash).entry_index
|
|
||||||
if index >= 0 {
|
|
||||||
data := uintptr(__dynamic_map_get_entry(h, index))
|
data := uintptr(__dynamic_map_get_entry(h, index))
|
||||||
return rawptr(data + h.value_offset)
|
return rawptr(data + h.value_offset)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check {
|
// USED INTERNALLY BY THE COMPILER
|
||||||
index: int
|
__dynamic_map_set :: proc "odin" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check {
|
||||||
|
add_entry :: proc "odin" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr, loc := #caller_location) -> Map_Index {
|
||||||
|
prev := Map_Index(h.m.entries.len)
|
||||||
|
c := Map_Index(__dynamic_array_append_nothing(&h.m.entries, h.entry_size, h.entry_align, loc))
|
||||||
|
if c != prev {
|
||||||
|
end := __dynamic_map_get_entry(h, c-1)
|
||||||
|
end.hash = key_hash
|
||||||
|
mem_copy(rawptr(uintptr(end) + h.key_offset), key_ptr, h.key_size)
|
||||||
|
end.next = MAP_SENTINEL
|
||||||
|
}
|
||||||
|
return prev
|
||||||
|
}
|
||||||
|
|
||||||
|
index := MAP_SENTINEL
|
||||||
|
|
||||||
if len(h.m.hashes) == 0 {
|
if len(h.m.hashes) == 0 {
|
||||||
__dynamic_map_reserve(h, INITIAL_MAP_CAP, loc)
|
__dynamic_map_reserve(h, INITIAL_MAP_CAP, loc)
|
||||||
__dynamic_map_grow(h, loc)
|
__dynamic_map_grow(h, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
fr := __dynamic_map_find(h, hash)
|
fr := __dynamic_map_find(h, key_hash, key_ptr)
|
||||||
if fr.entry_index >= 0 {
|
if fr.entry_index != MAP_SENTINEL {
|
||||||
index = fr.entry_index
|
index = fr.entry_index
|
||||||
} else {
|
} else {
|
||||||
index = __dynamic_map_add_entry(h, hash, loc)
|
index = add_entry(h, key_hash, key_ptr, loc)
|
||||||
if fr.entry_prev >= 0 {
|
if fr.entry_prev != MAP_SENTINEL {
|
||||||
entry := __dynamic_map_get_entry(h, fr.entry_prev)
|
entry := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||||
entry.next = index
|
entry.next = index
|
||||||
} else if fr.hash_index >= 0 {
|
} else if fr.hash_index != MAP_SENTINEL {
|
||||||
h.m.hashes[fr.hash_index] = index
|
h.m.hashes[fr.hash_index] = index
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
@@ -292,12 +298,12 @@ __dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := #
|
|||||||
}
|
}
|
||||||
|
|
||||||
e := __dynamic_map_get_entry(h, index)
|
e := __dynamic_map_get_entry(h, index)
|
||||||
e.hash = hash.hash
|
e.hash = key_hash
|
||||||
|
|
||||||
key := rawptr(uintptr(e) + h.key_offset)
|
key := rawptr(uintptr(e) + h.key_offset)
|
||||||
mem_copy(key, hash.key_ptr, h.key_size)
|
|
||||||
|
|
||||||
val := rawptr(uintptr(e) + h.value_offset)
|
val := rawptr(uintptr(e) + h.value_offset)
|
||||||
|
|
||||||
|
mem_copy(key, key_ptr, h.key_size)
|
||||||
mem_copy(val, value, h.value_size)
|
mem_copy(val, value, h.value_size)
|
||||||
|
|
||||||
if __dynamic_map_full(h) {
|
if __dynamic_map_full(h) {
|
||||||
@@ -309,13 +315,11 @@ __dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := #
|
|||||||
|
|
||||||
|
|
||||||
@(private="file")
|
@(private="file")
|
||||||
ceil_to_pow2 :: proc "contextless" (n: int) -> int {
|
ceil_to_pow2 :: proc "contextless" (n: uint) -> uint {
|
||||||
n := n
|
if n <= 2 {
|
||||||
if n <= 0 {
|
|
||||||
return 0
|
|
||||||
} else if n <= 2 {
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
n := n
|
||||||
n -= 1
|
n -= 1
|
||||||
n |= n >> 1
|
n |= n >> 1
|
||||||
n |= n >> 2
|
n |= n >> 2
|
||||||
@@ -329,33 +333,33 @@ ceil_to_pow2 :: proc "contextless" (n: int) -> int {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_grow :: proc(using h: Map_Header, loc := #caller_location) {
|
__dynamic_map_grow :: proc "odin" (h: Map_Header, loc := #caller_location) {
|
||||||
// TODO(bill): Determine an efficient growing rate
|
new_count := max(uint(h.m.entries.cap) * 2, INITIAL_MAP_CAP)
|
||||||
new_count := max(m.entries.cap * 2, INITIAL_MAP_CAP)
|
// Rehash through Reserve
|
||||||
__dynamic_map_rehash(h, new_count, loc)
|
__dynamic_map_reserve(h, new_count, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_full :: #force_inline proc "contextless" (using h: Map_Header) -> bool {
|
__dynamic_map_full :: #force_inline proc "contextless" (h: Map_Header) -> bool {
|
||||||
return int(0.75 * f64(len(m.hashes))) <= m.entries.len
|
return int(0.75 * f64(len(h.m.hashes))) <= h.m.entries.len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__dynamic_map_find_from_entry :: proc "contextless" (h: Map_Header, e: ^Map_Entry_Header) -> Map_Find_Result #no_bounds_check {
|
||||||
|
key_ptr := __get_map_entry_key_ptr(h, e)
|
||||||
|
return __dynamic_map_find(h, e.hash, key_ptr)
|
||||||
|
|
||||||
__dynamic_map_hash_equal :: proc "contextless" (h: Map_Header, a, b: Map_Hash) -> bool {
|
|
||||||
return a.hash == b.hash && h.equal(a.key_ptr, b.key_ptr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Result #no_bounds_check {
|
__dynamic_map_find :: proc "contextless" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr) -> Map_Find_Result #no_bounds_check {
|
||||||
fr := Map_Find_Result{-1, -1, -1}
|
fr := Map_Find_Result{MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}
|
||||||
if n := uintptr(len(m.hashes)); n != 0 {
|
if n := uintptr(len(h.m.hashes)); n != 0 {
|
||||||
fr.hash_index = int(hash.hash & (n-1))
|
fr.hash_index = Map_Index(key_hash & (n-1))
|
||||||
fr.entry_index = m.hashes[fr.hash_index]
|
fr.entry_index = h.m.hashes[fr.hash_index]
|
||||||
for fr.entry_index >= 0 {
|
for fr.entry_index != MAP_SENTINEL {
|
||||||
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
||||||
entry_hash := __get_map_hash_from_entry(h, entry)
|
entry_key_ptr := __get_map_entry_key_ptr(h, entry)
|
||||||
if __dynamic_map_hash_equal(h, entry_hash, hash) {
|
if entry.hash == key_hash && h.equal(entry_key_ptr, key_ptr) {
|
||||||
return fr
|
return fr
|
||||||
}
|
}
|
||||||
// assert(entry.next < m.entries.len)
|
|
||||||
|
|
||||||
fr.entry_prev = fr.entry_index
|
fr.entry_prev = fr.entry_index
|
||||||
fr.entry_index = entry.next
|
fr.entry_index = entry.next
|
||||||
@@ -364,58 +368,38 @@ __dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Resu
|
|||||||
return fr
|
return fr
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_add_entry :: proc(using h: Map_Header, hash: Map_Hash, loc := #caller_location) -> int {
|
// Utility procedure used by other runtime procedures
|
||||||
prev := m.entries.len
|
__map_find :: proc "contextless" (h: Map_Header, key_ptr: ^$K) -> Map_Find_Result #no_bounds_check {
|
||||||
c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc)
|
hash := __get_map_key_hash(key_ptr)
|
||||||
if c != prev {
|
return #force_inline __dynamic_map_find(h, hash, key_ptr)
|
||||||
end := __dynamic_map_get_entry(h, c-1)
|
|
||||||
end.hash = hash.hash
|
|
||||||
mem_copy(rawptr(uintptr(end) + key_offset), hash.key_ptr, key_size)
|
|
||||||
end.next = -1
|
|
||||||
}
|
|
||||||
return prev
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_delete_key :: proc(using h: Map_Header, hash: Map_Hash) {
|
__dynamic_map_get_entry :: #force_inline proc "contextless" (h: Map_Header, index: Map_Index) -> ^Map_Entry_Header {
|
||||||
fr := __dynamic_map_find(h, hash)
|
return (^Map_Entry_Header)(uintptr(h.m.entries.data) + uintptr(index*Map_Index(h.entry_size)))
|
||||||
if fr.entry_index >= 0 {
|
|
||||||
__dynamic_map_erase(h, fr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header {
|
__dynamic_map_erase :: proc "contextless" (h: Map_Header, fr: Map_Find_Result) #no_bounds_check {
|
||||||
// assert(0 <= index && index < m.entries.len)
|
if fr.entry_prev != MAP_SENTINEL {
|
||||||
return (^Map_Entry_Header)(uintptr(m.entries.data) + uintptr(index*entry_size))
|
|
||||||
}
|
|
||||||
|
|
||||||
__dynamic_map_copy_entry :: proc(h: Map_Header, new, old: ^Map_Entry_Header) {
|
|
||||||
mem_copy(new, old, h.entry_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds_check {
|
|
||||||
if fr.entry_prev < 0 {
|
|
||||||
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next
|
|
||||||
} else {
|
|
||||||
prev := __dynamic_map_get_entry(h, fr.entry_prev)
|
prev := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||||
curr := __dynamic_map_get_entry(h, fr.entry_index)
|
curr := __dynamic_map_get_entry(h, fr.entry_index)
|
||||||
prev.next = curr.next
|
prev.next = curr.next
|
||||||
}
|
|
||||||
if fr.entry_index == m.entries.len-1 {
|
|
||||||
// NOTE(bill): No need to do anything else, just pop
|
|
||||||
} else {
|
} else {
|
||||||
|
h.m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next
|
||||||
|
}
|
||||||
|
last_index := Map_Index(h.m.entries.len-1)
|
||||||
|
if fr.entry_index != last_index {
|
||||||
old := __dynamic_map_get_entry(h, fr.entry_index)
|
old := __dynamic_map_get_entry(h, fr.entry_index)
|
||||||
end := __dynamic_map_get_entry(h, m.entries.len-1)
|
end := __dynamic_map_get_entry(h, last_index)
|
||||||
__dynamic_map_copy_entry(h, old, end)
|
mem_copy(old, end, h.entry_size)
|
||||||
|
|
||||||
old_hash := __get_map_hash_from_entry(h, old)
|
last := __dynamic_map_find_from_entry(h, old)
|
||||||
|
if last.entry_prev != MAP_SENTINEL {
|
||||||
if last := __dynamic_map_find(h, old_hash); last.entry_prev >= 0 {
|
e := __dynamic_map_get_entry(h, last.entry_prev)
|
||||||
last_entry := __dynamic_map_get_entry(h, last.entry_prev)
|
e.next = fr.entry_index
|
||||||
last_entry.next = fr.entry_index
|
|
||||||
} else {
|
} else {
|
||||||
m.hashes[last.hash_index] = fr.entry_index
|
h.m.hashes[last.hash_index] = fr.entry_index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.entries.len -= 1
|
h.m.entries.len -= 1
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-15
@@ -502,10 +502,16 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A
|
|||||||
|
|
||||||
lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) {
|
lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) {
|
||||||
GB_ASSERT_MSG(is_type_pointer(map_val_ptr.type), "%s", type_to_string(map_val_ptr.type));
|
GB_ASSERT_MSG(is_type_pointer(map_val_ptr.type), "%s", type_to_string(map_val_ptr.type));
|
||||||
lbAddr h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later
|
|
||||||
map_type = base_type(map_type);
|
map_type = base_type(map_type);
|
||||||
GB_ASSERT(map_type->kind == Type_Map);
|
GB_ASSERT(map_type->kind == Type_Map);
|
||||||
|
|
||||||
|
lbAddr h = {};
|
||||||
|
lbAddr *found = map_get(&p->map_header_cache, map_val_ptr.value);
|
||||||
|
if (found != nullptr) {
|
||||||
|
h = *found;
|
||||||
|
} else {
|
||||||
|
h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later
|
||||||
|
|
||||||
Type *key_type = map_type->Map.key;
|
Type *key_type = map_type->Map.key;
|
||||||
Type *val_type = map_type->Map.value;
|
Type *val_type = map_type->Map.value;
|
||||||
gb_unused(val_type);
|
gb_unused(val_type);
|
||||||
@@ -545,6 +551,10 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) {
|
|||||||
lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type));
|
lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type));
|
||||||
lb_emit_store(p, gep0, m);
|
lb_emit_store(p, gep0, m);
|
||||||
|
|
||||||
|
|
||||||
|
map_set(&p->map_header_cache, map_val_ptr.value, h);
|
||||||
|
}
|
||||||
|
|
||||||
return lb_addr_load(p, h);
|
return lb_addr_load(p, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,14 +605,12 @@ lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
|
|||||||
return hashed_key;
|
return hashed_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) {
|
lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_) {
|
||||||
lbAddr v = lb_add_local_generated(p, t_map_hash, true);
|
|
||||||
lbValue vp = lb_addr_get_ptr(p, v);
|
|
||||||
key = lb_emit_conv(p, key, key_type);
|
|
||||||
|
|
||||||
lbValue key_ptr = lb_address_from_load_or_generate_local(p, key);
|
lbValue key_ptr = lb_address_from_load_or_generate_local(p, key);
|
||||||
key_ptr = lb_emit_conv(p, key_ptr, t_rawptr);
|
key_ptr = lb_emit_conv(p, key_ptr, t_rawptr);
|
||||||
|
|
||||||
|
if (key_ptr_) *key_ptr_ = key_ptr;
|
||||||
|
|
||||||
lbValue hashed_key = lb_const_hash(p->module, key, key_type);
|
lbValue hashed_key = lb_const_hash(p->module, key, key_type);
|
||||||
if (hashed_key.value == nullptr) {
|
if (hashed_key.value == nullptr) {
|
||||||
lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type);
|
lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type);
|
||||||
@@ -613,10 +621,7 @@ lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) {
|
|||||||
hashed_key = lb_emit_call(p, hasher, args);
|
hashed_key = lb_emit_call(p, hasher, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_key);
|
return hashed_key;
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr);
|
|
||||||
|
|
||||||
return lb_addr_load(p, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type,
|
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type,
|
||||||
@@ -625,17 +630,19 @@ void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_
|
|||||||
GB_ASSERT(map_type->kind == Type_Map);
|
GB_ASSERT(map_type->kind == Type_Map);
|
||||||
|
|
||||||
lbValue h = lb_gen_map_header(p, addr.addr, map_type);
|
lbValue h = lb_gen_map_header(p, addr.addr, map_type);
|
||||||
lbValue key = lb_gen_map_hash(p, map_key, map_type->Map.key);
|
lbValue key_ptr = {};
|
||||||
|
lbValue key_hash = lb_gen_map_key_hash(p, map_key, map_type->Map.key, &key_ptr);
|
||||||
lbValue v = lb_emit_conv(p, map_value, map_type->Map.value);
|
lbValue v = lb_emit_conv(p, map_value, map_type->Map.value);
|
||||||
|
|
||||||
lbAddr value_addr = lb_add_local_generated(p, v.type, false);
|
lbAddr value_addr = lb_add_local_generated(p, v.type, false);
|
||||||
lb_addr_store(p, value_addr, v);
|
lb_addr_store(p, value_addr, v);
|
||||||
|
|
||||||
auto args = array_make<lbValue>(permanent_allocator(), 4);
|
auto args = array_make<lbValue>(permanent_allocator(), 5);
|
||||||
args[0] = h;
|
args[0] = h;
|
||||||
args[1] = key;
|
args[1] = key_hash;
|
||||||
args[2] = lb_emit_conv(p, value_addr.addr, t_rawptr);
|
args[2] = key_ptr;
|
||||||
args[3] = lb_emit_source_code_location(p, node);
|
args[3] = lb_emit_conv(p, value_addr.addr, t_rawptr);
|
||||||
|
args[4] = lb_emit_source_code_location(p, node);
|
||||||
lb_emit_runtime_call(p, "__dynamic_map_set", args);
|
lb_emit_runtime_call(p, "__dynamic_map_set", args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -308,6 +308,7 @@ struct lbProcedure {
|
|||||||
|
|
||||||
PtrMap<Ast *, lbValue> selector_values;
|
PtrMap<Ast *, lbValue> selector_values;
|
||||||
PtrMap<Ast *, lbAddr> selector_addr;
|
PtrMap<Ast *, lbAddr> selector_addr;
|
||||||
|
PtrMap<LLVMValueRef, lbAddr> map_header_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -444,7 +445,7 @@ String lb_get_const_string(lbModule *m, lbValue value);
|
|||||||
lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
|
lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
|
||||||
lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
|
lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
|
||||||
lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type);
|
lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type);
|
||||||
lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type);
|
lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
|
||||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node);
|
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node);
|
||||||
|
|
||||||
lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e);
|
lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e);
|
||||||
|
|||||||
@@ -1423,15 +1423,9 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
|
|||||||
switch (rt->kind) {
|
switch (rt->kind) {
|
||||||
case Type_Map:
|
case Type_Map:
|
||||||
{
|
{
|
||||||
lbValue addr = lb_address_from_load_or_generate_local(p, right);
|
lbValue map_ptr = lb_address_from_load_or_generate_local(p, right);
|
||||||
lbValue h = lb_gen_map_header(p, addr, rt);
|
lbValue key = left;
|
||||||
lbValue key = lb_gen_map_hash(p, left, rt->Map.key);
|
lbValue ptr = lb_internal_dynamic_map_get_ptr(p, map_ptr, key);
|
||||||
|
|
||||||
auto args = array_make<lbValue>(permanent_allocator(), 2);
|
|
||||||
args[0] = h;
|
|
||||||
args[1] = key;
|
|
||||||
|
|
||||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
|
||||||
if (be->op.kind == Token_in) {
|
if (be->op.kind == Token_in) {
|
||||||
return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
|
return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -383,6 +383,21 @@ Type *lb_addr_type(lbAddr const &addr) {
|
|||||||
return type_deref(addr.addr.type);
|
return type_deref(addr.addr.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key) {
|
||||||
|
Type *map_type = base_type(type_deref(map_ptr.type));
|
||||||
|
lbValue h = lb_gen_map_header(p, map_ptr, map_type);
|
||||||
|
|
||||||
|
lbValue key_ptr = {};
|
||||||
|
auto args = array_make<lbValue>(permanent_allocator(), 3);
|
||||||
|
args[0] = h;
|
||||||
|
args[1] = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr);
|
||||||
|
args[2] = key_ptr;
|
||||||
|
|
||||||
|
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
||||||
|
|
||||||
|
return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
|
||||||
|
}
|
||||||
|
|
||||||
lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
|
lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
|
||||||
if (addr.addr.value == nullptr) {
|
if (addr.addr.value == nullptr) {
|
||||||
GB_PANIC("Illegal addr -> nullptr");
|
GB_PANIC("Illegal addr -> nullptr");
|
||||||
@@ -390,19 +405,8 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (addr.kind) {
|
switch (addr.kind) {
|
||||||
case lbAddr_Map: {
|
case lbAddr_Map:
|
||||||
Type *map_type = base_type(addr.map.type);
|
return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
|
||||||
lbValue h = lb_gen_map_header(p, addr.addr, map_type);
|
|
||||||
lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key);
|
|
||||||
|
|
||||||
auto args = array_make<lbValue>(permanent_allocator(), 2);
|
|
||||||
args[0] = h;
|
|
||||||
args[1] = key;
|
|
||||||
|
|
||||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
|
||||||
|
|
||||||
return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
|
|
||||||
}
|
|
||||||
|
|
||||||
case lbAddr_RelativePointer: {
|
case lbAddr_RelativePointer: {
|
||||||
Type *rel_ptr = base_type(lb_addr_type(addr));
|
Type *rel_ptr = base_type(lb_addr_type(addr));
|
||||||
@@ -1059,16 +1063,11 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
|
|||||||
|
|
||||||
|
|
||||||
} else if (addr.kind == lbAddr_Map) {
|
} else if (addr.kind == lbAddr_Map) {
|
||||||
Type *map_type = base_type(addr.map.type);
|
Type *map_type = base_type(type_deref(addr.addr.type));
|
||||||
|
GB_ASSERT(map_type->kind == Type_Map);
|
||||||
lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true);
|
lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true);
|
||||||
lbValue h = lb_gen_map_header(p, addr.addr, map_type);
|
|
||||||
lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key);
|
|
||||||
|
|
||||||
auto args = array_make<lbValue>(permanent_allocator(), 2);
|
lbValue ptr = lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
|
||||||
args[0] = h;
|
|
||||||
args[1] = key;
|
|
||||||
|
|
||||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
|
||||||
lbValue ok = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
|
lbValue ok = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), ok);
|
lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), ok);
|
||||||
|
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
|||||||
p->scope_stack.allocator = a;
|
p->scope_stack.allocator = a;
|
||||||
map_init(&p->selector_values, a, 0);
|
map_init(&p->selector_values, a, 0);
|
||||||
map_init(&p->selector_addr, a, 0);
|
map_init(&p->selector_addr, a, 0);
|
||||||
|
map_init(&p->map_header_cache, a, 0);
|
||||||
|
|
||||||
if (p->is_foreign) {
|
if (p->is_foreign) {
|
||||||
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
||||||
@@ -380,6 +381,8 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
|
|||||||
lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture");
|
lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map_init(&p->map_header_cache, heap_allocator(), 0);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user