Skip to content
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

Move Size from StaticArrays.jl #13

Merged
merged 3 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "StaticArraysCore"
uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c"
version = "1.3.0"
version = "1.4.0"

[compat]
julia = "1.6"
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ Interface package for [StaticArrays.jl](https://github.com/JuliaArrays/StaticArr
[![Build Status](https://github.com/JuliaArrays/StaticArraysCore.jl/workflows/CI/badge.svg)](https://github.com/JuliaArrays/StaticArraysCore.jl/actions?query=workflow%3ACI)
[![codecov.io](https://codecov.io/github/JuliaArrays/StaticArraysCore.jl/branch/main/graph/badge.svg)](http://codecov.io/github/JuliaArrays/StaticArraysCore.jl/branch/main)

Contains definitions for the following types:
Contains definitions for the following types and functions:

* immutable: `SArray`, `SVector` and `SMatrix`,
* mutable: `MArray`, `MVector` and `MMatrix`,
* wrapper: `SizedArray`, `SizedVector` and `SizedMatrix`.
* wrapper: `SizedArray`, `SizedVector` and `SizedMatrix`,
* `Size` and `Dynamic`,
* `similar_type`.
82 changes: 82 additions & 0 deletions src/StaticArraysCore.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export SArray, SMatrix, SVector
export MArray, MMatrix, MVector
export SizedArray, SizedMatrix, SizedVector
export FieldArray, FieldMatrix, FieldVector
export Size

"""
abstract type StaticArray{S, T, N} <: AbstractArray{T, N} end
Expand Down Expand Up @@ -411,4 +412,85 @@ if they wish to overload the default behavior.
"""
function similar_type end

"""
Dynamic()

Used to signify that a dimension of an array is not known statically.
"""
struct Dynamic end

const StaticDimension = Union{Int, Dynamic}

"""
Size(dims::Int...)

`Size` is used extensively throughout the `StaticArrays` API to describe _compile-time_
knowledge of the size of an array. The dimensions are stored as a type parameter and are
statically propagated by the compiler, resulting in efficient, type-inferrable code. For
example, to create a static matrix of zeros, use `A = zeros(SMatrix{3,3})`. The static
size of `A` can be obtained by `Size(A)`. (rather than `size(zeros(3,3))`, which returns
`Base.Tuple{2,Int}`).

Note that if dimensions are not known statically (e.g., for standard `Array`s),
[`Dynamic()`](@ref) should be used instead of an `Int`.

Size(a::AbstractArray)
Size(::Type{T<:AbstractArray})

The `Size` constructor can be used to extract static dimension information from a given
array. For example:

```julia-repl
julia> Size(zeros(SMatrix{3, 4}))
Size(3, 4)

julia> Size(zeros(3, 4))
Size(StaticArrays.Dynamic(), StaticArrays.Dynamic())
```

This has multiple uses, including "trait"-based dispatch on the size of a statically-sized
array. For example:

```julia
det(x::StaticMatrix) = _det(Size(x), x)
_det(::Size{(1,1)}, x::StaticMatrix) = x[1,1]
_det(::Size{(2,2)}, x::StaticMatrix) = x[1,1]*x[2,2] - x[1,2]*x[2,1]
# and other definitions as necessary
```

"""
struct Size{S}
function Size{S}() where {S}
new{S::Tuple{Vararg{StaticDimension}}}()
end
end

Base.@pure Size(s::Tuple{Vararg{StaticDimension}}) = Size{s}()
Base.@pure Size(s::StaticDimension...) = Size{s}()
Base.@pure Size(s::Type{<:Tuple}) = Size{tuple(s.parameters...)}()

Base.show(io::IO, ::Size{S}) where {S} = print(io, "Size", S)

function missing_size_error(::Type{SA}) where SA
error("""
The size of type `$SA` is not known.

If you were trying to construct (or `convert` to) a `StaticArray` you
may need to add the size explicitly as a type parameter so its size is
inferrable to the Julia compiler (or performance would be terrible). For
example, you might try

m = zeros(3,3)
SMatrix(m) # this error
SMatrix{3,3}(m) # correct - size is inferrable
SArray{Tuple{3,3}}(m) # correct, note Tuple{3,3}
""")
end

Size(a::T) where {T<:AbstractArray} = Size(T)
Size(::Type{SA}) where {SA <: StaticArray} = missing_size_error(SA)
Size(::Type{SA}) where {SA <: StaticArray{S}} where {S<:Tuple} = @isdefined(S) ? Size(S) : missing_size_error(SA)

Base.@pure Size(::Type{<:AbstractArray{<:Any, N}}) where {N} = Size(ntuple(_ -> Dynamic(), N))

end # module
13 changes: 13 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,16 @@ using StaticArraysCore, Test

@test StaticArraysCore.StaticArrayStyle{1}(Val(2)) === StaticArraysCore.StaticArrayStyle{2}()
end

@testset "Size" begin
M = SArray{Tuple{2,3,4},Int,3}(tuple(rand(Int, 24)...))
@test (@inferred Size(M)) === Size(2, 3, 4)
Ms = Size(M)
@test repr(Ms) == "Size(2, 3, 4)"
@test Size(2, StaticArraysCore.Dynamic(), 5) === Size{(2, StaticArraysCore.Dynamic(), 5)}()
@test Size((2, StaticArraysCore.Dynamic(), 5)) === Size{(2, StaticArraysCore.Dynamic(), 5)}()
@test Size(Tuple{2, StaticArraysCore.Dynamic(), 5}) === Size{(2, StaticArraysCore.Dynamic(), 5)}()
@test Size([2 3; 4 5]) === Size{(StaticArraysCore.Dynamic(), StaticArraysCore.Dynamic())}()

@test_throws ErrorException Size(SArray)
end