Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tape reading without alloc #226

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "JSON3"
uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
authors = ["Jacob Quinn <[email protected]>"]
version = "1.9.5"
version = "1.10.0"

[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Expand Down
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,41 @@ using StructTypes
JSON3.@generatetypes json_string_sample
JSON3.read(json_string, JSONTypes.Root)
```

#### Non-allocating interface

```julia
json_string = """
{
"a": 1,
"b": [1,2,3,5,8],
"c": {
"a": ["2"],
}
}
"""
reader = JSON3.Reader()
obj = JSON3.parse!(reader, json_string, JSON3.JSONObject) # returns a JSON3.JSONObject

# method 1
obj["a", Int64] # 1
# method 2
cursor = findcursor(obj, "a") # JSON3.Cursor
item = obj[cursor, Int64] # 1
# method 3
field = first(obj)
key(field) # "a", SubString
value(field, Int64) # 1

# Array
collect(obj["b", JSON3.JSONArray{Int64}]) # [1,2,3,5,8]
# Object
obj["c", JSON3.JSONObject] # JSON3.JSONObject

# Data is accessed by iterating over the fields.
# When fields are orders, it is possible to access them sequentially:
cursor = findcursor(obj, "a") # JSON3.Cursor
cursor2 = findcursor(obj, "b", cursor) # iterates from cursor
obj[cursor2] # obj["b"]

```
39 changes: 39 additions & 0 deletions benchmarks/lowlevel.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using JSON3, BenchmarkTools

str = """
{
"a": 1,
"b" :2.1,
"c":
"3",
"d": [1,2,3,5,8],
"e": [
1,"23",
[4,5]],
"f": {
"a": ["2"],
"b": 1
}
}
"""

reader = JSON3.Reader()
obj = JSON3.parse!(reader, str, JSON3.JSONObject)

function f0(str)
x = JSON3.read(str)
x["f"]["b"]
end

function f1(reader, str)
obj = JSON3.parse!(reader, str, JSON3.JSONObject)
obj["f", JSON3.JSONObject]["b", Int64]
end

function f2(obj)
obj["f", JSON3.JSONObject]["b", Int64]
end

@benchmark f0($str)
@benchmark f1($reader, $str)
@benchmark f2($obj)
9 changes: 5 additions & 4 deletions src/JSON3.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function populateinds!(x::Object)
key = getvalue(Symbol, buf, tape, tapeidx, t)
tapeidx += 2
inds[key] = tapeidx
@inbounds tapeidx += gettapelen(Any, tape[tapeidx])
@inbounds tapeidx += gettapelen(tape[tapeidx])
i += 1
end
return
Expand All @@ -64,7 +64,7 @@ function populateinds!(x::Array)
i = 1
while i <= len
@inbounds inds[i] = tapeidx
@inbounds tapeidx += gettapelen(Any, tape[tapeidx])
@inbounds tapeidx += gettapelen(tape[tapeidx])
i += 1
end
return
Expand All @@ -78,7 +78,7 @@ end
tapeidx += 2
@inbounds t = tape[tapeidx]
x = Pair{Symbol, Any}(key, getvalue(Any, getbuf(obj), tape, tapeidx, t))
tapeidx += gettapelen(Any, t)
tapeidx += gettapelen(t)
return x, (i + 1, tapeidx)
end

Expand Down Expand Up @@ -149,7 +149,7 @@ function Base.iterate(arr::Array{T}, (i, tapeidx)=(1, 3)) where {T}
tape = gettape(arr)
@inbounds t = tape[tapeidx]
val = getvalue(T, getbuf(arr), tape, tapeidx, t)
tapeidx += gettapelen(T, t)
tapeidx += gettapelen(t)
return val, (i + 1, tapeidx)
end

Expand All @@ -171,5 +171,6 @@ include("structs.jl")
include("write.jl")
include("pretty.jl")
include("gentypes.jl")
include("read_tape.jl")

end # module
Loading