Skip to content

Commit

Permalink
Parse floats using Parsers.jl
Browse files Browse the repository at this point in the history
  • Loading branch information
kmsquire committed May 30, 2019
1 parent 5973525 commit 0203f5e
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 8 deletions.
23 changes: 16 additions & 7 deletions src/Parser.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Parser # JSON

using Mmap
using ..Common
import Parsers

include("pushvector.jl")

Expand All @@ -27,7 +28,6 @@ end
# it is convenient to access MemoryParserState like a Vector{UInt8} to avoid copies
Base.@propagate_inbounds Base.getindex(state::MemoryParserState, i::Int) = codeunit(state.utf8, i)
Base.length(state::MemoryParserState) = sizeof(state.utf8)
Base.unsafe_convert(::Type{Ptr{UInt8}}, state::MemoryParserState) = Base.unsafe_convert(Ptr{UInt8}, state.utf8)

mutable struct StreamingParserState{T <: IO} <: ParserState
io::T
Expand Down Expand Up @@ -317,12 +317,21 @@ end
Parse a float from the given bytes vector, starting at `from` and ending at the
byte before `to`. Bytes enclosed should all be ASCII characters.
"""
function float_from_bytes(bytes, from::Int, to::Int)
# The ccall is not ideal (Base.tryparse would be better), but it actually
# makes an 2× difference to performance
hasvalue, val = ccall(:jl_try_substrtod, Tuple{Bool, Float64},
(Ptr{UInt8}, Csize_t, Csize_t), bytes, from - 1, to - from + 1)
hasvalue ? val : nothing
float_from_bytes(bytes::PushVector, from::Int, to::Int) = _float_from_bytes(bytes.v, from, to)
float_from_bytes(bytes::MemoryParserState, from::Int, to::Int) = _float_from_bytes(bytes.utf8, from, to)

function _float_from_bytes(bytes, from::Int, to::Int)::Union{Float64,Nothing}
# Would like to use tryparse, but we want it to consume the full input,
# and the version in Parsers does not do this.

# return Parsers.tryparse(Float64, @view bytes.utf8[from:to])

len = to - from + 1
x, code, vpos, vlen, tlen = Parsers.xparse(Float64, bytes, from, to, Parsers.OPTIONS)
if !Parsers.ok(code) || vlen < len
return nothing
end
return x::Float64
end

"""
Expand Down
1 change: 0 additions & 1 deletion src/pushvector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ end
# Default length of 20 should be enough to never need to grow in most cases
PushVector{T}() where {T} = PushVector(Vector{T}(undef, 20), 0)

Base.unsafe_convert(::Type{Ptr{UInt8}}, v::PushVector) = pointer(v.v)
Base.length(v::PushVector) = v.l
Base.size(v::PushVector) = (v.l,)
@inline function Base.getindex(v::PushVector, i)
Expand Down

0 comments on commit 0203f5e

Please sign in to comment.