-
Notifications
You must be signed in to change notification settings - Fork 41
/
indexing.jl
128 lines (116 loc) · 5.29 KB
/
indexing.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
@inline Base.getindex(d::Dimension) = val(d)
for f in (:getindex, :view, :dotview)
@eval begin
# Int and CartesianIndex forward to the parent array
@propagate_inbounds function Base.$f(d::Dimension{<:AbstractArray}, i::Union{Int,CartesianIndex})
Base.$f(val(d), i)
end
@propagate_inbounds function Base.$f(d::Dimension{<:AbstractArray}, i::Union{AbstractArray,Colon,CartesianIndices})
# AbstractArray/Colon return an AbstractArray - so rebuild the dimension
rebuild(d, Base.$f(val(d), i))
end
# Selector gets processed with `selectindices`
@propagate_inbounds function Base.$f(d::Dimension{<:AbstractArray}, i::SelectorOrInterval)
Base.$f(d, selectindices(val(d), i))
end
@propagate_inbounds function Base.$f(d::Dimension{<:AbstractArray}, i)
x = Base.$f(parent(d), i)
x isa AbstractArray ? rebuild(d, x) : x
end
end
end
#### dims2indices ####
"""
dims2indices(dim::Dimension, I) => NTuple{Union{Colon,AbstractArray,Int}}
Convert a `Dimension` or `Selector` `I` to indices of `Int`, `AbstractArray` or `Colon`.
"""
@inline dims2indices(dim::Dimension, I) = _dims2indices(dim, I)
@inline dims2indices(x, I) = dims2indices(dims(x), I)
@inline dims2indices(::Nothing, I) = _dimsnotdefinederror()
@inline dims2indices(::Tuple{}, I) = ()
@inline dims2indices(dims::DimTuple, I) = dims2indices(dims, (I,))
# Standard array indices are simply returned
@inline dims2indices(dims::DimTuple, I::Tuple{Vararg{StandardIndices}}) = I
@inline dims2indices(dims::DimTuple, I::Tuple{<:Extents.Extent}) = dims2indices(dims, _extent_as(Interval, first(I)))
@inline dims2indices(dims::DimTuple, I::Tuple{<:Touches{<:Extents.Extent}}) = dims2indices(dims, _extent_as(Touches, val(first(I))))
@inline dims2indices(dims::DimTuple, I::Tuple{<:Near{<:Extents.Extent}}) = dims2indices(dims, _extent_as(Near, val(first(I))))
@inline dims2indices(dims::DimTuple, I::Tuple{<:CartesianIndex}) = I
@inline dims2indices(dims::DimTuple, sel::Tuple) =
Lookups.selectindices(lookup(dims), sel)
@inline dims2indices(dims::DimTuple, ::Tuple{}) = ()
# Otherwise attempt to convert dims to indices
@inline function dims2indices(dims::DimTuple, I::DimTuple)
extradims = otherdims(I, dims)
length(extradims) > 0 && _extradimswarn(extradims)
_dims2indices(lookup(dims), dims, sortdims(I, dims))
end
# Handle tuples with @generated
@inline _dims2indices(::Tuple{}, dims::Tuple{}, ::Tuple{}) = ()
@generated function _dims2indices(lookups::Tuple, dims::Tuple, I::Tuple)
# We separate out Aligned and Unaligned lookups as
# Unaligned must be selected in groups e.g. X and Y together.
unalligned = Expr(:tuple)
uaI = Expr(:tuple)
alligned = Expr(:tuple)
dimmerge = Expr(:tuple)
a_count = ua_count = 0
for (i, lkup) in enumerate(lookups.parameters)
if lkup <: Unaligned
ua_count += 1
push!(unalligned.args, :(dims[$i]))
push!(uaI.args, :(I[$i]))
push!(dimmerge.args, :(uadims[$ua_count]))
else
a_count += 1
push!(alligned.args, :(_dims2indices(dims[$i], I[$i])))
# Update the merged tuple
push!(dimmerge.args, :(adims[$a_count]))
end
end
if length(unalligned.args) > 1
# Output the `dimmerge` tuple, which will
# combine uadimsand adims in the right order
quote
adims = $alligned
# Unaligned dims have to be run together as a set
uadims = unalligned_dims2indices($unalligned, map(_unwrapdim, $uaI))
$dimmerge
end
else
alligned
end
end
@inline function unalligned_dims2indices(dims::DimTuple, sel::Tuple)
map(sel) do s
s isa Union{Selector,Interval} && _unalligned_all_selector_error(dims)
isnothing(s) ? Colon() : s
end
end
@inline function unalligned_dims2indices(dims::DimTuple, sel::Tuple{Selector,Vararg{Selector}})
Lookups.select_unalligned_indices(lookup(dims), sel)
end
_unalligned_all_selector_error(dims) =
throw(ArgumentError("Unalligned dims: use selectors for all $(join(map(name, dims), ", ")) dims, or none of them"))
_unwrapdim(dim::Dimension) = val(dim)
_unwrapdim(x) = x
# Single dim methods
# Simply unwrap dimensions
@inline _dims2indices(dim::Dimension, seldim::Dimension) = _dims2indices(dim, val(seldim))
# A Dimension type always means Colon(), as if it was constructed with the default value.
@inline _dims2indices(dim::Dimension, ::Type{<:Dimension}) = Colon()
# Nothing means nothing was passed for this dimension
@inline _dims2indices(dim::Dimension, i::AbstractBeginEndRange) = i
@inline _dims2indices(dim::Dimension, i::Union{LU.Begin,LU.End,Type{LU.Begin},Type{LU.End},LU.LazyMath}) =
to_indices(parent(dim), LU._construct_types(i))[1]
@inline _dims2indices(dim::Dimension, ::Nothing) = Colon()
@inline _dims2indices(dim::Dimension, x) = Lookups.selectindices(val(dim), x)
function _extent_as(::Type{Lookups.Interval}, extent::Extents.Extent{Keys}) where Keys
map(map(name2dim, Keys), values(extent)) do k, v
rebuild(k, Lookups.Interval(v...))
end
end
function _extent_as(::Type{T}, extent::Extents.Extent{Keys}) where {T,Keys}
map(map(name2dim, Keys), values(extent)) do k, v
rebuild(k, T(v))
end
end