@@ -4,6 +4,7 @@ export SArray, SMatrix, SVector
4
4
export MArray, MMatrix, MVector
5
5
export SizedArray, SizedMatrix, SizedVector
6
6
export FieldArray, FieldMatrix, FieldVector
7
+ export Size
7
8
8
9
"""
9
10
abstract type StaticArray{S, T, N} <: AbstractArray{T, N} end
@@ -411,4 +412,85 @@ if they wish to overload the default behavior.
411
412
"""
412
413
function similar_type end
413
414
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
+
414
496
end # module
0 commit comments