From c1fc4c8f378cbde337557a314c7047edb86ed6e2 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 2 Jul 2009 17:21:48 -0700 Subject: [PATCH] indirection on array elements. R=rsc DELTA=57 (34 added, 10 deleted, 13 changed) OCL=31098 CL=31101 --- src/pkg/gob/codec_test.go | 4 ++++ src/pkg/gob/decode.go | 22 ++++++++++---------- src/pkg/gob/encode.go | 44 ++++++++++++++++++++++++++++----------- 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/pkg/gob/codec_test.go b/src/pkg/gob/codec_test.go index 7d77c0dda3..8dd252b4ce 100644 --- a/src/pkg/gob/codec_test.go +++ b/src/pkg/gob/codec_test.go @@ -529,9 +529,12 @@ func TestEncode(t *testing.T) { type T2 struct { t string } + s1 := "string1"; + s2 := "string2"; type T1 struct { a, b,c int; n *[3]float; + strs *[2]string; s string; y []byte; t *T2; @@ -541,6 +544,7 @@ func TestEncode(t *testing.T) { b: 18, c: -5, n: &[3]float{1.5, 2.5, 3.5}, + strs: &[2]string{s1, s2}, s: "Now is the time", y: strings.Bytes("hello, sailor"), t: &T2{"this is T2"}, diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go index bd25db1bbb..8a7440b0b4 100644 --- a/src/pkg/gob/decode.go +++ b/src/pkg/gob/decode.go @@ -313,7 +313,7 @@ func decodeStruct(engine *decEngine, rtyp reflect.StructType, r io.Reader, p uin return state.err } -func decodeArray(atyp reflect.ArrayType, state *DecState, p uintptr, elemOp decOp, elemWid int, length int, indir int) os.Error { +func decodeArray(atyp reflect.ArrayType, state *DecState, p uintptr, elemOp decOp, elemWid int, length int, indir, elemIndir int) os.Error { if indir > 0 { up := unsafe.Pointer(p); if *(*unsafe.Pointer)(up) == nil { @@ -324,12 +324,16 @@ func decodeArray(atyp reflect.ArrayType, state *DecState, p uintptr, elemOp decO } p = *(*uintptr)(up); } - instr := &decInstr{elemOp, 0, 0, 0}; // TODO(r): indir on elements + instr := &decInstr{elemOp, 0, elemIndir, 0}; if DecodeUint(state) != uint64(length) { state.err = os.ErrorString("length mismatch in decodeArray"); } for i := 0; i < length && state.err == nil; i++ { - elemOp(instr, state, unsafe.Pointer(p)); + up := unsafe.Pointer(p); + if elemIndir > 1 { + up = decIndirect(up, elemIndir); + } + elemOp(instr, state, up); p += uintptr(elemWid); } return state.err @@ -368,8 +372,9 @@ func decOpFor(typ reflect.Type) decOp { case atyp.IsSlice(): case !atyp.IsSlice(): elemOp := decOpFor(atyp.Elem()); + _, elemIndir := indirect(atyp.Elem()); op = func(i *decInstr, state *DecState, p unsafe.Pointer) { - state.err = decodeArray(atyp, state, uintptr(p), elemOp, atyp.Elem().Size(), atyp.Len(), i.indir); + state.err = decodeArray(atyp, state, uintptr(p), elemOp, atyp.Elem().Size(), atyp.Len(), i.indir, elemIndir); }; } } @@ -429,14 +434,9 @@ func getDecEngine(rt reflect.Type) *decEngine { func Decode(r io.Reader, e interface{}) os.Error { // Dereference down to the underlying object. - rt := reflect.Typeof(e); + rt, indir := indirect(reflect.Typeof(e)); v := reflect.NewValue(e); - for { - pt, ok := rt.(reflect.PtrType); - if !ok { - break - } - rt = pt.Sub(); + for i := 0; i < indir; i++ { v = reflect.Indirect(v); } if rt.Kind() != reflect.StructKind { diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go index 389799b32e..57fcec97d2 100644 --- a/src/pkg/gob/encode.go +++ b/src/pkg/gob/encode.go @@ -14,6 +14,21 @@ import ( "unsafe"; ) +// Step through the indirections on a type to discover the base type. +// Return the number of indirections. +func indirect(t reflect.Type) (rt reflect.Type, count int) { + rt = t; + for { + pt, ok := rt.(reflect.PtrType); + if !ok { + break + } + rt = pt.Sub(); + count++; + } + return; +} + // The global execution state of an instance of the encoder. // Field numbers are delta encoded and always increase. The field // number is initialized to -1 so 0 comes out as delta(1). A delta of @@ -280,13 +295,21 @@ func encodeStruct(engine *encEngine, w io.Writer, basep uintptr) os.Error { return state.err } -func encodeArray(w io.Writer, p uintptr, op encOp, elemWid int, length int) os.Error { +func encodeArray(w io.Writer, p uintptr, op encOp, elemWid int, length int, elemIndir int) os.Error { state := new(EncState); state.w = w; state.fieldnum = -1; EncodeUint(state, uint64(length)); for i := 0; i < length && state.err == nil; i++ { - op(nil, state, unsafe.Pointer(p)); // TODO(r): indir on elements + up := unsafe.Pointer(p); + if elemIndir > 0 { + if up = encIndirect(up, elemIndir); up == nil { + state.err = os.ErrorString("encodeArray: nil element"); + break + } + p = uintptr(up); + } + op(nil, state, unsafe.Pointer(p)); p += uintptr(elemWid); } return state.err @@ -325,20 +348,22 @@ func encOpFor(typ reflect.Type) encOp { case atyp.IsSlice(): // Slices have a header; we decode it to find the underlying array. elemOp := encOpFor(atyp.Elem()); + _, indir := indirect(atyp.Elem()); op = func(i *encInstr, state *EncState, p unsafe.Pointer) { slice := *(*reflect.SliceHeader)(p); if slice.Len == 0 { return } state.update(i); - state.err = encodeArray(state.w, slice.Data, elemOp, atyp.Elem().Size(), int(slice.Len)); + state.err = encodeArray(state.w, slice.Data, elemOp, atyp.Elem().Size(), int(slice.Len), indir); }; case !atyp.IsSlice(): // True arrays have size in the type. elemOp := encOpFor(atyp.Elem()); + _, indir := indirect(atyp.Elem()); op = func(i *encInstr, state *EncState, p unsafe.Pointer) { state.update(i); - state.err = encodeArray(state.w, uintptr(p), elemOp, atyp.Elem().Size(), atyp.Len()); + state.err = encodeArray(state.w, uintptr(p), elemOp, atyp.Elem().Size(), atyp.Len(), indir); }; } } @@ -398,18 +423,13 @@ func getEncEngine(rt reflect.Type) *encEngine { func Encode(w io.Writer, e interface{}) os.Error { // Dereference down to the underlying object. - rt := reflect.Typeof(e); + rt, indir := indirect(reflect.Typeof(e)); v := reflect.NewValue(e); - for { - pt, ok := rt.(reflect.PtrType); - if !ok { - break - } - rt = pt.Sub(); + for i := 0; i < indir; i++ { v = reflect.Indirect(v); } if v.Kind() != reflect.StructKind { - return os.ErrorString("decode can't handle " + v.Type().String()) + return os.ErrorString("encode can't handle " + v.Type().String()) } typeLock.Lock(); engine := getEncEngine(rt);