diff options
| author | gingerBill <bill@gingerbill.org> | 2020-11-23 15:53:49 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2020-11-23 15:53:49 +0000 |
| commit | 4e370e6ed8d6cfe3dee306dfbc298ba68722f12e (patch) | |
| tree | 075c3639d3378c47279800a97229d6ee159126ff /core | |
| parent | 0b30c3dc5ad3f3908719af19e9f7e61daae37706 (diff) | |
Add `equal` procedure field to `runtime.Type_Info_Struct`
Diffstat (limited to 'core')
| -rw-r--r-- | core/reflect/reflect.odin | 78 | ||||
| -rw-r--r-- | core/runtime/core.odin | 5 |
2 files changed, 83 insertions, 0 deletions
diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 947a10771..df183e2fd 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -1206,3 +1206,81 @@ as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) { return; } + + +not_equal :: proc(a, b: any) -> bool { + return !equal(a, b); +} +equal :: proc(a, b: any) -> bool { + if a == nil && b == nil { + return true; + } + + if a.id != b.id { + return false; + } + + if a.data == b.data { + return true; + } + + t := type_info_of(a.id); + if .Comparable not_in t.flags { + return false; + } + + if t.size == 0 { + return true; + } + + if .Simple_Compare in t.flags { + return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0; + } + + t = runtime.type_info_core(t); + + #partial switch v in t.variant { + case Type_Info_String: + if v.is_cstring { + x := string((^cstring)(a.data)^); + y := string((^cstring)(b.data)^); + return x == y; + } else { + x := (^string)(a.data)^; + y := (^string)(b.data)^; + return x == y; + } + + case Type_Info_Array: + for i in 0..<v.count { + x := rawptr(uintptr(a.data) + uintptr(v.elem_size*i)); + y := rawptr(uintptr(b.data) + uintptr(v.elem_size*i)); + if !equal(any{x, v.elem.id}, any{y, v.elem.id}) { + return false; + } + } + case Type_Info_Enumerated_Array: + for i in 0..<v.count { + x := rawptr(uintptr(a.data) + uintptr(v.elem_size*i)); + y := rawptr(uintptr(b.data) + uintptr(v.elem_size*i)); + if !equal(any{x, v.elem.id}, any{y, v.elem.id}) { + return false; + } + } + case Type_Info_Struct: + if v.equal != nil { + return v.equal(a.data, b.data); + } else { + for offset, i in v.offsets { + x := rawptr(uintptr(a.data) + offset); + y := rawptr(uintptr(b.data) + offset); + id := v.types[i].id; + if !equal(any{x, id}, any{y, id}) { + return false; + } + } + } + } + + return true; +} diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 2989c4700..14d5c99ce 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -88,6 +88,8 @@ Type_Info_Tuple :: struct { // Only used for procedures parameters and results types: []^Type_Info, names: []string, }; + +Type_Struct_Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; Type_Info_Struct :: struct { types: []^Type_Info, names: []string, @@ -97,6 +99,9 @@ Type_Info_Struct :: struct { is_packed: bool, is_raw_union: bool, custom_align: bool, + + equal: Type_Struct_Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set + // These are only set iff this structure is an SOA structure soa_kind: Type_Info_Struct_Soa_Kind, soa_base_type: ^Type_Info, |