From 855e12df51906acefd49ebc44587926e4cae25ec Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Sat, 18 Mar 2023 22:57:47 -0700 Subject: [PATCH] reflect: Convert(): add Float() conversions --- src/reflect/value.go | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/reflect/value.go b/src/reflect/value.go index 76ad7718..2c238efd 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -330,6 +330,27 @@ func (v Value) Uint() uint64 { } } +func (v Value) Float32() float32 { + switch v.Kind() { + case Float32: + if v.isIndirect() || unsafe.Sizeof(float32(0)) > unsafe.Sizeof(uintptr(0)) { + // The float is stored as an external value on systems with 16-bit + // pointers. + return *(*float32)(v.value) + } else { + // The float is directly stored in the interface value on systems + // with 32-bit and 64-bit pointers. + return *(*float32)(unsafe.Pointer(&v.value)) + } + + case Float64: + return float32(v.Float()) + + } + + panic(&ValueError{Method: "Float", Kind: v.Kind()}) +} + func (v Value) Float() float64 { switch v.Kind() { case Float32: @@ -1103,6 +1124,24 @@ func convertOp(src Value, typ Type) (Value, bool) { return cvtUintString(src, rtype), true } + case Float32, Float64: + switch rtype := typ.(*rawType); rtype.Kind() { + case Int, Int8, Int16, Int32, Int64: + return cvtFloatInt(src, rtype), true + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return cvtFloatUint(src, rtype), true + case Float32, Float64: + return cvtFloat(src, rtype), true + } + + /* + case Complex64, Complex128: + switch src.Kind() { + case Complex64, Complex128: + return cvtComplex + } + */ + case Slice: if typ.Kind() == String && !src.typecode.elem().isNamed() { rtype := typ.(*rawType) @@ -1149,6 +1188,24 @@ func cvtUintFloat(v Value, t *rawType) Value { return makeFloat(v.flags, float64(v.Uint()), t) } +func cvtFloatInt(v Value, t *rawType) Value { + return makeInt(v.flags, uint64(int64(v.Float())), t) +} + +func cvtFloatUint(v Value, t *rawType) Value { + return makeInt(v.flags, uint64(v.Float()), t) +} + +func cvtFloat(v Value, t *rawType) Value { + if v.Type().Kind() == Float32 && t.Kind() == Float32 { + // Don't do any conversion if both types have underlying type float32. + // This avoids converting to float64 and back, which will + // convert a signaling NaN to a quiet NaN. See issue 36400. + return makeFloat32(v.flags, v.Float32(), t) + } + return makeFloat(v.flags, v.Float(), t) +} + //go:linkname stringToBytes runtime.stringToBytesTyped func stringToBytes(x string) []byte @@ -1209,6 +1266,17 @@ func makeFloat(flags valueFlags, v float64, t *rawType) Value { } } +func makeFloat32(flags valueFlags, v float32, t *rawType) Value { + size := t.Size() + ptr := alloc(size, nil) + *(*float32)(ptr) = float32(v) + return Value{ + typecode: t, + value: ptr, + flags: flags | valueFlagIndirect, + } +} + func cvtIntString(src Value, t *rawType) Value { panic("cvtUintString: unimplemented") }