@muladd begin
abstract type AbstractContainer end
function invalidate! end
function raw_copy! end
function move_connectivity! end
function delete_connectivity! end
function reset_data_structures! end
function copy_data!(target::AbstractArray, source::AbstractArray,
first::Int, last::Int, destination::Int, block_size::Int = 1)
count = last - first + 1
if destination <= first || destination > last
for i in 0:(count - 1), j in 1:block_size
target[block_size * (destination + i - 1) + j] = source[block_size * (first + i - 1) + j]
end
else
for i in (count - 1):-1:0, j in 1:block_size
target[block_size * (destination + i - 1) + j] = source[block_size * (first + i - 1) + j]
end
end
return target
end
capacity(c::AbstractContainer) = c.capacity
Base.length(c::AbstractContainer) = c.length
Base.size(c::AbstractContainer) = (length(c),)
"""
resize!(c::AbstractContainer, new_length) -> AbstractContainer
Resize `c` to contain `new_length` elements. If `new_length` is smaller than the current container
length, the first `new_length` elements will be retained. If `new_length` is
larger, the new elements are invalidated.
"""
function Base.resize!(c::AbstractContainer, new_length)
@assert new_length>=zero(new_length) "New length must be >= 0"
@assert new_length<=capacity(c) "New length would exceed capacity"
if new_length > length(c)
invalidate!(c, length(c) + 1, new_length)
c.length = new_length
elseif new_length < length(c)
remove_shift!(c, new_length + 1, length(c))
end
return c
end
function Trixi.copy!(target::AbstractContainer, source::AbstractContainer,
first::Int, last::Int, destination::Int)
@assert 1<=first<=length(source) "First cell out of range"
@assert 1<=last<=length(source) "Last cell out of range"
@assert 1<=destination<=length(target) "Destination out of range"
@assert destination + (last - first)<=length(target) "Target range out of bounds"
if last < first || (source === target && first == destination)
return target
end
raw_copy!(target, source, first, last, destination)
return target
end
function Trixi.copy!(target::AbstractContainer, source::AbstractContainer, from::Int,
destination::Int)
Trixi.copy!(target, source, from, from, destination)
end
function Trixi.copy!(c::AbstractContainer, first::Int, last::Int, destination::Int)
Trixi.copy!(c, c, first, last, destination)
end
function Trixi.copy!(c::AbstractContainer, from::Int, destination::Int)
Trixi.copy!(c, c, from, from, destination)
end
function move!(c::AbstractContainer, first::Int, last::Int, destination::Int)
@assert 1<=first<=length(c) "First cell $first out of range"
@assert 1<=last<=length(c) "Last cell $last out of range"
@assert 1<=destination<=length(c) "Destination $destination out of range"
@assert destination + (last - first)<=length(c) "Target range out of bounds"
if last < first || first == destination
return c
end
raw_copy!(c, first, last, destination)
move_connectivity!(c, first, last, destination)
count = last - first + 1
first_invalid = (first <= destination + count - 1 <= last) ? destination + count :
first
last_invalid = (first <= destination <= last) ? destination - 1 : last
invalidate!(c, first_invalid, last_invalid)
return c
end
function move!(c::AbstractContainer, from::Int, destination::Int)
move!(c, from, from, destination)
end
function move_connectivity!(c::AbstractContainer, from::Int, destination::Int)
return move_connectivity!(c, from, from, destination)
end
function invalidate!(c::AbstractContainer, id::Int)
return invalidate!(c, id, id)
end
function swap!(c::AbstractContainer, a::Int, b::Int)
@assert 1<=a<=length(c) "a out of range"
@assert 1<=b<=length(c) "b out of range"
if a == b
return c
end
raw_copy!(c, a, c.dummy)
move_connectivity!(c, a, c.dummy)
raw_copy!(c, b, a)
move_connectivity!(c, b, a)
raw_copy!(c, c.dummy, b)
move_connectivity!(c, c.dummy, b)
invalidate!(c, c.dummy)
return c
end
function insert!(c::AbstractContainer, position::Int, count::Int)
@assert 1<=position<=length(c)+1 "Insert position out of range"
@assert count>=0 "Count must be non-negative"
@assert count + length(c)<=capacity(c) "New length would exceed capacity"
if count == 0
return c
end
if position == length(c) + 1
resize!(c, length(c) + count)
return c
end
c.length += count
if position <= length(c) - count
move!(c, position, length(c) - count, position + count)
end
return c
end
function erase!(c::AbstractContainer, first::Int, last::Int)
@assert 1<=first<=length(c) "First cell out of range"
@assert 1<=last<=length(c) "Last cell out of range"
if last < first
return c
end
delete_connectivity!(c, first, last)
invalidate!(c, first, last)
return c
end
erase!(c::AbstractContainer, id::Int) = erase!(c, id, id)
function remove_shift!(c::AbstractContainer, first::Int, last::Int)
@assert 1<=first<=length(c) "First cell out of range"
@assert 1<=last<=length(c) "Last cell out of range"
if last < first
return c
end
delete_connectivity!(c, first, last)
if last == length(c)
invalidate!(c, first, last)
else
move!(c, last + 1, length(c), first)
end
count = last - first + 1
c.length -= count
return c
end
remove_shift!(c::AbstractContainer, id::Int) = remove_shift!(c, id, id)
function remove_fill!(c::AbstractContainer, first::Int, last::Int)
@assert 1<=first<=length(c) "First cell out of range"
@assert 1<=last<=length(c) "Last cell out of range"
if last < first
return c
end
delete_connectivity!(c, first, last)
invalidate!(c, first, last)
count = last - first + 1
if last < length(c)
move!(c, max(length(c) - count + 1, last + 1), length(c), first)
end
c.length -= count
return c
end
function reset!(c::AbstractContainer, capacity::Int)
@assert capacity >= 0
c.capacity = capacity
c.length = 0
c.dummy = capacity + 1
reset_data_structures!(c)
return c
end
function clear!(c::AbstractContainer)
invalidate!(c)
c.length = 0
return c
end
function raw_copy!(c::AbstractContainer, first::Int, last::Int, destination::Int)
raw_copy!(c, c, first, last, destination)
end
function raw_copy!(target::AbstractContainer, source::AbstractContainer, from::Int,
destination::Int)
raw_copy!(target, source, from, from, destination)
end
function raw_copy!(c::AbstractContainer, from::Int, destination::Int)
raw_copy!(c, c, from, from, destination)
end
function Adapt.adapt_structure(to, c::AbstractContainer)
error("Interface: Must implement Adapt.adapt_structure(to, ::$(typeof(c)))")
end
function Adapt.parent_type(C::Type{<:AbstractContainer})
error("Interface: Must implement Adapt.parent_type(::Type{$C}")
end
function Adapt.unwrap_type(C::Type{<:AbstractContainer})
return Adapt.unwrap_type(Adapt.parent_type(C))
end
"""
storage_type(x)
Return the storage type of `x`, which is a concrete array type, such as `Array`, `CuArray`, or `ROCArray`.
"""
function storage_type(x)
return storage_type(typeof(x))
end
function storage_type(T::Type)
error("Interface: Must implement storage_type(::Type{$T}")
end
function storage_type(::Type{<:Array})
Array
end
function storage_type(C::Type{<:AbstractContainer})
return storage_type(Adapt.unwrap_type(C))
end
"""
trixi_backend(x)
Return the computational backend for `x`, which is either a KernelAbstractions backend or `nothing`.
If the backend is `nothing`, the default multi-threaded CPU backend is used.
"""
function trixi_backend(x)
if (_PREFERENCE_THREADING === :polyester && LoopVectorization.check_args(x)) ||
(_PREFERENCE_THREADING !== :kernelabstractions &&
get_backend(x) isa KernelAbstractions.CPU)
return nothing
end
return get_backend(x)
end
function trixi_backend(x::VectorOfArray)
u = parent(x)
if eltype(u) <: StaticArrays.StaticArray
return nothing
end
if length(u) == 0
error("VectorOfArray is empty, cannot determine backend.")
end
return get_backend(u[1])
end
function unsafe_wrap_or_alloc(to, vector, size)
if length(vector) == 0
return similar(vector, size)
else
return unsafe_wrap(to, pointer(vector), size)
end
end
struct TrixiAdaptor{Storage, RealT} end
"""
trixi_adapt(Storage, RealT, x)
Adapt `x` to the storage type `Storage` and real type `RealT`.
"""
function trixi_adapt(Storage, RealT, x)
adapt(TrixiAdaptor{Storage, RealT}(), x)
end
function Adapt.adapt_storage(::TrixiAdaptor{<:Any, RealT},
x::StaticArrays.StaticArray) where {RealT}
StaticArrays.similar_type(x, RealT)(x)
end
function Adapt.adapt_storage(::TrixiAdaptor{Storage, RealT},
x::AbstractArray{T}) where {Storage, RealT,
T <: AbstractFloat}
adapt(Storage{RealT}, x)
end
function Adapt.adapt_storage(::TrixiAdaptor{Storage, RealT},
x::AbstractArray{T}) where {Storage, RealT,
T <: StaticArrays.StaticArray}
adapt(Storage{StaticArrays.similar_type(T, RealT)}, x)
end
function Adapt.adapt_storage(::TrixiAdaptor{Storage, RealT},
x::Array{T}) where {Storage, RealT,
T <: StaticArrays.MArray}
adapt(Array{StaticArrays.similar_type(T, RealT)}, x)
end
function Adapt.adapt_storage(::TrixiAdaptor{Storage, RealT},
x::AbstractArray) where {Storage, RealT}
adapt(Storage, x)
end
function unsafe_wrap_or_alloc(::TrixiAdaptor{Storage}, vec, size) where {Storage}
return unsafe_wrap_or_alloc(Storage, vec, size)
end
end