github.com/xg0n/routine@v0.0.0-20240119033701-c364deb94aee/g/reflect.go (about) 1 // Copyright 2021-2024 TimAndy. All rights reserved. 2 // Licensed under the Apache-2.0 license that can be found in the LICENSE file. 3 4 package g 5 6 import ( 7 "reflect" 8 "unsafe" 9 ) 10 11 // eface The empty interface struct. 12 type eface struct { 13 _type unsafe.Pointer 14 data unsafe.Pointer 15 } 16 17 // iface The interface struct. 18 type iface struct { 19 tab unsafe.Pointer 20 data unsafe.Pointer 21 } 22 23 // typelinks returns a slice of the sections in each module, and a slice of *rtype offsets in each module. The types in each module are sorted by string. 24 // 25 //go:linkname typelinks reflect.typelinks 26 func typelinks() (sections []unsafe.Pointer, offset [][]int32) 27 28 // resolveTypeOff resolves an *rtype offset from a base type. 29 // 30 //go:linkname resolveTypeOff reflect.resolveTypeOff 31 func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer 32 33 // packEface returns an empty interface representing a value of the specified type, using p as the pointer to the data. 34 func packEface(typ reflect.Type, p unsafe.Pointer) (i interface{}) { 35 t := (*iface)(unsafe.Pointer(&typ)) 36 e := (*eface)(unsafe.Pointer(&i)) 37 e._type = t.data 38 e.data = p 39 return 40 } 41 42 // typeByString returns the type whose 'String' property equals to the given string, or nil if not found. 43 func typeByString(str string) reflect.Type { 44 // The s is search target 45 s := str 46 if len(str) == 0 || str[0] != '*' { 47 s = "*" + s 48 } 49 // The typ is a struct iface{tab(ptr->reflect.Type), data(ptr->rtype)} 50 typ := reflect.TypeOf(0) 51 face := (*iface)(unsafe.Pointer(&typ)) 52 // Find the specified target through binary search algorithm 53 sections, offset := typelinks() 54 for offsI, offs := range offset { 55 section := sections[offsI] 56 // We are looking for the first index i where the string becomes >= s. 57 // This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s). 58 i, j := 0, len(offs) 59 for i < j { 60 h := i + (j-i)/2 // avoid overflow when computing h 61 // i ≤ h < j 62 face.data = resolveTypeOff(section, offs[h]) 63 if !(typ.String() >= s) { 64 i = h + 1 // preserves f(i-1) == false 65 } else { 66 j = h // preserves f(j) == true 67 } 68 } 69 // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i. 70 // Having found the first, linear scan forward to find the last. 71 // We could do a second binary search, but the caller is going 72 // to do a linear scan anyway. 73 if i < len(offs) { 74 face.data = resolveTypeOff(section, offs[i]) 75 if typ.Kind() == reflect.Ptr { 76 if typ.String() == str { 77 return typ 78 } 79 elem := typ.Elem() 80 if elem.String() == str { 81 return elem 82 } 83 } 84 } 85 } 86 return nil 87 }