Browse Source

Add @(require_results) to map procedures where possible

gingerBill 2 years ago
parent
commit
489e8dc592
1 changed files with 36 additions and 14 deletions
  1. 36 14
      core/runtime/dynamic_map_internal.odin

+ 36 - 14
core/runtime/dynamic_map_internal.odin

@@ -107,6 +107,7 @@ Map_Cell_Info :: struct {
 map_cell_info :: intrinsics.type_map_cell_info
 map_cell_info :: intrinsics.type_map_cell_info
 
 
 // Same as the above procedure but at runtime with the cell Map_Cell_Info value.
 // Same as the above procedure but at runtime with the cell Map_Cell_Info value.
+@(require_results)
 map_cell_index_dynamic :: #force_inline proc "contextless" (base: uintptr, #no_alias info: ^Map_Cell_Info, index: uintptr) -> uintptr {
 map_cell_index_dynamic :: #force_inline proc "contextless" (base: uintptr, #no_alias info: ^Map_Cell_Info, index: uintptr) -> uintptr {
 	// Micro-optimize the common cases to save on integer division.
 	// Micro-optimize the common cases to save on integer division.
 	elements_per_cell := uintptr(info.elements_per_cell)
 	elements_per_cell := uintptr(info.elements_per_cell)
@@ -128,6 +129,7 @@ map_cell_index_dynamic :: #force_inline proc "contextless" (base: uintptr, #no_a
 }
 }
 
 
 // Same as above procedure but with compile-time constant index.
 // Same as above procedure but with compile-time constant index.
+@(require_results)
 map_cell_index_dynamic_const :: proc "contextless" (base: uintptr, #no_alias info: ^Map_Cell_Info, $INDEX: uintptr) -> uintptr {
 map_cell_index_dynamic_const :: proc "contextless" (base: uintptr, #no_alias info: ^Map_Cell_Info, $INDEX: uintptr) -> uintptr {
 	elements_per_cell := uintptr(info.elements_per_cell)
 	elements_per_cell := uintptr(info.elements_per_cell)
 	size_of_cell      := uintptr(info.size_of_cell)
 	size_of_cell      := uintptr(info.size_of_cell)
@@ -143,6 +145,7 @@ map_cell_index_dynamic_const :: proc "contextless" (base: uintptr, #no_alias inf
 // The following compile-time procedure indexes such a [N]Cell(T) structure as
 // The following compile-time procedure indexes such a [N]Cell(T) structure as
 // if it were a flat array accounting for the internal padding introduced by the
 // if it were a flat array accounting for the internal padding introduced by the
 // Cell structure.
 // Cell structure.
+@(require_results)
 map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T), index: uintptr) -> ^T #no_bounds_check {
 map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T), index: uintptr) -> ^T #no_bounds_check {
 	N :: size_of(Map_Cell(T){}.data) / size_of(T) when size_of(T) > 0 else 1
 	N :: size_of(Map_Cell(T){}.data) / size_of(T) when size_of(T) > 0 else 1
 
 
@@ -179,11 +182,13 @@ map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T
 }
 }
 
 
 // len() for map
 // len() for map
+@(require_results)
 map_len :: #force_inline proc "contextless" (m: Raw_Map) -> int {
 map_len :: #force_inline proc "contextless" (m: Raw_Map) -> int {
 	return m.len
 	return m.len
 }
 }
 
 
 // cap() for map
 // cap() for map
+@(require_results)
 map_cap :: #force_inline proc "contextless" (m: Raw_Map) -> int {
 map_cap :: #force_inline proc "contextless" (m: Raw_Map) -> int {
 	// The data uintptr stores the capacity in the lower six bits which gives the
 	// The data uintptr stores the capacity in the lower six bits which gives the
 	// a maximum value of 2^6-1, or 63. We store the integer log2 of capacity
 	// a maximum value of 2^6-1, or 63. We store the integer log2 of capacity
