|
99 | 99 | len |
100 | 100 | end |
101 | 101 |
|
| 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 | + |
102 | 153 | @inline function Transducers.__foldl__(rf, val, reader::BSONReader) |
103 | 154 | reader.type == BSON_TYPE_DOCUMENT || reader.type == BSON_TYPE_ARRAY || throw( |
104 | 155 | ArgumentError("Field access only available on documents and arrays") |
|
128 | 179 | end |
129 | 180 |
|
130 | 181 | @inline function Base.foreach(f, reader::BSONReader) |
131 | | - foreach(f, Map(identity), reader) |
| 182 | + foreach(f, Map(x->reader[x]), eachindex(reader)) |
132 | 183 | end |
133 | 184 |
|
134 | 185 | function Base.getindex(reader::BSONReader, target::Union{AbstractString, Symbol}) |
|
161 | 212 |
|
162 | 213 | function Base.getindex(reader::BSONReader, i::Integer) |
163 | 214 | 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 |
167 | 218 | end |
168 | 219 |
|
169 | 220 | @inline load_bits_(::Type{T}, p::Ptr{UInt8}) where T = ltoh(unsafe_load(Ptr{T}(p))) |
|
0 commit comments