Skip to content

Commit

Permalink
Decide type of plain BSON array based on its contents
Browse files Browse the repository at this point in the history
If an array has no Julia type information, then we previously made it
Vector{Any}. Even if it only contained a single concrete data type. Now we
create an array from the firts element's type and expand the type if another
type of object is discovered during parsing.

This may be surprising behaviour to some people, but this is also generally
how Julia works if you create an array from an iterator or untyped
literal. Certainly it could break some peoples code so I will bump the version
to 0.6.0.

If you really need an array of type Any after deserialisation, then just do
something like `Any[A...]`.

https://discourse.julialang.org/t/tail-call-optimization-and-function-barrier-based-accumulation-in-loops/25831

This doesn't happen when the array is referenced because we would have to
update the reference after type promotion and it is not clear if this is worth
the effort to implement.
  • Loading branch information
richiejp committed Jul 21, 2019
1 parent 2f24cf8 commit 8315b11
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 9 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ uuid = "d4e7598c-6ff7-5b24-8fdc-8d1c0c33c9cf"
keywords = ["BSON", "serialization"]
license = "MIT"
desc = "Mostly compatible Fork of BSON package with focus on composite type performance"
version = "0.5.0"
version = "0.6.0"

[deps]
Mmap = "a63ad114-7e13-5084-954f-fe012c677804"
Expand Down
42 changes: 34 additions & 8 deletions src/read_direct.jl
Original file line number Diff line number Diff line change
Expand Up @@ -467,17 +467,43 @@ function parse_type(io::IO,
p
end

function parse_any_array(io::IO, ctx::ParseCtx)::BSONArray
function parse_any_array(io::IO, ctx::ParseCtx)
len = read(io, Int32)
ps = BSONArray()
setref(ps, ctx)

while (tag = read(io, BSONType)) eof
# Note that arrays are dicts with the index as the key
while read(io, UInt8) != 0x00
nothing
# If this array has a reference, then it might reference itself.
if ctx.curref -1
ps = BSONArray()
setref(ps, ctx)

while (tag = parse_array_tag(io, ctx)) eof
push!(ps, parse_tag(io, tag, ctx))
end

ps
else
# If it is not referenced then we can recreate the array with a wider type
# as we discover new types (see base/array.jl)
tag = parse_array_tag(io, ctx)
tag eof || return BSONArray()
ps = [parse_tag(io, tag, ctx)]

parse_any_array!(io::IO, ps, ctx)
end
end

function parse_any_array!(io::IO, ps::Vector{T}, ctx::ParseCtx) where T
while (tag = parse_array_tag(io, ctx)) eof
e = parse_tag(io, tag, ctx)

if e isa T || typeof(e) === T
push!(ps, e::T)
else
new = sizehint!(empty(ps, Base.typejoin(T, typeof(e))), length(ps))

append!(new, ps)
push!(new, e)
return parse_any_array!(io, new, ctx)
end
push!(ps, parse_tag(io, tag, ctx))
end

ps
Expand Down
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct Baz <: Bar end
@test roundtrip_equal(UInt8[1,2,3])
@test roundtrip_equal("b")
@test roundtrip_equal([1,"b"])
@test roundtrip_equal([[1, 2, 3], "foo"])
@test roundtrip_equal(Tuple, :compat)
end

Expand Down

2 comments on commit 8315b11

@richiejp
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register branch=qs

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/2185

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if Julia TagBot is installed, or can be done manually through the github interface, or via:

git tag -a v0.6.0 -m "<description of version>" 8315b11408bb146a5f203bc4303b8965224c5f67
git push origin v0.6.0

Please sign in to comment.