Browse Source

Add `struct_fields_zipped` and `enum_fields_zipped` (allowing for iteration through an #soa slice)

gingerBill 4 years ago
parent
commit
3ca887a60a
1 changed files with 63 additions and 21 deletions
  1. 63 21
      core/reflect/reflect.odin

+ 63 - 21
core/reflect/reflect.odin

@@ -33,6 +33,8 @@ Type_Info_Simd_Vector      :: runtime.Type_Info_Simd_Vector;
 Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer;
 Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer;
 Type_Info_Relative_Slice   :: runtime.Type_Info_Relative_Slice;
 Type_Info_Relative_Slice   :: runtime.Type_Info_Relative_Slice;
 
 
+Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value;
+
 
 
 Type_Kind :: enum {
 Type_Kind :: enum {
 	Invalid,
 	Invalid,
@@ -111,7 +113,7 @@ backing_type_kind :: proc(T: typeid) -> Type_Kind {
 }
 }
 
 
 
 
-type_info_base :: proc(info: ^runtime.Type_Info) -> ^runtime.Type_Info {
+type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
 	if info == nil { return nil; }
 	if info == nil { return nil; }
 
 
 	base := info;
 	base := info;
@@ -125,7 +127,7 @@ type_info_base :: proc(info: ^runtime.Type_Info) -> ^runtime.Type_Info {
 }
 }
 
 
 
 
-type_info_core :: proc(info: ^runtime.Type_Info) -> ^runtime.Type_Info {
+type_info_core :: proc(info: ^Type_Info) -> ^Type_Info {
 	if info == nil { return nil; }
 	if info == nil { return nil; }
 
 
 	base := info;
 	base := info;
@@ -344,7 +346,7 @@ Struct_Tag :: distinct string;
 
 
 Struct_Field :: struct {
 Struct_Field :: struct {
 	name:     string,
 	name:     string,
-	type:     typeid,
+	type:     ^Type_Info,
 	tag:      Struct_Tag,
 	tag:      Struct_Tag,
 	offset:   uintptr,
 	offset:   uintptr,
 	is_using: bool,
 	is_using: bool,
@@ -355,7 +357,7 @@ struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
 	if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
 	if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
 		if 0 <= i && i < len(s.names) {
 		if 0 <= i && i < len(s.names) {
 			field.name     = s.names[i];
 			field.name     = s.names[i];
-			field.type     = s.types[i].id;
+			field.type     = s.types[i];
 			field.tag      = Struct_Tag(s.tags[i]);
 			field.tag      = Struct_Tag(s.tags[i]);
 			field.offset   = s.offsets[i];
 			field.offset   = s.offsets[i];
 			field.is_using = s.usings[i];
 			field.is_using = s.usings[i];
@@ -370,7 +372,7 @@ struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
 		for fname, i in s.names {
 		for fname, i in s.names {
 			if fname == name {
 			if fname == name {
 				field.name     = s.names[i];
 				field.name     = s.names[i];
-				field.type     = s.types[i].id;
+				field.type     = s.types[i];
 				field.tag      = Struct_Tag(s.tags[i]);
 				field.tag      = Struct_Tag(s.tags[i]);
 				field.offset   = s.offsets[i];
 				field.offset   = s.offsets[i];
 				field.is_using = s.usings[i];
 				field.is_using = s.usings[i];
@@ -381,7 +383,7 @@ struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
 	return;
 	return;
 }
 }
 
 
-struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> any {
+struct_field_value_by_name :: proc(a: any, field: string, allow_using := false) -> any {
 	if a == nil { return nil; }
 	if a == nil { return nil; }
 
 
 	ti := runtime.type_info_base(type_info_of(a.id));
 	ti := runtime.type_info_base(type_info_of(a.id));
@@ -395,13 +397,13 @@ struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> a
 				};
 				};
 			}
 			}
 
 
-			if recurse && s.usings[i] {
+			if allow_using && s.usings[i] {
 				f := any{
 				f := any{
 					rawptr(uintptr(a.data) + s.offsets[i]),
 					rawptr(uintptr(a.data) + s.offsets[i]),
 					s.types[i].id,
 					s.types[i].id,
 				};
 				};
 
 
-				if res := struct_field_value_by_name(f, field, recurse); res != nil {
+				if res := struct_field_value_by_name(f, field, allow_using); res != nil {
 					return res;
 					return res;
 				}
 				}
 			}
 			}
@@ -420,7 +422,7 @@ struct_field_names :: proc(T: typeid) -> []string {
 	return nil;
 	return nil;
 }
 }
 
 
-struct_field_types :: proc(T: typeid) -> []^runtime.Type_Info {
+struct_field_types :: proc(T: typeid) -> []^Type_Info {
 	ti := runtime.type_info_base(type_info_of(T));
 	ti := runtime.type_info_base(type_info_of(T));
 	if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
 	if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
 		return s.types;
 		return s.types;
@@ -445,6 +447,20 @@ struct_field_offsets :: proc(T: typeid) -> []uintptr {
 	return nil;
 	return nil;
 }
 }
 
 
+struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
+	ti := runtime.type_info_base(type_info_of(T));
+	if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
+		return soa_zip(
+			name     = s.names,
+			type     = s.types,
+			tag      = transmute([]Struct_Tag)s.tags,
+			offset   = s.offsets,
+			is_using = s.usings,
+		);
+	}
+	return nil;
+}
+
 
 
 
 
 struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag) {
 struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag) {
@@ -468,7 +484,7 @@ struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, o
 			switch t[i] {
 			switch t[i] {
 			case ':', '"':
 			case ':', '"':
 				break loop;
 				break loop;
-			case 0x00 ..< ' ', 0x7f .. 0x9f: // break if control character is found
+			case 0x00 ..< ' ', 0x7f ..= 0x9f: // break if control character is found
 				break loop;
 				break loop;
 			}
 			}
 			i += 1;
 			i += 1;
@@ -516,7 +532,7 @@ enum_string :: proc(a: any) -> string {
 	if e, ok := ti.variant.(runtime.Type_Info_Enum); ok {
 	if e, ok := ti.variant.(runtime.Type_Info_Enum); ok {
 		v, _ := as_i64(a);
 		v, _ := as_i64(a);
 		for value, i in e.values {
 		for value, i in e.values {
-			if value == runtime.Type_Info_Enum_Value(v) {
+			if value == Type_Info_Enum_Value(v) {
 				return e.names[i];
 				return e.names[i];
 			}
 			}
 		}
 		}
@@ -528,26 +544,24 @@ enum_string :: proc(a: any) -> string {
 }
 }
 
 
 // Given a enum type and a value name, get the enum value.
 // Given a enum type and a value name, get the enum value.
-enum_from_name :: proc($EnumType: typeid, name: string) -> (value: EnumType, ok: bool) {
-	ti := type_info_base(type_info_of(EnumType));
+enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, ok: bool) {
+	ti := type_info_base(type_info_of(Enum_Type));
 	if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
 	if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
 		for value_name, i in eti.names {
 		for value_name, i in eti.names {
 			if value_name != name {
 			if value_name != name {
 				continue;
 				continue;
 			}
 			}
 			v := eti.values[i];
 			v := eti.values[i];
-			value = EnumType(v);
+			value = Enum_Type(v);
 			ok = true;
 			ok = true;
 			return;
 			return;
 		}
 		}
-	} else {
-		panic("expected enum type to reflect.enum_from_name");
 	}
 	}
 	return;
 	return;
 }
 }
 
 
-enum_from_name_any :: proc(EnumType: typeid, name: string) -> (value: runtime.Type_Info_Enum_Value, ok: bool) {
-	ti := runtime.type_info_base(type_info_of(EnumType));
+enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info_Enum_Value, ok: bool) {
+	ti := runtime.type_info_base(type_info_of(Enum_Type));
 	if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
 	if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
 		for value_name, i in eti.names {
 		for value_name, i in eti.names {
 			if value_name != name {
 			if value_name != name {
@@ -557,14 +571,42 @@ enum_from_name_any :: proc(EnumType: typeid, name: string) -> (value: runtime.Ty
 			ok = true;
 			ok = true;
 			return;
 			return;
 		}
 		}
-	} else {
-		panic("expected enum type to reflect.enum_from_name_any");
 	}
 	}
 	return;
 	return;
 }
 }
 
 
 
 
-union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
+enum_field_names :: proc(Enum_Type: typeid) -> []string {
+	ti := runtime.type_info_base(type_info_of(Enum_Type));
+	if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
+		return eti.names;
+	}
+	return nil;
+}
+enum_field_values :: proc(Enum_Type: typeid) -> []Type_Info_Enum_Value {
+	ti := runtime.type_info_base(type_info_of(Enum_Type));
+	if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
+		return eti.values;
+	}
+	return nil;
+}
+
+Enum_Field :: struct {
+	name:  string,
+	value: Type_Info_Enum_Value,
+}
+
+enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
+	ti := runtime.type_info_base(type_info_of(Enum_Type));
+	if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
+		return soa_zip(name=eti.names, value=eti.values);
+	}
+	return nil;
+}
+
+
+
+union_variant_type_info :: proc(a: any) -> ^Type_Info {
 	id := union_variant_typeid(a);
 	id := union_variant_typeid(a);
 	return type_info_of(id);
 	return type_info_of(id);
 }
 }