2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-21 00:46:43 +08:00

Compare commits

..

3 commits

Author SHA1 Message Date
liu
78c2ade913
fix: readme typos (#323) 2022-10-28 17:32:48 +08:00
liu
6deed01a90
opt: reduce memory pool size (#302)
* fix: reduce state stack size

* fix types

* opt: shrink encoder stack size

* opt: reduce decoder stack size

* add bench.py loops

Co-authored-by: liuqiang <liuqiang.06@bytedance.com>
Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
2022-10-28 16:40:14 +08:00
linuxsong
3e6f839fb6
fix iterator traversal empty object panic (#314) 2022-10-18 10:59:51 +08:00
15 changed files with 114 additions and 81 deletions

View file

@ -101,19 +101,20 @@ err := sonic.Unmarshal(output, &data)
```
### Streaming IO
Sonic supports to decode json from `io.Reader` or encode objects into `io.Writer`, aiming at handling multiple values as well as reducing memory consuming.
Sonic supports decoding json from `io.Reader` or encoding objects into `io.`Writer`, aims at handling multiple values as well as reducing memory consumption.
- encoder
```go
import "github.com/bytedance/sonic/encoder"
var o1 = map[string]interface{}{
"a": "b"
var o1 = map[string]interface{}{
"a": "b",
}
var o2 = 1
var w = bytes.NewBuffer(nil)
var enc = encoder.NewStreamEncoder(w)
enc.Encode(o)
println(w1.String()) // "{\"a\":\"b\"}\n1"
enc.Encode(o1)
enc.Encode(o2)
println(w.String()) // "{"a":"b"}\n1"
```
- decoder
```go
@ -203,9 +204,9 @@ if err != nil {
```
### Ast.Node
Sonic/ast.Node is a completely self-contained AST for JSON. It implements serialization and deserialization both, and provides robust APIs for obtaining and modification of generic data.
Sonic/ast.Node is a completely self-contained AST for JSON. It implements serialization and deserialization both and provides robust APIs for obtaining and modification of generic data.
#### Get/Index
Search partial JSON by given paths, which must be non-negative integer or string or nil
Search partial JSON by given paths, which must be non-negative integer or string, or nil
```go
import "github.com/bytedance/sonic"
@ -219,7 +220,7 @@ raw := root.Raw() // == string(input)
root, err := sonic.Get(input, "key1", 1, "key2")
sub := root.Get("key3").Index(2).Int64() // == 3
```
**Tip**: since `Index()` uses offset to locate data, which is much faster than scanning like `Get()`, we suggest you use it as much as possible. And sonic also provides another API `IndexOrGet()` to underlying use offset as well as ensuring the key is matched.
**Tip**: since `Index()` uses offset to locate data, which is much faster than scanning like `Get()`, we suggest you use it as much as possible. And sonic also provides another API `IndexOrGet()` to underlying use offset as well as ensure the key is matched.
#### Set/Unset
Modify the json content by Set()/Unset()
@ -264,17 +265,17 @@ println(string(buf) == string(exp)) // true
Sonic **DOES NOT** ensure to support all environments, due to the difficulty of developing high-performance codes. For developers who use sonic to build their applications in different environments, we have the following suggestions:
- Developing on **Mac M1**: Make sure you have Rosetta 2 installed on your machine, and set `GOARCH=amd64` when building your application. Rosetta 2 can automatically translate x86 binaries to arm64 binaries and run x86 applications on Mac M1.
- Developing on **Linux arm64**: You can install qemu and use the `qemu-x86_64 -cpu max` command to convert x86 binaries to amr64 binaries for applications built with sonic. The qemu can achieve similar transfer effect to Rosetta 2 on Mac M1.
- Developing on **Linux arm64**: You can install qemu and use the `qemu-x86_64 -cpu max` command to convert x86 binaries to amr64 binaries for applications built with sonic. The qemu can achieve a similar transfer effect to Rosetta 2 on Mac M1.
For developers who want to use sonic on Linux arm64 without qemu, or those who want to handle JSON strictly consistent with `encoding/json`, we provide some compatible APIs as `sonic.API`
- `ConfigDefault`: the sonic's default config (`EscapeHTML=false`,`SortKeys=false`...) to run on sonic-supporting environment. It will fall back to `encoding/json` with the corresponding config, and some options like `SortKeys=false` will be invalid.
- `ConfigStd`: the std-compatible config (`EscapeHTML=true`,`SortKeys=true`...) to run on sonic-supporting environment. It will fall back to `encoding/json`.
- `ConfigFastest`: the fastest config (`NoQuoteTextMarshaler=true`) to run on sonic-supporting environment. It will fall back to `encoding/json` with corresponding config, and some options will be invalid.
- `ConfigFastest`: the fastest config (`NoQuoteTextMarshaler=true`) to run on sonic-supporting environment. It will fall back to `encoding/json` with the corresponding config, and some options will be invalid.
## Tips
### Pretouch
Since Sonic uses [golang-asm](https://github.com/twitchyliquid64/golang-asm) as a JIT assembler, which is NOT very suitable for runtime compiling, first-hit running of a huge schema may cause request-timeout or even process-OOM. For better stability, we advise to **use `Pretouch()` for huge-schema or compact-memory application** before `Marshal()/Unmarshal()`.
Since Sonic uses [golang-asm](https://github.com/twitchyliquid64/golang-asm) as a JIT assembler, which is NOT very suitable for runtime compiling, first-hit running of a huge schema may cause request-timeout or even process-OOM. For better stability, we advise **using `Pretouch()` for huge-schema or compact-memory applications** before `Marshal()/Unmarshal()`.
```go
import (
"reflect"
@ -293,7 +294,7 @@ func init() {
// If the type is too deep nesting (nesting depth > option.DefaultMaxInlineDepth),
// you can set compile recursive loops in Pretouch for better stability in JIT.
option.WithCompileRecursiveDepth(loop),
// For large nested struct, try to set smaller depth to reduce compiling time.
// For a large nested struct, try to set a smaller depth to reduce compiling time.
option.WithCompileMaxInlineDepth(depth),
)
}
@ -303,14 +304,14 @@ func init() {
When decoding **string values without any escaped characters**, sonic references them from the origin JSON buffer instead of mallocing a new buffer to copy. This helps a lot for CPU performance but may leave the whole JSON buffer in memory as long as the decoded objects are being used. In practice, we found the extra memory introduced by referring JSON buffer is usually 20% ~ 80% of decoded objects. Once an application holds these objects for a long time (for example, cache the decoded objects for reusing), its in-use memory on the server may go up. We provide the option `decoder.CopyString()` for users to choose not to reference the JSON buffer, which may cause a decline in CPU performance to some degree.
### Pass string or []byte?
For alignment to `encoding/json`, we provide API to pass `[]byte` as an argument, but the string-to-bytes copy is conducted at the same time considering safety, which may lose performance when origin JSON is huge. Therefore, you can use `UnmarshalString()` and `GetFromString()` to pass a string, as long as your origin data is a string or **nocopy-cast** is safe for your []byte. We also provide API `MarshalString()` for convenient **nocopy-cast** of encoded JSON []byte, which is safe since sonic's output bytes is always duplicated and unique.
For alignment to `encoding/json`, we provide API to pass `[]byte` as an argument, but the string-to-bytes copy is conducted at the same time considering safety, which may lose performance when the origin JSON is huge. Therefore, you can use `UnmarshalString()` and `GetFromString()` to pass a string, as long as your origin data is a string or **nocopy-cast** is safe for your []byte. We also provide API `MarshalString()` for convenient **nocopy-cast** of encoded JSON []byte, which is safe since sonic's output bytes is always duplicated and unique.
### Accelerate `encoding.TextMarshaler`
To ensure data security, sonic.Encoder quotes and escapes string values from `encoding.TextMarshaler` interfaces by default, which may degrade performance much if most of your data is in form of them. We provide `encoder.NoQuoteTextMarshaler` to skip these operations, which means you **MUST** ensure their output string escaped and quoted in accordance with [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259).
To ensure data security, sonic.Encoder quotes and escapes string values from `encoding.TextMarshaler` interfaces by default, which may degrade performance much if most of your data is in form of them. We provide `encoder.NoQuoteTextMarshaler` to skip these operations, which means you **MUST** ensure their output string escaped and quoted following [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259).
### Better performance for generic data
In **fully-parsed** scenario, `Unmarshal()` performs better than `Get()`+`Node.Interface()`. But if you only have a part of schema for specific json, you can combine `Get()` and `Unmarshal()` together:
In **fully-parsed** scenario, `Unmarshal()` performs better than `Get()`+`Node.Interface()`. But if you only have a part of the schema for specific json, you can combine `Get()` and `Unmarshal()` together:
```go
import "github.com/bytedance/sonic"
@ -334,7 +335,7 @@ Why? Because `ast.Node` stores its children using `array`:
- **Hashing** (`map[x]`) is not as efficient as **Indexing** (`array[x]`), which `ast.Node` can conduct on **both array and object**;
- Using `Interface()`/`Map()` means Sonic must parse all the underlying values, while `ast.Node` can parse them **on demand**.
**CAUTION:** `ast.Node` **DOESN'T** ensure concurrent security directly, due to its **lazy-load** design. However, your can call `Node.Load()`/`Node.LoadAll()` to achieve that, which may bring performance reduction while it still works faster than converting to `map` or `interface{}`
**CAUTION:** `ast.Node` **DOESN'T** ensure concurrent security directly, due to its **lazy-load** design. However, you can call `Node.Load()`/`Node.LoadAll()` to achieve that, which may bring performance reduction while it still works faster than converting to `map` or `interface{}`
## Community
Sonic is a subproject of [CloudWeGo](https://www.cloudwego.io/). We are committed to building a cloud native ecosystem.

View file

@ -63,7 +63,11 @@ func (self *Iterator) HasNext() bool {
} else if self.p.t == _V_ARRAY_LAZY {
return self.p.skipNextNode().Valid()
} else if self.p.t == _V_OBJECT_LAZY {
return self.p.skipNextPair().Value.Valid()
pair := self.p.skipNextPair()
if pair == nil {
return false
}
return pair.Value.Valid()
}
return false
}

View file

@ -195,6 +195,16 @@ func TestIterator(t *testing.T) {
if i != int64(loop) {
t.Fatal(i)
}
str, _ = getTestIteratorSample(0)
root, err = NewParser(str).Parse()
if err != 0 {
t.Fatal(err)
}
mi, _ = root.Get("object").Properties()
if mi.HasNext() {
t.Fatalf("should not have next")
}
}
func BenchmarkArrays(b *testing.B) {

View file

@ -19,7 +19,7 @@ import os
import subprocess
import argparse
repeat_time = 10
repeat_time = 100
gbench_prefix = "SONIC_NO_ASYNC_GC=1 go test -benchmem -run=none -count=%d "%(repeat_time)
def run(cmd):

View file

@ -38,6 +38,7 @@ import (
`unicode/utf8`
`github.com/bytedance/sonic/decoder`
`github.com/bytedance/sonic/internal/native/types`
`github.com/davecgh/go-spew/spew`
)
@ -2361,6 +2362,11 @@ func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) {
}
func TestUnmarshalMaxDepth(t *testing.T) {
const (
_MaxDepth = types.MAX_RECURSE
_OverMaxDepth = types.MAX_RECURSE + 1
_UnderMaxDepth = types.MAX_RECURSE - 2
)
testcases := []struct {
name string
data string
@ -2368,12 +2374,12 @@ func TestUnmarshalMaxDepth(t *testing.T) {
}{
{
name: "ArrayUnderMaxNestingDepth",
data: `{"a":` + strings.Repeat(`[`, 65534) + `0` + strings.Repeat(`]`, 65534) + `}`,
data: `{"a":` + strings.Repeat(`[`, _UnderMaxDepth) + `0` + strings.Repeat(`]`, _UnderMaxDepth) + `}`,
errMaxDepth: false,
},
{
name: "ArrayOverMaxNestingDepth",
data: `{"a":` + strings.Repeat(`[`, 65537) + `0` + strings.Repeat(`]`, 65537) + `}`,
data: `{"a":` + strings.Repeat(`[`, _OverMaxDepth) + `0` + strings.Repeat(`]`, _OverMaxDepth) + `}`,
errMaxDepth: true,
},
{
@ -2383,12 +2389,12 @@ func TestUnmarshalMaxDepth(t *testing.T) {
},
{
name: "ObjectUnderMaxNestingDepth",
data: `{"a":` + strings.Repeat(`{"a":`, 65534) + `0` + strings.Repeat(`}`, 65534) + `}`,
data: `{"a":` + strings.Repeat(`{"a":`, _UnderMaxDepth) + `0` + strings.Repeat(`}`, _UnderMaxDepth) + `}`,
errMaxDepth: false,
},
{
name: "ObjectOverMaxNestingDepth",
data: `{"a":` + strings.Repeat(`{"a":`, 65537) + `0` + strings.Repeat(`}`, 65537) + `}`,
data: `{"a":` + strings.Repeat(`{"a":`, _OverMaxDepth) + `0` + strings.Repeat(`}`, _OverMaxDepth) + `}`,
errMaxDepth: true,
},
{

View file

@ -28,7 +28,7 @@ import (
const (
_MinSlice = 16
_MaxStack = 65536 // 64k slots
_MaxStack = 4096 // 4k slots
_MaxStackBytes = _MaxStack * _PtrBytes
_MaxDigitNums = 800 // used in atof fallback algorithm
)

View file

@ -524,7 +524,7 @@ type f64Bench struct {
name string
float float64
}
func BenchmarkEncoder_Float64(b *testing.B) {
func BenchmarkEncode_Float64(b *testing.B) {
var bench = []f64Bench{
{"Zero", 0},
{"ShortDecimal", 1000},
@ -564,7 +564,7 @@ type f32Bench struct {
name string
float float32
}
func BenchmarkEncoder_Float32(b *testing.B) {
func BenchmarkEncode_Float32(b *testing.B) {
var bench = []f32Bench{
{"Zero", 0},
{"ShortDecimal", 1000},

View file

@ -27,7 +27,7 @@ import (
)
const (
_MaxStack = 65536 // 64k states
_MaxStack = 4096 // 4k states
_MaxBuffer = 1048576 // 1MB buffer size
_StackSize = unsafe.Sizeof(_Stack{})

View file

@ -6259,7 +6259,7 @@ LBB19_29:
LONG $0x0001fce9; BYTE $0x00 // jmp LBB19_75, $508(%rip)
LBB19_30:
LONG $0xfffffa81; WORD $0x0000 // cmpl $65535, %edx
LONG $0x0ffffa81; WORD $0x0000 // cmpl $4095, %edx
LONG $0x02028f0f; WORD $0x0000 // jg LBB19_58, $514(%rip)
WORD $0x428d; BYTE $0x01 // leal $1(%rdx), %eax
WORD $0x8941; BYTE $0x07 // movl %eax, (%r15)
@ -6267,7 +6267,7 @@ LBB19_30:
LONG $0xfffe04e9; BYTE $0xff // jmp LBB19_55, $-508(%rip)
LBB19_32:
LONG $0xfffffa81; WORD $0x0000 // cmpl $65535, %edx
LONG $0x0ffffa81; WORD $0x0000 // cmpl $4095, %edx
LONG $0x01e28f0f; WORD $0x0000 // jg LBB19_58, $482(%rip)
WORD $0x428d; BYTE $0x01 // leal $1(%rdx), %eax
WORD $0x8941; BYTE $0x07 // movl %eax, (%r15)
@ -6299,7 +6299,7 @@ LBB19_37:
WORD $0x854d; BYTE $0xed // testq %r13, %r13
LONG $0x016d880f; WORD $0x0000 // js LBB19_75, $365(%rip)
WORD $0x6349; BYTE $0x07 // movslq (%r15), %rax
LONG $0xffff3d48; WORD $0x0000 // cmpq $65535, %rax
LONG $0x0fff3d48; WORD $0x0000 // cmpq $4095, %rax
LONG $0x01708f0f; WORD $0x0000 // jg LBB19_58, $368(%rip)
WORD $0x488d; BYTE $0x01 // leal $1(%rax), %ecx
WORD $0x8941; BYTE $0x0f // movl %ecx, (%r15)
@ -6329,7 +6329,7 @@ LBB19_41:
LBB19_43:
WORD $0x6349; BYTE $0x07 // movslq (%r15), %rax
LONG $0xffff3d48; WORD $0x0000 // cmpq $65535, %rax
LONG $0x0fff3d48; WORD $0x0000 // cmpq $4095, %rax
LONG $0x01088f0f; WORD $0x0000 // jg LBB19_58, $264(%rip)
WORD $0x488d; BYTE $0x01 // leal $1(%rax), %ecx
WORD $0x8941; BYTE $0x0f // movl %ecx, (%r15)
@ -6387,7 +6387,7 @@ LBB19_52:
LBB19_53:
WORD $0x6349; BYTE $0x07 // movslq (%r15), %rax
LONG $0xffff3d48; WORD $0x0000 // cmpq $65535, %rax
LONG $0x0fff3d48; WORD $0x0000 // cmpq $4095, %rax
LONG $0x002d8f0f; WORD $0x0000 // jg LBB19_58, $45(%rip)
WORD $0x488d; BYTE $0x01 // leal $1(%rax), %ecx
WORD $0x8941; BYTE $0x0f // movl %ecx, (%r15)
@ -10089,7 +10089,7 @@ _Digits:
QUAD $0x3939383937393639 // .ascii 8, '96979899'
QUAD $0x0000000000000000 // .p2align 4, 0x00
_LB_a85a2e53: // _pow10_ceil_sig.g
_LB_844550f5: // _pow10_ceil_sig.g
QUAD $0xff77b1fcbebcdc4f // .quad -38366372719436721
QUAD $0x25e8e89c13bb0f7b // .quad 2731688931043774331
QUAD $0x9faacf3df73609b1 // .quad -6941508010590729807
@ -12744,7 +12744,7 @@ _P10_TAB:
QUAD $0x4480f0cf064dd592 // .quad 0x4480f0cf064dd592
QUAD $0x0000000000000000 // .p2align 4, 0x00
_LB_e1a02bb8: // _pow10_ceil_sig_f32.g
_LB_8e30165b: // _pow10_ceil_sig_f32.g
QUAD $0x81ceb32c4b43fcf5 // .quad -9093133594791772939
QUAD $0xa2425ff75e14fc32 // .quad -6754730975062328270
QUAD $0xcad2f7f5359a3b3f // .quad -3831727700400522433

View file

@ -6897,7 +6897,7 @@ _fsm_exec:
LONG $0x00002de9; BYTE $0x00 // jmp LBB19_7, $45(%rip)
LBB19_2:
LONG $0xfffffa81; WORD $0x0000 // cmpl $65535, %edx
LONG $0x0ffffa81; WORD $0x0000 // cmpl $4095, %edx
LONG $0x04188f0f; WORD $0x0000 // jg LBB19_64, $1048(%rip)
WORD $0x428d; BYTE $0x01 // leal $1(%rdx), %eax
WORD $0x0789 // movl %eax, (%rdi)
@ -7045,7 +7045,7 @@ LBB19_29:
LONG $0x00023de9; BYTE $0x00 // jmp LBB19_80, $573(%rip)
LBB19_31:
LONG $0xfffffa81; WORD $0x0000 // cmpl $65535, %edx
LONG $0x0ffffa81; WORD $0x0000 // cmpl $4095, %edx
LONG $0x02438f0f; WORD $0x0000 // jg LBB19_64, $579(%rip)
WORD $0x428d; BYTE $0x01 // leal $1(%rdx), %eax
WORD $0x0789 // movl %eax, (%rdi)
@ -7097,7 +7097,7 @@ LBB19_39:
LONG $0x01a0880f; WORD $0x0000 // js LBB19_80, $416(%rip)
WORD $0x894c; BYTE $0xe7 // movq %r12, %rdi
LONG $0x24046349 // movslq (%r12), %rax
LONG $0xffff3d48; WORD $0x0000 // cmpq $65535, %rax
LONG $0x0fff3d48; WORD $0x0000 // cmpq $4095, %rax
LONG $0x019f8f0f; WORD $0x0000 // jg LBB19_64, $415(%rip)
WORD $0x488d; BYTE $0x01 // leal $1(%rax), %ecx
WORD $0x0f89 // movl %ecx, (%rdi)
@ -7137,7 +7137,7 @@ LBB19_44:
LBB19_46:
WORD $0x6348; BYTE $0x07 // movslq (%rdi), %rax
LONG $0xffff3d48; WORD $0x0000 // cmpq $65535, %rax
LONG $0x0fff3d48; WORD $0x0000 // cmpq $4095, %rax
LONG $0x01178f0f; WORD $0x0000 // jg LBB19_64, $279(%rip)
WORD $0x488d; BYTE $0x01 // leal $1(%rax), %ecx
WORD $0x0f89 // movl %ecx, (%rdi)
@ -7197,7 +7197,7 @@ LBB19_55:
LBB19_56:
WORD $0x6348; BYTE $0x07 // movslq (%rdi), %rax
LONG $0xffff3d48; WORD $0x0000 // cmpq $65535, %rax
LONG $0x0fff3d48; WORD $0x0000 // cmpq $4095, %rax
LONG $0x00408f0f; WORD $0x0000 // jg LBB19_64, $64(%rip)
WORD $0x488d; BYTE $0x01 // leal $1(%rax), %ecx
WORD $0x0f89 // movl %ecx, (%rdi)
@ -11065,7 +11065,7 @@ _Digits:
QUAD $0x3939383937393639 // .ascii 8, '96979899'
QUAD $0x0000000000000000 // .p2align 4, 0x00
_LB_f7997817: // _pow10_ceil_sig.g
_LB_9ad33a8d: // _pow10_ceil_sig.g
QUAD $0xff77b1fcbebcdc4f // .quad -38366372719436721
QUAD $0x25e8e89c13bb0f7b // .quad 2731688931043774331
QUAD $0x9faacf3df73609b1 // .quad -6941508010590729807
@ -13720,7 +13720,7 @@ _P10_TAB:
QUAD $0x4480f0cf064dd592 // .quad 0x4480f0cf064dd592
QUAD $0x0000000000000000 // .p2align 4, 0x00
_LB_2989417c: // _pow10_ceil_sig_f32.g
_LB_792baa9e: // _pow10_ceil_sig_f32.g
QUAD $0x81ceb32c4b43fcf5 // .quad -9093133594791772939
QUAD $0xa2425ff75e14fc32 // .quad -6754730975062328270
QUAD $0xcad2f7f5359a3b3f // .quad -3831727700400522433

View file

@ -6313,7 +6313,7 @@ LBB19_29:
LONG $0x0001fce9; BYTE $0x00 // jmp LBB19_75, $508(%rip)
LBB19_30:
LONG $0xfffffa81; WORD $0x0000 // cmpl $65535, %edx
LONG $0x0ffffa81; WORD $0x0000 // cmpl $4095, %edx
LONG $0x02028f0f; WORD $0x0000 // jg LBB19_58, $514(%rip)
WORD $0x428d; BYTE $0x01 // leal $1(%rdx), %eax
WORD $0x8941; BYTE $0x07 // movl %eax, (%r15)
@ -6321,7 +6321,7 @@ LBB19_30:
LONG $0xfffe04e9; BYTE $0xff // jmp LBB19_55, $-508(%rip)
LBB19_32:
LONG $0xfffffa81; WORD $0x0000 // cmpl $65535, %edx
LONG $0x0ffffa81; WORD $0x0000 // cmpl $4095, %edx
LONG $0x01e28f0f; WORD $0x0000 // jg LBB19_58, $482(%rip)
WORD $0x428d; BYTE $0x01 // leal $1(%rdx), %eax
WORD $0x8941; BYTE $0x07 // movl %eax, (%r15)
@ -6353,7 +6353,7 @@ LBB19_37:
WORD $0x854d; BYTE $0xed // testq %r13, %r13
LONG $0x016d880f; WORD $0x0000 // js LBB19_75, $365(%rip)
WORD $0x6349; BYTE $0x07 // movslq (%r15), %rax
LONG $0xffff3d48; WORD $0x0000 // cmpq $65535, %rax
LONG $0x0fff3d48; WORD $0x0000 // cmpq $4095, %rax
LONG $0x01708f0f; WORD $0x0000 // jg LBB19_58, $368(%rip)
WORD $0x488d; BYTE $0x01 // leal $1(%rax), %ecx
WORD $0x8941; BYTE $0x0f // movl %ecx, (%r15)
@ -6383,7 +6383,7 @@ LBB19_41:
LBB19_43:
WORD $0x6349; BYTE $0x07 // movslq (%r15), %rax
LONG $0xffff3d48; WORD $0x0000 // cmpq $65535, %rax
LONG $0x0fff3d48; WORD $0x0000 // cmpq $4095, %rax
LONG $0x01088f0f; WORD $0x0000 // jg LBB19_58, $264(%rip)
WORD $0x488d; BYTE $0x01 // leal $1(%rax), %ecx
WORD $0x8941; BYTE $0x0f // movl %ecx, (%r15)
@ -6441,7 +6441,7 @@ LBB19_52:
LBB19_53:
WORD $0x6349; BYTE $0x07 // movslq (%r15), %rax
LONG $0xffff3d48; WORD $0x0000 // cmpq $65535, %rax
LONG $0x0fff3d48; WORD $0x0000 // cmpq $4095, %rax
LONG $0x002d8f0f; WORD $0x0000 // jg LBB19_58, $45(%rip)
WORD $0x488d; BYTE $0x01 // leal $1(%rax), %ecx
WORD $0x8941; BYTE $0x0f // movl %ecx, (%r15)
@ -10136,7 +10136,7 @@ _Digits:
QUAD $0x3939383937393639 // .ascii 8, '96979899'
QUAD $0x0000000000000000 // .p2align 4, 0x00
_LB_50bb57a5: // _pow10_ceil_sig.g
_LB_a03fbdd2: // _pow10_ceil_sig.g
QUAD $0xff77b1fcbebcdc4f // .quad -38366372719436721
QUAD $0x25e8e89c13bb0f7b // .quad 2731688931043774331
QUAD $0x9faacf3df73609b1 // .quad -6941508010590729807
@ -12791,7 +12791,7 @@ _P10_TAB:
QUAD $0x4480f0cf064dd592 // .quad 0x4480f0cf064dd592
QUAD $0x0000000000000000 // .p2align 4, 0x00
_LB_15b156e2: // _pow10_ceil_sig_f32.g
_LB_a00a2ccc: // _pow10_ceil_sig_f32.g
QUAD $0x81ceb32c4b43fcf5 // .quad -9093133594791772939
QUAD $0xa2425ff75e14fc32 // .quad -6754730975062328270
QUAD $0xcad2f7f5359a3b3f // .quad -3831727700400522433

View file

@ -25,6 +25,9 @@ type ValueType int
type ParsingError uint
type SearchingError uint
// !NOT MODIFIED ONLY.
// This definitions are followed in native/types.h.
const (
V_EOF ValueType = 1
V_NULL ValueType = 2
@ -55,7 +58,7 @@ const (
)
const (
MAX_RECURSE = 65536
MAX_RECURSE = 4096
)
const (

View file

@ -302,7 +302,7 @@ func TestPretouchSynteaRoot(t *testing.T) {
println("end decode:", e.UnixNano())
d2 := e.Sub(s).Nanoseconds()
println("elapsed:", d2, "ns")
if d1 > d2 * 10 {
if d1 > d2 * 20 {
t.Fatal("decoder pretouch not finish yet")
}

View file

@ -22,38 +22,7 @@
#include <immintrin.h>
#include <stdbool.h>
#define V_EOF 1
#define V_NULL 2
#define V_TRUE 3
#define V_FALSE 4
#define V_ARRAY 5
#define V_OBJECT 6
#define V_STRING 7
#define V_DOUBLE 8
#define V_INTEGER 9
#define V_KEY_SEP 10
#define V_ELEM_SEP 11
#define V_ARRAY_END 12
#define V_OBJECT_END 13
#define V_ATOF_NEED_FALLBACK 14
#define F_DBLUNQ (1 << 0)
#define F_UNIREP (1 << 1)
#define VS_NULL 0x6c6c756e // 'null' in little endian
#define VS_TRUE 0x65757274 // 'true' in little endian
#define VS_ALSE 0x65736c61 // 'alse' in little endian ('false' without the 'f')
#define ERR_EOF 1
#define ERR_INVAL 2
#define ERR_ESCAPE 3
#define ERR_UNICODE 4
#define ERR_OVERFLOW 5
#define ERR_NUMBER_FMT 6
#define ERR_RECURSE_MAX 7
#define ERR_FLOAT_INF 8
#define MAX_RECURSE 65536
#include "types.h"
#define likely(v) (__builtin_expect((v), 1))
#define unlikely(v) (__builtin_expect((v), 0))

40
native/types.h Normal file
View file

@ -0,0 +1,40 @@
#ifndef TYPES_H
#define TYPES_H
// !NOT MODIFIED ONLY.
// This definitions are copied from internal/native/types/types.go.
#define V_EOF 1
#define V_NULL 2
#define V_TRUE 3
#define V_FALSE 4
#define V_ARRAY 5
#define V_OBJECT 6
#define V_STRING 7
#define V_DOUBLE 8
#define V_INTEGER 9
#define V_KEY_SEP 10
#define V_ELEM_SEP 11
#define V_ARRAY_END 12
#define V_OBJECT_END 13
#define F_DBLUNQ (1 << 0)
#define F_UNIREP (1 << 1)
#define VS_NULL 0x6c6c756e // 'null' in little endian
#define VS_TRUE 0x65757274 // 'true' in little endian
#define VS_ALSE 0x65736c61 // 'alse' in little endian ('false' without the 'f')
#define ERR_EOF 1
#define ERR_INVAL 2
#define ERR_ESCAPE 3
#define ERR_UNICODE 4
#define ERR_OVERFLOW 5
#define ERR_NUMBER_FMT 6
#define ERR_RECURSE_MAX 7
#define ERR_FLOAT_INF 8
#define MAX_RECURSE 4096
#endif