|
| 1 | +#! format: off |
| 2 | +# ============================================================ Adapted from Base.Broadcast (julia version 1.10.4) |
| 3 | +@inline function Base.getindex(bc::Base.Broadcast.Broadcasted, I::DataSpecificCartesianIndex) |
| 4 | + @boundscheck checkbounds(bc, I) |
| 5 | + @inbounds _broadcast_getindex(bc, I) |
| 6 | +end |
| 7 | + |
| 8 | +# This code path is only ever reached when all datalayouts in |
| 9 | +# the broadcasted object are the same (e.g., ::VIJFH, ::VIJFH) |
| 10 | +# They may have different type parameters, but this means that |
| 11 | +# `permute_axes` will still produce the correct axes for all |
| 12 | +# datalayouts. |
| 13 | +@inline Base.checkbounds(bc::Base.Broadcast.Broadcasted, I::DataSpecificCartesianIndex) = |
| 14 | + # Base.checkbounds_indices(Bool, axes(bc), (I,)) || Base.throw_boundserror(bc, (I,)) # from Base |
| 15 | + Base.checkbounds_indices(Bool, permute_axes(axes(bc), first_datalayout_in_bc(bc)), (I.I,)) || Base.throw_boundserror(bc, (I,)) |
| 16 | + |
| 17 | +Base.@propagate_inbounds _broadcast_getindex(A::Union{Ref,AbstractArray{<:Any,0},Number}, I) = A[] # Scalar-likes can just ignore all indices |
| 18 | +Base.@propagate_inbounds _broadcast_getindex(::Ref{Type{T}}, I) where {T} = T |
| 19 | +# Tuples are statically known to be singleton or vector-like |
| 20 | +Base.@propagate_inbounds _broadcast_getindex(A::Tuple{Any}, I) = A[1] |
| 21 | +Base.@propagate_inbounds _broadcast_getindex(A::Tuple, I) = A[I[1]] |
| 22 | +# Everything else falls back to dynamically dropping broadcasted indices based upon its axes |
| 23 | +# Base.@propagate_inbounds _broadcast_getindex(A, I) = A[Base.Broadcast.newindex(A, I)] |
| 24 | +Base.@propagate_inbounds _broadcast_getindex(A, I) = A[I] |
| 25 | + |
| 26 | +# For Broadcasted |
| 27 | +Base.@propagate_inbounds function _broadcast_getindex(bc::Base.Broadcast.Broadcasted{<:Any,<:Any,<:Any,<:Any}, I) |
| 28 | + args = _getindex(bc.args, I) |
| 29 | + return _broadcast_getindex_evalf(bc.f, args...) |
| 30 | +end |
| 31 | +# Hack around losing Type{T} information in the final args tuple. Julia actually |
| 32 | +# knows (in `code_typed`) the _value_ of these types, statically displaying them, |
| 33 | +# but inference is currently skipping inferring the type of the types as they are |
| 34 | +# transiently placed in a tuple as the argument list is lispily constructed. These |
| 35 | +# additional methods recover type stability when a `Type` appears in one of the |
| 36 | +# first two arguments of a function. |
| 37 | +Base.@propagate_inbounds function _broadcast_getindex(bc::Base.Broadcast.Broadcasted{<:Any,<:Any,<:Any,<:Tuple{Ref{Type{T}},Vararg{Any}}}, I) where {T} |
| 38 | + args = _getindex(Base.tail(bc.args), I) |
| 39 | + return _broadcast_getindex_evalf(bc.f, T, args...) |
| 40 | +end |
| 41 | +Base.@propagate_inbounds function _broadcast_getindex(bc::Base.Broadcast.Broadcasted{<:Any,<:Any,<:Any,<:Tuple{Any,Ref{Type{T}},Vararg{Any}}}, I) where {T} |
| 42 | + arg1 = _broadcast_getindex(bc.args[1], I) |
| 43 | + args = _getindex(Base.tail(Base.tail(bc.args)), I) |
| 44 | + return _broadcast_getindex_evalf(bc.f, arg1, T, args...) |
| 45 | +end |
| 46 | +Base.@propagate_inbounds function _broadcast_getindex(bc::Base.Broadcast.Broadcasted{<:Any,<:Any,<:Any,<:Tuple{Ref{Type{T}},Ref{Type{S}},Vararg{Any}}}, I) where {T,S} |
| 47 | + args = _getindex(Base.tail(Base.tail(bc.args)), I) |
| 48 | + return _broadcast_getindex_evalf(bc.f, T, S, args...) |
| 49 | +end |
| 50 | + |
| 51 | +# Utilities for _broadcast_getindex |
| 52 | +Base.@propagate_inbounds _getindex(args::Tuple, I) = (_broadcast_getindex(args[1], I), _getindex(Base.tail(args), I)...) |
| 53 | +Base.@propagate_inbounds _getindex(args::Tuple{Any}, I) = (_broadcast_getindex(args[1], I),) |
| 54 | +Base.@propagate_inbounds _getindex(args::Tuple{}, I) = () |
| 55 | + |
| 56 | +@inline _broadcast_getindex_evalf(f::Tf, args::Vararg{Any,N}) where {Tf,N} = f(args...) # not propagate_inbounds |
| 57 | +# ============================================================ |
| 58 | + |
| 59 | +#! format: on |
| 60 | +# Datalayouts |
| 61 | +@propagate_inbounds function Base.getindex( |
| 62 | + data::AbstractData{S}, |
| 63 | + I::DataSpecificCartesianIndex, |
| 64 | +) where {S} |
| 65 | + @inbounds get_struct(parent(data), S, Val(field_dim(data)), I.I) |
| 66 | +end |
| 67 | +@propagate_inbounds function Base.setindex!( |
| 68 | + data::AbstractData{S}, |
| 69 | + val, |
| 70 | + I::DataSpecificCartesianIndex, |
| 71 | +) where {S} |
| 72 | + @inbounds set_struct!( |
| 73 | + parent(data), |
| 74 | + convert(S, val), |
| 75 | + Val(field_dim(data)), |
| 76 | + I.I, |
| 77 | + ) |
| 78 | +end |
| 79 | + |
| 80 | +# Returns the size of the backing array. |
| 81 | +@inline array_size(::IJKFVH{S, Nij, Nk, Nv, Nh}) where {S, Nij, Nk, Nv, Nh} = |
| 82 | + (Nij, Nij, Nk, 1, Nv, Nh) |
| 83 | +@inline array_size(::IJFH{S, Nij, Nh}) where {S, Nij, Nh} = (Nij, Nij, 1, Nh) |
| 84 | +@inline array_size(::IFH{S, Ni, Nh}) where {S, Ni, Nh} = (Ni, 1, Nh) |
| 85 | +@inline array_size(::DataF{S}) where {S} = (1,) |
| 86 | +@inline array_size(::IJF{S, Nij}) where {S, Nij} = (Nij, Nij, 1) |
| 87 | +@inline array_size(::IF{S, Ni}) where {S, Ni} = (Ni, 1) |
| 88 | +@inline array_size(::VF{S, Nv}) where {S, Nv} = (Nv, 1) |
| 89 | +@inline array_size(::VIJFH{S, Nv, Nij, Nh}) where {S, Nv, Nij, Nh} = |
| 90 | + (Nv, Nij, Nij, 1, Nh) |
| 91 | +@inline array_size(::VIFH{S, Nv, Ni, Nh}) where {S, Nv, Ni, Nh} = |
| 92 | + (Nv, Ni, 1, Nh) |
| 93 | + |
| 94 | +##### |
| 95 | +##### Helpers to support `Base.checkbounds` |
| 96 | +##### |
| 97 | + |
| 98 | +# Converts axes(::AbstractData) to a Data-specific axes |
| 99 | +@inline permute_axes(A, data::AbstractData) = |
| 100 | + map(x -> A[x], perm_to_array(data)) |
| 101 | + |
| 102 | +# axes for IJF and IF exclude the field dimension |
| 103 | +@inline permute_axes(A, ::IJF) = (A[1], A[2], Base.OneTo(1)) |
| 104 | +@inline permute_axes(A, ::IF) = (A[1], Base.OneTo(1)) |
| 105 | + |
| 106 | +# Permute dimensions of size(data) (the universal size) to |
| 107 | +# output size of array for example, this should satisfy: |
| 108 | +# @test size(parent(data)) == map(size(data)[i], perm_to_array(data)) |
| 109 | +@inline perm_to_array(::IJKFVH) = (1, 2, 3, 4, 5) |
| 110 | +@inline perm_to_array(::IJFH) = (1, 2, 3, 5) |
| 111 | +@inline perm_to_array(::IFH) = (1, 3, 5) |
| 112 | +@inline perm_to_array(::DataF) = (3,) |
| 113 | +@inline perm_to_array(::VF) = (4, 3) |
| 114 | +@inline perm_to_array(::VIJFH) = (4, 1, 2, 3, 5) |
| 115 | +@inline perm_to_array(::VIFH) = (4, 1, 3, 5) |
0 commit comments