Browse Source

implement backward shift during map insertion

jason 2 years ago
parent
commit
3032a4274d
1 changed files with 54 additions and 16 deletions
  1. 54 16
      core/runtime/dynamic_map_internal.odin

+ 54 - 16
core/runtime/dynamic_map_internal.odin

@@ -394,32 +394,71 @@ 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 {
 	for {
 		hp := &hs[pos]
 		hp := &hs[pos]
 		element_hash := hp^
 		element_hash := hp^
 
 
 		if map_hash_is_empty(element_hash) {
 		if map_hash_is_empty(element_hash) {
-			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), size_of_k)
-			intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
+			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)
 			hp^ = h
 			hp^ = h
 
 
-			return result if result != 0 else v_dst
+			return result if result != 0 else vp
 		}
 		}
 
 
-		if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance {
-			if map_hash_is_deleted(element_hash) {
-				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), size_of_k)
-				intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
-				hp^ = h
-
-				return result if result != 0 else v_dst
+		if map_hash_is_deleted(element_hash) {
+			next_pos := (pos + 1) & mask
+
+			// 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 result == 0 {
 			if result == 0 {
 				result = map_cell_index_dynamic(vs, info.vs, pos)
 				result = map_cell_index_dynamic(vs, info.vs, pos)
 			}
 			}
@@ -637,7 +676,6 @@ map_erase_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #n
 
 
 	{ // coalesce tombstones
 	{ // coalesce tombstones
 		// HACK NOTE(bill): This is an ugly bodge but it is coalescing the tombstone slots
 		// HACK NOTE(bill): This is an ugly bodge but it is coalescing the tombstone slots
-		// TODO(bill): we should do backward shift deletion and not rely on tombstone slots
 		mask := (uintptr(1)<<map_log2_cap(m^)) - 1
 		mask := (uintptr(1)<<map_log2_cap(m^)) - 1
 		curr_index := uintptr(index)
 		curr_index := uintptr(index)