Commit 37a6bc83 authored by Rob Pike's avatar Rob Pike

gob: add support for complex numbers

R=rsc
CC=golang-dev
https://golang.org/cl/1708048
parent 6d8b8101
...@@ -112,7 +112,9 @@ var boolResult = []byte{0x07, 0x01} ...@@ -112,7 +112,9 @@ var boolResult = []byte{0x07, 0x01}
var signedResult = []byte{0x07, 2 * 17} var signedResult = []byte{0x07, 2 * 17}
var unsignedResult = []byte{0x07, 17} var unsignedResult = []byte{0x07, 17}
var floatResult = []byte{0x07, 0xFE, 0x31, 0x40} var floatResult = []byte{0x07, 0xFE, 0x31, 0x40}
// The result of encoding "hello" with field number 6 // The result of encoding a number 17+19i with field number 7
var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
// The result of encoding "hello" with field number 7
var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'} var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
func newencoderState(b *bytes.Buffer) *encoderState { func newencoderState(b *bytes.Buffer) *encoderState {
...@@ -537,6 +539,45 @@ func TestScalarDecInstructions(t *testing.T) { ...@@ -537,6 +539,45 @@ func TestScalarDecInstructions(t *testing.T) {
} }
} }
// complex
{
var data struct {
a complex
}
instr := &decInstr{decOpMap[reflect.Complex], 6, 0, 0, ovfl}
state := newDecodeStateFromData(complexResult)
execDec("complex", instr, state, t, unsafe.Pointer(&data))
if data.a != 17+19i {
t.Errorf("complex a = %v not 17+19i", data.a)
}
}
// complex64
{
var data struct {
a complex64
}
instr := &decInstr{decOpMap[reflect.Complex64], 6, 0, 0, ovfl}
state := newDecodeStateFromData(complexResult)
execDec("complex", instr, state, t, unsafe.Pointer(&data))
if data.a != 17+19i {
t.Errorf("complex a = %v not 17+19i", data.a)
}
}
// complex128
{
var data struct {
a complex128
}
instr := &decInstr{decOpMap[reflect.Complex128], 6, 0, 0, ovfl}
state := newDecodeStateFromData(complexResult)
execDec("complex", instr, state, t, unsafe.Pointer(&data))
if data.a != 17+19i {
t.Errorf("complex a = %v not 17+19i", data.a)
}
}
// bytes == []uint8 // bytes == []uint8
{ {
var data struct { var data struct {
...@@ -576,6 +617,7 @@ func TestEndToEnd(t *testing.T) { ...@@ -576,6 +617,7 @@ func TestEndToEnd(t *testing.T) {
n *[3]float n *[3]float
strs *[2]string strs *[2]string
int64s *[]int64 int64s *[]int64
ri complex64
s string s string
y []byte y []byte
t *T2 t *T2
...@@ -590,6 +632,7 @@ func TestEndToEnd(t *testing.T) { ...@@ -590,6 +632,7 @@ func TestEndToEnd(t *testing.T) {
n: &[3]float{1.5, 2.5, 3.5}, n: &[3]float{1.5, 2.5, 3.5},
strs: &[2]string{s1, s2}, strs: &[2]string{s1, s2},
int64s: &[]int64{77, 89, 123412342134}, int64s: &[]int64{77, 89, 123412342134},
ri: 17 - 23i,
s: "Now is the time", s: "Now is the time",
y: []byte("hello, sailor"), y: []byte("hello, sailor"),
t: &T2{"this is T2"}, t: &T2{"this is T2"},
...@@ -616,6 +659,8 @@ func TestOverflow(t *testing.T) { ...@@ -616,6 +659,8 @@ func TestOverflow(t *testing.T) {
maxu uint64 maxu uint64
maxf float64 maxf float64
minf float64 minf float64
maxc complex128
minc complex128
} }
var it inputT var it inputT
var err os.Error var err os.Error
...@@ -758,6 +803,22 @@ func TestOverflow(t *testing.T) { ...@@ -758,6 +803,22 @@ func TestOverflow(t *testing.T) {
if err == nil || err.String() != `value for "maxf" out of range` { if err == nil || err.String() != `value for "maxf" out of range` {
t.Error("wrong overflow error for float32:", err) t.Error("wrong overflow error for float32:", err)
} }
// complex64
b.Reset()
it = inputT{
maxc: cmplx(math.MaxFloat32*2, math.MaxFloat32*2),
}
type outc64 struct {
maxc complex64
minc complex64
}
var o8 outc64
enc.Encode(it)
err = dec.Decode(&o8)
if err == nil || err.String() != `value for "maxc" out of range` {
t.Error("wrong overflow error for complex64:", err)
}
} }
......
...@@ -151,6 +151,11 @@ func ignoreUint(i *decInstr, state *decodeState, p unsafe.Pointer) { ...@@ -151,6 +151,11 @@ func ignoreUint(i *decInstr, state *decodeState, p unsafe.Pointer) {
decodeUint(state) decodeUint(state)
} }
func ignoreTwoUints(i *decInstr, state *decodeState, p unsafe.Pointer) {
decodeUint(state)
decodeUint(state)
}
func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) { func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) {
if i.indir > 0 { if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil { if *(*unsafe.Pointer)(p) == nil {
...@@ -286,25 +291,30 @@ func floatFromBits(u uint64) float64 { ...@@ -286,25 +291,30 @@ func floatFromBits(u uint64) float64 {
return math.Float64frombits(v) return math.Float64frombits(v)
} }
func decFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) { func storeFloat32(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)
}
v := floatFromBits(decodeUint(state)) v := floatFromBits(decodeUint(state))
av := v av := v
if av < 0 { if av < 0 {
av = -av 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 state.err = i.ovfl
} else { } else {
*(*float32)(p) = float32(v) *(*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) { func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) {
if i.indir > 0 { if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil { if *(*unsafe.Pointer)(p) == nil {
...@@ -315,6 +325,30 @@ func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) { ...@@ -315,6 +325,30 @@ func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) {
*(*float64)(p) = floatFromBits(uint64(decodeUint(state))) *(*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. // uint8 arrays are encoded as an unsigned count followed by the raw bytes.
func decUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) { func decUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) {
if i.indir > 0 { if i.indir > 0 {
...@@ -540,21 +574,25 @@ func ignoreSlice(state *decodeState, elemOp decOp) os.Error { ...@@ -540,21 +574,25 @@ func ignoreSlice(state *decodeState, elemOp decOp) os.Error {
return ignoreArrayHelper(state, elemOp, int(decodeUint(state))) return ignoreArrayHelper(state, elemOp, int(decodeUint(state)))
} }
// Index by Go types.
var decOpMap = []decOp{ var decOpMap = []decOp{
reflect.Bool: decBool, reflect.Bool: decBool,
reflect.Int8: decInt8, reflect.Int8: decInt8,
reflect.Int16: decInt16, reflect.Int16: decInt16,
reflect.Int32: decInt32, reflect.Int32: decInt32,
reflect.Int64: decInt64, reflect.Int64: decInt64,
reflect.Uint8: decUint8, reflect.Uint8: decUint8,
reflect.Uint16: decUint16, reflect.Uint16: decUint16,
reflect.Uint32: decUint32, reflect.Uint32: decUint32,
reflect.Uint64: decUint64, reflect.Uint64: decUint64,
reflect.Float32: decFloat32, reflect.Float32: decFloat32,
reflect.Float64: decFloat64, reflect.Float64: decFloat64,
reflect.String: decString, 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{ var decIgnoreOpMap = map[typeId]decOp{
tBool: ignoreUint, tBool: ignoreUint,
tInt: ignoreUint, tInt: ignoreUint,
...@@ -652,6 +690,8 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) (decOp, os.Error) { ...@@ -652,6 +690,8 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) (decOp, os.Error) {
// Special cases // Special cases
wire := dec.wireType[wireId] wire := dec.wireType[wireId]
switch { switch {
case wire == nil:
panic("internal error: can't find ignore op for type " + wireId.string())
case wire.arrayT != nil: case wire.arrayT != nil:
elemId := wire.arrayT.Elem elemId := wire.arrayT.Elem
elemOp, err := dec.decIgnoreOpFor(elemId) elemOp, err := dec.decIgnoreOpFor(elemId)
...@@ -728,6 +768,8 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool { ...@@ -728,6 +768,8 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
return fw == tUint return fw == tUint
case *reflect.FloatType: case *reflect.FloatType:
return fw == tFloat return fw == tFloat
case *reflect.ComplexType:
return fw == tComplex
case *reflect.StringType: case *reflect.StringType:
return fw == tString return fw == tString
case *reflect.ArrayType: case *reflect.ArrayType:
...@@ -866,39 +908,39 @@ func (dec *Decoder) decode(wireId typeId, e interface{}) os.Error { ...@@ -866,39 +908,39 @@ func (dec *Decoder) decode(wireId typeId, e interface{}) os.Error {
} }
func init() { func init() {
// We assume that the size of float is sufficient to tell us whether it is var fop, cop decOp
// equivalent to float32 or to float64. This is very unlikely to be wrong. switch reflect.Typeof(float(0)).Bits() {
var op decOp case 32:
switch unsafe.Sizeof(float(0)) { fop = decFloat32
case unsafe.Sizeof(float32(0)): cop = decComplex64
op = decFloat32 case 64:
case unsafe.Sizeof(float64(0)): fop = decFloat64
op = decFloat64 cop = decComplex128
default: default:
panic("gob: unknown size of float") 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 iop, uop decOp
var uop decOp switch reflect.Typeof(int(0)).Bits() {
switch unsafe.Sizeof(int(0)) { case 32:
case unsafe.Sizeof(int32(0)): iop = decInt32
op = decInt32
uop = decUint32 uop = decUint32
case unsafe.Sizeof(int64(0)): case 64:
op = decInt64 iop = decInt64
uop = decUint64 uop = decUint64
default: default:
panic("gob: unknown size of int/uint") panic("gob: unknown size of int/uint")
} }
decOpMap[reflect.Int] = op decOpMap[reflect.Int] = iop
decOpMap[reflect.Uint] = uop decOpMap[reflect.Uint] = uop
// Finally uintptr // Finally uintptr
switch unsafe.Sizeof(uintptr(0)) { switch reflect.Typeof(uintptr(0)).Bits() {
case unsafe.Sizeof(uint32(0)): case 32:
uop = decUint32 uop = decUint32
case unsafe.Sizeof(uint64(0)): case 64:
uop = decUint64 uop = decUint64
default: default:
panic("gob: unknown size of uintptr") panic("gob: unknown size of uintptr")
......
...@@ -467,7 +467,7 @@ func floatBits(f float64) uint64 { ...@@ -467,7 +467,7 @@ func floatBits(f float64) uint64 {
} }
func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) { func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) {
f := float(*(*float)(p)) f := *(*float)(p)
if f != 0 || state.inArray { if f != 0 || state.inArray {
v := floatBits(float64(f)) v := floatBits(float64(f))
state.update(i) state.update(i)
...@@ -476,7 +476,7 @@ func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) { ...@@ -476,7 +476,7 @@ func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) {
} }
func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) { func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) {
f := float32(*(*float32)(p)) f := *(*float32)(p)
if f != 0 || state.inArray { if f != 0 || state.inArray {
v := floatBits(float64(f)) v := floatBits(float64(f))
state.update(i) state.update(i)
...@@ -493,6 +493,40 @@ func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) { ...@@ -493,6 +493,40 @@ func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) {
} }
} }
// Complex numbers are just a pair of floating-point numbers, real part first.
func encComplex(i *encInstr, state *encoderState, p unsafe.Pointer) {
c := *(*complex)(p)
if c != 0+0i || state.inArray {
rpart := floatBits(float64(real(c)))
ipart := floatBits(float64(imag(c)))
state.update(i)
encodeUint(state, rpart)
encodeUint(state, ipart)
}
}
func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) {
c := *(*complex64)(p)
if c != 0+0i || state.inArray {
rpart := floatBits(float64(real(c)))
ipart := floatBits(float64(imag(c)))
state.update(i)
encodeUint(state, rpart)
encodeUint(state, ipart)
}
}
func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
c := *(*complex128)(p)
if c != 0+0i || state.inArray {
rpart := floatBits(real(c))
ipart := floatBits(imag(c))
state.update(i)
encodeUint(state, rpart)
encodeUint(state, ipart)
}
}
// Byte arrays are encoded as an unsigned count followed by the raw bytes. // Byte arrays are encoded as an unsigned count followed by the raw bytes.
func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) { func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
b := *(*[]byte)(p) b := *(*[]byte)(p)
...@@ -602,22 +636,25 @@ func encodeMap(b *bytes.Buffer, rt reflect.Type, p uintptr, keyOp, elemOp encOp, ...@@ -602,22 +636,25 @@ func encodeMap(b *bytes.Buffer, rt reflect.Type, p uintptr, keyOp, elemOp encOp,
} }
var encOpMap = []encOp{ var encOpMap = []encOp{
reflect.Bool: encBool, reflect.Bool: encBool,
reflect.Int: encInt, reflect.Int: encInt,
reflect.Int8: encInt8, reflect.Int8: encInt8,
reflect.Int16: encInt16, reflect.Int16: encInt16,
reflect.Int32: encInt32, reflect.Int32: encInt32,
reflect.Int64: encInt64, reflect.Int64: encInt64,
reflect.Uint: encUint, reflect.Uint: encUint,
reflect.Uint8: encUint8, reflect.Uint8: encUint8,
reflect.Uint16: encUint16, reflect.Uint16: encUint16,
reflect.Uint32: encUint32, reflect.Uint32: encUint32,
reflect.Uint64: encUint64, reflect.Uint64: encUint64,
reflect.Uintptr: encUintptr, reflect.Uintptr: encUintptr,
reflect.Float: encFloat, reflect.Float: encFloat,
reflect.Float32: encFloat32, reflect.Float32: encFloat32,
reflect.Float64: encFloat64, reflect.Float64: encFloat64,
reflect.String: encString, reflect.Complex: encComplex,
reflect.Complex64: encComplex64,
reflect.Complex128: encComplex128,
reflect.String: encString,
} }
// Return the encoding op for the base type under rt and // Return the encoding op for the base type under rt and
...@@ -688,7 +725,7 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) { ...@@ -688,7 +725,7 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) {
} }
} }
if op == nil { if op == nil {
return op, indir, os.ErrorString("gob enc: can't happen: encode type" + rt.String()) return op, indir, os.ErrorString("gob enc: can't happen: encode type " + rt.String())
} }
return op, indir, nil return op, indir, nil
} }
......
...@@ -78,12 +78,17 @@ func (t *commonType) Name() string { return t.name } ...@@ -78,12 +78,17 @@ func (t *commonType) Name() string { return t.name }
// Create and check predefined types // Create and check predefined types
// The string for tBytes is "bytes" not "[]byte" to signify its specialness. // The string for tBytes is "bytes" not "[]byte" to signify its specialness.
var tBool = bootstrapType("bool", false, 1) var (
var tInt = bootstrapType("int", int(0), 2) // Primordial types, needed during initialization.
var tUint = bootstrapType("uint", uint(0), 3) tBool = bootstrapType("bool", false, 1)
var tFloat = bootstrapType("float", float64(0), 4) tInt = bootstrapType("int", int(0), 2)
var tBytes = bootstrapType("bytes", make([]byte, 0), 5) tUint = bootstrapType("uint", uint(0), 3)
var tString = bootstrapType("string", "", 6) tFloat = bootstrapType("float", float64(0), 4)
tBytes = bootstrapType("bytes", make([]byte, 0), 5)
tString = bootstrapType("string", "", 6)
// Types added to the language later, not needed during initialization.
tComplex typeId
)
// Predefined because it's needed by the Decoder // Predefined because it's needed by the Decoder
var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
...@@ -94,10 +99,17 @@ func init() { ...@@ -94,10 +99,17 @@ func init() {
checkId(9, mustGetTypeInfo(reflect.Typeof(commonType{})).id) checkId(9, mustGetTypeInfo(reflect.Typeof(commonType{})).id)
checkId(11, mustGetTypeInfo(reflect.Typeof(structType{})).id) checkId(11, mustGetTypeInfo(reflect.Typeof(structType{})).id)
checkId(12, mustGetTypeInfo(reflect.Typeof(fieldType{})).id) checkId(12, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
// Complex was added after gob was written, so appears after the
// fundamental types are built.
tComplex = bootstrapType("complex", 0+0i, 15)
decIgnoreOpMap[tComplex] = ignoreTwoUints
builtinIdToType = make(map[typeId]gobType) builtinIdToType = make(map[typeId]gobType)
for k, v := range idToType { for k, v := range idToType {
builtinIdToType[k] = v builtinIdToType[k] = v
} }
// Move the id space upwards to allow for growth in the predefined world // Move the id space upwards to allow for growth in the predefined world
// without breaking existing files. // without breaking existing files.
if nextId > firstUserId { if nextId > firstUserId {
...@@ -241,6 +253,9 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) { ...@@ -241,6 +253,9 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
case *reflect.FloatType: case *reflect.FloatType:
return tFloat.gobType(), nil return tFloat.gobType(), nil
case *reflect.ComplexType:
return tComplex.gobType(), nil
case *reflect.StringType: case *reflect.StringType:
return tString.gobType(), nil return tString.gobType(), nil
...@@ -335,7 +350,7 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId { ...@@ -335,7 +350,7 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
rt := reflect.Typeof(e) rt := reflect.Typeof(e)
_, present := types[rt] _, present := types[rt]
if present { if present {
panic("bootstrap type already present: " + name) panic("bootstrap type already present: " + name + ", " + rt.String())
} }
typ := &commonType{name: name} typ := &commonType{name: name}
types[rt] = typ types[rt] = typ
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment