xunsafe

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2021 License: Apache-2.0 Imports: 4 Imported by: 58

README

xunsafe (faster golang reflection)

GoReportCard GoDoc

This library is compatible with Go 1.13+

Please refer to CHANGELOG.md if you encounter breaking changes.

Motivation

In order to solve a problem that can work with any golang type, one has no choice but to use reflection. Native golang reflection comes with hefty performance price, on benchmarking simple getter/setter case to manipulate struct dynamically I've seen around 100 time worst performance comparing to statically typed code. I believe that, native reflect package could be easily implemented way better to provide optimized performance. This library comes with reflection implementation that greatly improved performance, that is 50x time faster than native golang reflection. What that means that extra overhead of using reflection is only around twice comparing to statically typed code.

Introduction

In order to achieve better performance, this library uses unsafe.Pointer along with StructField.Offset to effectively access/modify struct fields.

Usage

Accessor/Mutator
func Example_FastReflection() {
    
    type Foo struct {
        ID int
        Name string
    }
    fooType := reflect.TypeOf(Foo{})

    fooID := xunsafe.FieldByName(fooType, "ID")
    fooName := xunsafe.FieldByName(fooType, "Name")

    var foos = make([]Foo, 100)
    for i := range foos {
        fooAddr := xunsafe.Addr(&foos[i])
        fooID.SetInt(fooAddr, i)
        fooName.SetString(fooAddr, fmt.Sprintf("name %d", i))
    }

    for i := range foos {
        fooAddr := unsafe.Pointer(&foos[i])
        fmt.Printf("[%v] ID: %v, Name: %v\n", i, fooID.Int(fooAddr), fooName.String(fooAddr))
    }
}
Field Address

Field Addr returns an interface{} wrapping actual field pointer

func ExampleAddr() {
	type Foo struct {
		ID int
		Name string
	}
	fooType := reflect.TypeOf(Foo{})
	fooID := xunsafe.FieldByName(fooType, "ID")
	foo := &Foo{ID: 101, Name: "name 101"}

	fooAddr := unsafe.Pointer(foo)
	*(fooID.Addr(fooAddr).(*int)) = 201
	fmt.Printf("foo.ID: %v\n", foo.ID)//prints 201
}
Field Value

Field Value returns an interface{} wrapping actual field value

func ExampleAddr() {
	type Foo struct {
		ID int
		Name string
	}
	fooType := reflect.TypeOf(Foo{})
	fooID := xunsafe.FieldByName(fooType, "ID")
	foo := &Foo{ID: 101, Name: "name 101"}

    fooAddr := unsafe.Pointer(foo)
	fmt.Printf("foo.ID: %v\n", fooID.Value(fooAddr))//prints 101
}