@@ -196,10 +201,12 @@ map_cap :: #force_inline proc "contextless" (m: Raw_Map) -> int {
 // some math is needed to compute it. Compute it as a fixed point percentage to
 // some math is needed to compute it. Compute it as a fixed point percentage to
 // avoid floating point operations. This division can be optimized out by
 // avoid floating point operations. This division can be optimized out by
 // multiplying by the multiplicative inverse of 100.
 // multiplying by the multiplicative inverse of 100.
+@(require_results)
 map_load_factor :: #force_inline proc "contextless" (log2_capacity: uintptr) -> uintptr {
 map_load_factor :: #force_inline proc "contextless" (log2_capacity: uintptr) -> uintptr {
 	return ((uintptr(1) << log2_capacity) * MAP_LOAD_FACTOR) / 100
 	return ((uintptr(1) << log2_capacity) * MAP_LOAD_FACTOR) / 100
 }
 }
 
 
+@(require_results)
 map_resize_threshold :: #force_inline proc "contextless" (m: Raw_Map) -> int {
 map_resize_threshold :: #force_inline proc "contextless" (m: Raw_Map) -> int {
 	return int(map_load_factor(map_log2_cap(m)))
 	return int(map_load_factor(map_log2_cap(m)))
 }
 }
@@ -208,12 +215,14 @@ map_resize_threshold :: #force_inline proc "contextless" (m: Raw_Map) -> int {
 // used in the implementation rather than map_cap since the check for data = 0
 // used in the implementation rather than map_cap since the check for data = 0
 // isn't necessary in the implementation. cap() on the otherhand needs to work
 // isn't necessary in the implementation. cap() on the otherhand needs to work
 // when called on an empty map.
 // when called on an empty map.
+@(require_results)
 map_log2_cap :: #force_inline proc "contextless" (m: Raw_Map) -> uintptr {
 map_log2_cap :: #force_inline proc "contextless" (m: Raw_Map) -> uintptr {
 	return m.data & (64 - 1)
 	return m.data & (64 - 1)
 }
 }
 
 
 // Canonicalize the data by removing the tagged capacity stored in the lower six
 // Canonicalize the data by removing the tagged capacity stored in the lower six
 // bits of the data uintptr.
 // bits of the data uintptr.
+@(require_results)
 map_data :: #force_inline proc "contextless" (m: Raw_Map) -> uintptr {
 map_data :: #force_inline proc "contextless" (m: Raw_Map) -> uintptr {
 	return m.data &~ uintptr(64 - 1)
 	return m.data &~ uintptr(64 - 1)
 }
 }
@@ -224,15 +233,18 @@ Map_Hash :: uintptr
 // Procedure to check if a slot is empty for a given hash. This is represented
 // Procedure to check if a slot is empty for a given hash. This is represented
 // by the zero value to make the zero value useful. This is a procedure just
 // by the zero value to make the zero value useful. This is a procedure just
 // for prose reasons.
 // for prose reasons.
+@(require_results)
 map_hash_is_empty :: #force_inline proc "contextless" (hash: Map_Hash) -> bool {
 map_hash_is_empty :: #force_inline proc "contextless" (hash: Map_Hash) -> bool {
 	return hash == 0
 	return hash == 0
 }
 }
 
 
+@(require_results)
 map_hash_is_deleted :: #force_no_inline proc "contextless" (hash: Map_Hash) -> bool {
 map_hash_is_deleted :: #force_no_inline proc "contextless" (hash: Map_Hash) -> bool {
 	// The MSB indicates a tombstone
 	// The MSB indicates a tombstone
 	N :: size_of(Map_Hash)*8 - 1
 	N :: size_of(Map_Hash)*8 - 1
 	return hash >> N != 0
 	return hash >> N != 0
 }
 }
+@(require_results)
 map_hash_is_valid :: #force_inline proc "contextless" (hash: Map_Hash) -> bool {
 map_hash_is_valid :: #force_inline proc "contextless" (hash: Map_Hash) -> bool {
 	// The MSB indicates a tombstone
 	// The MSB indicates a tombstone
 	N :: size_of(Map_Hash)*8 - 1
 	N :: size_of(Map_Hash)*8 - 1
