Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "PencilArrays"
uuid = "0e08944d-e94e-41b1-9406-dcf66b6a9d2e"
authors = ["Juan Ignacio Polanco <jipolanc@gmail.com> and contributors"]
version = "0.17.12"
version = "0.18.0"

[deps]
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
Expand Down Expand Up @@ -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"
1 change: 1 addition & 0 deletions docs/src/PencilArrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ in the PencilFFTs docs.
PencilArray
GlobalPencilArray
PencilArrayCollection
AbstractManyPencilArray
ManyPencilArray
```

Expand Down
156 changes: 88 additions & 68 deletions src/multiarrays.jl
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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"))