From e1825f3e42a4bc0453dbded0f9206561fcb78b50 Mon Sep 17 00:00:00 2001 From: molon <3739161+molon@users.noreply.github.com> Date: Wed, 28 Sep 2022 13:26:58 +0800 Subject: [PATCH 1/2] fix frozeWithCacheReuse --- adapter.go | 8 ++++---- config.go | 24 +++++++++++++++--------- extension_tests/extension_test.go | 20 +++++++++++++++++--- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/adapter.go b/adapter.go index 92d2cc4a..ba960ae8 100644 --- a/adapter.go +++ b/adapter.go @@ -100,7 +100,7 @@ func (adapter *Decoder) Buffered() io.Reader { func (adapter *Decoder) UseNumber() { cfg := adapter.iter.cfg.configBeforeFrozen cfg.UseNumber = true - adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions) + adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg) } // DisallowUnknownFields causes the Decoder to return an error when the destination @@ -109,7 +109,7 @@ func (adapter *Decoder) UseNumber() { func (adapter *Decoder) DisallowUnknownFields() { cfg := adapter.iter.cfg.configBeforeFrozen cfg.DisallowUnknownFields = true - adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions) + adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg) } // NewEncoder same as json.NewEncoder @@ -134,14 +134,14 @@ func (adapter *Encoder) Encode(val interface{}) error { func (adapter *Encoder) SetIndent(prefix, indent string) { config := adapter.stream.cfg.configBeforeFrozen config.IndentionStep = len(indent) - adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions) + adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg) } // SetEscapeHTML escape html by default, set to false to disable func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) { config := adapter.stream.cfg.configBeforeFrozen config.EscapeHTML = escapeHTML - adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions) + adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg) } // Valid reports whether data is a valid JSON encoding. diff --git a/config.go b/config.go index 2adcdc3b..6de4d51e 100644 --- a/config.go +++ b/config.go @@ -113,16 +113,16 @@ func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder { var cfgCache = concurrent.NewMap() -func getFrozenConfigFromCache(cfg Config) *frozenConfig { - obj, found := cfgCache.Load(cfg) +func getFrozenConfigFromCache(key interface{}) *frozenConfig { + obj, found := cfgCache.Load(key) if found { return obj.(*frozenConfig) } return nil } -func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) { - cfgCache.Store(cfg, frozenConfig) +func addFrozenConfigToCache(key interface{}, frozenConfig *frozenConfig) { + cfgCache.Store(key, frozenConfig) } // Froze forge API from config @@ -166,16 +166,22 @@ func (cfg Config) Froze() API { return api } -func (cfg Config) frozeWithCacheReuse(extraExtensions []Extension) *frozenConfig { - api := getFrozenConfigFromCache(cfg) +type configKey struct { + Config + cause *frozenConfig +} + +func (cfg Config) frozeWithCacheReuse(cause *frozenConfig) *frozenConfig { + key := configKey{cfg, cause} + api := getFrozenConfigFromCache(key) if api != nil { return api } api = cfg.Froze().(*frozenConfig) - for _, extension := range extraExtensions { + for _, extension := range cause.extraExtensions { api.RegisterExtension(extension) } - addFrozenConfigToCache(cfg, api) + addFrozenConfigToCache(key, api) return api } @@ -317,7 +323,7 @@ func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([] } newCfg := cfg.configBeforeFrozen newCfg.IndentionStep = len(indent) - return newCfg.frozeWithCacheReuse(cfg.extraExtensions).Marshal(v) + return newCfg.frozeWithCacheReuse(cfg).Marshal(v) } func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error { diff --git a/extension_tests/extension_test.go b/extension_tests/extension_test.go index 836db5bc..26fd9b12 100644 --- a/extension_tests/extension_test.go +++ b/extension_tests/extension_test.go @@ -1,13 +1,14 @@ package test import ( - "github.com/json-iterator/go" - "github.com/modern-go/reflect2" - "github.com/stretchr/testify/require" "reflect" "strconv" "testing" "unsafe" + + jsoniter "github.com/json-iterator/go" + "github.com/modern-go/reflect2" + "github.com/stretchr/testify/require" ) type TestObject1 struct { @@ -59,6 +60,19 @@ func Test_customize_map_key_encoder(t *testing.T) { m = map[int]int{} should.NoError(cfg.UnmarshalFromString(output, &m)) should.Equal(map[int]int{1: 2}, m) + + b, err := cfg.MarshalIndent(m, "", " ") + should.NoError(err) + should.Equal(`{ + "2": 2 +}`, string(b)) + + cfg = jsoniter.Config{}.Froze() // without testMapKeyExtension + b, err = cfg.MarshalIndent(m, "", " ") + should.NoError(err) + should.Equal(`{ + "1": 2 +}`, string(b)) } type testMapKeyExtension struct { From e1382e8d150328ec3d9f5e02b3e7642b1d306983 Mon Sep 17 00:00:00 2001 From: molon <3739161+molon@users.noreply.github.com> Date: Wed, 28 Sep 2022 13:36:44 +0800 Subject: [PATCH 2/2] getFrozenConfigFromCache use cfgKey instead of interface{} --- config.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config.go b/config.go index 6de4d51e..7cd22a4c 100644 --- a/config.go +++ b/config.go @@ -113,7 +113,12 @@ func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder { var cfgCache = concurrent.NewMap() -func getFrozenConfigFromCache(key interface{}) *frozenConfig { +type cfgKey struct { + Config + cause *frozenConfig +} + +func getFrozenConfigFromCache(key cfgKey) *frozenConfig { obj, found := cfgCache.Load(key) if found { return obj.(*frozenConfig) @@ -121,7 +126,7 @@ func getFrozenConfigFromCache(key interface{}) *frozenConfig { return nil } -func addFrozenConfigToCache(key interface{}, frozenConfig *frozenConfig) { +func addFrozenConfigToCache(key cfgKey, frozenConfig *frozenConfig) { cfgCache.Store(key, frozenConfig) } @@ -166,13 +171,8 @@ func (cfg Config) Froze() API { return api } -type configKey struct { - Config - cause *frozenConfig -} - func (cfg Config) frozeWithCacheReuse(cause *frozenConfig) *frozenConfig { - key := configKey{cfg, cause} + key := cfgKey{cfg, cause} api := getFrozenConfigFromCache(key) if api != nil { return api