Skip to content

Commit 190aa71

Browse files
Chris Fosterandyferris
authored andcommitted
Implement read() write() and read!() for static arrays
Unfortunately these allocate, but there doesn't seem to be a way to avoid this yet, until the compiler can allocate Base.RefValue on the stack (even Base.read(io, Float64) allocates!)
1 parent df19477 commit 190aa71

File tree

4 files changed

+59
-1
lines changed

4 files changed

+59
-1
lines changed

src/StaticArrays.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Base: getindex, setindex!, size, similar, vec, show,
1111
fill!, det, inv, eig, eigvals, trace, vecnorm, norm, dot, diagm,
1212
sum, diff, prod, count, any, all, sumabs, sumabs2, minimum,
1313
maximum, extrema, mean, copy, rand, randn, randexp, rand!, randn!,
14-
randexp!, normalize, normalize!
14+
randexp!, normalize, normalize!, read, read!, write
1515

1616
export StaticScalar, StaticArray, StaticVector, StaticMatrix
1717
export Scalar, SArray, SVector, SMatrix
@@ -92,6 +92,7 @@ include("solve.jl")
9292
include("eigen.jl")
9393
include("cholesky.jl")
9494
include("deque.jl")
95+
include("io.jl")
9596

9697
include("FixedSizeArrays.jl")
9798
include("ImmutableArrays.jl")

src/io.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
@inline function read(io::IO, ::Type{SA}) where {SA<:StaticArray}
3+
# Copy Base implementation of `read` for primitive types. This is less
4+
# efficient in 0.6 that we'd like because creating the Ref allocates.
5+
elements = Ref{NTuple{length(SA),eltype(SA)}}()
6+
read(io, elements)
7+
SA(elements[])
8+
end
9+
10+
@inline function read!(io::IO, a::SA) where {SA<:StaticArray}
11+
unsafe_read(io, Base.unsafe_convert(Ptr{eltype(SA)}, a), sizeof(a))
12+
a
13+
end
14+
15+
@inline function write(io::IO, a::SA) where {SA<:StaticArray}
16+
write(io, Ref(Tuple(a)))
17+
end
18+

test/io.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Serialize `xs` as type `T` to an IOBuffer one by one using Base.write.
2+
# Return the buffer positioned at the start, ready for reading
3+
write_buf(::Type{T}, xs...) where {T} = write_buf(map(T, xs)...)
4+
5+
function write_buf(xs...)
6+
io = IOBuffer()
7+
foreach(x->write(io, x), xs)
8+
seek(io, 0)
9+
io
10+
end
11+
12+
@testset "Binary IO" begin
13+
@testset "read" begin
14+
# Read static arrays from a stream which was serialized elementwise
15+
@test read(write_buf(UInt8, 1,2,3), SVector{3,UInt8}) === SVector{3,UInt8}(1,2,3)
16+
@test read(write_buf(Int32, -1,2,3), SVector{3,Int32}) === SVector{3,Int32}(-1,2,3)
17+
@test read(write_buf(Float64, 1,2,3), SVector{3,Float64}) === SVector{3,Float64}(1,2,3)
18+
@test read(write_buf(Float64, 1,2,3,4), SMatrix{2,2,Float64}) === @SMatrix [1.0 3.0; 2.0 4.0]
19+
end
20+
21+
@testset "write" begin
22+
# Compare serialized bytes
23+
@test take!(write_buf(UInt8, 1,2,3)) == take!(write_buf(SVector{3,UInt8}(1,2,3)))
24+
@test take!(write_buf(Int32, -1,2,3)) == take!(write_buf(SVector{3,Int32}(-1,2,3)))
25+
@test take!(write_buf(Float64, 1,2,3)) == take!(write_buf(SVector{3,Float64}(1,2,3)))
26+
@test take!(write_buf(Float64, 1,2,3,4)) == take!(write_buf(@SMatrix [1.0 3.0; 2.0 4.0]))
27+
end
28+
29+
@testset "read!" begin
30+
# Read static arrays from a stream which was serialized elementwise
31+
@test read!(write_buf(UInt8, 1,2,3), zeros(MVector{3,UInt8})) == MVector{3,UInt8}(1,2,3)
32+
@test read!(write_buf(Int32, -1,2,3), zeros(MVector{3,Int32})) == MVector{3,Int32}(-1,2,3)
33+
@test read!(write_buf(Float64, 1,2,3), zeros(MVector{3,Float64})) == MVector{3,Float64}(1,2,3)
34+
@test read!(write_buf(Float64, 1,2,3,4), zeros(MMatrix{2,2,Float64})) == @MMatrix [1.0 3.0; 2.0 4.0]
35+
end
36+
end
37+

test/runtests.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,7 @@ using Base.Test
2626
include("solve.jl") # Strange inference / world-age error
2727
include("eigen.jl")
2828
include("deque.jl")
29+
include("io.jl")
30+
2931
include("fixed_size_arrays.jl")
3032
end

0 commit comments

Comments
 (0)