]> Cypherpunks repositories - gostls13.git/commitdiff
indirection on array elements.
authorRob Pike <r@golang.org>
Fri, 3 Jul 2009 00:21:48 +0000 (17:21 -0700)
committerRob Pike <r@golang.org>
Fri, 3 Jul 2009 00:21:48 +0000 (17:21 -0700)
R=rsc
DELTA=57  (34 added, 10 deleted, 13 changed)
OCL=31098
CL=31101

src/pkg/gob/codec_test.go
src/pkg/gob/decode.go
src/pkg/gob/encode.go

index 7d77c0dda33b17ad4806c88f0505d5e25bec964f..8dd252b4ce49639002cae338f9ec74411800e4a1 100644 (file)
@@ -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"},
index bd25db1bbb5181a67f7722c533c2de462602fa2c..8a7440b0b4dfb0765f2bf0f502571c9d40bcf380 100644 (file)
@@ -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 {
index 389799b32ebdf0bc443c2d19016e94e6d15bbd64..57fcec97d27c4513f586954c51a16480f03f247a 100644 (file)
@@ -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);