1
0
mirror of https://github.com/json-iterator/go.git synced 2025-05-28 22:17:38 +02:00

#53 split config into Config and frozenConfig

This commit is contained in:
Tao Wen 2017-06-13 18:49:35 +08:00
parent d0418857ce
commit d867c8ba5c
11 changed files with 61 additions and 65 deletions

View File

@ -172,7 +172,7 @@ func (decoder *AdaptedDecoder) UseNumber() {
} }
func NewEncoder(writer io.Writer) *AdaptedEncoder { func NewEncoder(writer io.Writer) *AdaptedEncoder {
stream := NewStream(&Config{}, writer, 512) stream := NewStream(Config{}.Froze(), writer, 512)
return &AdaptedEncoder{stream} return &AdaptedEncoder{stream}
} }
@ -187,5 +187,5 @@ func (adapter *AdaptedEncoder) Encode(val interface{}) error {
} }
func (adapter *AdaptedEncoder) SetIndent(prefix, indent string) { func (adapter *AdaptedEncoder) SetIndent(prefix, indent string) {
adapter.stream.cfg.IndentionStep = len(indent) adapter.stream.cfg.indentionStep = len(indent)
} }

View File

@ -11,37 +11,38 @@ type Config struct {
IndentionStep int IndentionStep int
MarshalFloatWith6Digits bool MarshalFloatWith6Digits bool
SupportUnexportedStructFields bool SupportUnexportedStructFields bool
}
type frozenConfig struct {
indentionStep int
decoderCache unsafe.Pointer decoderCache unsafe.Pointer
encoderCache unsafe.Pointer encoderCache unsafe.Pointer
extensions []ExtensionFunc extensions []ExtensionFunc
} }
var DEFAULT_CONFIG = &Config{} var DEFAULT_CONFIG = Config{}.Froze()
func init() { func (cfg Config) Froze() *frozenConfig {
DEFAULT_CONFIG.init() frozenConfig := &frozenConfig{
} indentionStep: cfg.IndentionStep,
func (cfg *Config) init() *Config {
if cfg.encoderCache == nil {
atomic.StorePointer(&cfg.decoderCache, unsafe.Pointer(&map[string]Decoder{}))
atomic.StorePointer(&cfg.encoderCache, unsafe.Pointer(&map[string]Encoder{}))
if cfg.MarshalFloatWith6Digits {
cfg.marshalFloatWith6Digits()
}
if cfg.SupportUnexportedStructFields {
cfg.supportUnexportedStructFields()
}
} }
return cfg atomic.StorePointer(&frozenConfig.decoderCache, unsafe.Pointer(&map[string]Decoder{}))
atomic.StorePointer(&frozenConfig.encoderCache, unsafe.Pointer(&map[string]Encoder{}))
if cfg.MarshalFloatWith6Digits {
frozenConfig.marshalFloatWith6Digits()
}
if cfg.SupportUnexportedStructFields {
frozenConfig.supportUnexportedStructFields()
}
return frozenConfig
} }
// RegisterExtension can register a custom extension // RegisterExtension can register a custom extension
func (cfg *Config) RegisterExtension(extension ExtensionFunc) { func (cfg *frozenConfig) RegisterExtension(extension ExtensionFunc) {
cfg.extensions = append(cfg.extensions, extension) cfg.extensions = append(cfg.extensions, extension)
} }
func (cfg *Config) supportUnexportedStructFields() { func (cfg *frozenConfig) supportUnexportedStructFields() {
cfg.RegisterExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc) { cfg.RegisterExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc) {
return []string{field.Name}, nil, nil return []string{field.Name}, nil, nil
}) })
@ -49,7 +50,7 @@ func (cfg *Config) supportUnexportedStructFields() {
// EnableLossyFloatMarshalling keeps 10**(-6) precision // EnableLossyFloatMarshalling keeps 10**(-6) precision
// for float variables for better performance. // for float variables for better performance.
func (cfg *Config) marshalFloatWith6Digits() { func (cfg *frozenConfig) marshalFloatWith6Digits() {
// for better performance // for better performance
cfg.addEncoderToCache(reflect.TypeOf((*float32)(nil)).Elem(), &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) { cfg.addEncoderToCache(reflect.TypeOf((*float32)(nil)).Elem(), &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
val := *((*float32)(ptr)) val := *((*float32)(ptr))
@ -61,7 +62,7 @@ func (cfg *Config) marshalFloatWith6Digits() {
}}) }})
} }
func (cfg *Config) addDecoderToCache(cacheKey reflect.Type, decoder Decoder) { func (cfg *frozenConfig) addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
done := false done := false
for !done { for !done {
ptr := atomic.LoadPointer(&cfg.decoderCache) ptr := atomic.LoadPointer(&cfg.decoderCache)
@ -75,7 +76,7 @@ func (cfg *Config) addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
} }
} }
func (cfg *Config) addEncoderToCache(cacheKey reflect.Type, encoder Encoder) { func (cfg *frozenConfig) addEncoderToCache(cacheKey reflect.Type, encoder Encoder) {
done := false done := false
for !done { for !done {
ptr := atomic.LoadPointer(&cfg.encoderCache) ptr := atomic.LoadPointer(&cfg.encoderCache)
@ -89,33 +90,33 @@ func (cfg *Config) addEncoderToCache(cacheKey reflect.Type, encoder Encoder) {
} }
} }
func (cfg *Config) getDecoderFromCache(cacheKey reflect.Type) Decoder { func (cfg *frozenConfig) getDecoderFromCache(cacheKey reflect.Type) Decoder {
ptr := atomic.LoadPointer(&cfg.decoderCache) ptr := atomic.LoadPointer(&cfg.decoderCache)
cache := *(*map[reflect.Type]Decoder)(ptr) cache := *(*map[reflect.Type]Decoder)(ptr)
return cache[cacheKey] return cache[cacheKey]
} }
func (cfg *Config) getEncoderFromCache(cacheKey reflect.Type) Encoder { func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) Encoder {
ptr := atomic.LoadPointer(&cfg.encoderCache) ptr := atomic.LoadPointer(&cfg.encoderCache)
cache := *(*map[reflect.Type]Encoder)(ptr) cache := *(*map[reflect.Type]Encoder)(ptr)
return cache[cacheKey] return cache[cacheKey]
} }
// CleanDecoders cleans decoders registered or cached // CleanDecoders cleans decoders registered or cached
func (cfg *Config) CleanDecoders() { func (cfg *frozenConfig) CleanDecoders() {
typeDecoders = map[string]Decoder{} typeDecoders = map[string]Decoder{}
fieldDecoders = map[string]Decoder{} fieldDecoders = map[string]Decoder{}
atomic.StorePointer(&cfg.decoderCache, unsafe.Pointer(&map[string]Decoder{})) atomic.StorePointer(&cfg.decoderCache, unsafe.Pointer(&map[string]Decoder{}))
} }
// CleanEncoders cleans encoders registered or cached // CleanEncoders cleans encoders registered or cached
func (cfg *Config) CleanEncoders() { func (cfg *frozenConfig) CleanEncoders() {
typeEncoders = map[string]Encoder{} typeEncoders = map[string]Encoder{}
fieldEncoders = map[string]Encoder{} fieldEncoders = map[string]Encoder{}
atomic.StorePointer(&cfg.encoderCache, unsafe.Pointer(&map[string]Encoder{})) atomic.StorePointer(&cfg.encoderCache, unsafe.Pointer(&map[string]Encoder{}))
} }
func (cfg *Config) MarshalToString(v interface{}) (string, error) { func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) {
buf, err := cfg.Marshal(v) buf, err := cfg.Marshal(v)
if err != nil { if err != nil {
return "", err return "", err
@ -123,8 +124,7 @@ func (cfg *Config) MarshalToString(v interface{}) (string, error) {
return string(buf), nil return string(buf), nil
} }
func (cfg *Config) Marshal(v interface{}) ([]byte, error) { func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) {
cfg.init()
stream := NewStream(cfg, nil, 256) stream := NewStream(cfg, nil, 256)
stream.WriteVal(v) stream.WriteVal(v)
if stream.Error != nil { if stream.Error != nil {
@ -133,7 +133,7 @@ func (cfg *Config) Marshal(v interface{}) ([]byte, error) {
return stream.Buffer(), nil return stream.Buffer(), nil
} }
func (cfg *Config) UnmarshalFromString(str string, v interface{}) error { func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error {
data := []byte(str) data := []byte(str)
data = data[:lastNotSpacePos(data)] data = data[:lastNotSpacePos(data)]
iter := ParseBytes(cfg, data) iter := ParseBytes(cfg, data)

View File

@ -66,7 +66,7 @@ func init() {
// Iterator is a fast and flexible JSON parser // Iterator is a fast and flexible JSON parser
type Iterator struct { type Iterator struct {
cfg *Config cfg *frozenConfig
reader io.Reader reader io.Reader
buf []byte buf []byte
head int head int
@ -75,8 +75,7 @@ type Iterator struct {
} }
// Create creates an empty Iterator instance // Create creates an empty Iterator instance
func NewIterator(cfg *Config) *Iterator { func NewIterator(cfg *frozenConfig) *Iterator {
cfg.init()
return &Iterator{ return &Iterator{
cfg: cfg, cfg: cfg,
reader: nil, reader: nil,
@ -87,8 +86,7 @@ func NewIterator(cfg *Config) *Iterator {
} }
// Parse parses a json buffer in io.Reader into an Iterator instance // Parse parses a json buffer in io.Reader into an Iterator instance
func Parse(cfg *Config, reader io.Reader, bufSize int) *Iterator { func Parse(cfg *frozenConfig, reader io.Reader, bufSize int) *Iterator {
cfg.init()
return &Iterator{ return &Iterator{
cfg: cfg, cfg: cfg,
reader: reader, reader: reader,
@ -99,8 +97,7 @@ func Parse(cfg *Config, reader io.Reader, bufSize int) *Iterator {
} }
// ParseBytes parses a json byte slice into an Iterator instance // ParseBytes parses a json byte slice into an Iterator instance
func ParseBytes(cfg *Config, input []byte) *Iterator { func ParseBytes(cfg *frozenConfig, input []byte) *Iterator {
cfg.init()
return &Iterator{ return &Iterator{
cfg: cfg, cfg: cfg,
reader: nil, reader: nil,
@ -111,7 +108,7 @@ func ParseBytes(cfg *Config, input []byte) *Iterator {
} }
// ParseString parses a json string into an Iterator instance // ParseString parses a json string into an Iterator instance
func ParseString(cfg *Config, input string) *Iterator { func ParseString(cfg *frozenConfig, input string) *Iterator {
return ParseBytes(cfg, []byte(input)) return ParseBytes(cfg, []byte(input))
} }

View File

@ -264,7 +264,7 @@ func (p prefix) addToEncoder(encoder Encoder, err error) (Encoder, error) {
return encoder, err return encoder, err
} }
func decoderOfType(cfg *Config, typ reflect.Type) (Decoder, error) { func decoderOfType(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
typeName := typ.String() typeName := typ.String()
typeDecoder := typeDecoders[typeName] typeDecoder := typeDecoders[typeName]
if typeDecoder != nil { if typeDecoder != nil {
@ -289,7 +289,7 @@ func decoderOfType(cfg *Config, typ reflect.Type) (Decoder, error) {
return newDecoder, err return newDecoder, err
} }
func createDecoderOfType(cfg *Config, typ reflect.Type) (Decoder, error) { func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
if typ.String() == "[]uint8" { if typ.String() == "[]uint8" {
return &base64Codec{}, nil return &base64Codec{}, nil
} }
@ -354,7 +354,7 @@ func createDecoderOfType(cfg *Config, typ reflect.Type) (Decoder, error) {
} }
} }
func encoderOfType(cfg *Config, typ reflect.Type) (Encoder, error) { func encoderOfType(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
typeName := typ.String() typeName := typ.String()
typeEncoder := typeEncoders[typeName] typeEncoder := typeEncoders[typeName]
if typeEncoder != nil { if typeEncoder != nil {
@ -379,7 +379,7 @@ func encoderOfType(cfg *Config, typ reflect.Type) (Encoder, error) {
return newEncoder, err return newEncoder, err
} }
func createEncoderOfType(cfg *Config, typ reflect.Type) (Encoder, error) { func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
if typ.String() == "[]uint8" { if typ.String() == "[]uint8" {
return &base64Codec{}, nil return &base64Codec{}, nil
} }
@ -445,7 +445,7 @@ func createEncoderOfType(cfg *Config, typ reflect.Type) (Encoder, error) {
} }
} }
func decoderOfOptional(cfg *Config, typ reflect.Type) (Decoder, error) { func decoderOfOptional(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
elemType := typ.Elem() elemType := typ.Elem()
decoder, err := decoderOfType(cfg, elemType) decoder, err := decoderOfType(cfg, elemType)
if err != nil { if err != nil {
@ -454,7 +454,7 @@ func decoderOfOptional(cfg *Config, typ reflect.Type) (Decoder, error) {
return &optionalDecoder{elemType, decoder}, nil return &optionalDecoder{elemType, decoder}, nil
} }
func encoderOfOptional(cfg *Config, typ reflect.Type) (Encoder, error) { func encoderOfOptional(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
elemType := typ.Elem() elemType := typ.Elem()
elemEncoder, err := encoderOfType(cfg, elemType) elemEncoder, err := encoderOfType(cfg, elemType)
if err != nil { if err != nil {
@ -467,7 +467,7 @@ func encoderOfOptional(cfg *Config, typ reflect.Type) (Encoder, error) {
return encoder, nil return encoder, nil
} }
func decoderOfMap(cfg *Config, typ reflect.Type) (Decoder, error) { func decoderOfMap(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
decoder, err := decoderOfType(cfg, typ.Elem()) decoder, err := decoderOfType(cfg, typ.Elem())
if err != nil { if err != nil {
return nil, err return nil, err
@ -480,7 +480,7 @@ func extractInterface(val interface{}) emptyInterface {
return *((*emptyInterface)(unsafe.Pointer(&val))) return *((*emptyInterface)(unsafe.Pointer(&val)))
} }
func encoderOfMap(cfg *Config, typ reflect.Type) (Encoder, error) { func encoderOfMap(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
elemType := typ.Elem() elemType := typ.Elem()
encoder, err := encoderOfType(cfg, elemType) encoder, err := encoderOfType(cfg, elemType)
if err != nil { if err != nil {

View File

@ -7,7 +7,7 @@ import (
"unsafe" "unsafe"
) )
func decoderOfSlice(cfg *Config, typ reflect.Type) (Decoder, error) { func decoderOfSlice(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
decoder, err := decoderOfType(cfg, typ.Elem()) decoder, err := decoderOfType(cfg, typ.Elem())
if err != nil { if err != nil {
return nil, err return nil, err
@ -15,7 +15,7 @@ func decoderOfSlice(cfg *Config, typ reflect.Type) (Decoder, error) {
return &sliceDecoder{typ, typ.Elem(), decoder}, nil return &sliceDecoder{typ, typ.Elem(), decoder}, nil
} }
func encoderOfSlice(cfg *Config, typ reflect.Type) (Encoder, error) { func encoderOfSlice(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
encoder, err := encoderOfType(cfg, typ.Elem()) encoder, err := encoderOfType(cfg, typ.Elem())
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -9,7 +9,7 @@ import (
"unsafe" "unsafe"
) )
func encoderOfStruct(cfg *Config, typ reflect.Type) (Encoder, error) { func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
structEncoder_ := &structEncoder{} structEncoder_ := &structEncoder{}
fields := map[string]*structFieldEncoder{} fields := map[string]*structFieldEncoder{}
for _, field := range listStructFields(typ) { for _, field := range listStructFields(typ) {
@ -80,7 +80,7 @@ func listStructFields(typ reflect.Type) []*reflect.StructField {
return fields return fields
} }
func decoderOfStruct(cfg *Config, typ reflect.Type) (Decoder, error) { func decoderOfStruct(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
fields := map[string]*structFieldDecoder{} fields := map[string]*structFieldDecoder{}
for i := 0; i < typ.NumField(); i++ { for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i) field := typ.Field(i)

View File

@ -5,7 +5,7 @@ import (
) )
type Stream struct { type Stream struct {
cfg *Config cfg *frozenConfig
out io.Writer out io.Writer
buf []byte buf []byte
n int n int
@ -13,8 +13,7 @@ type Stream struct {
indention int indention int
} }
func NewStream(cfg *Config, out io.Writer, bufSize int) *Stream { func NewStream(cfg *frozenConfig, out io.Writer, bufSize int) *Stream {
cfg.init()
return &Stream{ return &Stream{
cfg: cfg, cfg: cfg,
out: out, out: out,
@ -277,7 +276,7 @@ func (stream *Stream) WriteBool(val bool) {
} }
func (stream *Stream) WriteObjectStart() { func (stream *Stream) WriteObjectStart() {
stream.indention += stream.cfg.IndentionStep stream.indention += stream.cfg.indentionStep
stream.writeByte('{') stream.writeByte('{')
stream.writeIndention(0) stream.writeIndention(0)
} }
@ -288,8 +287,8 @@ func (stream *Stream) WriteObjectField(field string) {
} }
func (stream *Stream) WriteObjectEnd() { func (stream *Stream) WriteObjectEnd() {
stream.writeIndention(stream.cfg.IndentionStep) stream.writeIndention(stream.cfg.indentionStep)
stream.indention -= stream.cfg.IndentionStep stream.indention -= stream.cfg.indentionStep
stream.writeByte('}') stream.writeByte('}')
} }
@ -304,7 +303,7 @@ func (stream *Stream) WriteMore() {
} }
func (stream *Stream) WriteArrayStart() { func (stream *Stream) WriteArrayStart() {
stream.indention += stream.cfg.IndentionStep stream.indention += stream.cfg.indentionStep
stream.writeByte('[') stream.writeByte('[')
stream.writeIndention(0) stream.writeIndention(0)
} }
@ -315,8 +314,8 @@ func (stream *Stream) WriteEmptyArray() {
} }
func (stream *Stream) WriteArrayEnd() { func (stream *Stream) WriteArrayEnd() {
stream.writeIndention(stream.cfg.IndentionStep) stream.writeIndention(stream.cfg.indentionStep)
stream.indention -= stream.cfg.IndentionStep stream.indention -= stream.cfg.indentionStep
stream.writeByte(']') stream.writeByte(']')
} }

View File

@ -213,7 +213,7 @@ func Test_whitespace_before_comma(t *testing.T) {
func Test_write_array(t *testing.T) { func Test_write_array(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(&Config{IndentionStep: 2}, buf, 4096) stream := NewStream(Config{IndentionStep: 2}.Froze(), buf, 4096)
stream.WriteArrayStart() stream.WriteArrayStart()
stream.WriteInt(1) stream.WriteInt(1)
stream.WriteMore() stream.WriteMore()

View File

@ -60,7 +60,7 @@ func Test_customize_byte_array_encoder(t *testing.T) {
func Test_customize_float_marshal(t *testing.T) { func Test_customize_float_marshal(t *testing.T) {
should := require.New(t) should := require.New(t)
json := Config{MarshalFloatWith6Digits: true} json := Config{MarshalFloatWith6Digits: true}.Froze()
str, err := json.MarshalToString(float32(1.23456789)) str, err := json.MarshalToString(float32(1.23456789))
should.Nil(err) should.Nil(err)
should.Equal("1.234568", str) should.Equal("1.234568", str)
@ -112,7 +112,7 @@ func Test_customize_field_by_extension(t *testing.T) {
} }
func Test_unexported_fields(t *testing.T) { func Test_unexported_fields(t *testing.T) {
jsoniter := &Config{SupportUnexportedStructFields: true} jsoniter := Config{SupportUnexportedStructFields: true}.Froze()
should := require.New(t) should := require.New(t)
type TestObject struct { type TestObject struct {
field1 string field1 string

View File

@ -210,7 +210,7 @@ func Test_object_wrapper_any_get_all(t *testing.T) {
func Test_write_object(t *testing.T) { func Test_write_object(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(&Config{IndentionStep: 2}, buf, 4096) stream := NewStream(Config{IndentionStep: 2}.Froze(), buf, 4096)
stream.WriteObjectStart() stream.WriteObjectStart()
stream.WriteObjectField("hello") stream.WriteObjectField("hello")
stream.WriteInt(1) stream.WriteInt(1)

View File

@ -31,7 +31,7 @@ func Test_writeBytes_should_grow_buffer(t *testing.T) {
func Test_writeIndention_should_grow_buffer(t *testing.T) { func Test_writeIndention_should_grow_buffer(t *testing.T) {
should := require.New(t) should := require.New(t)
stream := NewStream(&Config{IndentionStep: 2}, nil, 1) stream := NewStream(Config{IndentionStep: 2}.Froze(), nil, 1)
stream.WriteVal([]int{1, 2, 3}) stream.WriteVal([]int{1, 2, 3})
should.Equal("[\n 1,\n 2,\n 3\n]", string(stream.Buffer())) should.Equal("[\n 1,\n 2,\n 3\n]", string(stream.Buffer()))
} }