Skip to content

Commit bbd9b4b

Browse files
committed
Rename FirstClass as SizeEltypeAdaptable
And convert comments to docstring.
1 parent c16c367 commit bbd9b4b

File tree

1 file changed

+53
-30
lines changed

1 file changed

+53
-30
lines changed

src/convert.jl

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
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+
"""
26
struct Args{T<:Tuple}
37
args::T
48
end
@@ -20,45 +24,64 @@ end
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"))
2529
end
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
"""
3571
function construct_type(::Type{SA}, x) where {SA<:StaticArray}
3672
x isa BadArgs || return SA
3773
_no_precise_size(SA, x.args[1][1])
3874
end
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.")
5983
end
6084

61-
adapt_eltype_size(SA, x) = adapt_eltype(adapt_size(SA, x), x)
6285
function 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

114137
need_rewrap(::Type{<:StaticArray}, x) = false
115138
function 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
117140
end
118141

119-
check_parameters(::Type{<:FirstClass}) = nothing
142+
check_parameters(::Type{<:SizeEltypeAdaptable}) = nothing
120143
check_parameters(::Type{SArray{S,T,N,L}}) where {S<:Tuple,T,N,L} = check_array_parameters(S,T,Val{N},Val{L})
121144
check_parameters(::Type{MArray{S,T,N,L}}) where {S<:Tuple,T,N,L} = check_array_parameters(S,T,Val{N},Val{L})
122145
check_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)
133156
end

0 commit comments

Comments
 (0)