Browse Source

Do an extra check before insertion for pre-existing keys

This is test code
gingerBill 2 years ago
parent
commit
503eb470a7
1 changed files with 32 additions and 17 deletions
  1. 32 17
      core/runtime/dynamic_map_internal.odin

+ 32 - 17
core/runtime/dynamic_map_internal.odin

@@ -354,12 +354,27 @@ map_alloc_dynamic :: proc "odin" (info: ^Map_Info, log2_capacity: uintptr, alloc
 // This procedure returns the address of the just inserted value.
 @(optimization_mode="speed")
 map_insert_hash_dynamic :: proc "odin" (m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, ik: uintptr, iv: uintptr) -> (result: uintptr) {
-	p := map_desired_position(m, h)
-	d := uintptr(0)
-	c := (uintptr(1) << map_log2_cap(m)) - 1 // Saturating arithmetic mask
+	pos := map_desired_position(m, h)
+	distance := uintptr(0)
+	mask := (uintptr(1) << map_log2_cap(m)) - 1 // Saturating arithmetic mask
 
 	ks, vs, hs, sk, sv := map_kvh_data_dynamic(m, info)
 
+	get_loop: for {
+		element_hash := hs[pos]
+		if map_hash_is_empty(element_hash) {
+			break get_loop
+		} else if distance > map_probe_distance(m, element_hash, pos) {
+			break get_loop
+		} else if element_hash == h && info.key_equal(rawptr(ik), rawptr(map_cell_index_dynamic(ks, info.ks, pos))) {
+			result = map_cell_index_dynamic(vs, info.vs, pos)
+			intrinsics.mem_copy_non_overlapping(rawptr(result), rawptr(iv), info.ks.size_of_type)
+			return
+		}
+		pos = (pos + 1) & mask
+		distance += 1
+	}
+
 	// Avoid redundant loads of these values
 	size_of_k := info.ks.size_of_type
 	size_of_v := info.vs.size_of_type
@@ -381,38 +396,38 @@ map_insert_hash_dynamic :: proc "odin" (m: Raw_Map, #no_alias info: ^Map_Info, h
 	tv := map_cell_index_dynamic_const(sv, info.vs, 1)
 
 	for {
-		hp := &hs[p]
+		hp := &hs[pos]
 		element_hash := hp^
 
 		if map_hash_is_empty(element_hash) {
-			k_dst := map_cell_index_dynamic(ks, info.ks, p)
-			v_dst := map_cell_index_dynamic(vs, info.vs, p)
+			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 pd := map_probe_distance(m, element_hash, p); pd <= d {
+		if pd := map_probe_distance(m, element_hash, pos); pd <= distance {
 			if map_hash_is_deleted(element_hash) {
-				k_dst := map_cell_index_dynamic(ks, info.ks, p)
-				v_dst := map_cell_index_dynamic(vs, info.vs, p)
+				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
-			} else if element_hash == h && info.key_equal(rawptr(k), rawptr(map_cell_index_dynamic(ks, info.ks, p))) {
-				v_dst := map_cell_index_dynamic(vs, info.vs, p)
+			} else if element_hash == h && info.key_equal(rawptr(k), rawptr(map_cell_index_dynamic(ks, info.ks, pos))) {
+				v_dst := map_cell_index_dynamic(vs, info.vs, pos)
 				intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(iv), info.vs.size_of_type)
 				return v_dst
 			}
 
 			if result == 0 {
-				result = map_cell_index_dynamic(vs, info.vs, p)
+				result = map_cell_index_dynamic(vs, info.vs, pos)
 			}
 
-			kp := map_cell_index_dynamic(ks, info.vs, p)
-			vp := map_cell_index_dynamic(vs, info.ks, p)
+			kp := map_cell_index_dynamic(ks, info.vs, pos)
+			vp := map_cell_index_dynamic(vs, info.ks, pos)
 
 			// Simulate the following at runtime with dynamic storage
 			//
@@ -427,11 +442,11 @@ map_insert_hash_dynamic :: proc "odin" (m: Raw_Map, #no_alias info: ^Map_Info, h
 			intrinsics.mem_copy_non_overlapping(rawptr(v),  rawptr(tv), size_of_v)
 			hp^, h = h, hp^
 
-			d = pd
+			distance = pd
 		}
 
-		p = (p + 1) & c
-		d += 1
+		pos = (pos + 1) & mask
+		distance += 1
 	}
 }