forked from mirror/go-json
Merge pull request #79 from goccy/feature/add-noescape-api
Add noescape API for encoder
This commit is contained in:
commit
4c60205184
|
@ -9,24 +9,20 @@ jobs:
|
||||||
go-version: [ "1.13", "1.14", "1.15" ]
|
go-version: [ "1.13", "1.14", "1.15" ]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go ${{ matrix.go-version }}
|
- name: setup Go ${{ matrix.go-version }}
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
- name: checkout
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
- name: simple test
|
||||||
- name: Test
|
|
||||||
run: go test -v ./ -count=1
|
run: go test -v ./ -count=1
|
||||||
|
- name: test with GC pressure
|
||||||
# - name: Test with GC
|
run: go test -v ./ -count=1
|
||||||
# run: go test -v ./ -count=1
|
env:
|
||||||
# env:
|
GOGC: 1
|
||||||
# GOGC: 1
|
- name: test with race detector
|
||||||
|
run: go test -v -race ./ -count=1
|
||||||
# - name: Test with race detector
|
|
||||||
# run: go test -v -race ./ -count=1
|
|
||||||
coverage:
|
coverage:
|
||||||
name: Coverage
|
name: Coverage
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
@ -56,6 +56,15 @@ func Benchmark_Encode_SmallStruct_GoJson(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Benchmark_Encode_SmallStruct_GoJsonNoEscape(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, err := gojson.MarshalNoEscape(NewSmallPayload()); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Benchmark_Encode_SmallStructCached_EncodingJson(b *testing.B) {
|
func Benchmark_Encode_SmallStructCached_EncodingJson(b *testing.B) {
|
||||||
cached := NewSmallPayload()
|
cached := NewSmallPayload()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
@ -107,6 +116,16 @@ func Benchmark_Encode_SmallStructCached_GoJson(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Benchmark_Encode_SmallStructCached_GoJsonNoEscape(b *testing.B) {
|
||||||
|
cached := NewSmallPayload()
|
||||||
|
b.ReportAllocs()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, err := gojson.MarshalNoEscape(cached); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Benchmark_Encode_MediumStruct_EncodingJson(b *testing.B) {
|
func Benchmark_Encode_MediumStruct_EncodingJson(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
|
@ -153,6 +172,15 @@ func Benchmark_Encode_MediumStruct_GoJson(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Benchmark_Encode_MediumStruct_GoJsonNoEscape(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, err := gojson.MarshalNoEscape(NewMediumPayload()); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Benchmark_Encode_MediumStructCached_EncodingJson(b *testing.B) {
|
func Benchmark_Encode_MediumStructCached_EncodingJson(b *testing.B) {
|
||||||
cached := NewMediumPayload()
|
cached := NewMediumPayload()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
@ -204,6 +232,16 @@ func Benchmark_Encode_MediumStructCached_GoJson(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Benchmark_Encode_MediumStructCached_GoJsonNoEscape(b *testing.B) {
|
||||||
|
cached := NewMediumPayload()
|
||||||
|
b.ReportAllocs()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, err := gojson.MarshalNoEscape(cached); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Benchmark_Encode_LargeStruct_EncodingJson(b *testing.B) {
|
func Benchmark_Encode_LargeStruct_EncodingJson(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
|
@ -250,6 +288,15 @@ func Benchmark_Encode_LargeStruct_GoJson(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Benchmark_Encode_LargeStruct_GoJsonNoEscape(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, err := gojson.MarshalNoEscape(NewLargePayload()); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Benchmark_Encode_LargeStructCached_EncodingJson(b *testing.B) {
|
func Benchmark_Encode_LargeStructCached_EncodingJson(b *testing.B) {
|
||||||
cached := NewLargePayload()
|
cached := NewLargePayload()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
@ -300,3 +347,13 @@ func Benchmark_Encode_LargeStructCached_GoJson(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Benchmark_Encode_LargeStructCached_GoJsonNoEscape(b *testing.B) {
|
||||||
|
cached := NewLargePayload()
|
||||||
|
b.ReportAllocs()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, err := gojson.MarshalNoEscape(cached); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
12
encode.go
12
encode.go
|
@ -111,7 +111,8 @@ func (e *Encoder) EncodeWithOption(v interface{}, opts ...EncodeOption) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf, err := e.encode(v)
|
header := (*interfaceHeader)(unsafe.Pointer(&v))
|
||||||
|
buf, err := e.encode(header, v == nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -159,8 +160,8 @@ func (e *Encoder) reset() {
|
||||||
e.unorderedMap = false
|
e.unorderedMap = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) encodeForMarshal(v interface{}) ([]byte, error) {
|
func (e *Encoder) encodeForMarshal(header *interfaceHeader, isNil bool) ([]byte, error) {
|
||||||
buf, err := e.encode(v)
|
buf, err := e.encode(header, isNil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -177,9 +178,9 @@ func (e *Encoder) encodeForMarshal(v interface{}) ([]byte, error) {
|
||||||
return copied, nil
|
return copied, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) encode(v interface{}) ([]byte, error) {
|
func (e *Encoder) encode(header *interfaceHeader, isNil bool) ([]byte, error) {
|
||||||
b := e.buf[:0]
|
b := e.buf[:0]
|
||||||
if v == nil {
|
if isNil {
|
||||||
b = encodeNull(b)
|
b = encodeNull(b)
|
||||||
if e.enabledIndent {
|
if e.enabledIndent {
|
||||||
b = encodeIndentComma(b)
|
b = encodeIndentComma(b)
|
||||||
|
@ -188,7 +189,6 @@ func (e *Encoder) encode(v interface{}) ([]byte, error) {
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
header := (*interfaceHeader)(unsafe.Pointer(&v))
|
|
||||||
typ := header.typ
|
typ := header.typ
|
||||||
|
|
||||||
typeptr := uintptr(unsafe.Pointer(typ))
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
|
|
27
json.go
27
json.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Marshaler is the interface implemented by types that
|
// Marshaler is the interface implemented by types that
|
||||||
|
@ -157,6 +158,20 @@ func Marshal(v interface{}) ([]byte, error) {
|
||||||
return MarshalWithOption(v)
|
return MarshalWithOption(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalNoEscape
|
||||||
|
func MarshalNoEscape(v interface{}) ([]byte, error) {
|
||||||
|
var b *bytes.Buffer
|
||||||
|
enc := NewEncoder(b)
|
||||||
|
header := (*interfaceHeader)(unsafe.Pointer(&v))
|
||||||
|
bytes, err := enc.encodeForMarshal(header, v == nil)
|
||||||
|
if err != nil {
|
||||||
|
enc.release()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
enc.release()
|
||||||
|
return bytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalWithOption returns the JSON encoding of v with EncodeOption.
|
// MarshalWithOption returns the JSON encoding of v with EncodeOption.
|
||||||
func MarshalWithOption(v interface{}, opts ...EncodeOption) ([]byte, error) {
|
func MarshalWithOption(v interface{}, opts ...EncodeOption) ([]byte, error) {
|
||||||
var b *bytes.Buffer
|
var b *bytes.Buffer
|
||||||
|
@ -166,7 +181,9 @@ func MarshalWithOption(v interface{}, opts ...EncodeOption) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bytes, err := enc.encodeForMarshal(v)
|
header := (*interfaceHeader)(unsafe.Pointer(&v))
|
||||||
|
enc.ptr = header.ptr
|
||||||
|
bytes, err := enc.encodeForMarshal(header, v == nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
enc.release()
|
enc.release()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -192,7 +209,9 @@ func MarshalIndentWithOption(v interface{}, prefix, indent string, opts ...Encod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enc.SetIndent(prefix, indent)
|
enc.SetIndent(prefix, indent)
|
||||||
bytes, err := enc.encodeForMarshal(v)
|
header := (*interfaceHeader)(unsafe.Pointer(&v))
|
||||||
|
enc.ptr = header.ptr
|
||||||
|
bytes, err := enc.encodeForMarshal(header, v == nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
enc.release()
|
enc.release()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -393,7 +412,9 @@ func HTMLEscape(dst *bytes.Buffer, src []byte) {
|
||||||
}
|
}
|
||||||
enc := NewEncoder(dst)
|
enc := NewEncoder(dst)
|
||||||
enc.SetEscapeHTML(true)
|
enc.SetEscapeHTML(true)
|
||||||
enc.buf, _ = enc.encode(v)
|
header := (*interfaceHeader)(unsafe.Pointer(&v))
|
||||||
|
enc.ptr = header.ptr
|
||||||
|
enc.buf, _ = enc.encode(header, v == nil)
|
||||||
dst.Write(enc.buf[:len(enc.buf)-1]) // remove last ',' character
|
dst.Write(enc.buf[:len(enc.buf)-1]) // remove last ',' character
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue