Browse Source

Correct reflection usage of maps

gingerBill 2 years ago
parent
commit
6dd4d1a924
4 changed files with 36 additions and 82 deletions
  1. 11 14
      core/encoding/json/marshal.odin
  2. 3 6
      core/encoding/json/unmarshal.odin
  3. 0 36
      core/reflect/map.odin
  4. 22 26
      core/slice/map.odin

+ 11 - 14
core/encoding/json/marshal.odin

@@ -257,21 +257,18 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
 		opt_write_start(w, opt, '{') or_return
 
 		if m != nil {
-			if info.generated_struct == nil {
+			if info.map_info == nil {
 				return .Unsupported_Type
 			}
-			entries    := &m.entries
-			gs         := runtime.type_info_base(info.generated_struct).variant.(runtime.Type_Info_Struct)
-			ed         := runtime.type_info_base(gs.types[1]).variant.(runtime.Type_Info_Dynamic_Array)
-			entry_type := ed.elem.variant.(runtime.Type_Info_Struct)
-			entry_size := ed.elem_size
-
-			for i in 0..<entries.len {
-				opt_write_iteration(w, opt, i) or_return
+			map_cap := uintptr(runtime.map_cap(m^))
+			ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info)
+			for bucket_index in 0..<map_cap {
+				if !runtime.map_hash_is_valid(hs[bucket_index]) {
+					continue
+				}
 
-				data := uintptr(entries.data) + uintptr(i*entry_size)
-				key   := rawptr(data + entry_type.offsets[2])
-				value := rawptr(data + entry_type.offsets[3])
+				key   := rawptr(runtime.map_cell_index_dynamic(ks, &info.map_info.ks, bucket_index))
+				value := rawptr(runtime.map_cell_index_dynamic(vs, &info.map_info.vs, bucket_index))
 
 				// check for string type
 				{
@@ -281,13 +278,13 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
 					name: string
 
 					#partial switch info in ti.variant {
-					case runtime.Type_Info_String: 
+					case runtime.Type_Info_String:
 						switch s in a {
 							case string: name = s
 							case cstring: name = string(s)
 						}
 						opt_write_key(w, opt, name) or_return
-	
+
 					case: return .Unsupported_Type
 					}
 				}

+ 3 - 6
core/encoding/json/unmarshal.odin

@@ -399,12 +399,10 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
 			return UNSUPPORTED_TYPE
 		}
 		raw_map := (^mem.Raw_Map)(v.data)
-		if raw_map.entries.allocator.procedure == nil {
-			raw_map.entries.allocator = p.allocator
+		if raw_map.allocator.procedure == nil {
+			raw_map.allocator = p.allocator
 		}
 		
-		header := runtime.__get_map_header_table_runtime(t)
-		
 		elem_backing := bytes_make(t.value.size, t.value.align, p.allocator) or_return
 		defer delete(elem_backing, p.allocator)
 		
@@ -421,7 +419,6 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
 				return err
 			}
 
-			key_hash := runtime.default_hasher_string(&key, 0)
 			key_ptr := rawptr(&key)
 
 			key_cstr: cstring
@@ -430,7 +427,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
 				key_ptr = &key_cstr
 			}
 			
-			set_ptr := runtime.__dynamic_map_set(raw_map, header, key_hash, key_ptr, map_backing_value.data)
+			set_ptr := runtime.__dynamic_map_set(raw_map, t.map_info, key_ptr, map_backing_value.data)
 			if set_ptr == nil {
 				delete(key, p.allocator)
 			} 

+ 0 - 36
core/reflect/map.odin

