From 003211b4ff05408c2deda70a5aeb2e825089333e Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sun, 20 Jan 2019 21:16:52 +0100 Subject: [PATCH] reflect: implement Value.Set*() for basic types --- src/reflect/type.go | 3 +- src/reflect/value.go | 290 ++++++++++++++++++++++++++++++++----------- testdata/reflect.go | 144 +++++++++++++++++++-- testdata/reflect.txt | 65 ++++++++-- 4 files changed, 409 insertions(+), 93 deletions(-) diff --git a/src/reflect/type.go b/src/reflect/type.go index d21151df..a75aabde 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -199,8 +199,7 @@ func (t Type) Size() uintptr { case Slice: return unsafe.Sizeof(SliceHeader{}) default: - // Size unknown. - return 0 + panic("unimplemented: size of type") } } diff --git a/src/reflect/value.go b/src/reflect/value.go index 8d8d59c9..9f0633d9 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -4,22 +4,42 @@ import ( "unsafe" ) -// This is the same thing as an interface{}. type Value struct { typecode Type value unsafe.Pointer + indirect bool } func Indirect(v Value) Value { - return v + if v.Kind() != Ptr { + return v + } + return v.Elem() } func ValueOf(i interface{}) Value { - return *(*Value)(unsafe.Pointer(&i)) + v := (*interfaceHeader)(unsafe.Pointer(&i)) + return Value{ + typecode: v.typecode, + value: v.value, + } } func (v Value) Interface() interface{} { - return *(*interface{})(unsafe.Pointer(&v)) + i := interfaceHeader{ + typecode: v.typecode, + value: v.value, + } + if v.indirect && v.Type().Size() <= unsafe.Sizeof(uintptr(0)) { + // Value was indirect but must be put back directly in the interface + // value. + var value uintptr + for j := v.Type().Size(); j != 0; j-- { + value = (value << 8) | uintptr(*(*uint8)(unsafe.Pointer(uintptr(v.value) + j - 1))) + } + i.value = unsafe.Pointer(value) + } + return *(*interface{})(unsafe.Pointer(&i)) } func (v Value) Type() Type { @@ -47,7 +67,11 @@ func (v Value) IsNil() bool { slice := (*SliceHeader)(v.value) return slice.Data == 0 case Interface: - panic("unimplemented: (reflect.Value).IsNil()") + if v.value == nil { + return true + } + itf := (*interfaceHeader)(v.value) + return itf.value == nil default: panic(&ValueError{"IsNil"}) } @@ -85,13 +109,17 @@ func (v Value) Addr() Value { } func (v Value) CanSet() bool { - panic("unimplemented: (reflect.Value).CanSet()") + return v.indirect } func (v Value) Bool() bool { switch v.Kind() { case Bool: - return uintptr(v.value) != 0 + if v.indirect { + return *((*bool)(v.value)) + } else { + return uintptr(v.value) != 0 + } default: panic(&ValueError{"Bool"}) } @@ -100,27 +128,34 @@ func (v Value) Bool() bool { func (v Value) Int() int64 { switch v.Kind() { case Int: - if unsafe.Sizeof(int(0)) <= unsafe.Sizeof(uintptr(0)) { - return int64(int(uintptr(v.value))) - } else { + if v.indirect || unsafe.Sizeof(int(0)) > unsafe.Sizeof(uintptr(0)) { return int64(*(*int)(v.value)) + } else { + return int64(int(uintptr(v.value))) } case Int8: - return int64(int8(uintptr(v.value))) - case Int16: - return int64(int16(uintptr(v.value))) - case Int32: - if unsafe.Sizeof(int32(0)) <= unsafe.Sizeof(uintptr(0)) { - return int64(int32(uintptr(v.value))) + if v.indirect { + return int64(*(*int8)(v.value)) } else { - return int64(*(*int32)(v.value)) + return int64(int8(uintptr(v.value))) } - return int64(uintptr(v.value)) - case Int64: - if unsafe.Sizeof(int64(0)) <= unsafe.Sizeof(uintptr(0)) { - return int64(uintptr(v.value)) + case Int16: + if v.indirect { + return int64(*(*int16)(v.value)) } else { - return *(*int64)(v.value) + return int64(int16(uintptr(v.value))) + } + case Int32: + if v.indirect || unsafe.Sizeof(int32(0)) > unsafe.Sizeof(uintptr(0)) { + return int64(*(*int32)(v.value)) + } else { + return int64(int32(uintptr(v.value))) + } + case Int64: + if v.indirect || unsafe.Sizeof(int64(0)) > unsafe.Sizeof(uintptr(0)) { + return int64(*(*int64)(v.value)) + } else { + return int64(int64(uintptr(v.value))) } default: panic(&ValueError{"Int"}) @@ -129,28 +164,41 @@ func (v Value) Int() int64 { func (v Value) Uint() uint64 { switch v.Kind() { - case Uintptr, Uint8, Uint16: - return uint64(uintptr(v.value)) - case Uint: - if unsafe.Sizeof(uint(0)) <= unsafe.Sizeof(uintptr(0)) { - return uint64(uintptr(v.value)) + case Uintptr: + if v.indirect { + return uint64(*(*uintptr)(v.value)) } else { - // For systems with 16-bit pointers. + return uint64(uintptr(v.value)) + } + case Uint8: + if v.indirect { + return uint64(*(*uint8)(v.value)) + } else { + return uint64(uintptr(v.value)) + } + case Uint16: + if v.indirect { + return uint64(*(*uint16)(v.value)) + } else { + return uint64(uintptr(v.value)) + } + case Uint: + if v.indirect || unsafe.Sizeof(uint(0)) > unsafe.Sizeof(uintptr(0)) { return uint64(*(*uint)(v.value)) + } else { + return uint64(uintptr(v.value)) } case Uint32: - if unsafe.Sizeof(uint32(0)) <= unsafe.Sizeof(uintptr(0)) { - return uint64(uintptr(v.value)) - } else { - // For systems with 16-bit pointers. + if v.indirect || unsafe.Sizeof(uint32(0)) > unsafe.Sizeof(uintptr(0)) { return uint64(*(*uint32)(v.value)) + } else { + return uint64(uintptr(v.value)) } case Uint64: - if unsafe.Sizeof(uint64(0)) <= unsafe.Sizeof(uintptr(0)) { - return uint64(uintptr(v.value)) + if v.indirect || unsafe.Sizeof(uint64(0)) > unsafe.Sizeof(uintptr(0)) { + return uint64(*(*uint64)(v.value)) } else { - // For systems with 16-bit or 32-bit pointers. - return *(*uint64)(v.value) + return uint64(uintptr(v.value)) } default: panic(&ValueError{"Uint"}) @@ -160,23 +208,23 @@ func (v Value) Uint() uint64 { func (v Value) Float() float64 { switch v.Kind() { case Float32: - if unsafe.Sizeof(float32(0)) <= unsafe.Sizeof(uintptr(0)) { - // The float is directly stored in the interface value on systems - // with 32-bit and 64-bit pointers. - return float64(*(*float32)(unsafe.Pointer(&v.value))) - } else { + if v.indirect || unsafe.Sizeof(float32(0)) > unsafe.Sizeof(uintptr(0)) { // The float is stored as an external value on systems with 16-bit // pointers. return float64(*(*float32)(v.value)) + } else { + // The float is directly stored in the interface value on systems + // with 32-bit and 64-bit pointers. + return float64(*(*float32)(unsafe.Pointer(&v.value))) } case Float64: - if unsafe.Sizeof(float64(0)) <= unsafe.Sizeof(uintptr(0)) { + if v.indirect || unsafe.Sizeof(float64(0)) > unsafe.Sizeof(uintptr(0)) { + // For systems with 16-bit and 32-bit pointers. + return *(*float64)(v.value) + } else { // The float is directly stored in the interface value on systems // with 64-bit pointers. return *(*float64)(unsafe.Pointer(&v.value)) - } else { - // For systems with 16-bit and 32-bit pointers. - return *(*float64)(v.value) } default: panic(&ValueError{"Float"}) @@ -186,14 +234,14 @@ func (v Value) Float() float64 { func (v Value) Complex() complex128 { switch v.Kind() { case Complex64: - if unsafe.Sizeof(complex64(0)) <= unsafe.Sizeof(uintptr(0)) { - // The complex number is directly stored in the interface value on - // systems with 64-bit pointers. - return complex128(*(*complex64)(unsafe.Pointer(&v.value))) - } else { + if v.indirect || unsafe.Sizeof(complex64(0)) > unsafe.Sizeof(uintptr(0)) { // The complex number is stored as an external value on systems with // 16-bit and 32-bit pointers. return complex128(*(*complex64)(v.value)) + } else { + // The complex number is directly stored in the interface value on + // systems with 64-bit pointers. + return complex128(*(*complex64)(unsafe.Pointer(&v.value))) } case Complex128: // This is a 128-bit value, which is always stored as an external value. @@ -252,7 +300,23 @@ func (v Value) NumField() int { } func (v Value) Elem() Value { - panic("unimplemented: (reflect.Value).Elem()") + switch v.Kind() { + case Ptr: + ptr := v.value + if v.indirect { + ptr = *(*unsafe.Pointer)(ptr) + } + if ptr == nil { + return Value{} + } + return Value{ + typecode: v.Type().Elem(), + value: ptr, + indirect: true, + } + default: // not implemented: Interface + panic(&ValueError{"Elem"}) + } } func (v Value) Field(i int) Value { @@ -269,21 +333,10 @@ func (v Value) Index(i int) Value { } elem := Value{ typecode: v.Type().Elem(), + indirect: true, } addr := uintptr(slice.Data) + elem.Type().Size() * uintptr(i) // pointer to new value - if elem.Type().Size() <= unsafe.Sizeof(uintptr(0)) { - // Value fits inside interface value. - // Make sure to copy it from the slice to the interface value. - var value uintptr - for j := elem.Type().Size(); j != 0; j-- { - value = (value << 8) | uintptr(*(*uint8)(unsafe.Pointer(addr + j - 1))) - } - elem.value = unsafe.Pointer(value) - } else { - // Value doesn't fit in the interface. - // Store a pointer to the element in the interface. - elem.value = unsafe.Pointer(addr) - } + elem.value = unsafe.Pointer(addr) return elem case String: // Extract a character from a string. @@ -313,31 +366,117 @@ func (v Value) MapIndex(key Value) Value { } func (v Value) Set(x Value) { - panic("unimplemented: (reflect.Value).Set()") + if !v.indirect { + panic("reflect: value is not addressable") + } + if v.Type() != x.Type() { + if v.Kind() == Interface { + panic("reflect: unimplemented: assigning to interface of different type") + } else { + panic("reflect: cannot assign") + } + } + size := v.Type().Size() + xptr := x.value + if size <= unsafe.Sizeof(uintptr(0)) && !x.indirect { + value := x.value + xptr = unsafe.Pointer(&value) + } + memcpy(v.value, xptr, size) } func (v Value) SetBool(x bool) { - panic("unimplemented: (reflect.Value).SetBool()") + if !v.indirect { + panic("reflect: value is not addressable") + } + switch v.Kind() { + case Bool: + *(*bool)(v.value) = x + default: + panic(&ValueError{"SetBool"}) + } } func (v Value) SetInt(x int64) { - panic("unimplemented: (reflect.Value).SetInt()") + if !v.indirect { + panic("reflect: value is not addressable") + } + switch v.Kind() { + case Int: + *(*int)(v.value) = int(x) + case Int8: + *(*int8)(v.value) = int8(x) + case Int16: + *(*int16)(v.value) = int16(x) + case Int32: + *(*int32)(v.value) = int32(x) + case Int64: + *(*int64)(v.value) = x + default: + panic(&ValueError{"SetInt"}) + } } func (v Value) SetUint(x uint64) { - panic("unimplemented: (reflect.Value).SetUint()") + if !v.indirect { + panic("reflect: value is not addressable") + } + switch v.Kind() { + case Uint: + *(*uint)(v.value) = uint(x) + case Uint8: + *(*uint8)(v.value) = uint8(x) + case Uint16: + *(*uint16)(v.value) = uint16(x) + case Uint32: + *(*uint32)(v.value) = uint32(x) + case Uint64: + *(*uint64)(v.value) = x + case Uintptr: + *(*uintptr)(v.value) = uintptr(x) + default: + panic(&ValueError{"SetUint"}) + } } func (v Value) SetFloat(x float64) { - panic("unimplemented: (reflect.Value).SetFloat()") + if !v.indirect { + panic("reflect: value is not addressable") + } + switch v.Kind() { + case Float32: + *(*float32)(v.value) = float32(x) + case Float64: + *(*float64)(v.value) = x + default: + panic(&ValueError{"SetFloat"}) + } } func (v Value) SetComplex(x complex128) { - panic("unimplemented: (reflect.Value).SetComplex()") + if !v.indirect { + panic("reflect: value is not addressable") + } + switch v.Kind() { + case Complex64: + *(*complex64)(v.value) = complex64(x) + case Complex128: + *(*complex128)(v.value) = x + default: + panic(&ValueError{"SetComplex"}) + } } func (v Value) SetString(x string) { - panic("unimplemented: (reflect.Value).SetString()") + if !v.indirect { + panic("reflect: value is not addressable") + } + switch v.Kind() { + case String: + *(*string)(v.value) = x + default: + panic(&ValueError{"SetString"}) + } } func MakeSlice(typ Type, len, cap int) Value { @@ -349,6 +488,12 @@ type funcHeader struct { Code unsafe.Pointer } +// This is the same thing as an interface{}. +type interfaceHeader struct { + typecode Type + value unsafe.Pointer +} + type SliceHeader struct { Data uintptr Len uintptr @@ -367,3 +512,6 @@ type ValueError struct { func (e *ValueError) Error() string { return "reflect: call of reflect.Value." + e.Method + " on invalid type" } + +//go:linkname memcpy runtime.memcpy +func memcpy(dst, src unsafe.Pointer, size uintptr) diff --git a/testdata/reflect.go b/testdata/reflect.go index e8ca8ef3..960d1c08 100644 --- a/testdata/reflect.go +++ b/testdata/reflect.go @@ -66,6 +66,10 @@ func main() { []string{"xyz", "Z"}, zeroSlice, []byte{}, + []float32{1, 1.32}, + []float64{1, 1.64}, + []complex64{1, 1.64 + 0.3i}, + []complex128{1, 1.128 + 0.4i}, // array [4]int{1, 2, 3, 4}, // functions @@ -78,7 +82,7 @@ func main() { struct{}{}, struct{ error }{}, } { - showValue(v, "") + showValue(reflect.ValueOf(v), "") } // test sizes @@ -98,24 +102,136 @@ func main() { assertSize(reflect.TypeOf(uintptr(0)).Size() == unsafe.Sizeof(uintptr(0)), "uintptr") assertSize(reflect.TypeOf("").Size() == unsafe.Sizeof(""), "string") assertSize(reflect.TypeOf(new(int)).Size() == unsafe.Sizeof(new(int)), "*int") + + // SetBool + rv := reflect.ValueOf(new(bool)).Elem() + rv.SetBool(true) + if rv.Bool() != true { + panic("could not set bool with SetBool()") + } + + // SetInt + for _, v := range []interface{}{ + new(int), + new(int8), + new(int16), + new(int32), + new(int64), + } { + rv := reflect.ValueOf(v).Elem() + rv.SetInt(99) + if rv.Int() != 99 { + panic("could not set integer with SetInt()") + } + } + + // SetUint + for _, v := range []interface{}{ + new(uint), + new(uint8), + new(uint16), + new(uint32), + new(uint64), + new(uintptr), + } { + rv := reflect.ValueOf(v).Elem() + rv.SetUint(99) + if rv.Uint() != 99 { + panic("could not set integer with SetUint()") + } + } + + // SetFloat + for _, v := range []interface{}{ + new(float32), + new(float64), + } { + rv := reflect.ValueOf(v).Elem() + rv.SetFloat(2.25) + if rv.Float() != 2.25 { + panic("could not set float with SetFloat()") + } + } + + // SetComplex + for _, v := range []interface{}{ + new(complex64), + new(complex128), + } { + rv := reflect.ValueOf(v).Elem() + rv.SetComplex(3 + 2i) + if rv.Complex() != 3+2i { + panic("could not set complex with SetComplex()") + } + } + + // SetString + rv = reflect.ValueOf(new(string)).Elem() + rv.SetString("foo") + if rv.String() != "foo" { + panic("could not set string with SetString()") + } + + // Set int + rv = reflect.ValueOf(new(int)).Elem() + rv.SetInt(33) + rv.Set(reflect.ValueOf(22)) + if rv.Int() != 22 { + panic("could not set int with Set()") + } + + // Set uint8 + rv = reflect.ValueOf(new(uint8)).Elem() + rv.SetUint(33) + rv.Set(reflect.ValueOf(uint8(22))) + if rv.Uint() != 22 { + panic("could not set uint8 with Set()") + } + + // Set string + rv = reflect.ValueOf(new(string)).Elem() + rv.SetString("foo") + rv.Set(reflect.ValueOf("bar")) + if rv.String() != "bar" { + panic("could not set string with Set()") + } + + // Set complex128 + rv = reflect.ValueOf(new(complex128)).Elem() + rv.SetComplex(3 + 2i) + rv.Set(reflect.ValueOf(4 + 8i)) + if rv.Complex() != 4+8i { + panic("could not set complex128 with Set()") + } + + // Set to slice + rv = reflect.ValueOf([]int{3, 5}) + rv.Index(1).SetInt(7) + if rv.Index(1).Int() != 7 { + panic("could not set int in slice") + } + rv.Index(1).Set(reflect.ValueOf(8)) + if rv.Index(1).Int() != 8 { + panic("could not set int in slice") + } + if rv.Len() != 2 || rv.Index(0).Int() != 3 { + panic("slice was changed while setting part of it") + } } func emptyFunc() { } -func showValue(v interface{}, indent string) { - rv := reflect.ValueOf(v) +func showValue(rv reflect.Value, indent string) { rt := rv.Type() - if reflect.TypeOf(v) != rt { - panic("direct TypeOf() is different from ValueOf().Type()") - } if rt.Kind() != rv.Kind() { panic("type kind is different from value kind") } - if reflect.ValueOf(rv.Interface()) != rv { - panic("reflect.ValueOf(Value.Interface()) did not return the same value") + print(indent+"reflect type: ", rt.Kind().String()) + if rv.CanSet() { + print(" settable=", rv.CanSet()) } - println(indent+"reflect type:", rt.Kind().String()) + println() switch rt.Kind() { case reflect.Bool: println(indent+" bool:", rv.Bool()) @@ -130,7 +246,7 @@ func showValue(v interface{}, indent string) { case reflect.String: println(indent+" string:", rv.String(), rv.Len()) for i := 0; i < rv.Len(); i++ { - showValue(rv.Index(i).Interface(), indent+" ") + showValue(rv.Index(i), indent+" ") } case reflect.UnsafePointer: println(indent+" pointer:", rv.Pointer() != 0) @@ -142,19 +258,25 @@ func showValue(v interface{}, indent string) { case reflect.Func: println(indent + " func") println(indent+" nil:", rv.IsNil()) + case reflect.Interface: + println(indent + " interface") + println(indent+" nil:", rv.IsNil()) case reflect.Map: println(indent + " map") println(indent+" nil:", rv.IsNil()) case reflect.Ptr: println(indent+" pointer:", rv.Pointer() != 0, rt.Elem().Kind().String()) println(indent+" nil:", rv.IsNil()) + if !rv.IsNil() { + showValue(rv.Elem(), indent+" ") + } case reflect.Slice: println(indent+" slice:", rt.Elem().Kind().String(), rv.Len(), rv.Cap()) println(indent+" pointer:", rv.Pointer() != 0) println(indent+" nil:", rv.IsNil()) for i := 0; i < rv.Len(); i++ { println(indent+" indexing:", i) - showValue(rv.Index(i).Interface(), indent+" ") + showValue(rv.Index(i), indent+" ") } case reflect.Struct: println(indent + " struct") diff --git a/testdata/reflect.txt b/testdata/reflect.txt index fdb46034..68ab529f 100644 --- a/testdata/reflect.txt +++ b/testdata/reflect.txt @@ -69,51 +69,58 @@ reflect type: chan reflect type: ptr pointer: true int nil: false + reflect type: int settable=true + int: 0 reflect type: ptr pointer: true interface nil: false + reflect type: interface settable=true + interface + nil: true reflect type: ptr pointer: true int nil: false + reflect type: int settable=true + int: 42 reflect type: slice slice: uint8 3 3 pointer: true nil: false indexing: 0 - reflect type: uint8 + reflect type: uint8 settable=true uint: 1 indexing: 1 - reflect type: uint8 + reflect type: uint8 settable=true uint: 2 indexing: 2 - reflect type: uint8 + reflect type: uint8 settable=true uint: 3 reflect type: slice slice: uint8 2 5 pointer: true nil: false indexing: 0 - reflect type: uint8 + reflect type: uint8 settable=true uint: 0 indexing: 1 - reflect type: uint8 + reflect type: uint8 settable=true uint: 0 reflect type: slice slice: int32 2 2 pointer: true nil: false indexing: 0 - reflect type: int32 + reflect type: int32 settable=true int: 3 indexing: 1 - reflect type: int32 + reflect type: int32 settable=true int: 5 reflect type: slice slice: string 2 2 pointer: true nil: false indexing: 0 - reflect type: string + reflect type: string settable=true string: xyz 3 reflect type: uint8 uint: 120 @@ -122,7 +129,7 @@ reflect type: slice reflect type: uint8 uint: 122 indexing: 1 - reflect type: string + reflect type: string settable=true string: Z 1 reflect type: uint8 uint: 90 @@ -134,6 +141,46 @@ reflect type: slice slice: uint8 0 0 pointer: true nil: false +reflect type: slice + slice: float32 2 2 + pointer: true + nil: false + indexing: 0 + reflect type: float32 settable=true + float: +1.000000e+000 + indexing: 1 + reflect type: float32 settable=true + float: +1.320000e+000 +reflect type: slice + slice: float64 2 2 + pointer: true + nil: false + indexing: 0 + reflect type: float64 settable=true + float: +1.000000e+000 + indexing: 1 + reflect type: float64 settable=true + float: +1.640000e+000 +reflect type: slice + slice: complex64 2 2 + pointer: true + nil: false + indexing: 0 + reflect type: complex64 settable=true + complex: (+1.000000e+000+0.000000e+000i) + indexing: 1 + reflect type: complex64 settable=true + complex: (+1.640000e+000+3.000000e-001i) +reflect type: slice + slice: complex128 2 2 + pointer: true + nil: false + indexing: 0 + reflect type: complex128 settable=true + complex: (+1.000000e+000+0.000000e+000i) + indexing: 1 + reflect type: complex128 settable=true + complex: (+1.128000e+000+4.000000e-001i) reflect type: array array reflect type: func