mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
298 lines
7.1 KiB
298 lines
7.1 KiB
package reflect2 |
|
|
|
import ( |
|
"github.com/modern-go/concurrent" |
|
"reflect" |
|
"unsafe" |
|
) |
|
|
|
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 { |
|
if type1 == nil { |
|
return nil |
|
} |
|
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 { |
|
if type1 == nil { |
|
return nil |
|
} |
|
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) |
|
} |
|
|
|
func UnsafeCastString(str string) []byte { |
|
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&str)) |
|
sliceHeader := &reflect.SliceHeader{ |
|
Data: stringHeader.Data, |
|
Cap: stringHeader.Len, |
|
Len: stringHeader.Len, |
|
} |
|
return *(*[]byte)(unsafe.Pointer(sliceHeader)) |
|
}
|
|
|