feature_config.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package jsoniter
  2. import (
  3. "io"
  4. "reflect"
  5. "sync/atomic"
  6. "unsafe"
  7. )
  8. type Config struct {
  9. IndentionStep int
  10. MarshalFloatWith6Digits bool
  11. SupportUnexportedStructFields bool
  12. EscapeHtml bool
  13. }
  14. type frozenConfig struct {
  15. indentionStep int
  16. decoderCache unsafe.Pointer
  17. encoderCache unsafe.Pointer
  18. extensions []ExtensionFunc
  19. }
  20. var ConfigOfDefault = Config{}.Froze()
  21. // Trying to be 100% compatible with standard library behavior
  22. var ConfigCompatibleWithStandardLibrary = Config{
  23. EscapeHtml: true,
  24. }.Froze()
  25. func (cfg Config) Froze() *frozenConfig {
  26. frozenConfig := &frozenConfig{
  27. indentionStep: cfg.IndentionStep,
  28. }
  29. atomic.StorePointer(&frozenConfig.decoderCache, unsafe.Pointer(&map[string]Decoder{}))
  30. atomic.StorePointer(&frozenConfig.encoderCache, unsafe.Pointer(&map[string]Encoder{}))
  31. if cfg.MarshalFloatWith6Digits {
  32. frozenConfig.marshalFloatWith6Digits()
  33. }
  34. if cfg.SupportUnexportedStructFields {
  35. frozenConfig.supportUnexportedStructFields()
  36. }
  37. if cfg.EscapeHtml {
  38. frozenConfig.escapeHtml()
  39. }
  40. return frozenConfig
  41. }
  42. // RegisterExtension can register a custom extension
  43. func (cfg *frozenConfig) registerExtension(extension ExtensionFunc) {
  44. cfg.extensions = append(cfg.extensions, extension)
  45. }
  46. func (cfg *frozenConfig) supportUnexportedStructFields() {
  47. cfg.registerExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc) {
  48. return []string{field.Name}, nil, nil
  49. })
  50. }
  51. // EnableLossyFloatMarshalling keeps 10**(-6) precision
  52. // for float variables for better performance.
  53. func (cfg *frozenConfig) marshalFloatWith6Digits() {
  54. // for better performance
  55. cfg.addEncoderToCache(reflect.TypeOf((*float32)(nil)).Elem(), &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
  56. val := *((*float32)(ptr))
  57. stream.WriteFloat32Lossy(val)
  58. }})
  59. cfg.addEncoderToCache(reflect.TypeOf((*float64)(nil)).Elem(), &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
  60. val := *((*float64)(ptr))
  61. stream.WriteFloat64Lossy(val)
  62. }})
  63. }
  64. func (cfg *frozenConfig) escapeHtml() {
  65. // for better performance
  66. cfg.addEncoderToCache(reflect.TypeOf((*string)(nil)).Elem(), &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
  67. val := *((*string)(ptr))
  68. stream.WriteStringWithHtmlEscaped(val)
  69. }})
  70. }
  71. func (cfg *frozenConfig) addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
  72. done := false
  73. for !done {
  74. ptr := atomic.LoadPointer(&cfg.decoderCache)
  75. cache := *(*map[reflect.Type]Decoder)(ptr)
  76. copied := map[reflect.Type]Decoder{}
  77. for k, v := range cache {
  78. copied[k] = v
  79. }
  80. copied[cacheKey] = decoder
  81. done = atomic.CompareAndSwapPointer(&cfg.decoderCache, ptr, unsafe.Pointer(&copied))
  82. }
  83. }
  84. func (cfg *frozenConfig) addEncoderToCache(cacheKey reflect.Type, encoder Encoder) {
  85. done := false
  86. for !done {
  87. ptr := atomic.LoadPointer(&cfg.encoderCache)
  88. cache := *(*map[reflect.Type]Encoder)(ptr)
  89. copied := map[reflect.Type]Encoder{}
  90. for k, v := range cache {
  91. copied[k] = v
  92. }
  93. copied[cacheKey] = encoder
  94. done = atomic.CompareAndSwapPointer(&cfg.encoderCache, ptr, unsafe.Pointer(&copied))
  95. }
  96. }
  97. func (cfg *frozenConfig) getDecoderFromCache(cacheKey reflect.Type) Decoder {
  98. ptr := atomic.LoadPointer(&cfg.decoderCache)
  99. cache := *(*map[reflect.Type]Decoder)(ptr)
  100. return cache[cacheKey]
  101. }
  102. func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) Encoder {
  103. ptr := atomic.LoadPointer(&cfg.encoderCache)
  104. cache := *(*map[reflect.Type]Encoder)(ptr)
  105. return cache[cacheKey]
  106. }
  107. // CleanDecoders cleans decoders registered or cached
  108. func (cfg *frozenConfig) CleanDecoders() {
  109. typeDecoders = map[string]Decoder{}
  110. fieldDecoders = map[string]Decoder{}
  111. atomic.StorePointer(&cfg.decoderCache, unsafe.Pointer(&map[string]Decoder{}))
  112. }
  113. // CleanEncoders cleans encoders registered or cached
  114. func (cfg *frozenConfig) CleanEncoders() {
  115. typeEncoders = map[string]Encoder{}
  116. fieldEncoders = map[string]Encoder{}
  117. atomic.StorePointer(&cfg.encoderCache, unsafe.Pointer(&map[string]Encoder{}))
  118. }
  119. func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) {
  120. buf, err := cfg.Marshal(v)
  121. if err != nil {
  122. return "", err
  123. }
  124. return string(buf), nil
  125. }
  126. func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) {
  127. stream := NewStream(cfg, nil, 256)
  128. stream.WriteVal(v)
  129. if stream.Error != nil {
  130. return nil, stream.Error
  131. }
  132. return stream.Buffer(), nil
  133. }
  134. func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error {
  135. data := []byte(str)
  136. data = data[:lastNotSpacePos(data)]
  137. iter := ParseBytes(cfg, data)
  138. iter.ReadVal(v)
  139. if iter.head == iter.tail {
  140. iter.loadMore()
  141. }
  142. if iter.Error == io.EOF {
  143. return nil
  144. }
  145. if iter.Error == nil {
  146. iter.reportError("UnmarshalFromString", "there are bytes left after unmarshal")
  147. }
  148. return iter.Error
  149. }