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 {
stream := NewStream(&Config{}, writer, 512)
stream := NewStream(Config{}.Froze(), writer, 512)
return &AdaptedEncoder{stream}
}
@ -187,5 +187,5 @@ func (adapter *AdaptedEncoder) Encode(val interface{}) error {
}
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
MarshalFloatWith6Digits bool
SupportUnexportedStructFields bool
}
type frozenConfig struct {
indentionStep int
decoderCache unsafe.Pointer
encoderCache unsafe.Pointer
extensions []ExtensionFunc
}
var DEFAULT_CONFIG = &Config{}
var DEFAULT_CONFIG = Config{}.Froze()
func init() {
DEFAULT_CONFIG.init()
func (cfg Config) Froze() *frozenConfig {
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{}))
atomic.StorePointer(&frozenConfig.decoderCache, unsafe.Pointer(&map[string]Decoder{}))
atomic.StorePointer(&frozenConfig.encoderCache, unsafe.Pointer(&map[string]Encoder{}))
if cfg.MarshalFloatWith6Digits {
cfg.marshalFloatWith6Digits()
frozenConfig.marshalFloatWith6Digits()
}
if cfg.SupportUnexportedStructFields {
cfg.supportUnexportedStructFields()
frozenConfig.supportUnexportedStructFields()
}
}
return cfg
return frozenConfig
}
// RegisterExtension can register a custom extension
func (cfg *Config) RegisterExtension(extension ExtensionFunc) {
func (cfg *frozenConfig) RegisterExtension(extension ExtensionFunc) {
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) {
return []string{field.Name}, nil, nil
})
@ -49,7 +50,7 @@ func (cfg *Config) supportUnexportedStructFields() {
// EnableLossyFloatMarshalling keeps 10**(-6) precision
// for float variables for better performance.
func (cfg *Config) marshalFloatWith6Digits() {
func (cfg *frozenConfig) marshalFloatWith6Digits() {
// for better performance
cfg.addEncoderToCache(reflect.TypeOf((*float32)(nil)).Elem(), &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
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
for !done {
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
for !done {
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)
cache := *(*map[reflect.Type]Decoder)(ptr)
return cache[cacheKey]
}
func (cfg *Config) getEncoderFromCache(cacheKey reflect.Type) Encoder {
func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) Encoder {
ptr := atomic.LoadPointer(&cfg.encoderCache)
cache := *(*map[reflect.Type]Encoder)(ptr)
return cache[cacheKey]
}
// CleanDecoders cleans decoders registered or cached
func (cfg *Config) CleanDecoders() {
func (cfg *frozenConfig) CleanDecoders() {
typeDecoders = map[string]Decoder{}
fieldDecoders = map[string]Decoder{}
atomic.StorePointer(&cfg.decoderCache, unsafe.Pointer(&map[string]Decoder{}))
}
// CleanEncoders cleans encoders registered or cached
func (cfg *Config) CleanEncoders() {
func (cfg *frozenConfig) CleanEncoders() {
typeEncoders = map[string]Encoder{}
fieldEncoders = 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)
if err != nil {
return "", err
@ -123,8 +124,7 @@ func (cfg *Config) MarshalToString(v interface{}) (string, error) {
return string(buf), nil
}
func (cfg *Config) Marshal(v interface{}) ([]byte, error) {
cfg.init()
func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) {
stream := NewStream(cfg, nil, 256)
stream.WriteVal(v)
if stream.Error != nil {
@ -133,7 +133,7 @@ func (cfg *Config) Marshal(v interface{}) ([]byte, error) {
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 = data[:lastNotSpacePos(data)]
iter := ParseBytes(cfg, data)

View File

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

View File

@ -264,7 +264,7 @@ func (p prefix) addToEncoder(encoder Encoder, err error) (Encoder, error) {
return encoder, err
}
func decoderOfType(cfg *Config, typ reflect.Type) (Decoder, error) {
func decoderOfType(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
typeName := typ.String()
typeDecoder := typeDecoders[typeName]
if typeDecoder != nil {
@ -289,7 +289,7 @@ func decoderOfType(cfg *Config, typ reflect.Type) (Decoder, error) {
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" {
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()
typeEncoder := typeEncoders[typeName]
if typeEncoder != nil {
@ -379,7 +379,7 @@ func encoderOfType(cfg *Config, typ reflect.Type) (Encoder, error) {
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" {
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()
decoder, err := decoderOfType(cfg, elemType)
if err != nil {
@ -454,7 +454,7 @@ func decoderOfOptional(cfg *Config, typ reflect.Type) (Decoder, error) {
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()
elemEncoder, err := encoderOfType(cfg, elemType)
if err != nil {
@ -467,7 +467,7 @@ func encoderOfOptional(cfg *Config, typ reflect.Type) (Encoder, error) {
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())
if err != nil {
return nil, err
@ -480,7 +480,7 @@ func extractInterface(val interface{}) emptyInterface {
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()
encoder, err := encoderOfType(cfg, elemType)
if err != nil {

View File

@ -7,7 +7,7 @@ import (
"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())
if err != nil {
return nil, err
@ -15,7 +15,7 @@ func decoderOfSlice(cfg *Config, typ reflect.Type) (Decoder, error) {
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())
if err != nil {
return nil, err

View File

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

View File

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

View File

@ -213,7 +213,7 @@ func Test_whitespace_before_comma(t *testing.T) {
func Test_write_array(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(&Config{IndentionStep: 2}, buf, 4096)
stream := NewStream(Config{IndentionStep: 2}.Froze(), buf, 4096)
stream.WriteArrayStart()
stream.WriteInt(1)
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) {
should := require.New(t)
json := Config{MarshalFloatWith6Digits: true}
json := Config{MarshalFloatWith6Digits: true}.Froze()
str, err := json.MarshalToString(float32(1.23456789))
should.Nil(err)
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) {
jsoniter := &Config{SupportUnexportedStructFields: true}
jsoniter := Config{SupportUnexportedStructFields: true}.Froze()
should := require.New(t)
type TestObject struct {
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) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(&Config{IndentionStep: 2}, buf, 4096)
stream := NewStream(Config{IndentionStep: 2}.Froze(), buf, 4096)
stream.WriteObjectStart()
stream.WriteObjectField("hello")
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) {
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})
should.Equal("[\n 1,\n 2,\n 3\n]", string(stream.Buffer()))
}