diff --git a/benchmark/benchmark_set_test.go b/benchmark/benchmark_set_test.go new file mode 100644 index 0000000..6213ef3 --- /dev/null +++ b/benchmark/benchmark_set_test.go @@ -0,0 +1,20 @@ +package benchmark + +import ( + "github.com/buger/jsonparser" + "strconv" + "testing" +) + +func BenchmarkSetLarge(b *testing.B) { + b.ReportAllocs() + + keyPath := make([]string, 20000) + for i := range keyPath { + keyPath[i] = "keyPath" + strconv.Itoa(i) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = jsonparser.Set(largeFixture, largeFixture, keyPath...) + } +} diff --git a/parser.go b/parser.go index 4417469..c34d50d 100644 --- a/parser.go +++ b/parser.go @@ -591,48 +591,96 @@ var ( ) func createInsertComponent(keys []string, setValue []byte, comma, object bool) []byte { - var buffer bytes.Buffer isIndex := string(keys[0][0]) == "[" + offset := 0 + lk := calcAllocateSpace(keys, setValue, comma, object) + buffer := make([]byte, lk, lk) if comma { - buffer.WriteString(",") + offset += WriteToBuffer(buffer[offset:], ",") } if isIndex && !comma { - buffer.WriteString("[") + offset += WriteToBuffer(buffer[offset:], "[") } else { if object { - buffer.WriteString("{") + offset += WriteToBuffer(buffer[offset:], "{") } if !isIndex { - buffer.WriteString("\"") - buffer.WriteString(keys[0]) - buffer.WriteString("\":") + offset += WriteToBuffer(buffer[offset:], "\"") + offset += WriteToBuffer(buffer[offset:], keys[0]) + offset += WriteToBuffer(buffer[offset:], "\":") } } for i := 1; i < len(keys); i++ { if string(keys[i][0]) == "[" { - buffer.WriteString("[") + offset += WriteToBuffer(buffer[offset:], "[") } else { - buffer.WriteString("{\"") - buffer.WriteString(keys[i]) - buffer.WriteString("\":") + offset += WriteToBuffer(buffer[offset:], "{\"") + offset += WriteToBuffer(buffer[offset:], keys[i]) + offset += WriteToBuffer(buffer[offset:], "\":") } } - buffer.Write(setValue) + offset += WriteToBuffer(buffer[offset:], string(setValue)) for i := len(keys) - 1; i > 0; i-- { if string(keys[i][0]) == "[" { - buffer.WriteString("]") + offset += WriteToBuffer(buffer[offset:], "]") } else { - buffer.WriteString("}") + offset += WriteToBuffer(buffer[offset:], "}") } } if isIndex && !comma { - buffer.WriteString("]") + offset += WriteToBuffer(buffer[offset:], "]") + } + if object && !isIndex { + offset += WriteToBuffer(buffer[offset:], "}") + } + return buffer +} + +func calcAllocateSpace(keys []string, setValue []byte, comma, object bool) int { + isIndex := string(keys[0][0]) == "[" + lk := 0 + if comma { + // , + lk += 1 + } + if isIndex && !comma { + // [] + lk += 2 + } else { + if object { + // { + lk += 1 + } + if !isIndex { + // "keys[0]" + lk += len(keys[0]) + 3 + } } + + + lk += len(setValue) + for i := 1; i < len(keys); i++ { + if string(keys[i][0]) == "[" { + // [] + lk += 2 + } else { + // {"keys[i]":setValue} + lk += len(keys[i]) + 5 + } + } + if object && !isIndex { - buffer.WriteString("}") + // } + lk += 1 } - return buffer.Bytes() + + return lk +} + +func WriteToBuffer(buffer []byte, str string) int { + copy(buffer, str) + return len(str) } /*