|
@@ -0,0 +1,282 @@
|
|
|
|
|
+package reflect2
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "reflect"
|
|
|
|
|
+ "unsafe"
|
|
|
|
|
+ "github.com/v2pro/plz/concurrent"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+type Type interface {
|
|
|
|
|
+ Kind() reflect.Kind
|
|
|
|
|
+ // New return pointer to data of this type
|
|
|
|
|
+ New() interface{}
|
|
|
|
|
+ // UnsafeNew return the allocated space pointed by unsafe.Pointer
|
|
|
|
|
+ UnsafeNew() unsafe.Pointer
|
|
|
|
|
+ // PackEFace cast a unsafe pointer to object represented pointer
|
|
|
|
|
+ PackEFace(ptr unsafe.Pointer) interface{}
|
|
|
|
|
+ // Indirect dereference object represented pointer to this type
|
|
|
|
|
+ Indirect(obj interface{}) interface{}
|
|
|
|
|
+ // UnsafeIndirect dereference pointer to this type
|
|
|
|
|
+ UnsafeIndirect(ptr unsafe.Pointer) interface{}
|
|
|
|
|
+ // Type1 returns reflect.Type
|
|
|
|
|
+ Type1() reflect.Type
|
|
|
|
|
+ Implements(thatType Type) bool
|
|
|
|
|
+ String() string
|
|
|
|
|
+ RType() uintptr
|
|
|
|
|
+ // interface{} of this type has pointer like behavior
|
|
|
|
|
+ LikePtr() bool
|
|
|
|
|
+ IsNullable() bool
|
|
|
|
|
+ IsNil(obj interface{}) bool
|
|
|
|
|
+ UnsafeIsNil(ptr unsafe.Pointer) bool
|
|
|
|
|
+ Set(obj interface{}, val interface{})
|
|
|
|
|
+ UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer)
|
|
|
|
|
+ AssignableTo(anotherType Type) bool
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type ListType interface {
|
|
|
|
|
+ Type
|
|
|
|
|
+ Elem() Type
|
|
|
|
|
+ SetIndex(obj interface{}, index int, elem interface{})
|
|
|
|
|
+ UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer)
|
|
|
|
|
+ GetIndex(obj interface{}, index int) interface{}
|
|
|
|
|
+ UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type ArrayType interface {
|
|
|
|
|
+ ListType
|
|
|
|
|
+ Len() int
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type SliceType interface {
|
|
|
|
|
+ ListType
|
|
|
|
|
+ MakeSlice(length int, cap int) interface{}
|
|
|
|
|
+ UnsafeMakeSlice(length int, cap int) unsafe.Pointer
|
|
|
|
|
+ Grow(obj interface{}, newLength int)
|
|
|
|
|
+ UnsafeGrow(ptr unsafe.Pointer, newLength int)
|
|
|
|
|
+ Append(obj interface{}, elem interface{})
|
|
|
|
|
+ UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer)
|
|
|
|
|
+ LengthOf(obj interface{}) int
|
|
|
|
|
+ UnsafeLengthOf(ptr unsafe.Pointer) int
|
|
|
|
|
+ SetNil(obj interface{})
|
|
|
|
|
+ UnsafeSetNil(ptr unsafe.Pointer)
|
|
|
|
|
+ Cap(obj interface{}) int
|
|
|
|
|
+ UnsafeCap(ptr unsafe.Pointer) int
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type StructType interface {
|
|
|
|
|
+ Type
|
|
|
|
|
+ NumField() int
|
|
|
|
|
+ Field(i int) StructField
|
|
|
|
|
+ FieldByName(name string) StructField
|
|
|
|
|
+ FieldByIndex(index []int) StructField
|
|
|
|
|
+ FieldByNameFunc(match func(string) bool) StructField
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type StructField interface {
|
|
|
|
|
+ Offset() uintptr
|
|
|
|
|
+ Name() string
|
|
|
|
|
+ PkgPath() string
|
|
|
|
|
+ Type() Type
|
|
|
|
|
+ Tag() reflect.StructTag
|
|
|
|
|
+ Index() []int
|
|
|
|
|
+ Anonymous() bool
|
|
|
|
|
+ Set(obj interface{}, value interface{})
|
|
|
|
|
+ UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer)
|
|
|
|
|
+ Get(obj interface{}) interface{}
|
|
|
|
|
+ UnsafeGet(obj unsafe.Pointer) unsafe.Pointer
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type MapType interface {
|
|
|
|
|
+ Type
|
|
|
|
|
+ Key() Type
|
|
|
|
|
+ Elem() Type
|
|
|
|
|
+ MakeMap(cap int) interface{}
|
|
|
|
|
+ UnsafeMakeMap(cap int) unsafe.Pointer
|
|
|
|
|
+ SetIndex(obj interface{}, key interface{}, elem interface{})
|
|
|
|
|
+ UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer)
|
|
|
|
|
+ TryGetIndex(obj interface{}, key interface{}) (interface{}, bool)
|
|
|
|
|
+ GetIndex(obj interface{}, key interface{}) interface{}
|
|
|
|
|
+ UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
|
|
|
|
|
+ Iterate(obj interface{}) MapIterator
|
|
|
|
|
+ UnsafeIterate(obj unsafe.Pointer) MapIterator
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type MapIterator interface {
|
|
|
|
|
+ HasNext() bool
|
|
|
|
|
+ Next() (key interface{}, elem interface{})
|
|
|
|
|
+ UnsafeNext() (key unsafe.Pointer, elem unsafe.Pointer)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type PtrType interface {
|
|
|
|
|
+ Type
|
|
|
|
|
+ Elem() Type
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type InterfaceType interface {
|
|
|
|
|
+ NumMethod() int
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type Config struct {
|
|
|
|
|
+ UseSafeImplementation bool
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type API interface {
|
|
|
|
|
+ TypeOf(obj interface{}) Type
|
|
|
|
|
+ Type2(type1 reflect.Type) Type
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+var ConfigUnsafe = Config{UseSafeImplementation: false}.Froze()
|
|
|
|
|
+var ConfigSafe = Config{UseSafeImplementation: true}.Froze()
|
|
|
|
|
+
|
|
|
|
|
+type frozenConfig struct {
|
|
|
|
|
+ useSafeImplementation bool
|
|
|
|
|
+ cache *concurrent.Map
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (cfg Config) Froze() *frozenConfig {
|
|
|
|
|
+ return &frozenConfig{
|
|
|
|
|
+ useSafeImplementation: cfg.UseSafeImplementation,
|
|
|
|
|
+ cache: concurrent.NewMap(),
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (cfg *frozenConfig) TypeOf(obj interface{}) Type {
|
|
|
|
|
+ cacheKey := uintptr(unpackEFace(obj).rtype)
|
|
|
|
|
+ typeObj, found := cfg.cache.Load(cacheKey)
|
|
|
|
|
+ if found {
|
|
|
|
|
+ return typeObj.(Type)
|
|
|
|
|
+ }
|
|
|
|
|
+ return cfg.Type2(reflect.TypeOf(obj))
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (cfg *frozenConfig) Type2(type1 reflect.Type) Type {
|
|
|
|
|
+ cacheKey := uintptr(unpackEFace(type1).data)
|
|
|
|
|
+ typeObj, found := cfg.cache.Load(cacheKey)
|
|
|
|
|
+ if found {
|
|
|
|
|
+ return typeObj.(Type)
|
|
|
|
|
+ }
|
|
|
|
|
+ type2 := cfg.wrapType(type1)
|
|
|
|
|
+ cfg.cache.Store(cacheKey, type2)
|
|
|
|
|
+ return type2
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (cfg *frozenConfig) wrapType(type1 reflect.Type) Type {
|
|
|
|
|
+ safeType := safeType{Type: type1, cfg: cfg}
|
|
|
|
|
+ switch type1.Kind() {
|
|
|
|
|
+ case reflect.Struct:
|
|
|
|
|
+ if cfg.useSafeImplementation {
|
|
|
|
|
+ return &safeStructType{safeType}
|
|
|
|
|
+ }
|
|
|
|
|
+ return newUnsafeStructType(cfg, type1)
|
|
|
|
|
+ case reflect.Array:
|
|
|
|
|
+ if cfg.useSafeImplementation {
|
|
|
|
|
+ return &safeSliceType{safeType}
|
|
|
|
|
+ }
|
|
|
|
|
+ return newUnsafeArrayType(cfg, type1)
|
|
|
|
|
+ case reflect.Slice:
|
|
|
|
|
+ if cfg.useSafeImplementation {
|
|
|
|
|
+ return &safeSliceType{safeType}
|
|
|
|
|
+ }
|
|
|
|
|
+ return newUnsafeSliceType(cfg, type1)
|
|
|
|
|
+ case reflect.Map:
|
|
|
|
|
+ if cfg.useSafeImplementation {
|
|
|
|
|
+ return &safeMapType{safeType}
|
|
|
|
|
+ }
|
|
|
|
|
+ return newUnsafeMapType(cfg, type1)
|
|
|
|
|
+ case reflect.Ptr, reflect.Chan, reflect.Func:
|
|
|
|
|
+ if cfg.useSafeImplementation {
|
|
|
|
|
+ return &safeMapType{safeType}
|
|
|
|
|
+ }
|
|
|
|
|
+ return newUnsafePtrType(cfg, type1)
|
|
|
|
|
+ case reflect.Interface:
|
|
|
|
|
+ if cfg.useSafeImplementation {
|
|
|
|
|
+ return &safeMapType{safeType}
|
|
|
|
|
+ }
|
|
|
|
|
+ if type1.NumMethod() == 0 {
|
|
|
|
|
+ return newUnsafeEFaceType(cfg, type1)
|
|
|
|
|
+ }
|
|
|
|
|
+ return newUnsafeIFaceType(cfg, type1)
|
|
|
|
|
+ default:
|
|
|
|
|
+ if cfg.useSafeImplementation {
|
|
|
|
|
+ return &safeType
|
|
|
|
|
+ }
|
|
|
|
|
+ return newUnsafeType(cfg, type1)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func TypeOf(obj interface{}) Type {
|
|
|
|
|
+ return ConfigUnsafe.TypeOf(obj)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func TypeOfPtr(obj interface{}) PtrType {
|
|
|
|
|
+ return TypeOf(obj).(PtrType)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func Type2(type1 reflect.Type) Type {
|
|
|
|
|
+ return ConfigUnsafe.Type2(type1)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func PtrTo(typ Type) Type {
|
|
|
|
|
+ return Type2(reflect.PtrTo(typ.Type1()))
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func PtrOf(obj interface{}) unsafe.Pointer {
|
|
|
|
|
+ return unpackEFace(obj).data
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func RTypeOf(obj interface{}) uintptr {
|
|
|
|
|
+ return uintptr(unpackEFace(obj).rtype)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func IsNil(obj interface{}) bool {
|
|
|
|
|
+ if obj == nil {
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ return unpackEFace(obj).data == nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func IsNullable(kind reflect.Kind) bool {
|
|
|
|
|
+ switch kind {
|
|
|
|
|
+ case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func, reflect.Slice, reflect.Interface:
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ return false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func likePtrKind(kind reflect.Kind) bool {
|
|
|
|
|
+ switch kind {
|
|
|
|
|
+ case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func:
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ return false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func likePtrType(typ reflect.Type) bool {
|
|
|
|
|
+ if likePtrKind(typ.Kind()) {
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ if typ.Kind() == reflect.Struct {
|
|
|
|
|
+ if typ.NumField() != 1 {
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ return likePtrType(typ.Field(0).Type)
|
|
|
|
|
+ }
|
|
|
|
|
+ if typ.Kind() == reflect.Array {
|
|
|
|
|
+ if typ.Len() != 1 {
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ return likePtrType(typ.Elem())
|
|
|
|
|
+ }
|
|
|
|
|
+ return false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// NoEscape hides a pointer from escape analysis. noescape is
|
|
|
|
|
+// the identity function but escape analysis doesn't think the
|
|
|
|
|
+// output depends on the input. noescape is inlined and currently
|
|
|
|
|
+// compiles down to zero instructions.
|
|
|
|
|
+// USE CAREFULLY!
|
|
|
|
|
+//go:nosplit
|
|
|
|
|
+func NoEscape(p unsafe.Pointer) unsafe.Pointer {
|
|
|
|
|
+ x := uintptr(p)
|
|
|
|
|
+ return unsafe.Pointer(x ^ 0)
|
|
|
|
|
+}
|