1- # A help wrapper to distinguish `SA(x...)` and `SA((x...,))`
1+ """
2+ Args
3+
4+ A help wrapper to distinguish `SA(x...)` and `SA((x...,))`
5+ """
26struct Args{T<: Tuple }
37 args:: T
48end
2024_size1 (:: Type{<:StaticMatrix{M}} ) where {M} = M
2125@generated function _sqrt (:: Length{L} ) where {L}
2226 N = round (Int, sqrt (L))
23- N^ 2 == L || throw ( DimensionMismatch ( " Input's length must be perfect square " ) )
24- return :( $ N )
27+ N^ 2 == L && return :( $ N )
28+ throw ( DimensionMismatch ( " Input's length must be perfect square " ) )
2529end
2630
27- const FirstClass = Union{SArray, MArray, SHermitianCompact, SizedArray}
28-
2931"""
30- construct_type(::Type{<:StaticArray}, x)
32+ SA′ = construct_type(::Type{SA}, x) where {SA<:StaticArray}
33+
34+ Pick a proper constructor `SA′` based on `x` if `SA(x)`/`SA(x...)` has no specific definition.
35+ The default returned `SA′` is `SA` itself for user defined `StaticArray`s. This differs from
36+ `similar_type()` in that `SA′` should always be a subtype of `SA`.
37+
38+ !!! note
39+ To distinguish `SA(x...)` and `SA(x::Tuple)`, the former calls
40+ `construct_type(SA, StaticArrays.Args(x))` instead of `construct_type(SA, x)`.
41+
42+ !!! note
43+ Please make sure `SA'(x)` has a specific definition if the default behavior is overloaded.
44+ Otherwise construction might fall into infinite recursion.
3145
32- Returns a constructor for a statically-sized array based on `x`'s size and eltype.
33- The first argument is returned by default.
46+ ---
47+ The adaption rules for offical `StaticArray`s could be summarized as:
48+
49+ # `SA <: FieldArray`: `eltype` adaptable
50+
51+ `FieldArray`s are always static-sized. We only derive `SA′`'s `eltype` using type promotion if needed.
52+
53+ # `SA <: Union{SArray, MArray, SHermitianCompact, SizedArray}`: `size`/`eltype` adaptable
54+
55+ - SA(x::Tuple)
56+ If `SA` is fully static-sized, then we first try to fill `SA` with `x`'s elements.
57+ If failed and `length(SA) == 1`, then we try to fill `SA` with `x` itself.
58+
59+ If `SA` is not fully static-sized, then we always try to fill `SA` with `x`'s elements,
60+ and the constructor's `Size` is derived based on:
61+ 1. If `SA <: StaticVector`, then we use `length(x)` as the output `Length`
62+ 2. If `SA <: StaticMatrix{M}`, then we use `(M, N)` (`N = length(x) ÷ M`) as the output `Size`
63+ 3. If `SA <: StaticMatrix{M,M} where M`, then we use `(N, N)` (`N = sqrt(length(x)`) as the output `Size`.
64+ - SA(x...)
65+ Similar to `Tuple`, but we never fill `SA` with `x` itself.
66+ - SA(x::StaticArray)
67+ We treat `x` as `Tuple` whenever possible. If failed, then try to inherit `x`'s `Size`.
68+ - SA(x::AbstractArray)
69+ `x` is used to provide eltype. Thus `SA` must be static sized.
3470"""
3571function construct_type (:: Type{SA} , x) where {SA<: StaticArray }
3672 x isa BadArgs || return SA
3773 _no_precise_size (SA, x. args[1 ][1 ])
3874end
3975
40- # Here we define `construct_type(SA, x)` for `SArray`, `MArray`, `SHermitianCompact`, `SizedArray`
41- # Different `x` has different rules, to summarize:
42- # 1. Tuple
43- # We try to fill `SA` with elements in `x` if `SA` is static-sized.
44- # If `SA <: StaticVector`, the output `Length` is derived based on `length(x)`.
45- # If `SA <: StaticMatrix{M}`, the output `Size` is derived based on `length(x)÷M`.
46- # If `SA <: StaticMatrix{M,M} where M`, the output `Size` is derived based on `sqrt(length(x))`.
47- # If `length(SA) == 1 && length(x) > 1`, then we tries to fill `SA` with `x` itself. (rewrapping)
48- # 2. Args (`SA(x...)`)
49- # Similar to `Tuple`, but rewrapping is not allowed.
50- # 3. StaticArray
51- # Treat `x` as `Tuple` whenever possible. If failed, then try to inherit `x`'s `Size`.
52- # 4. AbstractArray
53- # `x` is used to provide eltype. Thus `SA` must be static sized.
54- function construct_type (:: Type{SA} , x) where {SA<: FirstClass }
55- SA′ = adapt_eltype_size (SA, x)
76+ # These StaticArrays support `size`/`eltype` adaption during construction.
77+ const SizeEltypeAdaptable = Union{SArray, MArray, SHermitianCompact, SizedArray}
78+ function construct_type (:: Type{SA} , x) where {SA<: SizeEltypeAdaptable }
79+ SA′ = adapt_eltype (adapt_size (SA, x), x)
5680 check_parameters (SA′)
57- x isa Tuple && SA === SA′ && error ( " Constructor for $SA is missing. Please file a bug. " )
58- return SA′
81+ ( x isa Tuple && SA === SA′) || return SA′
82+ error ( " Constructor for $SA is missing. Please file a bug. " )
5983end
6084
61- adapt_eltype_size (SA, x) = adapt_eltype (adapt_size (SA, x), x)
6285function adapt_size (:: Type{SA} , x) where {SA<: StaticArray }
6386 if has_size (SA) && length_match_size (SA, x)
6487 SZ = Tuple{size (SA)... }
@@ -113,10 +136,10 @@ end
113136
114137need_rewrap (:: Type{<:StaticArray} , x) = false
115138function need_rewrap (:: Type{SA} , x:: Union{Tuple,StaticArray} ) where {SA <: StaticArray }
116- has_size (SA) && length (SA) == 1 && length (x) > 1
139+ has_size (SA) && length (SA) == 1 && length (x) != 1
117140end
118141
119- check_parameters (:: Type{<:FirstClass } ) = nothing
142+ check_parameters (:: Type{<:SizeEltypeAdaptable } ) = nothing
120143check_parameters (:: Type{SArray{S,T,N,L}} ) where {S<: Tuple ,T,N,L} = check_array_parameters (S,T,Val{N},Val{L})
121144check_parameters (:: Type{MArray{S,T,N,L}} ) where {S<: Tuple ,T,N,L} = check_array_parameters (S,T,Val{N},Val{L})
122145check_parameters (:: Type{SHermitianCompact{N,T,L}} ) where {N,T,L} = _check_hermitian_parameters (Val (N), Val (L))
@@ -127,7 +150,7 @@ _no_precise_size(SA, x::StaticArray) = throw(DimensionMismatch("No precise const
127150_no_precise_size (SA, x) = throw (DimensionMismatch (" No precise constructor for $SA found. Input is not static sized." ))
128151
129152@inline (:: Type{SA} )(x... ) where {SA <: StaticArray } = construct_type (SA, Args (x))(x)
130- @inline function (:: Type{SA} )(x:: Tuple ) where {SA <: FirstClass }
153+ @inline function (:: Type{SA} )(x:: Tuple ) where {SA <: SizeEltypeAdaptable }
131154 SA′ = construct_type (SA, x)
132155 need_rewrap (SA′, x) ? SA′ ((x,)) : SA′ (x)
133156end
0 commit comments