diff --git a/benchmarks/encode_string_test.go b/benchmarks/encode_string_test.go new file mode 100644 index 0000000..40ac244 --- /dev/null +++ b/benchmarks/encode_string_test.go @@ -0,0 +1,25 @@ +package test + +import ( + "testing" + "github.com/json-iterator/go" + "bytes" +) + +func Benchmark_encode_string_with_SetEscapeHTML(b *testing.B) { + type V struct { + S string + B bool + I int + } + var json = jsoniter.ConfigCompatibleWithStandardLibrary + b.ReportAllocs() + for i := 0; i < b.N; i++ { + buf := &bytes.Buffer{} + enc := json.NewEncoder(buf) + enc.SetEscapeHTML(true) + if err := enc.Encode(V{S: "s", B: true, I: 233}); err != nil { + b.Fatal(err) + } + } +} diff --git a/feature_config.go b/feature_config.go index 2d2fc8c..cc1e75e 100644 --- a/feature_config.go +++ b/feature_config.go @@ -60,8 +60,11 @@ var ConfigFastest = Config{ // Froze forge API from config func (cfg Config) Froze() API { - // TODO: cache frozen config - frozenConfig := &frozenConfig{ + api := getFrozenConfigFromCache(cfg) + if api != nil { + return api + } + api = &frozenConfig{ sortMapKeys: cfg.SortMapKeys, indentionStep: cfg.IndentionStep, objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString, @@ -69,21 +72,22 @@ func (cfg Config) Froze() API { streamPool: make(chan *Stream, 16), iteratorPool: make(chan *Iterator, 16), } - frozenConfig.initCache() + api.initCache() if cfg.MarshalFloatWith6Digits { - frozenConfig.marshalFloatWith6Digits() + api.marshalFloatWith6Digits() } if cfg.EscapeHTML { - frozenConfig.escapeHTML() + api.escapeHTML() } if cfg.UseNumber { - frozenConfig.useNumber() + api.useNumber() } if cfg.ValidateJsonRawMessage { - frozenConfig.validateJsonRawMessage() + api.validateJsonRawMessage() } - frozenConfig.configBeforeFrozen = cfg - return frozenConfig + api.configBeforeFrozen = cfg + addFrozenConfigToCache(cfg, api) + return api } func (cfg *frozenConfig) validateJsonRawMessage() { diff --git a/feature_config_with_sync_map.go b/feature_config_with_sync_map.go index e81e1b7..3bee632 100644 --- a/feature_config_with_sync_map.go +++ b/feature_config_with_sync_map.go @@ -48,4 +48,18 @@ func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder { return encoder.(ValEncoder) } return nil +} + +var cfgCache = &sync.Map{} + +func getFrozenConfigFromCache(cfg Config) *frozenConfig { + obj, found := cfgCache.Load(cfg) + if found { + return obj.(*frozenConfig) + } + return nil +} + +func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) { + cfgCache.Store(cfg, frozenConfig) } \ No newline at end of file diff --git a/feature_config_without_sync_map.go b/feature_config_without_sync_map.go index f01f971..d91a583 100644 --- a/feature_config_without_sync_map.go +++ b/feature_config_without_sync_map.go @@ -52,3 +52,19 @@ func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder { cfg.cacheLock.RUnlock() return encoder } + +var cfgCacheLock = &sync.RWMutex{} +var cfgCache = map[Config]*frozenConfig{} + +func getFrozenConfigFromCache(cfg Config) *frozenConfig { + cfgCacheLock.RLock() + frozenConfig := cfgCache[cfg] + cfgCacheLock.RUnlock() + return frozenConfig +} + +func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) { + cfgCacheLock.Lock() + cfgCache[cfg] = frozenConfig + cfgCacheLock.Unlock() +}