Skip to content

Commit 33f4dad

Browse files
authored
Move Size from StaticArrays.jl (#13)
* Move `Size` from StaticArrays.jl * one more test * export Size
1 parent 3024fe6 commit 33f4dad

File tree

4 files changed

+100
-3
lines changed

4 files changed

+100
-3
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "StaticArraysCore"
22
uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c"
3-
version = "1.3.0"
3+
version = "1.4.0"
44

55
[compat]
66
julia = "1.6"

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ Interface package for [StaticArrays.jl](https://github.com/JuliaArrays/StaticArr
55
[![Build Status](https://github.com/JuliaArrays/StaticArraysCore.jl/workflows/CI/badge.svg)](https://github.com/JuliaArrays/StaticArraysCore.jl/actions?query=workflow%3ACI)
66
[![codecov.io](https://codecov.io/github/JuliaArrays/StaticArraysCore.jl/branch/main/graph/badge.svg)](http://codecov.io/github/JuliaArrays/StaticArraysCore.jl/branch/main)
77

8-
Contains definitions for the following types:
8+
Contains definitions for the following types and functions:
99

1010
* immutable: `SArray`, `SVector` and `SMatrix`,
1111
* mutable: `MArray`, `MVector` and `MMatrix`,
12-
* wrapper: `SizedArray`, `SizedVector` and `SizedMatrix`.
12+
* wrapper: `SizedArray`, `SizedVector` and `SizedMatrix`,
13+
* `Size` and `Dynamic`,
14+
* `similar_type`.

src/StaticArraysCore.jl

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export SArray, SMatrix, SVector
44
export MArray, MMatrix, MVector
55
export SizedArray, SizedMatrix, SizedVector
66
export FieldArray, FieldMatrix, FieldVector
7+
export Size
78

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

415+
"""
416+
Dynamic()
417+
418+
Used to signify that a dimension of an array is not known statically.
419+
"""
420+
struct Dynamic end
421+
422+
const StaticDimension = Union{Int, Dynamic}
423+
424+
"""
425+
Size(dims::Int...)
426+
427+
`Size` is used extensively throughout the `StaticArrays` API to describe _compile-time_
428+
knowledge of the size of an array. The dimensions are stored as a type parameter and are
429+
statically propagated by the compiler, resulting in efficient, type-inferrable code. For
430+
example, to create a static matrix of zeros, use `A = zeros(SMatrix{3,3})`. The static
431+
size of `A` can be obtained by `Size(A)`. (rather than `size(zeros(3,3))`, which returns
432+
`Base.Tuple{2,Int}`).
433+
434+
Note that if dimensions are not known statically (e.g., for standard `Array`s),
435+
[`Dynamic()`](@ref) should be used instead of an `Int`.
436+
437+
Size(a::AbstractArray)
438+
Size(::Type{T<:AbstractArray})
439+
440+
The `Size` constructor can be used to extract static dimension information from a given
441+
array. For example:
442+
443+
```julia-repl
444+
julia> Size(zeros(SMatrix{3, 4}))
445+
Size(3, 4)
446+
447+
julia> Size(zeros(3, 4))
448+
Size(StaticArrays.Dynamic(), StaticArrays.Dynamic())
449+
```
450+
451+
This has multiple uses, including "trait"-based dispatch on the size of a statically-sized
452+
array. For example:
453+
454+
```julia
455+
det(x::StaticMatrix) = _det(Size(x), x)
456+
_det(::Size{(1,1)}, x::StaticMatrix) = x[1,1]
457+
_det(::Size{(2,2)}, x::StaticMatrix) = x[1,1]*x[2,2] - x[1,2]*x[2,1]
458+
# and other definitions as necessary
459+
```
460+
461+
"""
462+
struct Size{S}
463+
function Size{S}() where {S}
464+
new{S::Tuple{Vararg{StaticDimension}}}()
465+
end
466+
end
467+
468+
Base.@pure Size(s::Tuple{Vararg{StaticDimension}}) = Size{s}()
469+
Base.@pure Size(s::StaticDimension...) = Size{s}()
470+
Base.@pure Size(s::Type{<:Tuple}) = Size{tuple(s.parameters...)}()
471+
472+
Base.show(io::IO, ::Size{S}) where {S} = print(io, "Size", S)
473+
474+
function missing_size_error(::Type{SA}) where SA
475+
error("""
476+
The size of type `$SA` is not known.
477+
478+
If you were trying to construct (or `convert` to) a `StaticArray` you
479+
may need to add the size explicitly as a type parameter so its size is
480+
inferrable to the Julia compiler (or performance would be terrible). For
481+
example, you might try
482+
483+
m = zeros(3,3)
484+
SMatrix(m) # this error
485+
SMatrix{3,3}(m) # correct - size is inferrable
486+
SArray{Tuple{3,3}}(m) # correct, note Tuple{3,3}
487+
""")
488+
end
489+
490+
Size(a::T) where {T<:AbstractArray} = Size(T)
491+
Size(::Type{SA}) where {SA <: StaticArray} = missing_size_error(SA)
492+
Size(::Type{SA}) where {SA <: StaticArray{S}} where {S<:Tuple} = @isdefined(S) ? Size(S) : missing_size_error(SA)
493+
494+
Base.@pure Size(::Type{<:AbstractArray{<:Any, N}}) where {N} = Size(ntuple(_ -> Dynamic(), N))
495+
414496
end # module

test/runtests.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,16 @@ using StaticArraysCore, Test
2525

2626
@test StaticArraysCore.StaticArrayStyle{1}(Val(2)) === StaticArraysCore.StaticArrayStyle{2}()
2727
end
28+
29+
@testset "Size" begin
30+
M = SArray{Tuple{2,3,4},Int,3}(tuple(rand(Int, 24)...))
31+
@test (@inferred Size(M)) === Size(2, 3, 4)
32+
Ms = Size(M)
33+
@test repr(Ms) == "Size(2, 3, 4)"
34+
@test Size(2, StaticArraysCore.Dynamic(), 5) === Size{(2, StaticArraysCore.Dynamic(), 5)}()
35+
@test Size((2, StaticArraysCore.Dynamic(), 5)) === Size{(2, StaticArraysCore.Dynamic(), 5)}()
36+
@test Size(Tuple{2, StaticArraysCore.Dynamic(), 5}) === Size{(2, StaticArraysCore.Dynamic(), 5)}()
37+
@test Size([2 3; 4 5]) === Size{(StaticArraysCore.Dynamic(), StaticArraysCore.Dynamic())}()
38+
39+
@test_throws ErrorException Size(SArray)
40+
end

0 commit comments

Comments
 (0)