@@ -4,6 +4,7 @@ export SArray, SMatrix, SVector
44export MArray, MMatrix, MVector
55export SizedArray, SizedMatrix, SizedVector
66export 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"""
412413function 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+
414496end # module
0 commit comments