summaryrefslogtreecommitdiff
path: root/src/pkg/gob/encode.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/gob/encode.go')
-rw-r--r--src/pkg/gob/encode.go123
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())
}