Skip to content

Commit

Permalink
Turn first deepcopy parameter into a pointer
Browse files Browse the repository at this point in the history
  • Loading branch information
sttts committed Jul 12, 2016
1 parent dbab1a8 commit 6049623
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 38 deletions.
58 changes: 30 additions & 28 deletions cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Wri

sw := generator.NewSnippetWriter(w, c, "$", "$")
funcName := g.funcNameTmpl(t)
sw.Do(fmt.Sprintf("func %s(in $.type|raw$, out *$.type|raw$, c *$.Cloner|raw$) error {\n", funcName), g.withGlobals(argsFromType(t)))
sw.Do(fmt.Sprintf("func %s(in *$.type|raw$, out *$.type|raw$, c *$.Cloner|raw$) error {\n", funcName), g.withGlobals(argsFromType(t)))
g.generateFor(t, sw)
sw.Do("return nil\n", nil)
sw.Do("}\n\n", nil)
Expand Down Expand Up @@ -459,71 +459,71 @@ func (g *genDeepCopy) generateFor(t *types.Type, sw *generator.SnippetWriter) {
}

func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("*out = in\n", nil)
sw.Do("*out = *in\n", nil)
}

func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("*out = make($.|raw$)\n", t)
if t.Key.IsAssignable() {
switch {
case hasDeepCopyMethod(t.Elem):
sw.Do("for key, val := range in {\n", nil)
sw.Do("for key, val := range *in {\n", nil)
sw.Do("(*out)[key] = val.DeepCopy()\n", nil)
sw.Do("}\n", nil)
case t.Elem.IsAnonymousStruct():
sw.Do("for key := range in {\n", nil)
sw.Do("for key := range *in {\n", nil)
sw.Do("(*out)[key] = struct{}{}\n", nil)
sw.Do("}\n", nil)
case t.Elem.IsAssignable():
sw.Do("for key, val := range in {\n", nil)
sw.Do("for key, val := range *in {\n", nil)
sw.Do("(*out)[key] = val\n", nil)
sw.Do("}\n", nil)
default:
sw.Do("for key, val := range in {\n", nil)
sw.Do("for key, val := range *in {\n", nil)
if g.copyableAndInBounds(t.Elem) {
sw.Do("newVal := new($.|raw$)\n", t.Elem)
funcName := g.funcNameTmpl(t.Elem)
sw.Do(fmt.Sprintf("if err := %s(val, newVal, c); err != nil {\n", funcName), argsFromType(t.Elem))
sw.Do(fmt.Sprintf("if err := %s(&val, newVal, c); err != nil {\n", funcName), argsFromType(t.Elem))
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
sw.Do("(*out)[key] = *newVal\n", nil)
} else {
sw.Do("if newVal, err := c.DeepCopy(val); err != nil {\n", nil)
sw.Do("if newVal, err := c.DeepCopy(&val); err != nil {\n", nil)
sw.Do("return err\n", nil)
sw.Do("} else {\n", nil)
sw.Do("(*out)[key] = newVal.($.|raw$)\n", t.Elem)
sw.Do("(*out)[key] = *newVal.(*$.|raw$)\n", t.Elem)
sw.Do("}\n", nil)
}
sw.Do("}\n", nil)
}
} else {
// TODO: Implement it when necessary.
sw.Do("for range in {\n", nil)
sw.Do("for range *in {\n", nil)
sw.Do("// FIXME: Copying unassignable keys unsupported $.|raw$\n", t.Key)
sw.Do("}\n", nil)
}
}

func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("*out = make($.|raw$, len(in))\n", t)
sw.Do("*out = make($.|raw$, len(*in))\n", t)
if t.Elem.Kind == types.Builtin {
sw.Do("copy(*out, in)\n", nil)
sw.Do("copy(*out, *in)\n", nil)
} else {
sw.Do("for i := range in {\n", nil)
sw.Do("for i := range *in {\n", nil)
if hasDeepCopyMethod(t.Elem) {
sw.Do("(*out)[i] = in[i].DeepCopy()\n", nil)
sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil)
} else if t.Elem.IsAssignable() {
sw.Do("(*out)[i] = in[i]\n", nil)
sw.Do("(*out)[i] = (*in)[i]\n", nil)
} else if g.copyableAndInBounds(t.Elem) {
funcName := g.funcNameTmpl(t.Elem)
sw.Do(fmt.Sprintf("if err := %s(in[i], &(*out)[i], c); err != nil {\n", funcName), argsFromType(t.Elem))
sw.Do(fmt.Sprintf("if err := %s(&(*in)[i], &(*out)[i], c); err != nil {\n", funcName), argsFromType(t.Elem))
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
} else {
sw.Do("if newVal, err := c.DeepCopy(in[i]); err != nil {\n", nil)
sw.Do("if newVal, err := c.DeepCopy(&(*in)[i]); err != nil {\n", nil)
sw.Do("return err\n", nil)
sw.Do("} else {\n", nil)
sw.Do("(*out)[i] = newVal.($.|raw$)\n", t.Elem)
sw.Do("(*out)[i] = *newVal.(*$.|raw$)\n", t.Elem)
sw.Do("}\n", nil)
}
sw.Do("}\n", nil)
Expand All @@ -547,7 +547,7 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("out.$.name$ = in.$.name$\n", args)
case types.Map, types.Slice, types.Pointer:
sw.Do("if in.$.name$ != nil {\n", args)
sw.Do("in, out := in.$.name$, &out.$.name$\n", args)
sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
g.generateFor(t, sw)
sw.Do("} else {\n", nil)
sw.Do("out.$.name$ = nil\n", args)
Expand All @@ -559,23 +559,23 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("out.$.name$ = in.$.name$\n", args)
} else if g.copyableAndInBounds(t) {
funcName := g.funcNameTmpl(t)
sw.Do(fmt.Sprintf("if err := %s(in.$.name$, &out.$.name$, c); err != nil {\n", funcName), args)
sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, c); err != nil {\n", funcName), args)
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
} else {
sw.Do("if newVal, err := c.DeepCopy(in.$.name$); err != nil {\n", args)
sw.Do("if newVal, err := c.DeepCopy(&in.$.name$); err != nil {\n", args)
sw.Do("return err\n", nil)
sw.Do("} else {\n", nil)
sw.Do("out.$.name$ = newVal.($.type|raw$)\n", args)
sw.Do("out.$.name$ = *newVal.(*$.type|raw$)\n", args)
sw.Do("}\n", nil)
}
default:
sw.Do("if in.$.name$ == nil {\n", args)
sw.Do("out.$.name$ = nil\n", args)
sw.Do("} else if newVal, err := c.DeepCopy(in.$.name$); err != nil {\n", args)
sw.Do("} else if newVal, err := c.DeepCopy(&in.$.name$); err != nil {\n", args)
sw.Do("return err\n", nil)
sw.Do("} else {\n", nil)
sw.Do("out.$.name$ = newVal.($.type|raw$)\n", args)
sw.Do("out.$.name$ = *newVal.(*$.type|raw$)\n", args)
sw.Do("}\n", nil)
}
}
Expand All @@ -587,21 +587,23 @@ func (g *genDeepCopy) doInterface(t *types.Type, sw *generator.SnippetWriter) {
}

