1
0
mirror of https://github.com/golang/go synced 2024-11-25 22:17:58 -07:00

indirection on array elements.

R=rsc
DELTA=57  (34 added, 10 deleted, 13 changed)
OCL=31098
CL=31101
This commit is contained in:
Rob Pike 2009-07-02 17:21:48 -07:00
parent b5666a123a
commit c1fc4c8f37
3 changed files with 47 additions and 23 deletions

View File

@ -529,9 +529,12 @@ func TestEncode(t *testing.T) {
type T2 struct { type T2 struct {
t string t string
} }
s1 := "string1";
s2 := "string2";
type T1 struct { type T1 struct {
a, b,c int; a, b,c int;
n *[3]float; n *[3]float;
strs *[2]string;
s string; s string;
y []byte; y []byte;
t *T2; t *T2;
@ -541,6 +544,7 @@ func TestEncode(t *testing.T) {
b: 18, b: 18,
c: -5, c: -5,
n: &[3]float{1.5, 2.5, 3.5}, n: &[3]float{1.5, 2.5, 3.5},
strs: &[2]string{s1, s2},
s: "Now is the time", s: "Now is the time",
y: strings.Bytes("hello, sailor"), y: strings.Bytes("hello, sailor"),
t: &T2{"this is T2"}, t: &T2{"this is T2"},

View File

@ -313,7 +313,7 @@ func decodeStruct(engine *decEngine, rtyp reflect.StructType, r io.Reader, p uin
return state.err 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 { if indir > 0 {
up := unsafe.Pointer(p); up := unsafe.Pointer(p);
if *(*unsafe.Pointer)(up) == nil { if *(*unsafe.Pointer)(up) == nil {
@ -324,12 +324,16 @@ func decodeArray(atyp reflect.ArrayType, state *DecState, p uintptr, elemOp decO
} }
p = *(*uintptr)(up); 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) { if DecodeUint(state) != uint64(length) {
state.err = os.ErrorString("length mismatch in decodeArray"); state.err = os.ErrorString("length mismatch in decodeArray");
} }
for i := 0; i < length && state.err == nil; i++ { 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); p += uintptr(elemWid);
} }
return state.err return state.err
@ -368,8 +372,9 @@ func decOpFor(typ reflect.Type) decOp {
case atyp.IsSlice(): case atyp.IsSlice():
case !atyp.IsSlice(): case !atyp.IsSlice():
elemOp := decOpFor(atyp.Elem()); elemOp := decOpFor(atyp.Elem());
_, elemIndir := indirect(atyp.Elem());
op = func(i *decInstr, state *DecState, p unsafe.Pointer) { 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 { func Decode(r io.Reader, e interface{}) os.Error {
// Dereference down to the underlying object. // Dereference down to the underlying object.
rt := reflect.Typeof(e); rt, indir := indirect(reflect.Typeof(e));
v := reflect.NewValue(e); v := reflect.NewValue(e);
for { for i := 0; i < indir; i++ {
pt, ok := rt.(reflect.PtrType);
if !ok {
break
}
rt = pt.Sub();
v = reflect.Indirect(v); v = reflect.Indirect(v);
} }
if rt.Kind() != reflect.StructKind { if rt.Kind() != reflect.StructKind {

View File

@ -14,6 +14,21 @@ import (
"unsafe"; "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. // The global execution state of an instance of the encoder.
// Field numbers are delta encoded and always increase. The field // 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 // 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 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 := new(EncState);
state.w = w; state.w = w;
state.fieldnum = -1; state.fieldnum = -1;
EncodeUint(state, uint64(length)); EncodeUint(state, uint64(length));
for i := 0; i < length && state.err == nil; i++ { 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); p += uintptr(elemWid);
} }
return state.err return state.err
@ -325,20 +348,22 @@ func encOpFor(typ reflect.Type) encOp {
case atyp.IsSlice(): case atyp.IsSlice():
// Slices have a header; we decode it to find the underlying array. // Slices have a header; we decode it to find the underlying array.
elemOp := encOpFor(atyp.Elem()); elemOp := encOpFor(atyp.Elem());
_, indir := indirect(atyp.Elem());
op = func(i *encInstr, state *EncState, p unsafe.Pointer) { op = func(i *encInstr, state *EncState, p unsafe.Pointer) {
slice := *(*reflect.SliceHeader)(p); slice := *(*reflect.SliceHeader)(p);
if slice.Len == 0 { if slice.Len == 0 {
return return
} }
state.update(i); 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(): case !atyp.IsSlice():
// True arrays have size in the type. // True arrays have size in the type.
elemOp := encOpFor(atyp.Elem()); elemOp := encOpFor(atyp.Elem());
_, indir := indirect(atyp.Elem());
op = func(i *encInstr, state *EncState, p unsafe.Pointer) { op = func(i *encInstr, state *EncState, p unsafe.Pointer) {
state.update(i); 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 { func Encode(w io.Writer, e interface{}) os.Error {
// Dereference down to the underlying object. // Dereference down to the underlying object.
rt := reflect.Typeof(e); rt, indir := indirect(reflect.Typeof(e));
v := reflect.NewValue(e); v := reflect.NewValue(e);
for { for i := 0; i < indir; i++ {
pt, ok := rt.(reflect.PtrType);
if !ok {
break
}
rt = pt.Sub();
v = reflect.Indirect(v); v = reflect.Indirect(v);
} }
if v.Kind() != reflect.StructKind { 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(); typeLock.Lock();
engine := getEncEngine(rt); engine := getEncEngine(rt);