@@ -242,12 +254,14 @@ map_hash_is_valid :: #force_inline proc "contextless" (hash: Map_Hash) -> bool {
 
 
 // Computes the desired position in the array. This is just index % capacity,
 // Computes the desired position in the array. This is just index % capacity,
 // but a procedure as there's some math involved here to recover the capacity.
 // but a procedure as there's some math involved here to recover the capacity.
+@(require_results)
 map_desired_position :: #force_inline proc "contextless" (m: Raw_Map, hash: Map_Hash) -> uintptr {
 map_desired_position :: #force_inline proc "contextless" (m: Raw_Map, hash: Map_Hash) -> uintptr {
 	// We do not use map_cap since we know the capacity will not be zero here.
 	// We do not use map_cap since we know the capacity will not be zero here.
 	capacity := uintptr(1) << map_log2_cap(m)
 	capacity := uintptr(1) << map_log2_cap(m)
 	return uintptr(hash & Map_Hash(capacity - 1))
 	return uintptr(hash & Map_Hash(capacity - 1))
 }
 }
 
 
+@(require_results)
 map_probe_distance :: #force_inline proc "contextless" (m: Raw_Map, hash: Map_Hash, slot: uintptr) -> uintptr {
 map_probe_distance :: #force_inline proc "contextless" (m: Raw_Map, hash: Map_Hash, slot: uintptr) -> uintptr {
 	// We do not use map_cap since we know the capacity will not be zero here.
 	// We do not use map_cap since we know the capacity will not be zero here.
 	capacity := uintptr(1) << map_log2_cap(m)
 	capacity := uintptr(1) << map_log2_cap(m)
@@ -275,6 +289,7 @@ Map_Info :: struct {
 // map_info :: proc "contextless" ($T: typeid/map[$K]$V) -> ^Map_Info {...}
 // map_info :: proc "contextless" ($T: typeid/map[$K]$V) -> ^Map_Info {...}
 map_info :: intrinsics.type_map_info
 map_info :: intrinsics.type_map_info
 
 
+@(require_results)
 map_kvh_data_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info) -> (ks: uintptr, vs: uintptr, hs: [^]Map_Hash, sk: uintptr, sv: uintptr) {
 map_kvh_data_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info) -> (ks: uintptr, vs: uintptr, hs: [^]Map_Hash, sk: uintptr, sv: uintptr) {
 	INFO_HS := intrinsics.type_map_cell_info(Map_Hash)
 	INFO_HS := intrinsics.type_map_cell_info(Map_Hash)
 
 
@@ -291,13 +306,14 @@ map_kvh_data_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Inf
 	return
 	return
 }
 }
 
 
+@(require_results)
 map_kvh_data_values_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info) -> (vs: uintptr) {
 map_kvh_data_values_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info) -> (vs: uintptr) {
 	capacity := uintptr(1) << map_log2_cap(m)
 	capacity := uintptr(1) << map_log2_cap(m)
 	return map_cell_index_dynamic(map_data(m), info.ks, capacity) // Skip past ks to get start of vs
 	return map_cell_index_dynamic(map_data(m), info.ks, capacity) // Skip past ks to get start of vs
 }
 }
 
 
 
 
-@(private)
+@(private, require_results)
 map_total_allocation_size :: #force_inline proc "contextless" (capacity: uintptr, info: ^Map_Info) -> uintptr {
 map_total_allocation_size :: #force_inline proc "contextless" (capacity: uintptr, info: ^Map_Info) -> uintptr {
 	round :: #force_inline proc "contextless" (value: uintptr) -> uintptr {
 	round :: #force_inline proc "contextless" (value: uintptr) -> uintptr {
 		CACHE_MASK :: MAP_CACHE_LINE_SIZE - 1
 		CACHE_MASK :: MAP_CACHE_LINE_SIZE - 1
