Merge branch 'master' of github.com:goccy/go-json into feature/improve-decoder-performance

This commit is contained in:
Masaaki Goshima 2021-02-06 22:15:26 +09:00
commit e9f947a29e
4 changed files with 55 additions and 20 deletions

View File

@ -15,6 +15,8 @@ linters:
- dogsled - dogsled
- dupl - dupl
- exhaustive - exhaustive
- exhaustivestruct
- errorlint
- funlen - funlen
- gci - gci
- gochecknoglobals - gochecknoglobals
@ -28,6 +30,16 @@ linters:
- gofumpt - gofumpt
- gomnd - gomnd
- gosec - gosec
- ifshort
- lll
- makezero
- nakedret
- nestif
- nlreturn
- paralleltest
- testpackage
- thelper
- wrapcheck
- interfacer - interfacer
- lll - lll
- nakedret - nakedret

View File

@ -1,3 +1,8 @@
BIN_DIR := $(CURDIR)/bin
$(BIN_DIR):
@mkdir -p $(BIN_DIR)
.PHONY: cover .PHONY: cover
cover: cover:
@ go test -coverprofile=cover.tmp.out . ; \ @ go test -coverprofile=cover.tmp.out . ; \
@ -7,3 +12,17 @@ cover:
.PHONY: cover-html .PHONY: cover-html
cover-html: cover cover-html: cover
go tool cover -html=cover.out go tool cover -html=cover.out
.PHONY: lint
lint: golangci-lint
golangci-lint run
golangci-lint: | $(BIN_DIR)
@{ \
set -e; \
GOLANGCI_LINT_TMP_DIR=$$(mktemp -d); \
cd $$GOLANGCI_LINT_TMP_DIR; \
go mod init tmp; \
GOBIN=$(BIN_DIR) go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.36.0; \
rm -rf $$GOLANGCI_LINT_TMP_DIR; \
}

View File

@ -23,6 +23,10 @@ type sliceHeader struct {
cap int cap int
} }
const (
defaultSliceCapacity = 2
)
func newSliceDecoder(dec decoder, elemType *rtype, size uintptr, structName, fieldName string) *sliceDecoder { func newSliceDecoder(dec decoder, elemType *rtype, size uintptr, structName, fieldName string) *sliceDecoder {
return &sliceDecoder{ return &sliceDecoder{
valueDecoder: dec, valueDecoder: dec,
@ -30,11 +34,10 @@ func newSliceDecoder(dec decoder, elemType *rtype, size uintptr, structName, fie
size: size, size: size,
arrayPool: sync.Pool{ arrayPool: sync.Pool{
New: func() interface{} { New: func() interface{} {
cap := 2
return &sliceHeader{ return &sliceHeader{
data: newArray(elemType, cap), data: newArray(elemType, defaultSliceCapacity),
len: 0, len: 0,
cap: cap, cap: defaultSliceCapacity,
} }
}, },
}, },
@ -84,14 +87,14 @@ func (d *sliceDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
} }
idx := 0 idx := 0
slice := d.newSlice() slice := d.newSlice()
cap := slice.cap capacity := slice.cap
data := slice.data data := slice.data
for { for {
if cap <= idx { if capacity <= idx {
src := sliceHeader{data: data, len: idx, cap: cap} src := sliceHeader{data: data, len: idx, cap: capacity}
cap *= 2 capacity *= 2
data = newArray(d.elemType, cap) data = newArray(d.elemType, capacity)
dst := sliceHeader{data: data, len: idx, cap: cap} dst := sliceHeader{data: data, len: idx, cap: capacity}
copySlice(d.elemType, dst, src) copySlice(d.elemType, dst, src)
} }
if err := d.valueDecoder.decodeStream(s, unsafe.Pointer(uintptr(data)+uintptr(idx)*d.size)); err != nil { if err := d.valueDecoder.decodeStream(s, unsafe.Pointer(uintptr(data)+uintptr(idx)*d.size)); err != nil {
@ -101,7 +104,7 @@ func (d *sliceDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
RETRY: RETRY:
switch s.char() { switch s.char() {
case ']': case ']':
slice.cap = cap slice.cap = capacity
slice.len = idx + 1 slice.len = idx + 1
slice.data = data slice.data = data
dstCap := idx + 1 dstCap := idx + 1
@ -125,12 +128,12 @@ func (d *sliceDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
if s.read() { if s.read() {
goto RETRY goto RETRY
} }
slice.cap = cap slice.cap = capacity
slice.data = data slice.data = data
d.releaseSlice(slice) d.releaseSlice(slice)
goto ERROR goto ERROR
default: default:
slice.cap = cap slice.cap = capacity
slice.data = data slice.data = data
d.releaseSlice(slice) d.releaseSlice(slice)
goto ERROR goto ERROR
@ -184,14 +187,14 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64
} }
idx := 0 idx := 0
slice := d.newSlice() slice := d.newSlice()
cap := slice.cap capacity := slice.cap
data := slice.data data := slice.data
for { for {
if cap <= idx { if capacity <= idx {
src := sliceHeader{data: data, len: idx, cap: cap} src := sliceHeader{data: data, len: idx, cap: capacity}
cap *= 2 capacity *= 2
data = newArray(d.elemType, cap) data = newArray(d.elemType, capacity)
dst := sliceHeader{data: data, len: idx, cap: cap} dst := sliceHeader{data: data, len: idx, cap: capacity}
copySlice(d.elemType, dst, src) copySlice(d.elemType, dst, src)
} }
c, err := d.valueDecoder.decode(buf, cursor, unsafe.Pointer(uintptr(data)+uintptr(idx)*d.size)) c, err := d.valueDecoder.decode(buf, cursor, unsafe.Pointer(uintptr(data)+uintptr(idx)*d.size))
@ -202,7 +205,7 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64
cursor = skipWhiteSpace(buf, cursor) cursor = skipWhiteSpace(buf, cursor)
switch buf[cursor] { switch buf[cursor] {
case ']': case ']':
slice.cap = cap slice.cap = capacity
slice.len = idx + 1 slice.len = idx + 1
slice.data = data slice.data = data
dstCap := idx + 1 dstCap := idx + 1
@ -223,7 +226,7 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64
case ',': case ',':
idx++ idx++
default: default:
slice.cap = cap slice.cap = capacity
slice.data = data slice.data = data
d.releaseSlice(slice) d.releaseSlice(slice)
return 0, errInvalidCharacter(buf[cursor], "slice", cursor) return 0, errInvalidCharacter(buf[cursor], "slice", cursor)

View File

@ -396,6 +396,7 @@ func expand(b byte) uint64 {
return lsb * uint64(b) return lsb * uint64(b)
} }
//nolint:govet
func stringToUint64Slice(s string) []uint64 { func stringToUint64Slice(s string) []uint64 {
return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{ return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{
Data: ((*reflect.StringHeader)(unsafe.Pointer(&s))).Data, Data: ((*reflect.StringHeader)(unsafe.Pointer(&s))).Data,