Skip to content

Commit 7998042

Browse files
committed
reducible with BSONIndexUnsafe
1 parent ed7432c commit 7998042

2 files changed

Lines changed: 56 additions & 5 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "LightBSON"
22
uuid = "a4a7f996-b3a6-4de6-b9db-2fa5f350df41"
33
authors = ["Christian Rorvik <christian.rorvik@gmail.com>"]
4-
version = "0.2.14"
4+
version = "0.2.15"
55

66
[deps]
77
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"

src/reader.jl

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,57 @@ end
9999
len
100100
end
101101

102+
103+
struct BSONIndices{T<:BSONReader}
104+
reader::T
105+
end
106+
Base.eachindex(x::BSONReader) = BSONIndices(x)
107+
Base.eltype(::BSONIndices) = BSONIndexUnsafe
108+
Base.eltype(::Type{<:BSONIndices}) = BSONIndexUnsafe
109+
110+
struct BSONIndexUnsafe
111+
name_p::Ptr{UInt8}
112+
name_len::Int
113+
field_start::Int
114+
el_type::Int # should be UInt8, but it degrades performance a lot. I don't know why.
115+
end
116+
BSONIndexUnsafe() = BSONIndexUnsafe(Ptr{UInt8}(0), 0,0,zero(UInt8))
117+
isuninitialized_fast_(x::BSONIndexUnsafe) = x.name_p == Ptr{UInt8}(0)
118+
119+
@inline function Base.getindex(x::BSONReader, i::BSONIndexUnsafe)
120+
reader = BSONReader(x.src, i.field_start, unsafe_trunc(UInt8, i.el_type), x.validator, x.conversions)
121+
str = UnsafeBSONString(i.name_p, i.name_len - 1)
122+
str => reader
123+
end
124+
125+
@inline function Transducers.__foldl__(rf, val, indices::BSONIndices)
126+
reader = indices.reader
127+
reader.type == BSON_TYPE_DOCUMENT || reader.type == BSON_TYPE_ARRAY || throw(
128+
ArgumentError("Field access only available on documents and arrays")
129+
)
130+
src = reader.src
131+
GC.@preserve src begin
132+
p = pointer(reader.src)
133+
offset = reader.offset
134+
doc_len = Int(ltoh(unsafe_load(Ptr{Int32}(p + offset))))
135+
doc_end = offset + doc_len - 1
136+
offset += 4
137+
while offset < doc_end
138+
el_type = unsafe_load(p, offset + 1)
139+
name_p = p + offset + 1
140+
name_len = name_len_(name_p)
141+
field_p = name_p + name_len
142+
value_len = element_size_(el_type, field_p)
143+
field_start = offset + 1 + name_len
144+
field_end = field_start + value_len
145+
validate_field(reader.validator, el_type, field_p, value_len, doc_end - field_start)
146+
val = Transducers.@next(rf, val, BSONIndexUnsafe(name_p, name_len, field_start, Int64(el_type)))
147+
offset = field_end
148+
end
149+
Transducers.complete(rf, val)
150+
end
151+
end
152+
102153
@inline function Transducers.__foldl__(rf, val, reader::BSONReader)
103154
reader.type == BSON_TYPE_DOCUMENT || reader.type == BSON_TYPE_ARRAY || throw(
104155
ArgumentError("Field access only available on documents and arrays")
@@ -128,7 +179,7 @@ end
128179
end
129180

130181
@inline function Base.foreach(f, reader::BSONReader)
131-
foreach(f, Map(identity), reader)
182+
foreach(f, Map(x->reader[x]), eachindex(reader))
132183
end
133184

134185
function Base.getindex(reader::BSONReader, target::Union{AbstractString, Symbol})
@@ -161,9 +212,9 @@ end
161212

162213
function Base.getindex(reader::BSONReader, i::Integer)
163214
i < 1 && throw(BoundsError(reader, i))
164-
el = foldl((_, x) -> reduced(x.second), Drop(i - 1), reader; init = nothing)
165-
el === nothing && throw(BoundsError(reader, i))
166-
el
215+
el = foldl((_, x) -> reduced(x), Drop(i - 1), eachindex(reader); init = LightBSON.BSONIndexUnsafe())
216+
isuninitialized_fast_(el) && throw(BoundsError(reader, i))
217+
reader[el].second
167218
end
168219

169220
@inline load_bits_(::Type{T}, p::Ptr{UInt8}) where T = ltoh(unsafe_load(Ptr{T}(p)))

0 commit comments

Comments
 (0)