For base golang type Field Addr and Value got optimized with casting unsafe address to actual corresponding type. For example for filed with int type, the casting come in form (*int)(unsafe.Pointer(structAddr + field.Offset)) in other cases reflect.NewAt(field.Type, unsafe.Pointer(structAddr + field.Offset) is used.

Unsafe struct casting registry

Given that reflect.NewAt is quite slow, you can register custom unsafe type casting bypassing reflect.NewAt all together

    xunsafe.Register(reflect.TypeOf(time.Time{}), func(addr unsafe.Pointer) interface{} {
		return (*time.Time)(addr)
	})
    xunsafe.Register(reflect.TypeOf(&time.Time{}), func(addr unsafe.Pointer) interface{} {
		return (**time.Time)(addr)
	})

Benchmark

Accessor/Mutator benchmark

goos: darwin
goarch: amd64
pkg: github.com/viant/xunsafe
cpu: Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
BenchmarkField_Accessor_Native-16         	890931754	          1.235 ns/op	       0 B/op	       0 allocs/op
BenchmarkField_Accessor_Fast-16           	558196452	          2.217 ns/op	       0 B/op	       0 allocs/op
BenchmarkField_Accessor_Reflect-16        	 8435084	          134.9 ns/op	      56 B/op	       4 allocs/op
BenchmarkField_Accessor_PtrFast-16        	94770246	          12.95 ns/op	       0 B/op	       0 allocs/op
BenchmarkField_Accessor_Reflect_Ptr-16    	17914276	          68.10 ns/op	       0 B/op	       0 allocs/op
BenchmarkField_Mutator_Native-16          	1000000000	         0.9271 ns/op	       0 B/op	       0 allocs/op
Benchmark_Mutator_Fast-16                 	879740266	          1.333 ns/op	       0 B/op	       0 allocs/op
Benchmark_Mutator_Fast_Ptr-16             	100000000	          10.05 ns/op	       0 B/op	       0 allocs/op
BenchmarkField_Mutator_Reflect-16         	11812810	          99.02 ns/op	      32 B/op	       3 allocs/op
BenchmarkField_Mutator_Reflect_Ptr-16     	22566876	          54.51 ns/op	       0 B/op	       0 allocs/op
  • 'Native' suffix represent statically typed code
  • 'Fast' suffix represent reflection implemented by this library
  • 'Reflect' suffix represent implementation with golang native reflect package

License

The source code is made available under the terms of the Apache License, Version 2, as stated in the file LICENSE.

Individual files may be made available under their own specific license, all compatible with Apache License, Version 2. Please see individual files for details.

Credits and Acknowledgements

Library Author: Adrian Witas

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Addr

func Addr(src interface{}) unsafe.Pointer

Addr returns src unsafe addr

Example
package main

import (
	"fmt"
	"github.com/viant/xunsafe"
	"reflect"
)

func main() {
	type Foo struct {
		ID   int
		Name string
	}
	fooType := reflect.TypeOf(Foo{})
	fooID := xunsafe.FieldByName(fooType, "ID")
	foo := &Foo{ID: 101, Name: "name 101"}

	fooAddr := xunsafe.Addr(foo)
	*(fooID.Addr(fooAddr).(*int)) = 201
	fmt.Printf("foo.ID: %v\n", foo.ID) //prints 201
}
Output:

func Register

func Register(aType reflect.Type, getter Getter)

Register register custom type with pointer getter

Types

type Field

type Field struct {
	Field *Field
	// contains filtered or unexported fields
}

Field represent a field

func FieldByIndex

func FieldByIndex(structType reflect.Type, index int) *Field

FieldByIndex creates a field for supplied struct type and field index

func FieldByName

func FieldByName(structType reflect.Type, name string) *Field

FieldByName creates a field for supplied struct type and field name

func FieldWithGetters

func FieldWithGetters(address, value Getter) *Field

FieldWithGetters creates a field supplied custom address, value getter

func NewField

func NewField(field reflect.StructField) *Field

NewField creates a new filed

func (*Field) Addr

func (f *Field) Addr(structAddr unsafe.Pointer) interface{}

Addr returns a field addr getter or error

func (*Field) AddrGetter

func (f *Field) AddrGetter() Getter

AddrGetter creates a Getter function returning filed pointer or error

func (*Field) Bool

func (f *Field) Bool(structAddr unsafe.Pointer) bool

Bool returns field bool

func (*Field) BoolAddr

func (f *Field) BoolAddr(structAddr unsafe.Pointer) *bool

BoolAddr returns field *bool addr

func (*Field) BoolPtr

func (f *Field) BoolPtr(structAddr unsafe.Pointer) *bool

BoolPtr returns field *bool

func (*Field) Bytes

func (f *Field) Bytes(structAddr unsafe.Pointer) []byte

Bytes returns field []byte

func (*Field) BytesAddr

func (f *Field) BytesAddr(structAddr unsafe.Pointer) *[]byte

BytesAddr returns field *[]byte addr

func (*Field) BytesPtr

func (f *Field) BytesPtr(structAddr unsafe.Pointer) *[]byte

BytesPtr returns field *[]byte

func (*Field) Float32

func (f *Field) Float32(structAddr unsafe.Pointer) float32

Float32 returns field float32

func (*Field) Float32Addr

func (f *Field) Float32Addr(structAddr unsafe.Pointer) *float32

Float32Addr returns field *float32 addr

func (*Field) Float32Ptr

func (f *Field) Float32Ptr(structAddr unsafe.Pointer) *float32

Float32Ptr returns field *float32

func (*Field) Float64

func (f *Field) Float64(structAddr unsafe.Pointer) float64

Float64 returns field float64

func (*Field) Float64Addr

func (f *Field) Float64Addr(structAddr unsafe.Pointer) *float64

Float64Addr returns field *float64 addr

func (*Field) Float64Ptr

func (f *Field) Float64Ptr(structAddr unsafe.Pointer) *float64

Float64Ptr returns field *float64

func (*Field) Int

func (f *Field) Int(structAddr unsafe.Pointer) int

Int returns field int

func (*Field) Int16

func (f *Field) Int16(structAddr unsafe.Pointer) int16

Int16 returns field int16

func (*Field) Int16Addr

func (f *Field) Int16Addr(structAddr unsafe.Pointer) *int16

Int16Addr returns field *int16 addr

func (*Field) Int16Ptr

func (f *Field) Int16Ptr(structAddr unsafe.Pointer) *int16

Int16Ptr returns field *int16

func (*Field) Int32

func (f *Field) Int32(structAddr unsafe.Pointer) int32

Int32 returns field int32

func (*Field) Int32Addr

func (f *Field) Int32Addr(structAddr unsafe.Pointer) *int32

Int32Addr returns field *int32 addr

func (*Field) Int32Ptr

func (f *Field) Int32Ptr(structAddr unsafe.Pointer) *int32

Int32Ptr returns field *int32

func (*Field) Int64

func (f *Field) Int64(structAddr unsafe.Pointer) int64

Int64 returns field int64

func (*Field) Int64Addr

func (f *Field) Int64Addr(structAddr unsafe.Pointer) *int64

Int64Addr returns field *int64 addr

func (*Field) Int64Ptr

func (f *Field) Int64Ptr(structAddr unsafe.Pointer) *int64

Int64Ptr returns field *int64

func (*Field) Int8

func (f *Field) Int8(structAddr unsafe.Pointer) int8

Int8 returns field int8

func (*Field) Int8Addr

func (f *Field) Int8Addr(structAddr unsafe.Pointer) *int8

Int8Addr returns field *int8 addr

func (*Field) Int8Ptr

func (f *Field) Int8Ptr(structAddr unsafe.Pointer) *int8

Int8Ptr returns field *int8

func (*Field) IntAddr

func (f *Field) IntAddr(structAddr unsafe.Pointer) *int

IntAddr returns field *int address

func (*Field) IntPtr

func (f *Field) IntPtr(structAddr unsafe.Pointer) *int

IntPtr returns field *int

func (*Field) Interface

func (f *Field) Interface(structAddr unsafe.Pointer) interface{}

Interface returns field address

func (*Field) SetBool

func (f *Field) SetBool(structAddr unsafe.Pointer, val bool)

SetBool sets field bool

func (*Field) SetBoolPtr

func (f *Field) SetBoolPtr(structAddr unsafe.Pointer, val *bool)

SetBoolPtr sets field *bool

func (*Field) SetBytes

func (f *Field) SetBytes(structAddr unsafe.Pointer, val []byte)

SetBytes sets field []byte

func (*Field) SetBytesPtr

func (f *Field) SetBytesPtr(structAddr unsafe.Pointer, val *[]byte)

SetBytesPtr sets field *[]byte

func (*Field) SetFloat32

func (f *Field) SetFloat32(structAddr unsafe.Pointer, val float32)

SetFloat32 sets field float32

func (*Field) SetFloat32Ptr

func (f *Field) SetFloat32Ptr(structAddr unsafe.Pointer, val *float32)

SetFloat32Ptr sets field *float32

func (*Field) SetFloat64

func (f *Field) SetFloat64(structAddr unsafe.Pointer, val float64)

SetFloat64 sets field float64

func (*Field) SetFloat64Ptr

func (f *Field) SetFloat64Ptr(structAddr unsafe.Pointer, val *float64)

SetFloat64Ptr sets field *float64

func (*Field) SetInt

func (f *Field) SetInt(structAddr unsafe.Pointer, val int)

SetInt sets field int

func (*Field) SetInt16

func (f *Field) SetInt16(structAddr unsafe.Pointer, val int16)

SetInt16 sets field int

func (*Field) SetInt16Ptr

func (f *Field) SetInt16Ptr(structAddr unsafe.Pointer, val *int16)

SetInt16Ptr sets field *int

func (*Field) SetInt32

func (f *Field) SetInt32(structAddr unsafe.Pointer, val int32)

SetInt32 sets field int

func (*Field) SetInt32Ptr

func (f *Field) SetInt32Ptr(structAddr unsafe.Pointer, val *int32)

SetInt32Ptr sets field *int

func (*Field) SetInt64

func (f *Field) SetInt64(structAddr unsafe.Pointer, val int64)

SetInt64 sets field int

func (*Field) SetInt64Ptr

func (f *Field) SetInt64Ptr(structAddr unsafe.Pointer, val *int64)

SetInt64Ptr sets field *int

func (*Field) SetInt8

func (f *Field) SetInt8(structAddr unsafe.Pointer, val int8)

SetInt8 sets field int

func (*Field) SetInt8Ptr

func (f *Field) SetInt8Ptr(structAddr unsafe.Pointer, val *int8)

SetInt8Ptr sets field *int

func (*Field) SetIntPtr

func (f *Field) SetIntPtr(structAddr unsafe.Pointer, val *int)

SetIntPtr sets field *int

func (*Field) SetInterface

func (f *Field) SetInterface(structAddr unsafe.Pointer, val interface{})

SetInterface set field interface{}

func (*Field) SetString

func (f *Field) SetString(structAddr unsafe.Pointer, val string)

SetString sets field string

func (*Field) SetStringPtr

func (f *Field) SetStringPtr(structAddr unsafe.Pointer, val *string)

SetStringPtr sets field *string

func (*Field) SetTime

func (f *Field) SetTime(structAddr unsafe.Pointer, val time.Time)

SetTime sets field time.Time

func (*Field) SetTimePtr

func (f *Field) SetTimePtr(structAddr unsafe.Pointer, val *time.Time)

SetTimePtr sets field *time.Time

func (*Field) SetUint

func (f *Field) SetUint(structAddr unsafe.Pointer, val uint)

SetUint sets field uint

func (*Field) SetUint16

func (f *Field) SetUint16(structAddr unsafe.Pointer, val uint16)

SetUint16 sets field uint

func (*Field) SetUint16Ptr

func (f *Field) SetUint16Ptr(structAddr unsafe.Pointer, val *uint16)

SetUint16Ptr sets field *uint

func (*Field) SetUint32

func (f *Field) SetUint32(structAddr unsafe.Pointer, val uint32)

SetUint32 sets field uint

func (*Field) SetUint32Ptr

func (f *Field) SetUint32Ptr(structAddr unsafe.Pointer, val *uint32)

SetUint32Ptr sets field *uint

func (*Field) SetUint64

func (f *Field) SetUint64(structAddr unsafe.Pointer, val uint64)

SetUint64 sets field uint

func (*Field) SetUint64Ptr

func (f *Field) SetUint64Ptr(structAddr unsafe.Pointer, val *uint64)

SetUint64Ptr sets field *uint

func (*Field) SetUint8

func (f *Field) SetUint8(structAddr unsafe.Pointer, val uint8)

SetUint8 sets field uint

func (*Field) SetUint8Ptr

func (f *Field) SetUint8Ptr(structAddr unsafe.Pointer, val *uint8)

SetUint8Ptr sets field *uint

func (*Field) SetUintPtr

func (f *Field) SetUintPtr(structAddr unsafe.Pointer, val *uint)

SetUintPtr sets field *uint

func (*Field) SetValue

func (f *Field) SetValue(structAddr unsafe.Pointer, val interface{})

SetValue sets value

func (*Field) String

func (f *Field) String(structAddr unsafe.Pointer) string

String returns field string

func (*Field) StringAddr

func (f *Field) StringAddr(structAddr unsafe.Pointer) *string

StringAddr returns field *string addr

func (*Field) StringPtr

func (f *Field) StringPtr(structAddr unsafe.Pointer) *string

StringPtr returns field *string

func (*Field) Time

func (f *Field) Time(structAddr unsafe.Pointer) time.Time

Time returns field time.Time

func (*Field) TimeAddr

func (f *Field) TimeAddr(structAddr unsafe.Pointer) *time.Time

TimeAddr returns field *time.Time addr

func (*Field) TimePtr

func (f *Field) TimePtr(structAddr unsafe.Pointer) *time.Time

TimePtr returns field *time.Time

func (*Field) Uint

func (f *Field) Uint(structAddr unsafe.Pointer) uint

Uint returns field uint

func (*Field) Uint16

func (f *Field) Uint16(structAddr unsafe.Pointer) uint16

Uint16 returns field uint16

func (*Field) Uint16Addr

func (f *Field) Uint16Addr(structAddr unsafe.Pointer) *uint16

Uint16Addr returns field *uint16 addr

func (*Field) Uint16Ptr

func (f *Field) Uint16Ptr(structAddr unsafe.Pointer) *uint16

Uint16Ptr returns field *uint16

func (*Field) Uint32

func (f *Field) Uint32(structAddr unsafe.Pointer) uint32

Uint32 returns field uint32

func (*Field) Uint32Addr

func (f *Field) Uint32Addr(structAddr unsafe.Pointer) *uint32

Uint32Addr returns field *uint32 addr

func (*Field) Uint32Ptr

func (f *Field) Uint32Ptr(structAddr unsafe.Pointer) *uint32

Uint32Ptr returns field *uint32

func (*Field) Uint64

func (f *Field) Uint64(structAddr unsafe.Pointer) uint64

Uint64 returns field uint64

func (*Field) Uint64Addr

func (f *Field) Uint64Addr(structAddr unsafe.Pointer) *uint64

Uint64Addr returns field *uint64 addr

func (*Field) Uint64Ptr

func (f *Field) Uint64Ptr(structAddr unsafe.Pointer) *uint64

Uint64Ptr returns field *uint64

func (*Field) Uint8

func (f *Field) Uint8(structAddr unsafe.Pointer) uint8

Uint8 returns field uint8

func (*Field) Uint8Addr

func (f *Field) Uint8Addr(structAddr unsafe.Pointer) *uint8

Uint8Addr returns field *uint8 addr

func (*Field) Uint8Ptr

func (f *Field) Uint8Ptr(structAddr unsafe.Pointer) *uint8

Uint8Ptr returns field *uint8

func (*Field) UintAddr

func (f *Field) UintAddr(structAddr unsafe.Pointer) *uint

UintAddr returns field *uint address

func (*Field) UintPtr

func (f *Field) UintPtr(structAddr unsafe.Pointer) *uint

UintPtr returns field *uint

func (*Field) Value

func (f *Field) Value(structAddr unsafe.Pointer) interface{}

Value returns a value getter or error

type Getter

type Getter func(structAdd unsafe.Pointer) interface{}

Getter represents a func returning field value pointer, it takes holder address

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL