1
0
mirror of https://github.com/json-iterator/go.git synced 2025-05-13 21:36:29 +02:00

document public symbols

This commit is contained in:
Tao Wen 2017-07-09 16:09:23 +08:00
parent 46574e7d09
commit f0487718f6
22 changed files with 227 additions and 176 deletions

View File

@ -160,8 +160,8 @@ type tolerateEmptyArrayDecoder struct {
func (decoder *tolerateEmptyArrayDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { func (decoder *tolerateEmptyArrayDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if iter.WhatIsNext() == jsoniter.Array { if iter.WhatIsNext() == jsoniter.Array {
iter.Skip() iter.Skip()
newIter := iter.Config().BorrowIterator([]byte("{}")) newIter := iter.Pool().BorrowIterator([]byte("{}"))
defer iter.Config().ReturnIterator(newIter) defer iter.Pool().ReturnIterator(newIter)
decoder.valDecoder.Decode(ptr, newIter) decoder.valDecoder.Decode(ptr, newIter)
} else { } else {
decoder.valDecoder.Decode(ptr, iter) decoder.valDecoder.Decode(ptr, iter)
@ -202,8 +202,8 @@ func (decoder *fuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It
default: default:
iter.ReportError("fuzzyIntegerDecoder", "not number or string") iter.ReportError("fuzzyIntegerDecoder", "not number or string")
} }
newIter := iter.Config().BorrowIterator([]byte(str)) newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Config().ReturnIterator(newIter) defer iter.Pool().ReturnIterator(newIter)
isFloat := strings.IndexByte(str, '.') != -1 isFloat := strings.IndexByte(str, '.') != -1
decoder.fun(isFloat, ptr, newIter) decoder.fun(isFloat, ptr, newIter)
if newIter.Error != nil { if newIter.Error != nil {
@ -222,8 +222,8 @@ func (decoder *fuzzyFloat32Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It
*((*float32)(ptr)) = iter.ReadFloat32() *((*float32)(ptr)) = iter.ReadFloat32()
case jsoniter.String: case jsoniter.String:
str = iter.ReadString() str = iter.ReadString()
newIter := iter.Config().BorrowIterator([]byte(str)) newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Config().ReturnIterator(newIter) defer iter.Pool().ReturnIterator(newIter)
*((*float32)(ptr)) = newIter.ReadFloat32() *((*float32)(ptr)) = newIter.ReadFloat32()
if newIter.Error != nil { if newIter.Error != nil {
iter.Error = newIter.Error iter.Error = newIter.Error
@ -244,8 +244,8 @@ func (decoder *fuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It
*((*float64)(ptr)) = iter.ReadFloat64() *((*float64)(ptr)) = iter.ReadFloat64()
case jsoniter.String: case jsoniter.String:
str = iter.ReadString() str = iter.ReadString()
newIter := iter.Config().BorrowIterator([]byte(str)) newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Config().ReturnIterator(newIter) defer iter.Pool().ReturnIterator(newIter)
*((*float64)(ptr)) = newIter.ReadFloat64() *((*float64)(ptr)) = newIter.ReadFloat64()
if newIter.Error != nil { if newIter.Error != nil {
iter.Error = newIter.Error iter.Error = newIter.Error

View File

@ -1,14 +1,3 @@
// Package jsoniter implements encoding and decoding of JSON as defined in
// RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json.
// Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter
// and variable type declarations (if any).
// jsoniter interfaces gives 100% compatibility with code using standard lib.
//
// "JSON and Go"
// (https://golang.org/doc/articles/json_and_go.html)
// gives a description of how Marshal/Unmarshal operate
// between arbitrary or predefined json objects and bytes,
// and it applies to jsoniter.Marshal/Unmarshal as well.
package jsoniter package jsoniter
import ( import (
@ -96,7 +85,7 @@ func (adapter *Decoder) Buffered() io.Reader {
func (decoder *Decoder) UseNumber() { func (decoder *Decoder) UseNumber() {
origCfg := decoder.iter.cfg.configBeforeFrozen origCfg := decoder.iter.cfg.configBeforeFrozen
origCfg.UseNumber = true origCfg.UseNumber = true
decoder.iter.cfg = origCfg.Froze() decoder.iter.cfg = origCfg.Froze().(*frozenConfig)
} }
func NewEncoder(writer io.Writer) *Encoder { func NewEncoder(writer io.Writer) *Encoder {
@ -119,6 +108,6 @@ func (adapter *Encoder) SetIndent(prefix, indent string) {
func (adapter *Encoder) SetEscapeHTML(escapeHtml bool) { func (adapter *Encoder) SetEscapeHTML(escapeHtml bool) {
config := adapter.stream.cfg.configBeforeFrozen config := adapter.stream.cfg.configBeforeFrozen
config.EscapeHtml = escapeHtml config.EscapeHTML = escapeHtml
adapter.stream.cfg = config.Froze() adapter.stream.cfg = config.Froze().(*frozenConfig)
} }

View File

@ -9,10 +9,12 @@ import (
"unsafe" "unsafe"
) )
// Config customize how the API should behave.
// The API is created from Config by Froze.
type Config struct { type Config struct {
IndentionStep int IndentionStep int
MarshalFloatWith6Digits bool MarshalFloatWith6Digits bool
EscapeHtml bool EscapeHTML bool
SortMapKeys bool SortMapKeys bool
UseNumber bool UseNumber bool
} }
@ -28,7 +30,11 @@ type frozenConfig struct {
iteratorPool chan *Iterator iteratorPool chan *Iterator
} }
type Api interface { // API the public interface of this package.
// Primary Marshal and Unmarshal.
type API interface {
IteratorPool
StreamPool
MarshalToString(v interface{}) (string, error) MarshalToString(v interface{}) (string, error)
Marshal(v interface{}) ([]byte, error) Marshal(v interface{}) ([]byte, error)
MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
@ -39,22 +45,25 @@ type Api interface {
NewDecoder(reader io.Reader) *Decoder NewDecoder(reader io.Reader) *Decoder
} }
// ConfigDefault the default API
var ConfigDefault = Config{ var ConfigDefault = Config{
EscapeHtml: true, EscapeHTML: true,
}.Froze() }.Froze()
// Trying to be 100% compatible with standard library behavior // ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior
var ConfigCompatibleWithStandardLibrary = Config{ var ConfigCompatibleWithStandardLibrary = Config{
EscapeHtml: true, EscapeHTML: true,
SortMapKeys: true, SortMapKeys: true,
}.Froze() }.Froze()
// ConfigFastest marshals float with only 6 digits precision
var ConfigFastest = Config{ var ConfigFastest = Config{
EscapeHtml: false, EscapeHTML: false,
MarshalFloatWith6Digits: true, MarshalFloatWith6Digits: true,
}.Froze() }.Froze()
func (cfg Config) Froze() *frozenConfig { // Froze forge API from config
func (cfg Config) Froze() API {
// TODO: cache frozen config // TODO: cache frozen config
frozenConfig := &frozenConfig{ frozenConfig := &frozenConfig{
sortMapKeys: cfg.SortMapKeys, sortMapKeys: cfg.SortMapKeys,
@ -67,8 +76,8 @@ func (cfg Config) Froze() *frozenConfig {
if cfg.MarshalFloatWith6Digits { if cfg.MarshalFloatWith6Digits {
frozenConfig.marshalFloatWith6Digits() frozenConfig.marshalFloatWith6Digits()
} }
if cfg.EscapeHtml { if cfg.EscapeHTML {
frozenConfig.escapeHtml() frozenConfig.escapeHTML()
} }
if cfg.UseNumber { if cfg.UseNumber {
frozenConfig.useNumber() frozenConfig.useNumber()
@ -145,7 +154,7 @@ func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return *((*string)(ptr)) == "" return *((*string)(ptr)) == ""
} }
func (cfg *frozenConfig) escapeHtml() { func (cfg *frozenConfig) escapeHTML() {
cfg.addEncoderToCache(reflect.TypeOf((*string)(nil)).Elem(), &htmlEscapedStringEncoder{}) cfg.addEncoderToCache(reflect.TypeOf((*string)(nil)).Elem(), &htmlEscapedStringEncoder{})
} }
@ -189,18 +198,16 @@ func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder {
return cache[cacheKey] return cache[cacheKey]
} }
// cleanDecoders cleans decoders registered or cached
func (cfg *frozenConfig) cleanDecoders() { func (cfg *frozenConfig) cleanDecoders() {
typeDecoders = map[string]ValDecoder{} typeDecoders = map[string]ValDecoder{}
fieldDecoders = map[string]ValDecoder{} fieldDecoders = map[string]ValDecoder{}
*cfg = *cfg.configBeforeFrozen.Froze() *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
} }
// cleanEncoders cleans encoders registered or cached
func (cfg *frozenConfig) cleanEncoders() { func (cfg *frozenConfig) cleanEncoders() {
typeEncoders = map[string]ValEncoder{} typeEncoders = map[string]ValEncoder{}
fieldEncoders = map[string]ValEncoder{} fieldEncoders = map[string]ValEncoder{}
*cfg = *cfg.configBeforeFrozen.Froze() *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
} }
func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) { func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) {

View File

@ -1,9 +1,3 @@
//
// Besides, jsoniter.Iterator provides a different set of interfaces
// iterating given bytes/string/reader
// and yielding parsed elements one by one.
// This set of interfaces reads input as required and gives
// better performance.
package jsoniter package jsoniter
import ( import (
@ -11,15 +5,23 @@ import (
"io" "io"
) )
// ValueType the type for JSON element
type ValueType int type ValueType int
const ( const (
// Invalid invalid JSON element
Invalid ValueType = iota Invalid ValueType = iota
// String JSON element "string"
String String
// Number JSON element 100 or 0.10
Number Number
// Nil JSON element null
Nil Nil
// Bool JSON element true or false
Bool Bool
// Array JSON element []
Array Array
// Object JSON element {}
Object Object
) )
@ -63,7 +65,8 @@ func init() {
valueTypes['{'] = Object valueTypes['{'] = Object
} }
// Iterator is a fast and flexible JSON parser // Iterator is a io.Reader like object, with JSON specific read functions.
// Error is not returned as return value, but stored as Error member on this iterator instance.
type Iterator struct { type Iterator struct {
cfg *frozenConfig cfg *frozenConfig
reader io.Reader reader io.Reader
@ -75,10 +78,10 @@ type Iterator struct {
Error error Error error
} }
// Create creates an empty Iterator instance // NewIterator creates an empty Iterator instance
func NewIterator(cfg *frozenConfig) *Iterator { func NewIterator(cfg API) *Iterator {
return &Iterator{ return &Iterator{
cfg: cfg, cfg: cfg.(*frozenConfig),
reader: nil, reader: nil,
buf: nil, buf: nil,
head: 0, head: 0,
@ -86,10 +89,10 @@ func NewIterator(cfg *frozenConfig) *Iterator {
} }
} }
// Parse parses a json buffer in io.Reader into an Iterator instance // Parse creates an Iterator instance from io.Reader
func Parse(cfg *frozenConfig, reader io.Reader, bufSize int) *Iterator { func Parse(cfg API, reader io.Reader, bufSize int) *Iterator {
return &Iterator{ return &Iterator{
cfg: cfg, cfg: cfg.(*frozenConfig),
reader: reader, reader: reader,
buf: make([]byte, bufSize), buf: make([]byte, bufSize),
head: 0, head: 0,
@ -97,10 +100,10 @@ func Parse(cfg *frozenConfig, reader io.Reader, bufSize int) *Iterator {
} }
} }
// ParseBytes parses a json byte slice into an Iterator instance // ParseBytes creates an Iterator instance from byte array
func ParseBytes(cfg *frozenConfig, input []byte) *Iterator { func ParseBytes(cfg API, input []byte) *Iterator {
return &Iterator{ return &Iterator{
cfg: cfg, cfg: cfg.(*frozenConfig),
reader: nil, reader: nil,
buf: input, buf: input,
head: 0, head: 0,
@ -108,16 +111,17 @@ func ParseBytes(cfg *frozenConfig, input []byte) *Iterator {
} }
} }
// ParseString parses a json string into an Iterator instance // ParseString creates an Iterator instance from string
func ParseString(cfg *frozenConfig, input string) *Iterator { func ParseString(cfg API, input string) *Iterator {
return ParseBytes(cfg, []byte(input)) return ParseBytes(cfg, []byte(input))
} }
func (iter *Iterator) Config() *frozenConfig { // Pool returns a pool can provide more iterator with same configuration
func (iter *Iterator) Pool() IteratorPool {
return iter.cfg return iter.cfg
} }
// Reset can reset an Iterator instance for another json buffer in io.Reader // Reset reuse iterator instance by specifying another reader
func (iter *Iterator) Reset(reader io.Reader) *Iterator { func (iter *Iterator) Reset(reader io.Reader) *Iterator {
iter.reader = reader iter.reader = reader
iter.head = 0 iter.head = 0
@ -125,7 +129,7 @@ func (iter *Iterator) Reset(reader io.Reader) *Iterator {
return iter return iter
} }
// ResetBytes can reset an Iterator instance for another json byte slice // ResetBytes reuse iterator instance by specifying another byte array as input
func (iter *Iterator) ResetBytes(input []byte) *Iterator { func (iter *Iterator) ResetBytes(input []byte) *Iterator {
iter.reader = nil iter.reader = nil
iter.buf = input iter.buf = input
@ -134,7 +138,7 @@ func (iter *Iterator) ResetBytes(input []byte) *Iterator {
return iter return iter
} }
// WhatIsNext gets ValueType of relatively next json object // WhatIsNext gets ValueType of relatively next json element
func (iter *Iterator) WhatIsNext() ValueType { func (iter *Iterator) WhatIsNext() ValueType {
valueType := valueTypes[iter.nextToken()] valueType := valueTypes[iter.nextToken()]
iter.unreadByte() iter.unreadByte()
@ -184,6 +188,7 @@ func (iter *Iterator) nextToken() byte {
} }
} }
// ReportError record a error in iterator instance with current position.
func (iter *Iterator) ReportError(operation string, msg string) { func (iter *Iterator) ReportError(operation string, msg string) {
if iter.Error != nil { if iter.Error != nil {
if iter.Error != io.EOF { if iter.Error != io.EOF {
@ -198,7 +203,7 @@ func (iter *Iterator) ReportError(operation string, msg string) {
string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
} }
// CurrentBuffer gets current buffer as string // CurrentBuffer gets current buffer as string for debugging purpose
func (iter *Iterator) CurrentBuffer() string { func (iter *Iterator) CurrentBuffer() string {
peekStart := iter.head - 10 peekStart := iter.head - 10
if peekStart < 0 { if peekStart < 0 {
@ -261,6 +266,7 @@ func (iter *Iterator) unreadByte() {
return return
} }
// Read read the next JSON element as generic interface{}.
func (iter *Iterator) Read() interface{} { func (iter *Iterator) Read() interface{} {
valueType := iter.WhatIsNext() valueType := iter.WhatIsNext()
switch valueType { switch valueType {

View File

@ -1,5 +1,6 @@
package jsoniter package jsoniter
// ReadArray read array element, tells if the array has more element to read.
func (iter *Iterator) ReadArray() (ret bool) { func (iter *Iterator) ReadArray() (ret bool) {
c := iter.nextToken() c := iter.nextToken()
switch c { switch c {
@ -23,6 +24,7 @@ func (iter *Iterator) ReadArray() (ret bool) {
} }
} }
// ReadArrayCB read array with callback
func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) { func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
c := iter.nextToken() c := iter.nextToken()
if c == '[' { if c == '[' {

View File

@ -30,6 +30,7 @@ func init() {
floatDigits['.'] = dotInNumber floatDigits['.'] = dotInNumber
} }
// ReadBigFloat read big.Float
func (iter *Iterator) ReadBigFloat() (ret *big.Float) { func (iter *Iterator) ReadBigFloat() (ret *big.Float) {
str := iter.readNumberAsString() str := iter.readNumberAsString()
if iter.Error != nil && iter.Error != io.EOF { if iter.Error != nil && iter.Error != io.EOF {
@ -47,6 +48,7 @@ func (iter *Iterator) ReadBigFloat() (ret *big.Float) {
return val return val
} }
// ReadBigInt read big.Int
func (iter *Iterator) ReadBigInt() (ret *big.Int) { func (iter *Iterator) ReadBigInt() (ret *big.Int) {
str := iter.readNumberAsString() str := iter.readNumberAsString()
if iter.Error != nil && iter.Error != io.EOF { if iter.Error != nil && iter.Error != io.EOF {
@ -62,15 +64,15 @@ func (iter *Iterator) ReadBigInt() (ret *big.Int) {
return ret return ret
} }
//ReadFloat32 read float32
func (iter *Iterator) ReadFloat32() (ret float32) { func (iter *Iterator) ReadFloat32() (ret float32) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
return -iter.readPositiveFloat32() return -iter.readPositiveFloat32()
} else { }
iter.unreadByte() iter.unreadByte()
return iter.readPositiveFloat32() return iter.readPositiveFloat32()
} }
}
func (iter *Iterator) readPositiveFloat32() (ret float32) { func (iter *Iterator) readPositiveFloat32() (ret float32) {
value := uint64(0) value := uint64(0)
@ -165,15 +167,15 @@ func (iter *Iterator) readFloat32SlowPath() (ret float32) {
return float32(val) return float32(val)
} }
// ReadFloat64 read float64
func (iter *Iterator) ReadFloat64() (ret float64) { func (iter *Iterator) ReadFloat64() (ret float64) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
return -iter.readPositiveFloat64() return -iter.readPositiveFloat64()
} else { }
iter.unreadByte() iter.unreadByte()
return iter.readPositiveFloat64() return iter.readPositiveFloat64()
} }
}
func (iter *Iterator) readPositiveFloat64() (ret float64) { func (iter *Iterator) readPositiveFloat64() (ret float64) {
value := uint64(0) value := uint64(0)

View File

@ -20,14 +20,17 @@ func init() {
} }
} }
// ReadUint read uint
func (iter *Iterator) ReadUint() uint { func (iter *Iterator) ReadUint() uint {
return uint(iter.ReadUint64()) return uint(iter.ReadUint64())
} }
// ReadInt read int
func (iter *Iterator) ReadInt() int { func (iter *Iterator) ReadInt() int {
return int(iter.ReadInt64()) return int(iter.ReadInt64())
} }
// ReadInt8 read int8
func (iter *Iterator) ReadInt8() (ret int8) { func (iter *Iterator) ReadInt8() (ret int8) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
@ -37,7 +40,7 @@ func (iter *Iterator) ReadInt8() (ret int8) {
return return
} }
return -int8(val) return -int8(val)
} else { }
val := iter.readUint32(c) val := iter.readUint32(c)
if val > math.MaxInt8 { if val > math.MaxInt8 {
iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10))
@ -45,8 +48,8 @@ func (iter *Iterator) ReadInt8() (ret int8) {
} }
return int8(val) return int8(val)
} }
}
// ReadUint8 read uint8
func (iter *Iterator) ReadUint8() (ret uint8) { func (iter *Iterator) ReadUint8() (ret uint8) {
val := iter.readUint32(iter.nextToken()) val := iter.readUint32(iter.nextToken())
if val > math.MaxUint8 { if val > math.MaxUint8 {
@ -56,6 +59,7 @@ func (iter *Iterator) ReadUint8() (ret uint8) {
return uint8(val) return uint8(val)
} }
// ReadInt16 read int16
func (iter *Iterator) ReadInt16() (ret int16) { func (iter *Iterator) ReadInt16() (ret int16) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
@ -65,7 +69,7 @@ func (iter *Iterator) ReadInt16() (ret int16) {
return return
} }
return -int16(val) return -int16(val)
} else { }
val := iter.readUint32(c) val := iter.readUint32(c)
if val > math.MaxInt16 { if val > math.MaxInt16 {
iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10))
@ -73,8 +77,8 @@ func (iter *Iterator) ReadInt16() (ret int16) {
} }
return int16(val) return int16(val)
} }
}
// ReadUint16 read uint16
func (iter *Iterator) ReadUint16() (ret uint16) { func (iter *Iterator) ReadUint16() (ret uint16) {
val := iter.readUint32(iter.nextToken()) val := iter.readUint32(iter.nextToken())
if val > math.MaxUint16 { if val > math.MaxUint16 {
@ -84,6 +88,7 @@ func (iter *Iterator) ReadUint16() (ret uint16) {
return uint16(val) return uint16(val)
} }
// ReadInt32 read int32
func (iter *Iterator) ReadInt32() (ret int32) { func (iter *Iterator) ReadInt32() (ret int32) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
@ -93,7 +98,7 @@ func (iter *Iterator) ReadInt32() (ret int32) {
return return
} }
return -int32(val) return -int32(val)
} else { }
val := iter.readUint32(c) val := iter.readUint32(c)
if val > math.MaxInt32 { if val > math.MaxInt32 {
iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10))
@ -101,8 +106,8 @@ func (iter *Iterator) ReadInt32() (ret int32) {
} }
return int32(val) return int32(val)
} }
}
// ReadUint32 read uint32
func (iter *Iterator) ReadUint32() (ret uint32) { func (iter *Iterator) ReadUint32() (ret uint32) {
return iter.readUint32(iter.nextToken()) return iter.readUint32(iter.nextToken())
} }
@ -182,11 +187,10 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) {
if value2 < value { if value2 < value {
iter.ReportError("readUint32", "overflow") iter.ReportError("readUint32", "overflow")
return return
} else { }
value = value2 value = value2
continue continue
} }
}
value = (value << 3) + (value << 1) + uint32(ind) value = (value << 3) + (value << 1) + uint32(ind)
} }
if !iter.loadMore() { if !iter.loadMore() {
@ -195,6 +199,7 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) {
} }
} }
// ReadInt64 read int64
func (iter *Iterator) ReadInt64() (ret int64) { func (iter *Iterator) ReadInt64() (ret int64) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
@ -204,7 +209,7 @@ func (iter *Iterator) ReadInt64() (ret int64) {
return return
} }
return -int64(val) return -int64(val)
} else { }
val := iter.readUint64(c) val := iter.readUint64(c)
if val > math.MaxInt64 { if val > math.MaxInt64 {
iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10))
@ -212,8 +217,8 @@ func (iter *Iterator) ReadInt64() (ret int64) {
} }
return int64(val) return int64(val)
} }
}
// ReadUint64 read uint64
func (iter *Iterator) ReadUint64() uint64 { func (iter *Iterator) ReadUint64() uint64 {
return iter.readUint64(iter.nextToken()) return iter.readUint64(iter.nextToken())
} }
@ -240,11 +245,10 @@ func (iter *Iterator) readUint64(c byte) (ret uint64) {
if value2 < value { if value2 < value {
iter.ReportError("readUint64", "overflow") iter.ReportError("readUint64", "overflow")
return return
} else { }
value = value2 value = value2
continue continue
} }
}
value = (value << 3) + (value << 1) + uint64(ind) value = (value << 3) + (value << 1) + uint64(ind)
} }
if !iter.loadMore() { if !iter.loadMore() {

View File

@ -6,6 +6,9 @@ import (
"unsafe" "unsafe"
) )
// ReadObject read one field from object.
// If object ended, returns empty string.
// Otherwise, returns the field name.
func (iter *Iterator) ReadObject() (ret string) { func (iter *Iterator) ReadObject() (ret string) {
c := iter.nextToken() c := iter.nextToken()
switch c { switch c {
@ -74,6 +77,7 @@ func calcHash(str string) int32 {
return int32(hash) return int32(hash)
} }
// ReadObjectCB read object with callback, the key is ascii only and field name not copied
func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
c := iter.nextToken() c := iter.nextToken()
if c == '{' { if c == '{' {
@ -106,6 +110,7 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
return false return false
} }
// ReadMapCB read map with callback, the key can be any string
func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
c := iter.nextToken() c := iter.nextToken()
if c == '{' { if c == '{' {

View File

@ -29,6 +29,8 @@ func (iter *Iterator) ReadBool() (ret bool) {
return return
} }
// SkipAndReturnBytes skip next JSON element, and return its content as []byte.
// The []byte can be kept, it is a copy of data.
func (iter *Iterator) SkipAndReturnBytes() []byte { func (iter *Iterator) SkipAndReturnBytes() []byte {
iter.startCapture(iter.head) iter.startCapture(iter.head)
iter.Skip() iter.Skip()
@ -58,11 +60,10 @@ func (iter *Iterator) stopCapture() []byte {
iter.captured = nil iter.captured = nil
if len(captured) == 0 { if len(captured) == 0 {
return remaining return remaining
} else { }
captured = append(captured, remaining...) captured = append(captured, remaining...)
return captured return captured
} }
}
// Skip skips a json object and positions to relatively the next json object // Skip skips a json object and positions to relatively the next json object
func (iter *Iterator) Skip() { func (iter *Iterator) Skip() {

View File

@ -4,6 +4,7 @@ import (
"unicode/utf16" "unicode/utf16"
) )
// ReadString read string from iterator
func (iter *Iterator) ReadString() (ret string) { func (iter *Iterator) ReadString() (ret string) {
c := iter.nextToken() c := iter.nextToken()
if c == '"' { if c == '"' {
@ -96,6 +97,8 @@ func (iter *Iterator) readStringSlowPath() (ret string) {
return return
} }
// ReadStringAsSlice read string from iterator without copying into string form.
// The []byte can not be kept, as it will change after next iterator call.
func (iter *Iterator) ReadStringAsSlice() (ret []byte) { func (iter *Iterator) ReadStringAsSlice() (ret []byte) {
c := iter.nextToken() c := iter.nextToken()
if c == '"' { if c == '"' {

View File

@ -4,6 +4,18 @@ import (
"io" "io"
) )
// IteratorPool a thread safe pool of iterators with same configuration
type IteratorPool interface {
BorrowIterator(data []byte) *Iterator
ReturnIterator(iter *Iterator)
}
// StreamPool a thread safe pool of streams with same configuration
type StreamPool interface {
BorrowStream(writer io.Writer) *Stream
ReturnStream(stream *Stream)
}
func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream { func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream {
select { select {
case stream := <-cfg.streamPool: case stream := <-cfg.streamPool:

View File

@ -36,6 +36,7 @@ type checkIsEmpty interface {
IsEmpty(ptr unsafe.Pointer) bool IsEmpty(ptr unsafe.Pointer) bool
} }
// WriteToStream the default implementation for TypeEncoder method EncodeInterface
func WriteToStream(val interface{}, stream *Stream, encoder ValEncoder) { func WriteToStream(val interface{}, stream *Stream, encoder ValEncoder) {
e := (*emptyInterface)(unsafe.Pointer(&val)) e := (*emptyInterface)(unsafe.Pointer(&val))
if e.word == nil { if e.word == nil {
@ -49,9 +50,6 @@ func WriteToStream(val interface{}, stream *Stream, encoder ValEncoder) {
} }
} }
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
type EncoderFunc func(ptr unsafe.Pointer, stream *Stream)
var jsonNumberType reflect.Type var jsonNumberType reflect.Type
var jsonRawMessageType reflect.Type var jsonRawMessageType reflect.Type
var jsoniterRawMessageType reflect.Type var jsoniterRawMessageType reflect.Type
@ -132,9 +130,8 @@ func (encoder *optionalEncoder) EncodeInterface(val interface{}, stream *Stream)
func (encoder *optionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *optionalEncoder) IsEmpty(ptr unsafe.Pointer) bool {
if *((*unsafe.Pointer)(ptr)) == nil { if *((*unsafe.Pointer)(ptr)) == nil {
return true return true
} else {
return false
} }
return false
} }
type placeholderEncoder struct { type placeholderEncoder struct {
@ -206,7 +203,7 @@ type nonEmptyInterface struct {
word unsafe.Pointer word unsafe.Pointer
} }
// Read converts an Iterator instance into go interface, same as json.Unmarshal // ReadVal copy the underlying JSON into go interface, same as json.Unmarshal
func (iter *Iterator) ReadVal(obj interface{}) { func (iter *Iterator) ReadVal(obj interface{}) {
typ := reflect.TypeOf(obj) typ := reflect.TypeOf(obj)
cacheKey := typ.Elem() cacheKey := typ.Elem()
@ -219,6 +216,7 @@ func (iter *Iterator) ReadVal(obj interface{}) {
decoder.Decode(e.word, iter) decoder.Decode(e.word, iter)
} }
// WriteVal copy the go interface into underlying JSON, same as json.Marshal
func (stream *Stream) WriteVal(val interface{}) { func (stream *Stream) WriteVal(val interface{}) {
if nil == val { if nil == val {
stream.WriteNil() stream.WriteNil()
@ -393,9 +391,8 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error
case reflect.Interface: case reflect.Interface:
if typ.NumMethod() == 0 { if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}, nil return &emptyInterfaceCodec{}, nil
} else {
return &nonEmptyInterfaceCodec{}, nil
} }
return &nonEmptyInterfaceCodec{}, nil
case reflect.Struct: case reflect.Struct:
return prefix(fmt.Sprintf("[%s]", typeName)).addToDecoder(decoderOfStruct(cfg, typ)) return prefix(fmt.Sprintf("[%s]", typeName)).addToDecoder(decoderOfStruct(cfg, typ))
case reflect.Array: case reflect.Array:
@ -517,9 +514,8 @@ func createCheckIsEmpty(typ reflect.Type) (checkIsEmpty, error) {
case reflect.Interface: case reflect.Interface:
if typ.NumMethod() == 0 { if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}, nil return &emptyInterfaceCodec{}, nil
} else {
return &nonEmptyInterfaceCodec{}, nil
} }
return &nonEmptyInterfaceCodec{}, nil
case reflect.Struct: case reflect.Struct:
return &structEncoder{}, nil return &structEncoder{}, nil
case reflect.Array: case reflect.Array:
@ -617,9 +613,8 @@ func createEncoderOfSimpleType(cfg *frozenConfig, typ reflect.Type) (ValEncoder,
case reflect.Interface: case reflect.Interface:
if typ.NumMethod() == 0 { if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}, nil return &emptyInterfaceCodec{}, nil
} else {
return &nonEmptyInterfaceCodec{}, nil
} }
return &nonEmptyInterfaceCodec{}, nil
case reflect.Struct: case reflect.Struct:
return prefix(fmt.Sprintf("[%s]", typeName)).addToEncoder(encoderOfStruct(cfg, typ)) return prefix(fmt.Sprintf("[%s]", typeName)).addToEncoder(encoderOfStruct(cfg, typ))
case reflect.Array: case reflect.Array:
@ -679,7 +674,6 @@ func encoderOfMap(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
mapInterface := reflect.New(typ).Elem().Interface() mapInterface := reflect.New(typ).Elem().Interface()
if cfg.sortMapKeys { if cfg.sortMapKeys {
return &sortKeysMapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil return &sortKeysMapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
} else { }
return &mapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil return &mapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
} }
}

View File

@ -110,6 +110,11 @@ func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.isEmptyFunc(ptr) return encoder.isEmptyFunc(ptr)
} }
// DecoderFunc the function form of TypeDecoder
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
// EncoderFunc the function form of TypeEncoder
type EncoderFunc func(ptr unsafe.Pointer, stream *Stream)
// RegisterTypeDecoderFunc register TypeDecoder for a type with function // RegisterTypeDecoderFunc register TypeDecoder for a type with function
func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) { func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) {
typeDecoders[typ] = &funcDecoder{fun} typeDecoders[typ] = &funcDecoder{fun}

View File

@ -1,9 +1,9 @@
package jsoniter package jsoniter
import ( import (
"reflect"
"io"
"fmt" "fmt"
"io"
"reflect"
"unsafe" "unsafe"
) )
@ -417,7 +417,6 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
return &generalStructDecoder{typ, fields}, nil return &generalStructDecoder{typ, fields}, nil
} }
type generalStructDecoder struct { type generalStructDecoder struct {
typ reflect.Type typ reflect.Type
fields map[string]*structFieldDecoder fields map[string]*structFieldDecoder

View File

@ -4,7 +4,7 @@ import (
"io" "io"
) )
// Stream is a writer like object, with JSON specific write functions. // Stream is a io.Writer like object, with JSON specific write functions.
// Error is not returned as return value, but stored as Error member on this stream instance. // Error is not returned as return value, but stored as Error member on this stream instance.
type Stream struct { type Stream struct {
cfg *frozenConfig cfg *frozenConfig
@ -19,9 +19,9 @@ type Stream struct {
// cfg can be jsoniter.ConfigDefault. // cfg can be jsoniter.ConfigDefault.
// out can be nil if write to internal buffer. // out can be nil if write to internal buffer.
// bufSize is the initial size for the internal buffer in bytes. // bufSize is the initial size for the internal buffer in bytes.
func NewStream(cfg *frozenConfig, out io.Writer, bufSize int) *Stream { func NewStream(cfg API, out io.Writer, bufSize int) *Stream {
return &Stream{ return &Stream{
cfg: cfg, cfg: cfg.(*frozenConfig),
out: out, out: out,
buf: make([]byte, bufSize), buf: make([]byte, bufSize),
n: 0, n: 0,
@ -30,6 +30,11 @@ func NewStream(cfg *frozenConfig, out io.Writer, bufSize int) *Stream {
} }
} }
// Pool returns a pool can provide more stream with same configuration
func (stream *Stream) Pool() StreamPool {
return stream.cfg
}
// Reset reuse this stream instance by assign a new writer // Reset reuse this stream instance by assign a new writer
func (stream *Stream) Reset(out io.Writer) { func (stream *Stream) Reset(out io.Writer) {
stream.out = out stream.out = out
@ -196,7 +201,6 @@ func (stream *Stream) growAtLeast(minimal int) {
stream.buf = newBuf stream.buf = newBuf
} }
// WriteRaw write string out without quotes, just like []byte // WriteRaw write string out without quotes, just like []byte
func (stream *Stream) WriteRaw(s string) { func (stream *Stream) WriteRaw(s string) {
stream.ensure(len(s)) stream.ensure(len(s))

18
jsoniter.go Normal file
View File

@ -0,0 +1,18 @@
// Package jsoniter implements encoding and decoding of JSON as defined in
// RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json.
// Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter
// and variable type declarations (if any).
// jsoniter interfaces gives 100% compatibility with code using standard lib.
//
// "JSON and Go"
// (https://golang.org/doc/articles/json_and_go.html)
// gives a description of how Marshal/Unmarshal operate
// between arbitrary or predefined json objects and bytes,
// and it applies to jsoniter.Marshal/Unmarshal as well.
//
// Besides, jsoniter.Iterator provides a different set of interfaces
// iterating given bytes/string/reader
// and yielding parsed elements one by one.
// This set of interfaces reads input as required and gives
// better performance.
package jsoniter

View File

@ -26,7 +26,7 @@ func Test_new_encoder(t *testing.T) {
} }
func Test_string_encode_with_std_without_html_escape(t *testing.T) { func Test_string_encode_with_std_without_html_escape(t *testing.T) {
api := Config{EscapeHtml: false}.Froze() api := Config{EscapeHTML: false}.Froze()
should := require.New(t) should := require.New(t)
for i := 0; i < utf8.RuneSelf; i++ { for i := 0; i < utf8.RuneSelf; i++ {
input := string([]byte{byte(i)}) input := string([]byte{byte(i)})

View File

@ -18,7 +18,7 @@ func Test_customize_type_decoder(t *testing.T) {
} }
*((*time.Time)(ptr)) = t *((*time.Time)(ptr)) = t
}) })
defer ConfigDefault.cleanDecoders() defer ConfigDefault.(*frozenConfig).cleanDecoders()
val := time.Time{} val := time.Time{}
err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val) err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val)
if err != nil { if err != nil {
@ -36,7 +36,7 @@ func Test_customize_type_encoder(t *testing.T) {
t := *((*time.Time)(ptr)) t := *((*time.Time)(ptr))
stream.WriteString(t.UTC().Format("2006-01-02 15:04:05")) stream.WriteString(t.UTC().Format("2006-01-02 15:04:05"))
}, nil) }, nil)
defer ConfigDefault.cleanEncoders() defer ConfigDefault.(*frozenConfig).cleanEncoders()
val := time.Unix(0, 0) val := time.Unix(0, 0)
str, err := MarshalToString(val) str, err := MarshalToString(val)
should.Nil(err) should.Nil(err)
@ -44,13 +44,13 @@ func Test_customize_type_encoder(t *testing.T) {
} }
func Test_customize_byte_array_encoder(t *testing.T) { func Test_customize_byte_array_encoder(t *testing.T) {
ConfigDefault.cleanEncoders() ConfigDefault.(*frozenConfig).cleanEncoders()
should := require.New(t) should := require.New(t)
RegisterTypeEncoderFunc("[]uint8", func(ptr unsafe.Pointer, stream *Stream) { RegisterTypeEncoderFunc("[]uint8", func(ptr unsafe.Pointer, stream *Stream) {
t := *((*[]byte)(ptr)) t := *((*[]byte)(ptr))
stream.WriteString(string(t)) stream.WriteString(string(t))
}, nil) }, nil)
defer ConfigDefault.cleanEncoders() defer ConfigDefault.(*frozenConfig).cleanEncoders()
val := []byte("abc") val := []byte("abc")
str, err := MarshalToString(val) str, err := MarshalToString(val)
should.Nil(err) should.Nil(err)
@ -73,7 +73,7 @@ func Test_customize_field_decoder(t *testing.T) {
RegisterFieldDecoderFunc("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) { RegisterFieldDecoderFunc("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt()) *((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
}) })
defer ConfigDefault.cleanDecoders() defer ConfigDefault.(*frozenConfig).cleanDecoders()
tom := Tom{} tom := Tom{}
err := Unmarshal([]byte(`{"field1": 100}`), &tom) err := Unmarshal([]byte(`{"field1": 100}`), &tom)
if err != nil { if err != nil {
@ -144,7 +144,7 @@ func Test_marshaler_and_encoder(t *testing.T) {
type TestObject struct { type TestObject struct {
Field *timeImplementedMarshaler Field *timeImplementedMarshaler
} }
ConfigDefault.cleanEncoders() ConfigDefault.(*frozenConfig).cleanEncoders()
should := require.New(t) should := require.New(t)
RegisterTypeEncoderFunc("jsoniter.timeImplementedMarshaler", func(ptr unsafe.Pointer, stream *Stream) { RegisterTypeEncoderFunc("jsoniter.timeImplementedMarshaler", func(ptr unsafe.Pointer, stream *Stream) {
stream.WriteString("hello from encoder") stream.WriteString("hello from encoder")
@ -184,7 +184,7 @@ func Test_unmarshaler_and_decoder(t *testing.T) {
Field *ObjectImplementedUnmarshaler Field *ObjectImplementedUnmarshaler
Field2 string Field2 string
} }
ConfigDefault.cleanDecoders() ConfigDefault.(*frozenConfig).cleanDecoders()
should := require.New(t) should := require.New(t)
RegisterTypeDecoderFunc("jsoniter.ObjectImplementedUnmarshaler", func(ptr unsafe.Pointer, iter *Iterator) { RegisterTypeDecoderFunc("jsoniter.ObjectImplementedUnmarshaler", func(ptr unsafe.Pointer, iter *Iterator) {
*(*ObjectImplementedUnmarshaler)(ptr) = 10 *(*ObjectImplementedUnmarshaler)(ptr) = 10

View File

@ -141,8 +141,8 @@ func Test_encode_object_contain_non_empty_interface(t *testing.T) {
} }
func Test_nil_non_empty_interface(t *testing.T) { func Test_nil_non_empty_interface(t *testing.T) {
ConfigDefault.cleanEncoders() ConfigDefault.(*frozenConfig).cleanEncoders()
ConfigDefault.cleanDecoders() ConfigDefault.(*frozenConfig).cleanDecoders()
type TestObject struct { type TestObject struct {
Field []MyInterface Field []MyInterface
} }

View File

@ -2,9 +2,9 @@ package jsoniter
import ( import (
"bytes" "bytes"
"github.com/stretchr/testify/require"
"io" "io"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func Test_read_by_one(t *testing.T) { func Test_read_by_one(t *testing.T) {

View File

@ -127,7 +127,7 @@ func Test_unicode(t *testing.T) {
should := require.New(t) should := require.New(t)
output, _ := MarshalToString(map[string]interface{}{"a": "数字山谷"}) output, _ := MarshalToString(map[string]interface{}{"a": "数字山谷"})
should.Equal(`{"a":"数字山谷"}`, output) should.Equal(`{"a":"数字山谷"}`, output)
output, _ = Config{EscapeHtml: false}.Froze().MarshalToString(map[string]interface{}{"a": "数字山谷"}) output, _ = Config{EscapeHTML: false}.Froze().MarshalToString(map[string]interface{}{"a": "数字山谷"})
should.Equal(`{"a":"数字山谷"}`, output) should.Equal(`{"a":"数字山谷"}`, output)
} }
@ -142,7 +142,7 @@ func Test_unicode_and_escape(t *testing.T) {
} }
func Test_unsafe_unicode(t *testing.T) { func Test_unsafe_unicode(t *testing.T) {
ConfigDefault.cleanEncoders() ConfigDefault.(*frozenConfig).cleanEncoders()
should := require.New(t) should := require.New(t)
output, err := ConfigDefault.MarshalToString("he\u2029\u2028he") output, err := ConfigDefault.MarshalToString("he\u2029\u2028he")
should.Nil(err) should.Nil(err)