Skip to content

docfix reinterpret #502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 54 additions & 8 deletions docs/src/pages/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,62 @@ Another common way of storing the same data is as a 3×`N` `Matrix{Float64}`.
Rather conveniently, such types have *exactly* the same binary layout in memory,
and therefore we can use `reinterpret` to convert between the two formats
```julia
function svectors(x::Matrix{Float64})
@assert size(x,1) == 3
reinterpret(SVector{3,Float64}, x, (size(x,2),))
function svectors(x::Matrix{T}, ::Val{N}) where {T,N}
size(x,1) == N || throw("sizes mismatch")
isbitstype(T) || throw("use for bitstypes only")
reinterpret(SVector{N,T}, reshape(x, length(x)))
Copy link
Member

Choose a reason for hiding this comment

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

We can use vec(x) rather than reshape here.

end
```
Such a conversion does not copy the data, rather it refers to the *same* memory
referenced by two different Julia `Array`s. Arguably, a `Vector` of `SVector`s
is preferable to a `Matrix` because (a) it provides a better abstraction of the
objects contained in the array and (b) it allows the fast *StaticArrays* methods
to act on elements.
Such a conversion does not copy the data, rather it refers to the *same* memory.
Arguably, a `Vector` of `SVector`s is often preferable to a `Matrix` because
(a) it provides a better abstraction of the objects contained in the array and
(b) it allows the fast *StaticArrays* methods to act on elements

However, the resulting object is a Base.ReinterpretArray, not an Array, which may carry some
runtime penalty on every single access. If you can afford the memory for a copy and can live with
the non-shared mutation semantics, then it is better to pull a copy by e.g.
```julia
function svectorscopy(x::Matrix{T}, ::Val{N}) where {T,N}
size(x,1) == N || throw("sizes mismatch")
isbitstype(T) || throw("use for bitstypes only")
res = Vector{SVector{N,T}}(undef, size(x,2))
GC.@preserve res x ccall(:memcpy, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), pointer(res), pointer(x), sizeof(x))
Copy link
Member

Choose a reason for hiding this comment

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

This seems unnecessarily low level for the documentation. How about simply using

copy(reinterpret(SVector{N,T}, vec(x)))

If you do think we need this low level optimization perhaps we should be providing some version of svectors as part of the official API rather than suggesting users do these low level hacks themselves? (#496 I guess)

return res
end
```
For example:
```
julia> M=reshape(collect(1:6), (2,3))
2×3 Array{Int64,2}:
1 3 5
2 4 6

julia> svectors(M, Val{2}())
3-element reinterpret(SArray{Tuple{2},Int64,1,2}, ::Array{Int64,1}):
[1, 2]
[3, 4]
[5, 6]

julia> svectorscopy(M, Val{2}())
3-element Array{SArray{Tuple{2},Int64,1,2},1}:
[1, 2]
[3, 4]
[5, 6]
```
If applications absolutely insist on obtaining a `Vector{<:SVector}` referencing the same memory,
then this is possible by directly calling into the runtime. However, starting from
Julia 0.7 and 1.0, this violates the language specifications about aliasing
(Arrays with different `eltype` must not share memory), and is to be considered a dirty hack.
This is nevertheless safe on 1.0.* or earlier versions of the Julia compiler, but will violate
compiler assumptions on Julia 1.1 or later, and cause subtle data-corrupting miscompilation bugs.
Copy link
Member

Choose a reason for hiding this comment

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

If this is so broken, let's not suggest doing it in the docs! (I suggest we just delete this section ;-) )

```julia
function unmaintainable_svectors(x::Matrix{T}, ::Val{N}) where {T,N}
size(x,1) == N || throw("sizes mismatch")
isbitstype(T) || throw("use for bitstypes only")
ccall(:jl_reshape_array, Vector{SVector{N,T}}, (Any,Any,Any), Vector{SVector{N,T}}, x, (size(x,2),))
end
```


### Working with mutable and immutable arrays

Expand Down