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 {
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
type N struct{}; func (_ *N) encoding() byte { return 'N' }
......@@ -981,11 +990,18 @@ func (d *decoderN) genBuf(assignto string) {
// emit code to size/encode/decode slice
// len u32
// [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)
}
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
elemSize, ok := typeSizeFixed(s.encoding(), typ.Elem())
elemSize, ok := typeSizeFixed(xs.encoding(), typ.Elem())
if ok {
s.size.AddExpr("len(%v) * %v", path, elemSize)
return
......@@ -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("a := &%s[i]", path)
codegenType("(*a)", typ.Elem(), obj, s)
codegenType("(*a)", typ.Elem(), obj, xs)
// merge-in size updates
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) {
s.size = curSize
}
func (e *encoderN) genSlice(path string, typ *types.Slice, obj types.Object) {
e.emit("{")
e.emit("l := uint32(len(%s))", path)
e.genBasic("l", types.Typ[types.Uint32], nil)
func (e *encoderN) genSliceHead(path string, typ *types.Slice, obj types.Object) {
e.emit("l := len(%s)", path)
e.genBasic("l", types.Typ[types.Uint32], types.Typ[types.Int])
e.emit("data = data[%v:]", e.n)
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)
codegenType("(*a)", typ.Elem(), obj, e)
codegenType("(*a)", typ.Elem(), obj, xe)
if e.n != 0 {
e.emit("data = data[%v:]", e.n)
e.n = 0
}
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) {
d.genSliceCommon(d, assignto, typ, obj)
}
func (d *decoderCommon) genSliceCommon(xd CodeGenCustomize, assignto string, typ *types.Slice, obj types.Object) {
d.emit("{")
d.genBasic("l:", types.Typ[types.Uint32], nil)
xd.genSliceHead(assignto, typ, obj)
d.resetPos()
// 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 {
d.overflowCheck()
d.overflow.AddExpr("uint64(l) * %v", elemSize)
......@@ -1043,7 +1075,7 @@ func (d *decoderN) genSlice(assignto string, typ *types.Slice, obj types.Object)
d.emit("a := &%s[i]", assignto)
d.overflowCheckLoopEntry()
codegenType("(*a)", typ.Elem(), obj, d)
codegenType("(*a)", typ.Elem(), obj, xd)
d.resetPos()
d.emit("}")
......@@ -1055,24 +1087,31 @@ func (d *decoderN) genSlice(assignto string, typ *types.Slice, obj types.Object)
// generate code to encode/decode map
// len u32
// [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) {
keySize, keyFixed := typeSizeFixed(s.encoding(), typ.Key())
elemSize, elemFixed := typeSizeFixed(s.encoding(), typ.Elem())
s.genMapCommon(s, path, typ, obj)
}
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 {
s.size.Add(4)
s.size.AddExpr("len(%v) * %v", path, keySize+elemSize)
return
}
s.size.Add(4)
curSize := s.size
s.size.Reset()
// FIXME for map of map gives ...[key][key] => key -> different variables
s.emit("for key := range %s {", path)
codegenType("key", typ.Key(), obj, s)
codegenType(fmt.Sprintf("%s[key]", path), typ.Elem(), obj, s)
codegenType("key", typ.Key(), obj, xs)
codegenType(fmt.Sprintf("%s[key]", path), typ.Elem(), obj, xs)
// merge-in size updates
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) {
s.size = curSize
}
func (e *encoderN) genMap(path string, typ *types.Map, obj types.Object) {
e.emit("{")
e.emit("l := uint32(len(%s))", path)
e.genBasic("l", types.Typ[types.Uint32], nil)
func (e *encoderN) genMapHead(path string, typ *types.Map, obj types.Object) {
e.emit("l := len(%s)", path)
e.genBasic("l", types.Typ[types.Uint32], types.Typ[types.Int])
e.emit("data = data[%v:]", e.n)
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
// (easier for debugging & deterministic for testing)
......@@ -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("for _, key := range keyv {")
codegenType("key", typ.Key(), obj, e)
codegenType(fmt.Sprintf("%s[key]", path), typ.Elem(), obj, e)
codegenType("key", typ.Key(), obj, xe)
codegenType(fmt.Sprintf("%s[key]", path), typ.Elem(), obj, xe)
if e.n != 0 {
e.emit("data = data[%v:]", e.n) // XXX wrt map of map?
e.n = 0
}
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) {
d.genMapCommon(d, assignto, typ, obj)
}
func (d *decoderCommon) genMapCommon(xd CodeGenCustomize, assignto string, typ *types.Map, obj types.Object) {
d.emit("{")
d.genBasic("l:", types.Typ[types.Uint32], nil)
xd.genMapHead(assignto, typ, obj)
d.resetPos()
// if size(key,item)==const - check overflow in one go
keySize, keyFixed := typeSizeFixed(d.encoding(), typ.Key())
elemSize, elemFixed := typeSizeFixed(d.encoding(), typ.Elem())
keySize, keyFixed := typeSizeFixed(xd.encoding(), typ.Key())
elemSize, elemFixed := typeSizeFixed(xd.encoding(), typ.Elem())
if keyFixed && elemFixed {
d.overflowCheck()
d.overflow.AddExpr("uint64(l) * %v", keySize+elemSize)
......@@ -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.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) {
// basic types can be directly assigned to map entry
case *types.Basic:
codegenType("m[key]", typ.Elem(), obj, d)
codegenType("m[key]", typ.Elem(), obj, xd)
// otherwise assign via temporary
default:
d.emit("var v %v", typeName(typ.Elem()))
codegenType("v", typ.Elem(), obj, d)
d.emit("m[key] = v")
d.emit("var mv %v", typeName(typ.Elem()))
codegenType("mv", typ.Elem(), obj, xd)
d.emit("m[key] = mv")
}
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