@@ -1,36 +0,0 @@
-package reflect
-
-import "core:runtime"
-_ :: runtime
-
-Map_Entry_Info :: struct($Key, $Value: typeid) {
-	hash:  uintptr,
-	key:   Key,
-	value: Value,
-}
-
-map_entry_info_slice :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry_Info(K, V), err: runtime.Allocator_Error) #no_bounds_check {
-	m := m
-	rm := (^runtime.Raw_Map)(&m)
-
-	info := type_info_base(type_info_of(M)).variant.(Type_Info_Map)
-	if info.map_info != nil {
-		entries = make(type_of(entries), len(m), allocator) or_return
-
-		map_cap := uintptr(cap(m))
-		ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(rm^, info.map_info)
-		entry_index := 0
-		for bucket_index in 0..<map_cap {
-			if hash := hs[bucket_index]; runtime.map_hash_is_valid(hash) {
-				key   := runtime.map_cell_index_dynamic(ks, &info.map_info.ks, bucket_index)
-				value := runtime.map_cell_index_dynamic(vs, &info.map_info.vs, bucket_index)
-				entries[entry_index].hash  = hash
-				entries[entry_index].key   = (^K)(key)^
-				entries[entry_index].value = (^V)(value)^
-
-				entry_index += 1
-			}
-		}
-	}
-	return
-}

+ 22 - 26
core/slice/map.odin

@@ -6,8 +6,8 @@ import "core:runtime"
 _ :: intrinsics
 _ :: runtime
 
-map_keys :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (keys: []K) {
-	keys = make(type_of(keys), len(m), allocator)
+map_keys :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (keys: []K, err: runtime.Allocator_Error) {
+	keys = make(type_of(keys), len(m), allocator) or_return
 	i := 0
 	for key in m {
 		keys[i] = key
@@ -15,8 +15,8 @@ map_keys :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (keys: []K)
 	}
 	return
 }
-map_values :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (values: []V) {
-	values = make(type_of(values), len(m), allocator)
+map_values :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (values: []V, err: runtime.Allocator_Error) {
+	values = make(type_of(values), len(m), allocator) or_return
 	i := 0
 	for _, value in m {
 		values[i] = value
@@ -37,8 +37,8 @@ Map_Entry_Info :: struct($Key, $Value: typeid) {
 }
 
 
-map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry(K, V)) {
-	entries = make(type_of(entries), len(m), allocator)
+map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry(K, V), err: runtime.Allocator) {
+	entries = make(type_of(entries), len(m), allocator) or_return
 	i := 0
 	for key, value in m {
 		entries[i].key   = key
@@ -52,28 +52,24 @@ map_entry_infos :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (ent
 	m := m
 	rm := (^runtime.Raw_Map)(&m)
 
-	info := runtime.type_info_base(type_info_of(M)).variant.(runtime.Type_Info_Map)
-	gs := runtime.type_info_base(info.generated_struct).variant.(runtime.Type_Info_Struct)
-	ed := runtime.type_info_base(gs.types[1]).variant.(runtime.Type_Info_Dynamic_Array)
-	entry_type := ed.elem.variant.(runtime.Type_Info_Struct)
-	key_offset :=  entry_type.offsets[2]
-	value_offset :=  entry_type.offsets[3]
-	entry_size := uintptr(ed.elem_size)
+	info := type_info_base(type_info_of(M)).variant.(Type_Info_Map)
+	if info.map_info != nil {
+		entries = make(type_of(entries), len(m), allocator) or_return
 
-	entries = make(type_of(entries), rm.entries.len)
+		map_cap := uintptr(cap(m))
+		ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(rm^, info.map_info)
+		entry_index := 0
+		for bucket_index in 0..<map_cap {
+			if hash := hs[bucket_index]; runtime.map_hash_is_valid(hash) {
+				key   := runtime.map_cell_index_dynamic(ks, &info.map_info.ks, bucket_index)
+				value := runtime.map_cell_index_dynamic(vs, &info.map_info.vs, bucket_index)
+				entries[entry_index].hash  = hash
+				entries[entry_index].key   = (^K)(key)^
+				entries[entry_index].value = (^V)(value)^
 
-	data := uintptr(rm.entries.data)
-	for i in 0..<rm.entries.len {
-		header := (^runtime.Map_Entry_Header)(data)
-
-		hash  := header.hash
-		key   := (^K)(data + key_offset)^
-		value := (^V)(data + value_offset)^
-
-		entries[i] = {hash, key, value}
-
-		data += entry_size
+				entry_index += 1
+			}
+		}
 	}
-
 	return
 }