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:
parent
d0418857ce
commit
d867c8ba5c
@ -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)
|
||||
}
|
||||
|
@ -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) init() *Config {
|
||||
if cfg.encoderCache == nil {
|
||||
atomic.StorePointer(&cfg.decoderCache, unsafe.Pointer(&map[string]Decoder{}))
|
||||
atomic.StorePointer(&cfg.encoderCache, unsafe.Pointer(&map[string]Encoder{}))
|
||||
func (cfg Config) Froze() *frozenConfig {
|
||||
frozenConfig := &frozenConfig{
|
||||
indentionStep: cfg.IndentionStep,
|
||||
}
|
||||
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)
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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(']')
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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()))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user