Commit 6e705e4e authored by Kirill Smelkov's avatar Kirill Smelkov

go/neo/proto: protogen: Factor-out handling of slice and map heads into common place

genSliceHead and genMapHead will be reused for MsgPack encoding.
Changes in generated code are mostly due to move of where things are
typecasted to e.g. uint32 without any change in semantic.
parent 1bb595cf
...@@ -479,6 +479,15 @@ type CodeGenerator interface { ...@@ -479,6 +479,15 @@ type CodeGenerator interface {
generatedCode() string generatedCode() string
} }
// interface for codegenerators to inject themselves into {sizer/encoder/decoder}Common.
type CodeGenCustomize interface {
CodeGenerator
// generate code to process slice or map header
genSliceHead(path string, typ *types.Slice, obj types.Object)
genMapHead(path string, typ *types.Map, obj types.Object)
}
// X reports encoding=X // X reports encoding=X
type N struct{}; func (_ *N) encoding() byte { return 'N' } type N struct{}; func (_ *N) encoding() byte { return 'N' }
...@@ -981,11 +990,18 @@ func (d *decoderN) genBuf(assignto string) { ...@@ -981,11 +990,18 @@ func (d *decoderN) genBuf(assignto string) {
// emit code to size/encode/decode slice // emit code to size/encode/decode slice
// len u32 // len u32
// [len]item // [len]item
func (s *sizerN) genSlice(path string, typ *types.Slice, obj types.Object) { func (s *sizerN) genSliceHead(path string, typ *types.Slice, obj types.Object) {
s.size.Add(4) s.size.Add(4)
}
func (s *sizerN) genSlice(path string, typ *types.Slice, obj types.Object) {
s.genSliceCommon(s, path, typ, obj)
}
func (s *sizerCommon) genSliceCommon(xs CodeGenCustomize, path string, typ *types.Slice, obj types.Object) {
xs.genSliceHead(path, typ, obj)
// if size(item)==const - size update in one go // if size(item)==const - size update in one go
elemSize, ok := typeSizeFixed(s.encoding(), typ.Elem()) elemSize, ok := typeSizeFixed(xs.encoding(), typ.Elem())
if ok { if ok {
s.size.AddExpr("len(%v) * %v", path, elemSize) s.size.AddExpr("len(%v) * %v", path, elemSize)
return return
...@@ -997,7 +1013,7 @@ func (s *sizerN) genSlice(path string, typ *types.Slice, obj types.Object) { ...@@ -997,7 +1013,7 @@ func (s *sizerN) genSlice(path string, typ *types.Slice, obj types.Object) {
s.emit("for i := 0; i < len(%v); i++ {", path) s.emit("for i := 0; i < len(%v); i++ {", path)
s.emit("a := &%s[i]", path) s.emit("a := &%s[i]", path)
codegenType("(*a)", typ.Elem(), obj, s) codegenType("(*a)", typ.Elem(), obj, xs)
// merge-in size updates // merge-in size updates
s.emit("%v += %v", s.var_("size"), s.size.ExprString()) s.emit("%v += %v", s.var_("size"), s.size.ExprString())
...@@ -1008,29 +1024,45 @@ func (s *sizerN) genSlice(path string, typ *types.Slice, obj types.Object) { ...@@ -1008,29 +1024,45 @@ func (s *sizerN) genSlice(path string, typ *types.Slice, obj types.Object) {
s.size = curSize s.size = curSize
} }
func (e *encoderN) genSlice(path string, typ *types.Slice, obj types.Object) { func (e *encoderN) genSliceHead(path string, typ *types.Slice, obj types.Object) {
e.emit("{") e.emit("l := len(%s)", path)
e.emit("l := uint32(len(%s))", path) e.genBasic("l", types.Typ[types.Uint32], types.Typ[types.Int])
e.genBasic("l", types.Typ[types.Uint32], nil)
e.emit("data = data[%v:]", e.n) e.emit("data = data[%v:]", e.n)
e.n = 0 e.n = 0
e.emit("for i := 0; uint32(i) <l; i++ {") }
func (e *encoderN) genSlice(path string, typ *types.Slice, obj types.Object) {
e.genSliceCommon(e, path, typ, obj)
}
func (e *encoderCommon) genSliceCommon(xe CodeGenCustomize, path string, typ *types.Slice, obj types.Object) {
e.emit("{")
xe.genSliceHead(path, typ, obj)
e.emit("for i := 0; i <l; i++ {")
e.emit("a := &%s[i]", path) e.emit("a := &%s[i]", path)
codegenType("(*a)", typ.Elem(), obj, e) codegenType("(*a)", typ.Elem(), obj, xe)
e.emit("data = data[%v:]", e.n) if e.n != 0 {
e.emit("data = data[%v:]", e.n)
e.n = 0
}
e.emit("}") e.emit("}")
e.emit("}") e.emit("}")
e.n = 0
} }
func (d *decoderN) genSliceHead(assignto string, typ *types.Slice, obj types.Object) {
d.genBasic("l:", types.Typ[types.Uint32], nil)
}
func (d *decoderN) genSlice(assignto string, typ *types.Slice, obj types.Object) { func (d *decoderN) genSlice(assignto string, typ *types.Slice, obj types.Object) {
d.genSliceCommon(d, assignto, typ, obj)
}
func (d *decoderCommon) genSliceCommon(xd CodeGenCustomize, assignto string, typ *types.Slice, obj types.Object) {
d.emit("{") d.emit("{")
d.genBasic("l:", types.Typ[types.Uint32], nil) xd.genSliceHead(assignto, typ, obj)
d.resetPos() d.resetPos()
// if size(item)==const - check overflow in one go // if size(item)==const - check overflow in one go
elemSize, elemFixed := typeSizeFixed(d.encoding(), typ.Elem()) elemSize, elemFixed := typeSizeFixed(xd.encoding(), typ.Elem())
if elemFixed { if elemFixed {
d.overflowCheck() d.overflowCheck()
d.overflow.AddExpr("uint64(l) * %v", elemSize) d.overflow.AddExpr("uint64(l) * %v", elemSize)
...@@ -1043,7 +1075,7 @@ func (d *decoderN) genSlice(assignto string, typ *types.Slice, obj types.Object) ...@@ -1043,7 +1075,7 @@ func (d *decoderN) genSlice(assignto string, typ *types.Slice, obj types.Object)
d.emit("a := &%s[i]", assignto) d.emit("a := &%s[i]", assignto)
d.overflowCheckLoopEntry() d.overflowCheckLoopEntry()
codegenType("(*a)", typ.Elem(), obj, d) codegenType("(*a)", typ.Elem(), obj, xd)
d.resetPos() d.resetPos()
d.emit("}") d.emit("}")
...@@ -1055,24 +1087,31 @@ func (d *decoderN) genSlice(assignto string, typ *types.Slice, obj types.Object) ...@@ -1055,24 +1087,31 @@ func (d *decoderN) genSlice(assignto string, typ *types.Slice, obj types.Object)
// generate code to encode/decode map // generate code to encode/decode map
// len u32 // len u32
// [len](key, value) // [len](key, value)
func (s *sizerN) genMapHead(path string, typ *types.Map, obj types.Object) {
s.size.Add(4)
}
func (s *sizerN) genMap(path string, typ *types.Map, obj types.Object) { func (s *sizerN) genMap(path string, typ *types.Map, obj types.Object) {
keySize, keyFixed := typeSizeFixed(s.encoding(), typ.Key()) s.genMapCommon(s, path, typ, obj)
elemSize, elemFixed := typeSizeFixed(s.encoding(), typ.Elem()) }
func (s *sizerCommon) genMapCommon(xs CodeGenCustomize, path string, typ *types.Map, obj types.Object) {
xs.genMapHead(path, typ, obj)
keySize, keyFixed := typeSizeFixed(xs.encoding(), typ.Key())
elemSize, elemFixed := typeSizeFixed(xs.encoding(), typ.Elem())
if keyFixed && elemFixed { if keyFixed && elemFixed {
s.size.Add(4)
s.size.AddExpr("len(%v) * %v", path, keySize+elemSize) s.size.AddExpr("len(%v) * %v", path, keySize+elemSize)
return return
} }
s.size.Add(4)
curSize := s.size curSize := s.size
s.size.Reset() s.size.Reset()
// FIXME for map of map gives ...[key][key] => key -> different variables // FIXME for map of map gives ...[key][key] => key -> different variables
s.emit("for key := range %s {", path) s.emit("for key := range %s {", path)
codegenType("key", typ.Key(), obj, s) codegenType("key", typ.Key(), obj, xs)
codegenType(fmt.Sprintf("%s[key]", path), typ.Elem(), obj, s) codegenType(fmt.Sprintf("%s[key]", path), typ.Elem(), obj, xs)
// merge-in size updates // merge-in size updates
s.emit("%v += %v", s.var_("size"), s.size.ExprString()) s.emit("%v += %v", s.var_("size"), s.size.ExprString())
...@@ -1083,12 +1122,19 @@ func (s *sizerN) genMap(path string, typ *types.Map, obj types.Object) { ...@@ -1083,12 +1122,19 @@ func (s *sizerN) genMap(path string, typ *types.Map, obj types.Object) {
s.size = curSize s.size = curSize
} }
func (e *encoderN) genMap(path string, typ *types.Map, obj types.Object) { func (e *encoderN) genMapHead(path string, typ *types.Map, obj types.Object) {
e.emit("{") e.emit("l := len(%s)", path)
e.emit("l := uint32(len(%s))", path) e.genBasic("l", types.Typ[types.Uint32], types.Typ[types.Int])
e.genBasic("l", types.Typ[types.Uint32], nil)
e.emit("data = data[%v:]", e.n) e.emit("data = data[%v:]", e.n)
e.n = 0 e.n = 0
}
func (e *encoderN) genMap(path string, typ *types.Map, obj types.Object) {
e.genMapCommon(e, path, typ, obj)
}
func (e *encoderCommon) genMapCommon(xe CodeGenCustomize, path string, typ *types.Map, obj types.Object) {
e.emit("{")
xe.genMapHead(path, typ, obj)
// output keys in sorted order on the wire // output keys in sorted order on the wire
// (easier for debugging & deterministic for testing) // (easier for debugging & deterministic for testing)
...@@ -1099,23 +1145,32 @@ func (e *encoderN) genMap(path string, typ *types.Map, obj types.Object) { ...@@ -1099,23 +1145,32 @@ func (e *encoderN) genMap(path string, typ *types.Map, obj types.Object) {
e.emit("sort.Slice(keyv, func (i, j int) bool { return keyv[i] < keyv[j] })") e.emit("sort.Slice(keyv, func (i, j int) bool { return keyv[i] < keyv[j] })")
e.emit("for _, key := range keyv {") e.emit("for _, key := range keyv {")
codegenType("key", typ.Key(), obj, e) codegenType("key", typ.Key(), obj, xe)
codegenType(fmt.Sprintf("%s[key]", path), typ.Elem(), obj, e) codegenType(fmt.Sprintf("%s[key]", path), typ.Elem(), obj, xe)
e.emit("data = data[%v:]", e.n) // XXX wrt map of map? if e.n != 0 {
e.emit("data = data[%v:]", e.n) // XXX wrt map of map?
e.n = 0
}
e.emit("}") e.emit("}")
e.emit("}") e.emit("}")
e.n = 0
} }
func (d *decoderN) genMapHead(assignto string, typ *types.Map, obj types.Object) {
d.genBasic("l:", types.Typ[types.Uint32], nil)
}
func (d *decoderN) genMap(assignto string, typ *types.Map, obj types.Object) { func (d *decoderN) genMap(assignto string, typ *types.Map, obj types.Object) {
d.genMapCommon(d, assignto, typ, obj)
}
func (d *decoderCommon) genMapCommon(xd CodeGenCustomize, assignto string, typ *types.Map, obj types.Object) {
d.emit("{") d.emit("{")
d.genBasic("l:", types.Typ[types.Uint32], nil) xd.genMapHead(assignto, typ, obj)
d.resetPos() d.resetPos()
// if size(key,item)==const - check overflow in one go // if size(key,item)==const - check overflow in one go
keySize, keyFixed := typeSizeFixed(d.encoding(), typ.Key()) keySize, keyFixed := typeSizeFixed(xd.encoding(), typ.Key())
elemSize, elemFixed := typeSizeFixed(d.encoding(), typ.Elem()) elemSize, elemFixed := typeSizeFixed(xd.encoding(), typ.Elem())
if keyFixed && elemFixed { if keyFixed && elemFixed {
d.overflowCheck() d.overflowCheck()
d.overflow.AddExpr("uint64(l) * %v", keySize+elemSize) d.overflow.AddExpr("uint64(l) * %v", keySize+elemSize)
...@@ -1128,18 +1183,19 @@ func (d *decoderN) genMap(assignto string, typ *types.Map, obj types.Object) { ...@@ -1128,18 +1183,19 @@ func (d *decoderN) genMap(assignto string, typ *types.Map, obj types.Object) {
d.emit("for i := 0; uint32(i) < l; i++ {") d.emit("for i := 0; uint32(i) < l; i++ {")
d.overflowCheckLoopEntry() d.overflowCheckLoopEntry()
codegenType("key:", typ.Key(), obj, d) d.emit("var key %s", typeName(typ.Key()))
codegenType("key", typ.Key(), obj, xd)
switch typ.Elem().Underlying().(type) { switch typ.Elem().Underlying().(type) {
// basic types can be directly assigned to map entry // basic types can be directly assigned to map entry
case *types.Basic: case *types.Basic:
codegenType("m[key]", typ.Elem(), obj, d) codegenType("m[key]", typ.Elem(), obj, xd)
// otherwise assign via temporary // otherwise assign via temporary
default: default:
d.emit("var v %v", typeName(typ.Elem())) d.emit("var mv %v", typeName(typ.Elem()))
codegenType("v", typ.Elem(), obj, d) codegenType("mv", typ.Elem(), obj, xd)
d.emit("m[key] = v") d.emit("m[key] = mv")
} }
d.resetPos() d.resetPos()
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment