diff options
| author | Rob Pike <r@golang.org> | 2010-06-24 15:07:28 -0700 |
|---|---|---|
| committer | Rob Pike <r@golang.org> | 2010-06-24 15:07:28 -0700 |
| commit | c3a14037297827d36b77a49cf0cbd0849295e79a (patch) | |
| tree | 365bcb1ed0badd25b77e36df53af1f9b737212eb /src/pkg/gob/decode.go | |
| parent | 3b43d32ad60104619f13cf98f8724dedbfc6ce0a (diff) | |
| download | golang-c3a14037297827d36b77a49cf0cbd0849295e79a.tar.gz | |
gob: add support for complex numbers
R=rsc
CC=golang-dev
http://codereview.appspot.com/1708048
Diffstat (limited to 'src/pkg/gob/decode.go')
| -rw-r--r-- | src/pkg/gob/decode.go | 126 |
1 files changed, 84 insertions, 42 deletions
diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go index 8f5c383ea..0dbf81488 100644 --- a/src/pkg/gob/decode.go +++ b/src/pkg/gob/decode.go @@ -151,6 +151,11 @@ func ignoreUint(i *decInstr, state *decodeState, p unsafe.Pointer) { decodeUint(state) } +func ignoreTwoUints(i *decInstr, state *decodeState, p unsafe.Pointer) { + decodeUint(state) + decodeUint(state) +} + func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) { if i.indir > 0 { if *(*unsafe.Pointer)(p) == nil { @@ -286,25 +291,30 @@ func floatFromBits(u uint64) float64 { return math.Float64frombits(v) } -func decFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) { - if i.indir > 0 { - if *(*unsafe.Pointer)(p) == nil { - *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float32)) - } - p = *(*unsafe.Pointer)(p) - } +func storeFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) { v := floatFromBits(decodeUint(state)) av := v if av < 0 { av = -av } - if math.MaxFloat32 < av { // underflow is OK + // +Inf is OK in both 32- and 64-bit floats. Underflow is always OK. + if math.MaxFloat32 < av && av <= math.MaxFloat64 { state.err = i.ovfl } else { *(*float32)(p) = float32(v) } } +func decFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) { + if i.indir > 0 { + if *(*unsafe.Pointer)(p) == nil { + *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float32)) + } + p = *(*unsafe.Pointer)(p) + } + storeFloat32(i, state, p) +} + func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) { if i.indir > 0 { if *(*unsafe.Pointer)(p) == nil { @@ -315,6 +325,30 @@ func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) { *(*float64)(p) = floatFromBits(uint64(decodeUint(state))) } +// Complex numbers are just a pair of floating-point numbers, real part first. +func decComplex64(i *decInstr, state *decodeState, p unsafe.Pointer) { + if i.indir > 0 { + if *(*unsafe.Pointer)(p) == nil { + *(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex64)) + } + p = *(*unsafe.Pointer)(p) + } + storeFloat32(i, state, p) + storeFloat32(i, state, unsafe.Pointer(uintptr(p)+uintptr(unsafe.Sizeof(float(0))))) +} + +func decComplex128(i *decInstr, state *decodeState, p unsafe.Pointer) { + if i.indir > 0 { + if *(*unsafe.Pointer)(p) == nil { + *(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex128)) + } + p = *(*unsafe.Pointer)(p) + } + real := floatFromBits(uint64(decodeUint(state))) + imag := floatFromBits(uint64(decodeUint(state))) + *(*complex128)(p) = cmplx(real, imag) +} + // uint8 arrays are encoded as an unsigned count followed by the raw bytes. func decUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) { if i.indir > 0 { @@ -540,21 +574,25 @@ func ignoreSlice(state *decodeState, elemOp decOp) os.Error { return ignoreArrayHelper(state, elemOp, int(decodeUint(state))) } +// Index by Go types. var decOpMap = []decOp{ - reflect.Bool: decBool, - reflect.Int8: decInt8, - reflect.Int16: decInt16, - reflect.Int32: decInt32, - reflect.Int64: decInt64, - reflect.Uint8: decUint8, - reflect.Uint16: decUint16, - reflect.Uint32: decUint32, - reflect.Uint64: decUint64, - reflect.Float32: decFloat32, - reflect.Float64: decFloat64, - reflect.String: decString, -} - + reflect.Bool: decBool, + reflect.Int8: decInt8, + reflect.Int16: decInt16, + reflect.Int32: decInt32, + reflect.Int64: decInt64, + reflect.Uint8: decUint8, + reflect.Uint16: decUint16, + reflect.Uint32: decUint32, + reflect.Uint64: decUint64, + reflect.Float32: decFloat32, + reflect.Float64: decFloat64, + reflect.Complex64: decComplex64, + reflect.Complex128: decComplex128, + reflect.String: decString, +} + +// Indexed by gob types. tComplex will be added during type.init(). var decIgnoreOpMap = map[typeId]decOp{ tBool: ignoreUint, tInt: ignoreUint, @@ -652,6 +690,8 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) (decOp, os.Error) { // Special cases wire := dec.wireType[wireId] switch { + case wire == nil: + panic("internal error: can't find ignore op for type " + wireId.string()) case wire.arrayT != nil: elemId := wire.arrayT.Elem elemOp, err := dec.decIgnoreOpFor(elemId) @@ -728,6 +768,8 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool { return fw == tUint case *reflect.FloatType: return fw == tFloat + case *reflect.ComplexType: + return fw == tComplex case *reflect.StringType: return fw == tString case *reflect.ArrayType: @@ -866,39 +908,39 @@ func (dec *Decoder) decode(wireId typeId, e interface{}) os.Error { } func init() { - // We assume that the size of float is sufficient to tell us whether it is - // equivalent to float32 or to float64. This is very unlikely to be wrong. - var op decOp - switch unsafe.Sizeof(float(0)) { - case unsafe.Sizeof(float32(0)): - op = decFloat32 - case unsafe.Sizeof(float64(0)): - op = decFloat64 + var fop, cop decOp + switch reflect.Typeof(float(0)).Bits() { + case 32: + fop = decFloat32 + cop = decComplex64 + case 64: + fop = decFloat64 + cop = decComplex128 default: panic("gob: unknown size of float") } - decOpMap[reflect.Float] = op + decOpMap[reflect.Float] = fop + decOpMap[reflect.Complex] = cop - // A similar assumption about int and uint. Also assume int and uint have the same size. - var uop decOp - switch unsafe.Sizeof(int(0)) { - case unsafe.Sizeof(int32(0)): - op = decInt32 + var iop, uop decOp + switch reflect.Typeof(int(0)).Bits() { + case 32: + iop = decInt32 uop = decUint32 - case unsafe.Sizeof(int64(0)): - op = decInt64 + case 64: + iop = decInt64 uop = decUint64 default: panic("gob: unknown size of int/uint") } - decOpMap[reflect.Int] = op + decOpMap[reflect.Int] = iop decOpMap[reflect.Uint] = uop // Finally uintptr - switch unsafe.Sizeof(uintptr(0)) { - case unsafe.Sizeof(uint32(0)): + switch reflect.Typeof(uintptr(0)).Bits() { + case 32: uop = decUint32 - case unsafe.Sizeof(uint64(0)): + case 64: uop = decUint64 default: panic("gob: unknown size of uintptr") |
