mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
coalesce tombstones in map insert
This commit is contained in:
@@ -414,68 +414,21 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
|
|||||||
tk := map_cell_index_dynamic(sk, info.ks, 1)
|
tk := map_cell_index_dynamic(sk, info.ks, 1)
|
||||||
tv := map_cell_index_dynamic(sv, info.vs, 1)
|
tv := map_cell_index_dynamic(sv, info.vs, 1)
|
||||||
|
|
||||||
for {
|
swap_loop: for {
|
||||||
hp := &hs[pos]
|
element_hash := hs[pos]
|
||||||
element_hash := hp^
|
|
||||||
|
|
||||||
if map_hash_is_empty(element_hash) {
|
if map_hash_is_empty(element_hash) {
|
||||||
kp := map_cell_index_dynamic(ks, info.ks, pos)
|
k_dst := map_cell_index_dynamic(ks, info.ks, pos)
|
||||||
vp := map_cell_index_dynamic(vs, info.vs, pos)
|
v_dst := map_cell_index_dynamic(vs, info.vs, pos)
|
||||||
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
|
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
|
||||||
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
|
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
|
||||||
hp^ = h
|
hs[pos] = h
|
||||||
|
|
||||||
return result if result != 0 else vp
|
return result if result != 0 else v_dst
|
||||||
}
|
}
|
||||||
|
|
||||||
if map_hash_is_deleted(element_hash) {
|
if map_hash_is_deleted(element_hash) {
|
||||||
next_pos := (pos + 1) & mask
|
break swap_loop
|
||||||
|
|
||||||
// backward shift
|
|
||||||
for !map_hash_is_empty(hs[next_pos]) {
|
|
||||||
probe_distance := map_probe_distance(m^, hs[next_pos], next_pos)
|
|
||||||
if probe_distance == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
probe_distance -= 1
|
|
||||||
|
|
||||||
kp := map_cell_index_dynamic(ks, info.ks, pos)
|
|
||||||
vp := map_cell_index_dynamic(vs, info.vs, pos)
|
|
||||||
kn := map_cell_index_dynamic(ks, info.ks, next_pos)
|
|
||||||
vn := map_cell_index_dynamic(vs, info.vs, next_pos)
|
|
||||||
|
|
||||||
if distance > probe_distance {
|
|
||||||
if result == 0 {
|
|
||||||
result = vp
|
|
||||||
}
|
|
||||||
// move stored into pos; store next
|
|
||||||
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
|
|
||||||
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
|
|
||||||
hs[pos] = h
|
|
||||||
|
|
||||||
intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(kn), size_of_k)
|
|
||||||
intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(vn), size_of_v)
|
|
||||||
h = hs[next_pos]
|
|
||||||
} else {
|
|
||||||
// move next back 1
|
|
||||||
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(kn), size_of_k)
|
|
||||||
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(vn), size_of_v)
|
|
||||||
hs[pos] = hs[next_pos]
|
|
||||||
distance = probe_distance
|
|
||||||
}
|
|
||||||
hs[next_pos] = 0
|
|
||||||
pos = (pos + 1) & mask
|
|
||||||
next_pos = (next_pos + 1) & mask
|
|
||||||
distance += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
kp := map_cell_index_dynamic(ks, info.ks, pos)
|
|
||||||
vp := map_cell_index_dynamic(vs, info.vs, pos)
|
|
||||||
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
|
|
||||||
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
|
|
||||||
hs[pos] = h
|
|
||||||
|
|
||||||
return result if result != 0 else vp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance {
|
if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance {
|
||||||
@@ -495,8 +448,8 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
|
|||||||
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(tv), size_of_v)
|
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(tv), size_of_v)
|
||||||
|
|
||||||
th := h
|
th := h
|
||||||
h = hp^
|
h = hs[pos]
|
||||||
hp^ = th
|
hs[pos] = th
|
||||||
|
|
||||||
distance = probe_distance
|
distance = probe_distance
|
||||||
}
|
}
|
||||||
@@ -504,6 +457,103 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
|
|||||||
pos = (pos + 1) & mask
|
pos = (pos + 1) & mask
|
||||||
distance += 1
|
distance += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// backward shift loop
|
||||||
|
hs[pos] = 0
|
||||||
|
look_ahead: uintptr = 1
|
||||||
|
for {
|
||||||
|
la_pos := (pos + look_ahead) & mask
|
||||||
|
element_hash := hs[la_pos]
|
||||||
|
|
||||||
|
if map_hash_is_deleted(element_hash) {
|
||||||
|
look_ahead += 1
|
||||||
|
hs[la_pos] = 0
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
k_dst := map_cell_index_dynamic(ks, info.ks, pos)
|
||||||
|
v_dst := map_cell_index_dynamic(vs, info.vs, pos)
|
||||||
|
|
||||||
|
if map_hash_is_empty(element_hash) {
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
|
||||||
|
hs[pos] = h
|
||||||
|
|
||||||
|
return result if result != 0 else v_dst
|
||||||
|
}
|
||||||
|
|
||||||
|
k_src := map_cell_index_dynamic(ks, info.ks, la_pos)
|
||||||
|
v_src := map_cell_index_dynamic(vs, info.vs, la_pos)
|
||||||
|
probe_distance := map_probe_distance(m^, element_hash, la_pos)
|
||||||
|
|
||||||
|
if probe_distance < look_ahead {
|
||||||
|
// probed can be made ideal while placing saved (ending condition)
|
||||||
|
if result == 0 {
|
||||||
|
result = v_dst
|
||||||
|
}
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
|
||||||
|
hs[pos] = h
|
||||||
|
|
||||||
|
// This will be an ideal move
|
||||||
|
pos = (la_pos - probe_distance) & mask
|
||||||
|
look_ahead -= probe_distance
|
||||||
|
|
||||||
|
// shift until we hit ideal/empty
|
||||||
|
for probe_distance != 0 {
|
||||||
|
k_dst = map_cell_index_dynamic(ks, info.ks, pos)
|
||||||
|
v_dst = map_cell_index_dynamic(vs, info.vs, pos)
|
||||||
|
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k_src), size_of_k)
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v_src), size_of_v)
|
||||||
|
hs[pos] = element_hash
|
||||||
|
hs[la_pos] = 0
|
||||||
|
|
||||||
|
pos = (pos + 1) & mask
|
||||||
|
la_pos = (la_pos + 1) & mask
|
||||||
|
look_ahead = (la_pos - pos) & mask
|
||||||
|
element_hash = hs[la_pos]
|
||||||
|
if map_hash_is_empty(element_hash) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
probe_distance = map_probe_distance(m^, element_hash, la_pos)
|
||||||
|
if probe_distance == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// can be ideal?
|
||||||
|
if probe_distance < look_ahead {
|
||||||
|
pos = (la_pos - probe_distance) & mask
|
||||||
|
}
|
||||||
|
k_src = map_cell_index_dynamic(ks, info.ks, la_pos)
|
||||||
|
v_src = map_cell_index_dynamic(vs, info.vs, la_pos)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if distance < probe_distance - look_ahead {
|
||||||
|
// shift back probed
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k_src), size_of_k)
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v_src), size_of_v)
|
||||||
|
hs[pos] = element_hash
|
||||||
|
hs[la_pos] = 0
|
||||||
|
} else {
|
||||||
|
// place saved, save probed
|
||||||
|
if result == 0 {
|
||||||
|
result = v_dst
|
||||||
|
}
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
|
||||||
|
hs[pos] = h
|
||||||
|
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(k_src), size_of_k)
|
||||||
|
intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(v_src), size_of_v)
|
||||||
|
h = hs[la_pos]
|
||||||
|
hs[la_pos] = 0
|
||||||
|
distance = probe_distance - look_ahead
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = (pos + 1) & mask
|
||||||
|
distance += 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
@@ -696,49 +746,19 @@ map_erase_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #n
|
|||||||
m.len -= 1
|
m.len -= 1
|
||||||
ok = true
|
ok = true
|
||||||
|
|
||||||
{ // coalesce tombstones
|
mask := (uintptr(1)<<map_log2_cap(m^)) - 1
|
||||||
// HACK NOTE(bill): This is an ugly bodge but it is coalescing the tombstone slots
|
curr_index := uintptr(index)
|
||||||
mask := (uintptr(1)<<map_log2_cap(m^)) - 1
|
next_index := (curr_index + 1) & mask
|
||||||
curr_index := uintptr(index)
|
|
||||||
|
|
||||||
// TODO(bill): determine a good value for this empirically
|
|
||||||
// if we do not implement backward shift deletion
|
|
||||||
PROBE_COUNT :: 8
|
|
||||||
for _ in 0..<PROBE_COUNT {
|
|
||||||
next_index := (curr_index + 1) & mask
|
|
||||||
if next_index == index {
|
|
||||||
// looped around
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the next element is empty or has zero probe distance, then any lookup
|
|
||||||
// will always fail on the next, so we can clear both of them
|
|
||||||
hash := hs[next_index]
|
|
||||||
if map_hash_is_empty(hash) || map_probe_distance(m^, hash, next_index) == 0 {
|
|
||||||
hs[curr_index] = 0
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// now the next element will have a probe count of at least one,
|
|
||||||
// so it can use the delete slot instead
|
|
||||||
hs[curr_index] = hs[next_index]
|
|
||||||
|
|
||||||
mem_copy_non_overlapping(
|
|
||||||
rawptr(map_cell_index_dynamic(ks, info.ks, curr_index)),
|
|
||||||
rawptr(map_cell_index_dynamic(ks, info.ks, next_index)),
|
|
||||||
int(info.ks.size_of_type),
|
|
||||||
)
|
|
||||||
mem_copy_non_overlapping(
|
|
||||||
rawptr(map_cell_index_dynamic(vs, info.vs, curr_index)),
|
|
||||||
rawptr(map_cell_index_dynamic(vs, info.vs, next_index)),
|
|
||||||
int(info.vs.size_of_type),
|
|
||||||
)
|
|
||||||
|
|
||||||
curr_index = next_index
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// if the next element is empty or has zero probe distance, then any lookup
|
||||||
|
// will always fail on the next, so we can clear both of them
|
||||||
|
hash := hs[next_index]
|
||||||
|
if map_hash_is_empty(hash) || map_probe_distance(m^, hash, next_index) == 0 {
|
||||||
|
hs[curr_index] = 0
|
||||||
|
} else {
|
||||||
hs[curr_index] |= TOMBSTONE_MASK
|
hs[curr_index] |= TOMBSTONE_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user