Skip to content

Commit

Permalink
use sync.OnceFunc instead of sync.Once
Browse files Browse the repository at this point in the history
sync.OnceFunc was added in Go 1.21 and simplifies the code slightly.
Worth noting that, compared to Once, OnceFunc does a bit more work
as it replays any panic that happens on the first call:

    goos: linux
    goarch: amd64
    pkg: github.com/go-json-experiment/json
    cpu: AMD Ryzen 7 PRO 5850U with Radeon Graphics
                                                  │     old     │                new                │
                                                  │   sec/op    │   sec/op     vs base              │
    Testdata/CanadaGeometry/Marshal/Concrete-8      1.311m ± 0%   1.339m ± 0%  +2.17% (p=0.002 n=6)
    Testdata/CanadaGeometry/Marshal/Interface-8     1.347m ± 1%   1.434m ± 0%  +6.46% (p=0.002 n=6)
    Testdata/CanadaGeometry/Unmarshal/Concrete-8    1.832m ± 0%   1.867m ± 0%  +1.92% (p=0.002 n=6)
    Testdata/CanadaGeometry/Unmarshal/Interface-8   2.962m ± 0%   2.827m ± 1%  -4.54% (p=0.002 n=6)
    geomean                                         1.759m        1.785m       +1.43%
  • Loading branch information
mvdan committed Apr 2, 2024
1 parent 908677b commit 2449b35
Showing 1 changed file with 23 additions and 34 deletions.
57 changes: 23 additions & 34 deletions arshal_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,14 +612,13 @@ func makeMapArshaler(t reflect.Type) *arshaler {

var fncs arshaler
var (
once sync.Once
keyFncs *arshaler
valFncs *arshaler
)
init := func() {
initOnce := sync.OnceFunc(func() {
keyFncs = lookupArshaler(t.Key())
valFncs = lookupArshaler(t.Elem())
}
})
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
// Check for cycles.
xe := export.Encoder(enc)
Expand Down Expand Up @@ -661,7 +660,7 @@ func makeMapArshaler(t reflect.Type) *arshaler {
}
}

once.Do(init)
initOnce()
if err := enc.WriteToken(jsontext.ObjectStart); err != nil {
return err
}
Expand Down Expand Up @@ -792,7 +791,7 @@ func makeMapArshaler(t reflect.Type) *arshaler {
va.SetZero()
return nil
case '{':
once.Do(init)
initOnce()
if va.IsNil() {
va.Set(reflect.MakeMap(t))
}
Expand Down Expand Up @@ -900,19 +899,18 @@ func makeStructArshaler(t reflect.Type) *arshaler {

var fncs arshaler
var (
once sync.Once
fields structFields
errInit *SemanticError
)
init := func() {
initOnce := sync.OnceFunc(func() {
fields, errInit = makeStructFields(t)
}
})
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
return newInvalidFormatError("marshal", t, mo.Format)
}
once.Do(init)
initOnce()
if errInit != nil {
err := *errInit // shallow copy SemanticError
err.action = "marshal"
Expand Down Expand Up @@ -1080,7 +1078,7 @@ func makeStructArshaler(t reflect.Type) *arshaler {
va.SetZero()
return nil
case '{':
once.Do(init)
initOnce()
if errInit != nil {
err := *errInit // shallow copy SemanticError
err.action = "unmarshal"
Expand Down Expand Up @@ -1214,13 +1212,10 @@ func isLegacyEmpty(v addressableValue) bool {

func makeSliceArshaler(t reflect.Type) *arshaler {
var fncs arshaler
var (
once sync.Once
valFncs *arshaler
)
init := func() {
var valFncs *arshaler
initOnce := sync.OnceFunc(func() {
valFncs = lookupArshaler(t.Elem())
}
})
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
// Check for cycles.
xe := export.Encoder(enc)
Expand Down Expand Up @@ -1262,7 +1257,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler {
}
}

once.Do(init)
initOnce()
if err := enc.WriteToken(jsontext.ArrayStart); err != nil {
return err
}
Expand Down Expand Up @@ -1303,7 +1298,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler {
va.SetZero()
return nil
case '[':
once.Do(init)
initOnce()
unmarshal := valFncs.unmarshal
if uo.Unmarshalers != nil {
unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t.Elem())
Expand Down Expand Up @@ -1348,20 +1343,17 @@ func makeSliceArshaler(t reflect.Type) *arshaler {

func makeArrayArshaler(t reflect.Type) *arshaler {
var fncs arshaler
var (
once sync.Once
valFncs *arshaler
)
init := func() {
var valFncs *arshaler
initOnce := sync.OnceFunc(func() {
valFncs = lookupArshaler(t.Elem())
}
})
n := t.Len()
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
return newInvalidFormatError("marshal", t, mo.Format)
}
once.Do(init)
initOnce()
if err := enc.WriteToken(jsontext.ArrayStart); err != nil {
return err
}
Expand Down Expand Up @@ -1395,7 +1387,7 @@ func makeArrayArshaler(t reflect.Type) *arshaler {
va.SetZero()
return nil
case '[':
once.Do(init)
initOnce()
unmarshal := valFncs.unmarshal
if uo.Unmarshalers != nil {
unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t.Elem())
Expand Down Expand Up @@ -1441,13 +1433,10 @@ func makeArrayArshaler(t reflect.Type) *arshaler {

func makePointerArshaler(t reflect.Type) *arshaler {
var fncs arshaler
var (
once sync.Once
valFncs *arshaler
)
init := func() {
var valFncs *arshaler
initOnce := sync.OnceFunc(func() {
valFncs = lookupArshaler(t.Elem())
}
})
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
// Check for cycles.
xe := export.Encoder(enc)
Expand All @@ -1462,7 +1451,7 @@ func makePointerArshaler(t reflect.Type) *arshaler {
if va.IsNil() {
return enc.WriteToken(jsontext.Null)
}
once.Do(init)
initOnce()
marshal := valFncs.marshal
if mo.Marshalers != nil {
marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t.Elem())
Expand All @@ -1479,7 +1468,7 @@ func makePointerArshaler(t reflect.Type) *arshaler {
va.SetZero()
return nil
}
once.Do(init)
initOnce()
unmarshal := valFncs.unmarshal
if uo.Unmarshalers != nil {
unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t.Elem())
Expand Down

0 comments on commit 2449b35

Please sign in to comment.