@@ -315,6 +331,7 @@ map_total_allocation_size :: #force_inline proc "contextless" (capacity: uintptr
 }
 }
 
 
 // The only procedure which needs access to the context is the one which allocates the map.
 // The only procedure which needs access to the context is the one which allocates the map.
+@(require_results)
 map_alloc_dynamic :: proc "odin" (info: ^Map_Info, log2_capacity: uintptr, allocator := context.allocator, loc := #caller_location) -> (result: Raw_Map, err: Allocator_Error) {
 map_alloc_dynamic :: proc "odin" (info: ^Map_Info, log2_capacity: uintptr, allocator := context.allocator, loc := #caller_location) -> (result: Raw_Map, err: Allocator_Error) {
 	result.allocator = allocator // set the allocator always
 	result.allocator = allocator // set the allocator always
 	if log2_capacity == 0 {
 	if log2_capacity == 0 {
@@ -355,6 +372,7 @@ map_alloc_dynamic :: proc "odin" (info: ^Map_Info, log2_capacity: uintptr, alloc
 // there is no type information.
 // there is no type information.
 //
 //
 // This procedure returns the address of the just inserted value.
 // This procedure returns the address of the just inserted value.
+@(require_results)
 map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, ik: uintptr, iv: uintptr) -> (result: uintptr) {
 map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, ik: uintptr, iv: uintptr) -> (result: uintptr) {
 	h        := h
 	h        := h
 	pos      := map_desired_position(m^, h)
 	pos      := map_desired_position(m^, h)
@@ -429,6 +447,7 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
 	}
 	}
 }
 }
 
 
+@(require_results)
 map_grow_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> Allocator_Error {
 map_grow_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> Allocator_Error {
 	log2_capacity := map_log2_cap(m^)
 	log2_capacity := map_log2_cap(m^)
 	new_capacity := uintptr(1) << max(log2_capacity + 1, MAP_MIN_LOG2_CAPACITY)
 	new_capacity := uintptr(1) << max(log2_capacity + 1, MAP_MIN_LOG2_CAPACITY)
@@ -436,7 +455,9 @@ map_grow_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Inf
 }
 }
 
 
 
 
+@(require_results)
 map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uintptr, loc := #caller_location) -> Allocator_Error {
 map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uintptr, loc := #caller_location) -> Allocator_Error {
+	@(require_results)
 	ceil_log2 :: #force_inline proc "contextless" (x: uintptr) -> uintptr {
 	ceil_log2 :: #force_inline proc "contextless" (x: uintptr) -> uintptr {
 		z := intrinsics.count_leading_zeros(x)
 		z := intrinsics.count_leading_zeros(x)
 		if z > 0 && x & (x-1) != 0 {
 		if z > 0 && x & (x-1) != 0 {
@@ -482,7 +503,7 @@ map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_
 		}
 		}
 		k := map_cell_index_dynamic(ks, info.ks, i)
 		k := map_cell_index_dynamic(ks, info.ks, i)
 		v := map_cell_index_dynamic(vs, info.vs, i)
 		v := map_cell_index_dynamic(vs, info.vs, i)
-		map_insert_hash_dynamic(&resized, info, hash, k, v)
+		_ = map_insert_hash_dynamic(&resized, info, hash, k, v)
 		// Only need to do this comparison on each actually added pair, so do not
 		// Only need to do this comparison on each actually added pair, so do not
 		// fold it into the for loop comparator as a micro-optimization.
 		// fold it into the for loop comparator as a micro-optimization.
 		n -= 1
 		n -= 1
@@ -499,6 +520,7 @@ map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_
 }
 }
 
 
 
 
