diff options
Diffstat (limited to 'src/pkg/gob/encode.go')
-rw-r--r-- | src/pkg/gob/encode.go | 123 |
1 files changed, 78 insertions, 45 deletions
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go index b48c1f698..a7d44ecc2 100644 --- a/src/pkg/gob/encode.go +++ b/src/pkg/gob/encode.go @@ -271,7 +271,7 @@ const uint64Size = unsafe.Sizeof(uint64(0)) type encoderState struct { b *bytes.Buffer err os.Error // error encountered during encoding. - inArray bool // encoding an array element or map key/value pair + sendZero bool // encoding an array element or map key/value pair; send zero values fieldnum int // the last field number written. buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation. } @@ -352,7 +352,7 @@ func encIndirect(p unsafe.Pointer, indir int) unsafe.Pointer { func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) { b := *(*bool)(p) - if b || state.inArray { + if b || state.sendZero { state.update(i) if b { encodeUint(state, 1) @@ -364,7 +364,7 @@ func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) { func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) { v := int64(*(*int)(p)) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeInt(state, v) } @@ -372,7 +372,7 @@ func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) { func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) { v := uint64(*(*uint)(p)) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeUint(state, v) } @@ -380,7 +380,7 @@ func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) { func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) { v := int64(*(*int8)(p)) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeInt(state, v) } @@ -388,7 +388,7 @@ func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) { func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) { v := uint64(*(*uint8)(p)) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeUint(state, v) } @@ -396,7 +396,7 @@ func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) { func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) { v := int64(*(*int16)(p)) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeInt(state, v) } @@ -404,7 +404,7 @@ func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) { func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) { v := uint64(*(*uint16)(p)) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeUint(state, v) } @@ -412,7 +412,7 @@ func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) { func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) { v := int64(*(*int32)(p)) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeInt(state, v) } @@ -420,7 +420,7 @@ func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) { func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) { v := uint64(*(*uint32)(p)) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeUint(state, v) } @@ -428,7 +428,7 @@ func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) { func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) { v := *(*int64)(p) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeInt(state, v) } @@ -436,7 +436,7 @@ func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) { func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) { v := *(*uint64)(p) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeUint(state, v) } @@ -444,7 +444,7 @@ func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) { func encUintptr(i *encInstr, state *encoderState, p unsafe.Pointer) { v := uint64(*(*uintptr)(p)) - if v != 0 || state.inArray { + if v != 0 || state.sendZero { state.update(i) encodeUint(state, v) } @@ -468,7 +468,7 @@ func floatBits(f float64) uint64 { func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) { f := *(*float)(p) - if f != 0 || state.inArray { + if f != 0 || state.sendZero { v := floatBits(float64(f)) state.update(i) encodeUint(state, v) @@ -477,7 +477,7 @@ func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) { func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) { f := *(*float32)(p) - if f != 0 || state.inArray { + if f != 0 || state.sendZero { v := floatBits(float64(f)) state.update(i) encodeUint(state, v) @@ -486,7 +486,7 @@ func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) { func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) { f := *(*float64)(p) - if f != 0 || state.inArray { + if f != 0 || state.sendZero { state.update(i) v := floatBits(f) encodeUint(state, v) @@ -496,7 +496,7 @@ 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 { + if c != 0+0i || state.sendZero { rpart := floatBits(float64(real(c))) ipart := floatBits(float64(imag(c))) state.update(i) @@ -507,7 +507,7 @@ func encComplex(i *encInstr, state *encoderState, p unsafe.Pointer) { func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) { c := *(*complex64)(p) - if c != 0+0i || state.inArray { + if c != 0+0i || state.sendZero { rpart := floatBits(float64(real(c))) ipart := floatBits(float64(imag(c))) state.update(i) @@ -518,7 +518,7 @@ func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) { func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) { c := *(*complex128)(p) - if c != 0+0i || state.inArray { + if c != 0+0i || state.sendZero { rpart := floatBits(real(c)) ipart := floatBits(imag(c)) state.update(i) @@ -530,7 +530,7 @@ func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) { // Byte arrays are encoded as an unsigned count followed by the raw bytes. func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) { b := *(*[]byte)(p) - if len(b) > 0 || state.inArray { + if len(b) > 0 || state.sendZero { state.update(i) encodeUint(state, uint64(len(b))) state.b.Write(b) @@ -540,7 +540,7 @@ func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) { // Strings are encoded as an unsigned count followed by the raw bytes. func encString(i *encInstr, state *encoderState, p unsafe.Pointer) { s := *(*string)(p) - if len(s) > 0 || state.inArray { + if len(s) > 0 || state.sendZero { state.update(i) encodeUint(state, uint64(len(s))) io.WriteString(state.b, s) @@ -560,6 +560,26 @@ type encEngine struct { instr []encInstr } +const singletonField = 0 + +func encodeSingle(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error { + state := new(encoderState) + state.b = b + state.fieldnum = singletonField + // There is no surrounding struct to frame the transmission, so we must + // generate data even if the item is zero. To do this, set sendZero. + state.sendZero = true + instr := &engine.instr[singletonField] + p := unsafe.Pointer(basep) // offset will be zero + if instr.indir > 0 { + if p = encIndirect(p, instr.indir); p == nil { + return nil + } + } + instr.op(instr, state, p) + return state.err +} + func encodeStruct(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error { state := new(encoderState) state.b = b @@ -584,7 +604,7 @@ func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndi state := new(encoderState) state.b = b state.fieldnum = -1 - state.inArray = true + state.sendZero = true encodeUint(state, uint64(length)) for i := 0; i < length && state.err == nil; i++ { elemp := p @@ -607,22 +627,17 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in v = reflect.Indirect(v) } if v == nil { - state.err = os.ErrorString("gob: encodeMap: nil element") + state.err = os.ErrorString("gob: encodeReflectValue: nil element") return } op(nil, state, unsafe.Pointer(v.Addr())) } -func encodeMap(b *bytes.Buffer, rt reflect.Type, p uintptr, keyOp, elemOp encOp, keyIndir, elemIndir int) os.Error { +func encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) os.Error { state := new(encoderState) state.b = b state.fieldnum = -1 - state.inArray = true - // Maps cannot be accessed by moving addresses around the way - // that slices etc. can. We must recover a full reflection value for - // the iteration. - v := reflect.NewValue(unsafe.Unreflect(rt, unsafe.Pointer((p)))) - mv := reflect.Indirect(v).(*reflect.MapValue) + state.sendZero = true keys := mv.Keys() encodeUint(state, uint64(len(keys))) for _, key := range keys { @@ -694,6 +709,10 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) { return nil, 0, err } op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { + slice := (*reflect.SliceHeader)(p) + if slice.Len == 0 { + return + } state.update(i) state.err = encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), indir, t.Len()) } @@ -707,8 +726,16 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) { return nil, 0, err } op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { + // Maps cannot be accessed by moving addresses around the way + // that slices etc. can. We must recover a full reflection value for + // the iteration. + v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p)))) + mv := reflect.Indirect(v).(*reflect.MapValue) + if mv.Len() == 0 { + return + } state.update(i) - state.err = encodeMap(state.b, typ, uintptr(p), keyOp, elemOp, keyIndir, elemIndir) + state.err = encodeMap(state.b, mv, keyOp, elemOp, keyIndir, elemIndir) } case *reflect.StructType: // Generate a closure that calls out to the engine for the nested type. @@ -732,21 +759,27 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) { // The local Type was compiled from the actual value, so we know it's compatible. func compileEnc(rt reflect.Type) (*encEngine, os.Error) { - srt, ok := rt.(*reflect.StructType) - if !ok { - panic("can't happen: non-struct") - } + srt, isStruct := rt.(*reflect.StructType) engine := new(encEngine) - engine.instr = make([]encInstr, srt.NumField()+1) // +1 for terminator - for fieldnum := 0; fieldnum < srt.NumField(); fieldnum++ { - f := srt.Field(fieldnum) - op, indir, err := encOpFor(f.Type) + if isStruct { + engine.instr = make([]encInstr, srt.NumField()+1) // +1 for terminator + for fieldnum := 0; fieldnum < srt.NumField(); fieldnum++ { + f := srt.Field(fieldnum) + op, indir, err := encOpFor(f.Type) + if err != nil { + return nil, err + } + engine.instr[fieldnum] = encInstr{op, fieldnum, indir, uintptr(f.Offset)} + } + engine.instr[srt.NumField()] = encInstr{encStructTerminator, 0, 0, 0} + } else { + engine.instr = make([]encInstr, 1) + op, indir, err := encOpFor(rt) if err != nil { return nil, err } - engine.instr[fieldnum] = encInstr{op, fieldnum, indir, uintptr(f.Offset)} + engine.instr[0] = encInstr{op, singletonField, indir, 0} // offset is zero } - engine.instr[srt.NumField()] = encInstr{encStructTerminator, 0, 0, 0} return engine, nil } @@ -772,14 +805,14 @@ func encode(b *bytes.Buffer, e interface{}) os.Error { for i := 0; i < indir; i++ { v = reflect.Indirect(v) } - if _, ok := v.(*reflect.StructValue); !ok { - return os.ErrorString("gob: encode can't handle " + v.Type().String()) - } typeLock.Lock() engine, err := getEncEngine(rt) typeLock.Unlock() if err != nil { return err } - return encodeStruct(engine, b, v.Addr()) + if _, ok := v.(*reflect.StructValue); ok { + return encodeStruct(engine, b, v.Addr()) + } + return encodeSingle(engine, b, v.Addr()) } |