mirror of
https://github.com/vlang/v.git
synced 2025-09-13 09:25:45 -04:00
x.json2: predefine buffer capacity for encoding to avoid reallocations (#20920)
This commit is contained in:
parent
9a0435db05
commit
49b7f9a94a
@ -7,6 +7,8 @@ import benchmark
|
||||
// recommendations:
|
||||
// ./v wipe-cache && MAX_ITERATIONS=100_000 ./v run vlib/v/tests/bench/bench_json_vs_json2.v
|
||||
// ./v wipe-cache && MAX_ITERATIONS=100_000 ./v -prod crun vlib/v/tests/bench/bench_json_vs_json2.v
|
||||
// ./v wipe-cache && ./v -gc boehm_leak -o testcase_leak -prod vlib/v/tests/bench/bench_json_vs_json2.v && ./testcase_leak 2>leaks.txt
|
||||
// ./v wipe-cache && ./v -prod vlib/v/tests/bench/bench_json_vs_json2.v -o b_out && valgrind --track-origins=yes ./b_out
|
||||
|
||||
const max_iterations = os.getenv_opt('MAX_ITERATIONS') or { '1000' }.int()
|
||||
|
||||
|
98
vlib/x/json2/count.v
Normal file
98
vlib/x/json2/count.v
Normal file
@ -0,0 +1,98 @@
|
||||
module json2
|
||||
|
||||
import time
|
||||
|
||||
struct Count {
|
||||
mut:
|
||||
total int
|
||||
}
|
||||
|
||||
// get_total
|
||||
fn (mut count Count) get_total() int {
|
||||
return count.total
|
||||
}
|
||||
|
||||
// reset_total
|
||||
fn (mut count Count) reset_total() {
|
||||
count.total = 0
|
||||
}
|
||||
|
||||
// count_chars count json sizen whithout new encode
|
||||
fn (mut count Count) count_chars[T](val T) {
|
||||
$if val is $option {
|
||||
workaround := val
|
||||
if workaround != none {
|
||||
count.count_chars(val)
|
||||
}
|
||||
} $else $if T is string {
|
||||
count.chars_in_string(val)
|
||||
} $else $if T is $sumtype {
|
||||
$for v in val.variants {
|
||||
if val is v {
|
||||
count.count_chars(val)
|
||||
}
|
||||
}
|
||||
} $else $if T is $alias {
|
||||
// TODO
|
||||
} $else $if T is time.Time {
|
||||
count.total += 26 // "YYYY-MM-DDTHH:mm:ss.123Z"
|
||||
} $else $if T is $map {
|
||||
count.total++ // {
|
||||
for k, v in val {
|
||||
count.count_chars(k)
|
||||
count.total++ // :
|
||||
count.count_chars(v)
|
||||
}
|
||||
count.total++ // }
|
||||
} $else $if T is $array {
|
||||
count.total += 2 // []
|
||||
if val.len > 0 {
|
||||
for element in val {
|
||||
count.count_chars(element)
|
||||
}
|
||||
count.total += val.len - 1 // ,
|
||||
}
|
||||
} $else $if T is $struct {
|
||||
count.chars_in_struct(val)
|
||||
} $else $if T is $enum {
|
||||
count.count_chars(int(val))
|
||||
} $else $if T is $int {
|
||||
// TODO benchmark
|
||||
mut abs_val := val
|
||||
if val < 0 {
|
||||
count.total++ // -
|
||||
abs_val = -val
|
||||
}
|
||||
for number_value := abs_val; number_value >= 1; number_value /= 10 {
|
||||
count.total++
|
||||
}
|
||||
if val == 0 {
|
||||
count.total++
|
||||
}
|
||||
} $else $if T is $float {
|
||||
// TODO
|
||||
} $else $if T is bool {
|
||||
if val {
|
||||
count.total += 4 // true
|
||||
} else {
|
||||
count.total += 5 // false
|
||||
}
|
||||
} $else {
|
||||
}
|
||||
}
|
||||
|
||||
// chars_in_struct
|
||||
fn (mut count Count) chars_in_struct[T](val T) {
|
||||
count.total += 2 // {}
|
||||
$for field in T.fields {
|
||||
// TODO handle attributes
|
||||
count.total += field.name.len + 3 // "":
|
||||
workaround := val.$(field.name)
|
||||
count.count_chars(workaround)
|
||||
}
|
||||
}
|
||||
|
||||
// chars_in_string
|
||||
fn (mut count Count) chars_in_string(val string) {
|
||||
count.total += val.len + 2 // ""
|
||||
}
|
100
vlib/x/json2/count_test.v
Normal file
100
vlib/x/json2/count_test.v
Normal file
@ -0,0 +1,100 @@
|
||||
module json2
|
||||
|
||||
import time
|
||||
|
||||
const fixed_time = time.Time{
|
||||
year: 2022
|
||||
month: 3
|
||||
day: 11
|
||||
hour: 13
|
||||
minute: 54
|
||||
second: 25
|
||||
unix: 1647006865
|
||||
}
|
||||
|
||||
type StringAlias = string
|
||||
type BoolAlias = bool
|
||||
type IntAlias = int
|
||||
type TimeAlias = time.Time
|
||||
type StructAlias = StructType[int]
|
||||
type EnumAlias = Enumerates
|
||||
|
||||
type SumTypes = StructType[string] | []SumTypes | []string | bool | int | string | time.Time
|
||||
|
||||
enum Enumerates {
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e = 99
|
||||
f
|
||||
}
|
||||
|
||||
struct StructType[T] {
|
||||
mut:
|
||||
val T
|
||||
}
|
||||
|
||||
struct StructTypeOption[T] {
|
||||
mut:
|
||||
val ?T
|
||||
}
|
||||
|
||||
struct StructTypePointer[T] {
|
||||
mut:
|
||||
val &T
|
||||
}
|
||||
|
||||
fn count_test[T](value T) {
|
||||
mut count := Count{0}
|
||||
|
||||
count.count_chars(value)
|
||||
assert encode(value).len == count.get_total()
|
||||
}
|
||||
|
||||
fn test_empty() {
|
||||
count_test(map[string]string{})
|
||||
|
||||
count_test([]string{})
|
||||
|
||||
count_test(StructType[bool]{})
|
||||
|
||||
count_test(map[string]string{})
|
||||
}
|
||||
|
||||
fn test_types() {
|
||||
count_test(StructType[string]{})
|
||||
|
||||
count_test(StructType[string]{ val: '' })
|
||||
|
||||
count_test(StructType[string]{ val: 'abcd' })
|
||||
|
||||
count_test(StructType[bool]{ val: false })
|
||||
|
||||
count_test(StructType[bool]{ val: true })
|
||||
|
||||
count_test(StructType[int]{ val: 26 })
|
||||
|
||||
count_test(StructType[int]{ val: 1 })
|
||||
|
||||
count_test(StructType[int]{ val: -125 })
|
||||
|
||||
count_test(StructType[u64]{ val: u64(-1) })
|
||||
|
||||
count_test(StructType[time.Time]{})
|
||||
|
||||
count_test(StructType[time.Time]{ val: json2.fixed_time })
|
||||
|
||||
count_test(StructType[StructType[int]]{
|
||||
val: StructType[int]{
|
||||
val: 1
|
||||
}
|
||||
})
|
||||
|
||||
count_test(StructType[Enumerates]{})
|
||||
count_test(StructType[Enumerates]{})
|
||||
count_test(StructType[Enumerates]{ val: Enumerates.f })
|
||||
count_test(StructType[[]int]{})
|
||||
count_test(StructType[[]int]{ val: [0] })
|
||||
count_test(StructType[[]int]{ val: [0, 1, 0, 2, 3, 2, 5, 1] })
|
||||
}
|
@ -53,7 +53,10 @@ pub fn encode[T](val T) string {
|
||||
$if T is $array {
|
||||
return encode_array(val)
|
||||
} $else {
|
||||
mut buf := []u8{}
|
||||
mut count := Count{0}
|
||||
count.count_chars(val)
|
||||
|
||||
mut buf := []u8{cap: count.total}
|
||||
|
||||
defer {
|
||||
unsafe { buf.free() }
|
||||
|
Loading…
x
Reference in New Issue
Block a user