Skip to content

Commit 760748c

Browse files
committed
Improve Mutable read perf by ensuring we merge NamedTuples and not fallback to Dict merging. Fixes #41
1 parent 347cdfa commit 760748c

4 files changed

Lines changed: 50 additions & 16 deletions

File tree

benchmarks/benchmarks.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using JSON3, StructTypes, BenchmarkTools
2+
3+
mutable struct T
4+
a::Int
5+
b::Float64
6+
c::String
7+
null::Nothing
8+
maybe::Union{Int, Nothing}
9+
T() = new()
10+
end
11+
12+
JSON3.StructType(::Type{T}) = JSON3.Mutable()
13+
StructTypes.StructType(::Type{T}) = StructTypes.Mutable()
14+
15+
@btime JSON3.read("{}", T)
16+
17+
@btime JSON3.read(b"""
18+
{
19+
"a": 1,
20+
"b": 3.14,
21+
"c": "hey",
22+
"null": null,
23+
"maybe": 10
24+
}""", T)
25+
26+
# master: 4.114 μs (62 allocations: 6.70 KiB)
27+
# 0.1.13: 3.784 μs (16 allocations: 400 bytes)
28+
# new: 950.759 ns (11 allocations: 432 bytes)

src/read.jl

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ struct VectorString{T <: AbstractVector{UInt8}} <: AbstractString
22
bytes::T
33
end
44

5-
Base.ncodeunits(s::VectorString) = length(s.bytes)
6-
Base.codeunit(s::VectorString) = UInt8
7-
Base.length(s::VectorString) = ncodeunits(s)
8-
function Base.codeunit(s::VectorString, i::Int)
9-
@inbounds b = s.bytes[i]
10-
return b
11-
end
12-
Base.pointer(v::VectorString) = pointer(v.bytes)
13-
Base.pointer(v::VectorString, i::Integer) = pointer(v.bytes, i)
14-
Base.unsafe_convert(::Type{Ptr{UInt8}}, v::VectorString) = pointer(v)
5+
Base.codeunits(x::VectorString) = x.bytes
6+
# Base.ncodeunits(s::VectorString) = length(s.bytes)
7+
# Base.codeunit(s::VectorString) = UInt8
8+
# Base.length(s::VectorString) = ncodeunits(s)
9+
# function Base.codeunit(s::VectorString, i::Int)
10+
# @inbounds b = s.bytes[i]
11+
# return b
12+
# end
13+
# Base.pointer(v::VectorString) = pointer(v.bytes)
14+
# Base.pointer(v::VectorString, i::Integer) = pointer(v.bytes, i)
15+
# Base.unsafe_convert(::Type{Ptr{UInt8}}, v::VectorString) = pointer(v)
1516

1617
# high-level user API functions
1718
read(io::IO) = read(Base.read(io, String))

src/structs.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ end
6767
invalid(InvalidChar, buf, pos, Any)
6868
end
6969

70-
@inline function read(::StringType, buf, pos, len, b, ::Type{T}; kw...) where {T}
70+
function read(::StringType, buf, pos, len, b, ::Type{T}; kw...) where {T}
7171
if b != UInt8('"')
7272
error = ExpectedOpeningQuoteChar
7373
@goto invalid
@@ -98,7 +98,7 @@ end
9898
invalid(error, buf, pos, T)
9999
end
100100

101-
@inline function read(::BoolType, buf, pos, len, b, ::Type{T}; kw...) where {T}
101+
function read(::BoolType, buf, pos, len, b, ::Type{T}; kw...) where {T}
102102
if pos + 3 <= len &&
103103
b == UInt8('t') &&
104104
buf[pos + 1] == UInt8('r') &&
@@ -117,7 +117,7 @@ end
117117
end
118118
end
119119

120-
@inline function read(::NullType, buf, pos, len, b, ::Type{T}; kw...) where {T}
120+
function read(::NullType, buf, pos, len, b, ::Type{T}; kw...) where {T}
121121
if pos + 3 <= len &&
122122
b == UInt8('n') &&
123123
buf[pos + 1] == UInt8('u') &&
@@ -129,7 +129,7 @@ end
129129
end
130130
end
131131

132-
@inline function read(::NumberType, buf, pos, len, b, ::Type{T}; kw...) where {T}
132+
function read(::NumberType, buf, pos, len, b, ::Type{T}; kw...) where {T}
133133
x, code, pos = Parsers.typeparser(StructTypes.numbertype(T), buf, pos, len, b, Int16(0), Parsers.OPTIONS)
134134
if code > 0
135135
return pos, construct(T, x; kw...)
@@ -327,7 +327,7 @@ mutable struct MutableClosure{T, KW}
327327
end
328328

329329
@inline function (f::MutableClosure)(i, nm, TT; kw...)
330-
kw2 = merge(kw, f.kw)
330+
kw2 = merge(kw.data, f.kw)
331331
pos_i, y_i = read(StructType(TT), f.buf, f.pos, f.len, f.b, TT; kw2...)
332332
f.pos = pos_i
333333
return y_i
@@ -383,7 +383,7 @@ end
383383
@eof
384384
b = getbyte(buf, pos)
385385
@wh
386-
c = MutableClosure(buf, pos, len, b, kw)
386+
c = MutableClosure(buf, pos, len, b, kw.data)
387387
if StructTypes.applyfield!(c, x, key)
388388
pos = c.pos
389389
else

src/utils.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ function getbyte(buf, pos)
44
unsafe_load(pointer(buf.s), pos)
55
end
66

7+
function getbyte(buf::AbstractVector{UInt8}, pos)
8+
@inbounds b = buf[pos]
9+
return b
10+
end
11+
712
macro eof()
813
esc(quote
914
if pos > len

0 commit comments

Comments
 (0)