|
| 1 | +module StaticArraysCore |
| 2 | + |
| 3 | + |
| 4 | +""" |
| 5 | + abstract type StaticArray{S, T, N} <: AbstractArray{T, N} end |
| 6 | + StaticScalar{T} = StaticArray{Tuple{}, T, 0} |
| 7 | + StaticVector{N,T} = StaticArray{Tuple{N}, T, 1} |
| 8 | + StaticMatrix{N,M,T} = StaticArray{Tuple{N,M}, T, 2} |
| 9 | +
|
| 10 | +`StaticArray`s are Julia arrays with fixed, known size. |
| 11 | +
|
| 12 | +## Dev docs |
| 13 | +
|
| 14 | +They must define the following methods: |
| 15 | + - Constructors that accept a flat tuple of data. |
| 16 | + - `getindex()` with an integer (linear indexing) (preferably `@inline` with `@boundscheck`). |
| 17 | + - `Tuple()`, returning the data in a flat Tuple. |
| 18 | +
|
| 19 | +It may be useful to implement: |
| 20 | +
|
| 21 | +- `similar_type(::Type{MyStaticArray}, ::Type{NewElType}, ::Size{NewSize})`, returning a |
| 22 | + type (or type constructor) that accepts a flat tuple of data. |
| 23 | +
|
| 24 | +For mutable containers you may also need to define the following: |
| 25 | +
|
| 26 | + - `setindex!` for a single element (linear indexing). |
| 27 | + - `similar(::Type{MyStaticArray}, ::Type{NewElType}, ::Size{NewSize})`. |
| 28 | + - In some cases, a zero-parameter constructor, `MyStaticArray{...}()` for unintialized data |
| 29 | + is assumed to exist. |
| 30 | +
|
| 31 | +(see also `SVector`, `SMatrix`, `SArray`, `MVector`, `MMatrix`, `MArray`, `SizedArray`, `FieldVector`, `FieldMatrix` and `FieldArray`) |
| 32 | +""" |
| 33 | +abstract type StaticArray{S <: Tuple, T, N} <: AbstractArray{T, N} end |
| 34 | +const StaticScalar{T} = StaticArray{Tuple{}, T, 0} |
| 35 | +const StaticVector{N, T} = StaticArray{Tuple{N}, T, 1} |
| 36 | +const StaticMatrix{N, M, T} = StaticArray{Tuple{N, M}, T, 2} |
| 37 | +const StaticVecOrMat{T} = Union{StaticVector{<:Any, T}, StaticMatrix{<:Any, <:Any, T}} |
| 38 | + |
| 39 | +# The ::Tuple variants exist to make sure that anything that calls with a tuple |
| 40 | +# instead of a Tuple gets through to the constructor, so the user gets a nice |
| 41 | +# error message |
| 42 | +Base.@pure tuple_length(T::Type{<:Tuple}) = length(T.parameters) |
| 43 | +Base.@pure tuple_length(T::Tuple) = length(T) |
| 44 | +Base.@pure tuple_prod(T::Type{<:Tuple}) = length(T.parameters) == 0 ? 1 : *(T.parameters...) |
| 45 | +Base.@pure tuple_prod(T::Tuple) = prod(T) |
| 46 | +Base.@pure tuple_minimum(T::Type{<:Tuple}) = length(T.parameters) == 0 ? 0 : minimum(tuple(T.parameters...)) |
| 47 | +Base.@pure tuple_minimum(T::Tuple) = minimum(T) |
| 48 | + |
| 49 | + |
| 50 | +# Something doesn't match up type wise |
| 51 | +function check_array_parameters(Size, T, N, L) |
| 52 | + (!isa(Size, DataType) || (Size.name !== Tuple.name)) && throw(ArgumentError("Static Array parameter Size must be a Tuple type, got $Size")) |
| 53 | + !isa(T, Type) && throw(ArgumentError("Static Array parameter T must be a type, got $T")) |
| 54 | + !isa(N.parameters[1], Int) && throw(ArgumentError("Static Array parameter N must be an integer, got $(N.parameters[1])")) |
| 55 | + !isa(L.parameters[1], Int) && throw(ArgumentError("Static Array parameter L must be an integer, got $(L.parameters[1])")) |
| 56 | + # shouldn't reach here. Anything else should have made it to the function below |
| 57 | + error("Internal error. Please file a bug") |
| 58 | +end |
| 59 | +@generated function check_array_parameters(::Type{Size}, ::Type{T}, ::Type{Val{N}}, ::Type{Val{L}}) where {Size,T,N,L} |
| 60 | + if !all(x->isa(x, Int), Size.parameters) |
| 61 | + return :(throw(ArgumentError("Static Array parameter Size must be a tuple of Ints (e.g. `SArray{Tuple{3,3}}` or `SMatrix{3,3}`)."))) |
| 62 | + end |
| 63 | + |
| 64 | + if L != tuple_prod(Size) || L < 0 || tuple_minimum(Size) < 0 || tuple_length(Size) != N |
| 65 | + return :(throw(ArgumentError("Size mismatch in Static Array parameters. Got size $Size, dimension $N and length $L."))) |
| 66 | + end |
| 67 | + |
| 68 | + return nothing |
| 69 | +end |
| 70 | + |
| 71 | + |
| 72 | +""" |
| 73 | + SArray{S, T, N, L}(x::NTuple{L}) |
| 74 | + SArray{S, T, N, L}(x1, x2, x3, ...) |
| 75 | +
|
| 76 | +Construct a statically-sized array `SArray`. Since this type is immutable, the data must be |
| 77 | +provided upon construction and cannot be mutated later. The `S` parameter is a Tuple-type |
| 78 | +specifying the dimensions, or size, of the array - such as `Tuple{3,4,5}` for a 3×4×5-sized |
| 79 | +array. The `N` parameter is the dimension of the array; the `L` parameter is the `length` |
| 80 | +of the array and is always equal to `prod(S)`. Constructors may drop the `L`, `N` and `T` |
| 81 | +parameters if they are inferrable from the input (e.g. `L` is always inferrable from `S`). |
| 82 | +
|
| 83 | + SArray{S}(a::Array) |
| 84 | +
|
| 85 | +Construct a statically-sized array of dimensions `S` (expressed as a `Tuple{...}`) using |
| 86 | +the data from `a`. The `S` parameter is mandatory since the size of `a` is unknown to the |
| 87 | +compiler (the element type may optionally also be specified). |
| 88 | +""" |
| 89 | +struct SArray{S <: Tuple, T, N, L} <: StaticArray{S, T, N} |
| 90 | + data::NTuple{L,T} |
| 91 | + |
| 92 | + function SArray{S, T, N, L}(x::NTuple{L,T}) where {S<:Tuple, T, N, L} |
| 93 | + check_array_parameters(S, T, Val{N}, Val{L}) |
| 94 | + new{S, T, N, L}(x) |
| 95 | + end |
| 96 | + |
| 97 | + function SArray{S, T, N, L}(x::NTuple{L,Any}) where {S<:Tuple, T, N, L} |
| 98 | + check_array_parameters(S, T, Val{N}, Val{L}) |
| 99 | + new{S, T, N, L}(convert_ntuple(T, x)) |
| 100 | + end |
| 101 | +end |
| 102 | + |
| 103 | +@inline SArray{S,T,N}(x::Tuple) where {S<:Tuple,T,N} = SArray{S,T,N,tuple_prod(S)}(x) |
| 104 | + |
| 105 | + |
| 106 | +""" |
| 107 | + MArray{S, T, N, L}(undef) |
| 108 | + MArray{S, T, N, L}(x::NTuple{L}) |
| 109 | + MArray{S, T, N, L}(x1, x2, x3, ...) |
| 110 | +
|
| 111 | +
|
| 112 | +Construct a statically-sized, mutable array `MArray`. The data may optionally be |
| 113 | +provided upon construction and can be mutated later. The `S` parameter is a Tuple-type |
| 114 | +specifying the dimensions, or size, of the array - such as `Tuple{3,4,5}` for a 3×4×5-sized |
| 115 | +array. The `N` parameter is the dimension of the array; the `L` parameter is the `length` |
| 116 | +of the array and is always equal to `prod(S)`. Constructors may drop the `L`, `N` and `T` |
| 117 | +parameters if they are inferrable from the input (e.g. `L` is always inferrable from `S`). |
| 118 | +
|
| 119 | + MArray{S}(a::Array) |
| 120 | +
|
| 121 | +Construct a statically-sized, mutable array of dimensions `S` (expressed as a `Tuple{...}`) |
| 122 | +using the data from `a`. The `S` parameter is mandatory since the size of `a` is unknown to |
| 123 | +the compiler (the element type may optionally also be specified). |
| 124 | +""" |
| 125 | +mutable struct MArray{S <: Tuple, T, N, L} <: StaticArray{S, T, N} |
| 126 | + data::NTuple{L,T} |
| 127 | + |
| 128 | + function MArray{S,T,N,L}(x::NTuple{L,T}) where {S<:Tuple,T,N,L} |
| 129 | + check_array_parameters(S, T, Val{N}, Val{L}) |
| 130 | + new{S,T,N,L}(x) |
| 131 | + end |
| 132 | + |
| 133 | + function MArray{S,T,N,L}(x::NTuple{L,Any}) where {S<:Tuple,T,N,L} |
| 134 | + check_array_parameters(S, T, Val{N}, Val{L}) |
| 135 | + new{S,T,N,L}(convert_ntuple(T, x)) |
| 136 | + end |
| 137 | + |
| 138 | + function MArray{S,T,N,L}(::UndefInitializer) where {S<:Tuple,T,N,L} |
| 139 | + check_array_parameters(S, T, Val{N}, Val{L}) |
| 140 | + new{S,T,N,L}() |
| 141 | + end |
| 142 | +end |
| 143 | + |
| 144 | +@inline MArray{S,T,N}(x::Tuple) where {S<:Tuple,T,N} = MArray{S,T,N,tuple_prod(S)}(x) |
| 145 | + |
| 146 | +@generated function (::Type{MArray{S,T,N}})(::UndefInitializer) where {S,T,N} |
| 147 | + return quote |
| 148 | + $(Expr(:meta, :inline)) |
| 149 | + MArray{S, T, N, $(tuple_prod(S))}(undef) |
| 150 | + end |
| 151 | +end |
| 152 | + |
| 153 | +@generated function (::Type{MArray{S,T}})(::UndefInitializer) where {S,T} |
| 154 | + return quote |
| 155 | + $(Expr(:meta, :inline)) |
| 156 | + MArray{S, T, $(tuple_length(S)), $(tuple_prod(S))}(undef) |
| 157 | + end |
| 158 | +end |
| 159 | + |
| 160 | + |
| 161 | + |
| 162 | +end # module |
0 commit comments