Skip to content

Commit

Permalink
cue: use append-like funcs inside Value.MarshalJSON
Browse files Browse the repository at this point in the history
So that we can reuse buffers where possible rather than making new ones
only to copy the data over to the final buffer.

Note that this doesn't happen everywhere yet, as the underlying API
we use to marshal literals is json.Marshal, which is not append-like.

                            │     old      │                new                 │
                            │    sec/op    │   sec/op     vs base               │
    LargeValueMarshalJSON-8   12.240m ± 1%   7.772m ± 1%  -36.50% (p=0.002 n=6)

                            │      old      │                 new                 │
                            │     B/op      │     B/op      vs base               │
    LargeValueMarshalJSON-8   23.508Mi ± 0%   7.158Mi ± 0%  -69.55% (p=0.002 n=6)

                            │     old     │                new                 │
                            │  allocs/op  │  allocs/op   vs base               │
    LargeValueMarshalJSON-8   78.36k ± 0%   70.28k ± 0%  -10.32% (p=0.002 n=6)

Updates cue-lang#2470.

Signed-off-by: Daniel Martí <[email protected]>
Change-Id: Idd806ce52f9726ffd87d6bf71c2759131d2553a5
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1201808
Unity-Result: CUE porcuepine <[email protected]>
Reviewed-by: Roger Peppe <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
  • Loading branch information
mvdan committed Sep 25, 2024
1 parent 3f1e72b commit fed4998
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 19 deletions.
2 changes: 1 addition & 1 deletion cue/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func (d *decoder) decode(x reflect.Value, v Value, isPtr bool) {
ij, it, x := indirect(x, v.IsNull())

if ij != nil {
b, err := v.marshalJSON()
b, err := v.appendJSON(nil)
d.addErr(err)
d.addErr(ij.UnmarshalJSON(b))
return
Expand Down
38 changes: 20 additions & 18 deletions cue/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func (o *hiddenStructValue) Lookup(key string) Value {

// MarshalJSON returns a valid JSON encoding or reports an error if any of the
// fields is invalid.
func (o *structValue) marshalJSON() (b []byte, err error) {
func (o *structValue) appendJSON(b []byte) ([]byte, error) {
b = append(b, '{')
n := o.Len()
for i := range n {
Expand All @@ -154,11 +154,10 @@ func (o *structValue) marshalJSON() (b []byte, err error) {
}
b = append(b, s...)
b = append(b, ':')
bb, err := v.marshalJSON()
b, err = v.appendJSON(b)
if err != nil {
return nil, err
}
b = append(b, bb...)
if i < n-1 {
b = append(b, ',')
}
Expand Down Expand Up @@ -294,15 +293,15 @@ func (i *hiddenIterator) IsDefinition() bool {

// marshalJSON iterates over the list and generates JSON output. HasNext
// will return false after this operation.
func marshalList(l *Iterator) (b []byte, err error) {
func listAppendJSON(b []byte, l *Iterator) ([]byte, error) {
b = append(b, '[')
if l.Next() {
for i := 0; ; i++ {
x, err := l.Value().marshalJSON()
var err error
b, err = l.Value().appendJSON(b)
if err != nil {
return nil, err
}
b = append(b, x...)
if !l.Next() {
break
}
Expand Down Expand Up @@ -901,17 +900,17 @@ func (v Value) IncompleteKind() Kind {

// MarshalJSON marshalls this value into valid JSON.
func (v Value) MarshalJSON() (b []byte, err error) {
b, err = v.marshalJSON()
b, err = v.appendJSON(nil)
if err != nil {
return nil, unwrapJSONError(err)
}
return b, nil
}

func (v Value) marshalJSON() (b []byte, err error) {
func (v Value) appendJSON(b []byte) ([]byte, error) {
v, _ = v.Default()
if v.v == nil {
return []byte("null"), nil
return append(b, "null"...), nil
}
ctx := newContext(v.idx)
x := v.eval(ctx)
Expand All @@ -926,26 +925,29 @@ func (v Value) marshalJSON() (b []byte, err error) {
// TODO: implement marshalles in value.
switch k := x.Kind(); k {
case adt.NullKind:
return []byte("null"), nil
return append(b, "null"...), nil
case adt.BoolKind:
return internaljson.Marshal(x.(*adt.Bool).B)
b2, err := internaljson.Marshal(x.(*adt.Bool).B)
return append(b, b2...), err
case adt.IntKind, adt.FloatKind, adt.NumberKind:
b, err := x.(*adt.Num).X.MarshalText()
b = bytes.TrimLeft(b, "+")
return b, err
b2, err := x.(*adt.Num).X.MarshalText()
b2 = bytes.TrimLeft(b2, "+")
return append(b, b2...), err
case adt.StringKind:
return internaljson.Marshal(x.(*adt.String).Str)
b2, err := internaljson.Marshal(x.(*adt.String).Str)
return append(b, b2...), err
case adt.BytesKind:
return internaljson.Marshal(x.(*adt.Bytes).B)
b2, err := internaljson.Marshal(x.(*adt.Bytes).B)
return append(b, b2...), err
case adt.ListKind:
i, _ := v.List()
return marshalList(&i)
return listAppendJSON(b, &i)
case adt.StructKind:
obj, err := v.structValData(ctx)
if err != nil {
return nil, toMarshalErr(v, err)
}
return obj.marshalJSON()
return obj.appendJSON(b)
case adt.BottomKind:
return nil, toMarshalErr(v, x.(*adt.Bottom))
default:
Expand Down

0 comments on commit fed4998

Please sign in to comment.