func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("*out = new($.Elem|raw$)\n", t)
if hasDeepCopyMethod(t.Elem) {
sw.Do("**out = in.DeepCopy()\n", nil)
sw.Do("*out = new($.Elem|raw$)\n", t)
sw.Do("**out = (*in).DeepCopy()\n", nil)
} else if t.Elem.IsAssignable() {
sw.Do("**out = *in", nil)
sw.Do("*out = new($.Elem|raw$)\n", t)
sw.Do("**out = **in", nil)
} else if g.copyableAndInBounds(t.Elem) {
funcName := g.funcNameTmpl(t.Elem)
sw.Do("*out = new($.Elem|raw$)\n", t)
sw.Do(fmt.Sprintf("if err := %s(*in, *out, c); err != nil {\n", funcName), argsFromType(t.Elem))
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
} else {
sw.Do("if newVal, err := c.DeepCopy(*in); err != nil {\n", nil)
sw.Do("return err\n", nil)
sw.Do("} else {\n", nil)
sw.Do("**out = newVal.($.|raw$)\n", t.Elem)
sw.Do("*out = newVal.($.|raw$)\n", t.Elem)
sw.Do("}\n", nil)
}
}
Expand Down
27 changes: 17 additions & 10 deletions pkg/conversion/cloner.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ func NewCloner() *Cloner {
}

// Prevent recursing into every byte...
func byteSliceDeepCopy(in []byte, out *[]byte, c *Cloner) error {
if in != nil {
*out = make([]byte, len(in))
copy(*out, in)
func byteSliceDeepCopy(in *[]byte, out *[]byte, c *Cloner) error {
if *in != nil {
*out = make([]byte, len(*in))
copy(*out, *in)
} else {
*out = nil
}
Expand All @@ -63,10 +63,10 @@ func verifyDeepCopyFunctionSignature(ft reflect.Type) error {
if ft.NumOut() != 1 {
return fmt.Errorf("expected one 'out' param, got %v", ft)
}
if ft.In(1).Kind() != reflect.Ptr {
return fmt.Errorf("expected pointer arg for 'in' param 1, got: %v", ft)
if ft.In(0).Kind() != reflect.Ptr {
return fmt.Errorf("expected pointer arg for 'in' param 0, got: %v", ft)
}
if ft.In(1).Elem() != ft.In(0) {
if ft.In(1) != ft.In(0) {
return fmt.Errorf("expected 'in' param 0 the same as param 1, got: %v", ft)
}
var forClonerType Cloner
Expand Down Expand Up @@ -135,6 +135,13 @@ func (c *Cloner) DeepCopy(in interface{}) (interface{}, error) {
func (c *Cloner) deepCopy(src reflect.Value) (reflect.Value, error) {
inType := src.Type()

switch src.Kind() {
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
if src.IsNil() {
return src, nil
}
}

if fv, ok := c.deepCopyFuncs[inType]; ok {
return c.customDeepCopy(src, fv)
}
Expand All @@ -145,15 +152,15 @@ func (c *Cloner) deepCopy(src reflect.Value) (reflect.Value, error) {
}

func (c *Cloner) customDeepCopy(src, fv reflect.Value) (reflect.Value, error) {
outValue := reflect.New(src.Type())
outValue := reflect.New(src.Type().Elem())
args := []reflect.Value{src, outValue, reflect.ValueOf(c)}
result := fv.Call(args)[0].Interface()
// This convolution is necessary because nil interfaces won't convert
// to error.
if result == nil {
return outValue.Elem(), nil
return outValue, nil
}
return outValue.Elem(), result.(error)
return outValue, result.(error)
}

func (c *Cloner) defaultDeepCopy(src reflect.Value) (reflect.Value, error) {
Expand Down

0 comments on commit 6049623

Please sign in to comment.