github.com/avicd/go-utilx@v0.1.0/goid/reflect.go (about)

     1  package goid
     2  
     3  import (
     4  	"reflect"
     5  	"unsafe"
     6  )
     7  
     8  // iface The interface struct.
     9  type iface struct {
    10  	tab  unsafe.Pointer
    11  	data unsafe.Pointer
    12  }
    13  
    14  // 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.
    15  //
    16  //go:linkname typelinks reflect.typelinks
    17  func typelinks() (sections []unsafe.Pointer, offset [][]int32)
    18  
    19  // resolveTypeOff resolves an *rtype offset from a base type.
    20  //
    21  //go:linkname resolveTypeOff reflect.resolveTypeOff
    22  func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
    23  
    24  // typeByString returns the type whose 'String' property equals to the given string, or nil if not found.
    25  func typeByString(str string) reflect.Type {
    26  	// The s is search target
    27  	s := str
    28  	if len(str) == 0 || str[0] != '*' {
    29  		s = "*" + s
    30  	}
    31  	// The typ is a struct iface{tab(ptr->reflect.Type), dsx(ptr->rtype)}
    32  	typ := reflect.TypeOf(0)
    33  	face := (*iface)(unsafe.Pointer(&typ))
    34  	// Find the specified target through binary search algorithm
    35  	sections, offset := typelinks()
    36  	for offsI, offs := range offset {
    37  		section := sections[offsI]
    38  		// We are looking for the first index i where the string becomes >= s.
    39  		// This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s).
    40  		i, j := 0, len(offs)
    41  		for i < j {
    42  			h := i + (j-i)/2 // avoid overflow when computing h
    43  			// i ≤ h < j
    44  			face.data = resolveTypeOff(section, offs[h])
    45  			if !(typ.String() >= s) {
    46  				i = h + 1 // preserves f(i-1) == false
    47  			} else {
    48  				j = h // preserves f(j) == true
    49  			}
    50  		}
    51  		// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
    52  		// Having found the first, linear scan forward to find the last.
    53  		// We could do a second binary search, but the caller is going
    54  		// to do a linear scan anyway.
    55  		if i < len(offs) {
    56  			face.data = resolveTypeOff(section, offs[i])
    57  			if typ.Kind() == reflect.Ptr {
    58  				if typ.String() == str {
    59  					return typ
    60  				}
    61  				elem := typ.Elem()
    62  				if elem.String() == str {
    63  					return elem
    64  				}
    65  			}
    66  		}
    67  	}
    68  	return nil
    69  }