diff --git a/Project.toml b/Project.toml index 46d5ab82..82832100 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PencilArrays" uuid = "0e08944d-e94e-41b1-9406-dcf66b6a9d2e" authors = ["Juan Ignacio Polanco and contributors"] -version = "0.17.12" +version = "0.18.0" [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" @@ -29,7 +29,7 @@ Requires = "1" StaticArrayInterface = "1" StaticArrays = "1" StaticPermutations = "0.3" -Strided = "1.1, 2" +Strided = "2" TimerOutputs = "0.5" VersionParsing = "1" julia = "1.7" diff --git a/docs/src/PencilArrays.md b/docs/src/PencilArrays.md index 6c365132..1ceb2e84 100644 --- a/docs/src/PencilArrays.md +++ b/docs/src/PencilArrays.md @@ -83,6 +83,7 @@ in the PencilFFTs docs. PencilArray GlobalPencilArray PencilArrayCollection +AbstractManyPencilArray ManyPencilArray ``` diff --git a/src/multiarrays.jl b/src/multiarrays.jl index 9926d051..47b71554 100644 --- a/src/multiarrays.jl +++ b/src/multiarrays.jl @@ -1,5 +1,91 @@ +## Definition of AbstractManyPencilArray + +""" + AbstractManyPencilArray{N,M} + +Abstract type specifying a container holding `M` different +[`PencilArray`](@ref) views to the same underlying. + +All views share the same dimensionality `N`. In principle, their element types +can be different. + +A concrete implementation, [`ManyPencilArray`](@ref), is proposed in which all +arrays have the same element type `T`. +""" +abstract type AbstractManyPencilArray{N,M} end + +Base.ndims(::AbstractManyPencilArray{N}) where {N} = N + """ - ManyPencilArray{T,N,M} + length(A::AbstractManyPencilArray) + +Returns the number of [`PencilArray`](@ref)s wrapped by `A`. +""" +Base.length(::AbstractManyPencilArray{N,M}) where {N,M} = M + +""" + Tuple(A::AbstractManyPencilArray) -> (u1, u2, …) + +Returns the [`PencilArray`](@ref)s wrapped by `A`. + +This can be useful for iterating over all the wrapped arrays. +""" +@inline Base.Tuple(A::AbstractManyPencilArray) = A.arrays + +""" + first(A::AbstractManyPencilArray) + +Returns the first [`PencilArray`](@ref) wrapped by `A`. +""" +Base.first(A::AbstractManyPencilArray) = first(A.arrays) + +""" + last(A::AbstractManyPencilArray) + +Returns the last [`PencilArray`](@ref) wrapped by `A`. +""" +Base.last(A::AbstractManyPencilArray) = last(A.arrays) + +""" + getindex(A::AbstractManyPencilArray, ::Val{i}) + getindex(A::AbstractManyPencilArray, i::Integer) + +Returns the i-th [`PencilArray`](@ref) wrapped by `A`. + +If possible, the `Val{i}` form should be preferred, as it ensures that the full +type of the returned `PencilArray` is known by the compiler. + +See also [`first(::AbstractManyPencilArray)`](@ref), [`last(::AbstractManyPencilArray)`](@ref). + +# Example + +```julia +A = ManyPencilArray(pencil1, pencil2, pencil3) + +# Get the PencilArray associated to `pencil2`. +u2 = A[2] +u2 = A[Val(2)] +``` +""" +Base.getindex(A::AbstractManyPencilArray, ::Val{i}) where {i} = + _getindex(Val(i), A.arrays...) +@inline Base.getindex(A::AbstractManyPencilArray, i) = A[Val(i)] + +@inline function _getindex(::Val{i}, a, t::Vararg) where {i} + i :: Integer + i <= 0 && throw(BoundsError("index must be >= 1")) + i == 1 && return a + _getindex(Val(i - 1), t...) +end + +# This will happen if the index `i` intially passed is too large. +@inline _getindex(::Val) = throw(BoundsError("invalid index")) + +# ====================================================================== # +## Concrete implementation: ManyPencilArray + +""" + ManyPencilArray{T,N,M} <: AbstractManyPencilArray{N,M} Container holding `M` different [`PencilArray`](@ref) views to the same underlying data buffer. All views share the same element type `T` and @@ -23,7 +109,7 @@ struct ManyPencilArray{ M, # number of arrays Arrays <: Tuple{Vararg{PencilArray,M}}, DataVector <: AbstractVector{T}, - } + } <: AbstractManyPencilArray{N, M} data :: DataVector arrays :: Arrays @@ -57,69 +143,3 @@ end _make_arrays(::DenseVector, ::Dims) = () Base.eltype(::ManyPencilArray{T}) where {T} = T -Base.ndims(::ManyPencilArray{T,N}) where {T,N} = N - -""" - Tuple(A::ManyPencilArray) -> (u1, u2, …) - -Returns the [`PencilArray`](@ref)s wrapped by `A`. - -This can be useful for iterating over all the wrapped arrays. -""" -@inline Base.Tuple(A::ManyPencilArray) = A.arrays - -""" - length(A::ManyPencilArray) - -Returns the number of [`PencilArray`](@ref)s wrapped by `A`. -""" -Base.length(::ManyPencilArray{T,N,M}) where {T,N,M} = M - -""" - first(A::ManyPencilArray) - -Returns the first [`PencilArray`](@ref) wrapped by `A`. -""" -Base.first(A::ManyPencilArray) = first(A.arrays) - -""" - last(A::ManyPencilArray) - -Returns the last [`PencilArray`](@ref) wrapped by `A`. -""" -Base.last(A::ManyPencilArray) = last(A.arrays) - -""" - getindex(A::ManyPencilArray, ::Val{i}) - getindex(A::ManyPencilArray, i::Integer) - -Returns the i-th [`PencilArray`](@ref) wrapped by `A`. - -If possible, the `Val{i}` form should be preferred, as it ensures that the full -type of the returned `PencilArray` is known by the compiler. - -See also [`first(::ManyPencilArray)`](@ref), [`last(::ManyPencilArray)`](@ref). - -# Example - -```julia -A = ManyPencilArray(pencil1, pencil2, pencil3) - -# Get the PencilArray associated to `pencil2`. -u2 = A[2] -u2 = A[Val(2)] -``` -""" -Base.getindex(A::ManyPencilArray, ::Val{i}) where {i} = - _getindex(Val(i), A.arrays...) -@inline Base.getindex(A::ManyPencilArray, i) = A[Val(i)] - -@inline function _getindex(::Val{i}, a, t::Vararg) where {i} - i :: Integer - i <= 0 && throw(BoundsError("index must be >= 1")) - i == 1 && return a - _getindex(Val(i - 1), t...) -end - -# This will happen if the index `i` intially passed is too large. -@inline _getindex(::Val) = throw(BoundsError("invalid index"))