+@(require_results)
 map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> Allocator_Error {
 map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> Allocator_Error {
 	if m.allocator.procedure == nil {
 	if m.allocator.procedure == nil {
 		m.allocator = context.allocator
 		m.allocator = context.allocator
@@ -530,9 +552,7 @@ map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_I
 
 
 		k := map_cell_index_dynamic(ks, info.ks, i)
 		k := map_cell_index_dynamic(ks, info.ks, i)
 		v := map_cell_index_dynamic(vs, info.vs, i)
 		v := map_cell_index_dynamic(vs, info.vs, i)
-
-		map_insert_hash_dynamic(&shrunk, info, hash, k, v)
-
+		_ = map_insert_hash_dynamic(&shrunk, info, hash, k, v)
 		// Only need to do this comparison on each actually added pair, so do not
 		// Only need to do this comparison on each actually added pair, so do not
 		// fold it into the for loop comparator as a micro-optimization.
 		// fold it into the for loop comparator as a micro-optimization.
 		n -= 1
 		n -= 1
@@ -555,6 +575,7 @@ map_free_dynamic :: proc "odin" (m: Raw_Map, info: ^Map_Info, loc := #caller_loc
 	return mem_free_with_size(ptr, size, m.allocator, loc)
 	return mem_free_with_size(ptr, size, m.allocator, loc)
 }
 }
 
 
+@(require_results)
 map_lookup_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (index: uintptr, ok: bool) {
 map_lookup_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (index: uintptr, ok: bool) {
 	if map_len(m) == 0 {
 	if map_len(m) == 0 {
 		return 0, false
 		return 0, false
@@ -577,6 +598,7 @@ map_lookup_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info,
 		d += 1
 		d += 1
 	}
 	}
 }
 }
+@(require_results)
 map_exists_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (ok: bool) {
 map_exists_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (ok: bool) {
 	if map_len(m) == 0 {
 	if map_len(m) == 0 {
 		return false
 		return false
@@ -626,16 +648,17 @@ map_clear_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #n
 }
 }
 
 
 
 
-map_kvh_data_static :: #force_inline proc "contextless" (m: $T/map[$K]$V) -> ([^]Map_Cell(K), [^]Map_Cell(V), [^]Map_Hash) {
-	H :: Map_Hash
+@(require_results)
+map_kvh_data_static :: #force_inline proc "contextless" (m: $T/map[$K]$V) -> (ks: [^]Map_Cell(K), vs: [^]Map_Cell(V), hs: [^]Map_Hash) {
 	capacity := uintptr(cap(m))
 	capacity := uintptr(cap(m))
-	ks := ([^]Map_Cell(K))(map_data(transmute(Raw_Map)m))
-	vs := ([^]Map_Cell(V))(map_cell_index_static(ks, capacity))
-	hs := ([^]Map_Cell(H))(map_cell_index_static(vs, capacity))
-	return ks, vs, ([^]Map_Hash)(hs)
+	ks = ([^]Map_Cell(K))(map_data(transmute(Raw_Map)m))
+	vs = ([^]Map_Cell(V))(map_cell_index_static(ks, capacity))
+	hs = ([^]Map_Hash)(map_cell_index_static(vs, capacity))
+	return
 }
 }
 
 
 
 
+@(require_results)
 map_get :: proc "contextless" (m: $T/map[$K]$V, key: K) -> (stored_key: K, stored_value: V, ok: bool) {
 map_get :: proc "contextless" (m: $T/map[$K]$V, key: K) -> (stored_key: K, stored_value: V, ok: bool) {
 	rm := transmute(Raw_Map)m
 	rm := transmute(Raw_Map)m
 	if rm.len == 0 {
 	if rm.len == 0 {
@@ -719,15 +742,14 @@ __dynamic_map_set :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_In
 	}
 	}
 
 
 	result := map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(value))
 	result := map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(value))
-	assert(result != 0)
 	m.len += 1
 	m.len += 1
 	return rawptr(result)
 	return rawptr(result)
 }
 }
 
 
 // IMPORTANT: USED WITHIN THE COMPILER
 // IMPORTANT: USED WITHIN THE COMPILER
 @(private)
 @(private)
-__dynamic_map_reserve :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uint, loc := #caller_location) {
-	map_reserve_dynamic(m, info, uintptr(new_capacity), loc)
+__dynamic_map_reserve :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uint, loc := #caller_location) -> Allocator_Error {
+	return map_reserve_dynamic(m, info, uintptr(new_capacity), loc)
 }
 }