1
1
const Idx = Union{Real,Colon,AbstractArray{Int}}
2
2
3
- using Base: ViewIndex, @propagate_inbounds
3
+ using Base: ViewIndex, @propagate_inbounds , tail
4
4
5
5
# Defer IndexStyle to the wrapped array
6
6
@compat Base. IndexStyle {T,N,D,Ax} (:: Type{AxisArray{T,N,D,Ax}} ) = IndexStyle (D)
@@ -12,46 +12,58 @@ using Base: ViewIndex, @propagate_inbounds
12
12
# Cartesian iteration
13
13
Base. eachindex (A:: AxisArray ) = eachindex (A. data)
14
14
15
- @generated function reaxis (A:: AxisArray , I:: Idx... )
16
- N = length (I)
17
- # Determine the new axes:
18
- # Drop linear indexing over multiple axes
19
- droplastaxis = ndims (A) > N && ! (I[end ] <: Real ) ? 1 : 0
20
- # Drop trailing scalar dimensions
21
- lastnonscalar = N
22
- while lastnonscalar > 0 && I[lastnonscalar] <: Real
23
- lastnonscalar -= 1
15
+ """
16
+ reaxis(A::AxisArray, I...)
17
+
18
+ This internal function determines the new set of axes that are constructed upon
19
+ indexing with I.
20
+ """
21
+ reaxis (A:: AxisArray , I:: Idx... ) = _reaxis (make_axes_match (axes (A), I), I)
22
+ # Ensure the number of axes matches the number of indexing dimensions
23
+ @inline make_axes_match (axs, idxs) = _make_axes_match ((), axs, Base. index_ndims (idxs... ))
24
+ # Move the axes into newaxes, until we run out of both simultaneously
25
+ @inline _make_axes_match (newaxes, axs:: Tuple , nidxs:: Tuple ) =
26
+ _make_axes_match ((newaxes... , axs[1 ]), tail (axs), tail (nidxs))
27
+ @inline _make_axes_match (newaxes, axs:: Tuple{} , nidxs:: Tuple{} ) = newaxes
28
+ # Drop trailing axes, replacing it with a default name for the linear span
29
+ @inline _make_axes_match (newaxes, axs:: Tuple , nidxs:: Tuple{} ) =
30
+ (maybefront (newaxes)... , _nextaxistype (newaxes)(Base. OneTo (length (newaxes[end ]) * prod (map (length, axs)))))
31
+ # Insert phony singleton trailing axes
32
+ @inline _make_axes_match (newaxes, axs:: Tuple{} , nidxs:: Tuple ) =
33
+ _make_axes_match ((newaxes... , _nextaxistype (newaxes)(Base. OneTo (1 ))), (), tail (nidxs))
34
+
35
+ @inline maybefront (:: Tuple{} ) = ()
36
+ @inline maybefront (t:: Tuple ) = Base. front (t)
37
+
38
+ # Now we can reaxis without worrying about mismatched axes/indices
39
+ @inline _reaxis (axs:: Tuple{} , idxs:: Tuple{} ) = ()
40
+ # Scalars are dropped
41
+ const ScalarIndex = @compat Union{Real, AbstractArray{<: Any , 0 }}
42
+ @inline _reaxis (axs:: Tuple , idxs:: Tuple{ScalarIndex, Vararg{Any}} ) = _reaxis (tail (axs), tail (idxs))
43
+ # Colon passes straight through
44
+ @inline _reaxis (axs:: Tuple , idxs:: Tuple{Colon, Vararg{Any}} ) = (axs[1 ], _reaxis (tail (axs), tail (idxs))... )
45
+ # But arrays can add or change dimensions and accompanying axis names
46
+ @inline _reaxis (axs:: Tuple , idxs:: Tuple{AbstractArray, Vararg{Any}} ) =
47
+ (_new_axes (axs[1 ], idxs[1 ])... , _reaxis (tail (axs), tail (idxs))... )
48
+
49
+ # Vectors simply create new axes with the same name; just subsetted by their value
50
+ @inline _new_axes {name} (ax:: Axis{name} , idx:: AbstractVector ) = (Axis {name} (ax. val[idx]),)
51
+ # Arrays create multiple axes with _N appended to the axis name containing their indices
52
+ @generated function _new_axes {name, N} (ax:: Axis{name} , idx: :@compat (AbstractArray{<: Any ,N}))
53
+ newaxes = Expr (:tuple )
54
+ for i= 1 : N
55
+ push! (newaxes. args, :($ (Axis{Symbol (name, " _" , i)})(indices (idx, $ i))))
24
56
end
25
- names = axisnames (A)
26
- newaxes = Expr[]
27
- drange = 1 : lastnonscalar- droplastaxis
28
- for d= drange
29
- if I[d] <: AxisArray
30
- # Indexing with an AxisArray joins the axis names
31
- idxnames = axisnames (I[d])
32
- for i= 1 : ndims (I[d])
33
- push! (newaxes, :($ (Axis{Symbol (names[d], " _" , idxnames[i])})(I[$ d]. axes[$ i]. val)))
34
- end
35
- elseif I[d] <: Real
36
- elseif I[d] <: AbstractVector
37
- push! (newaxes, :($ (Axis{names[d]})(A. axes[$ d]. val[Base. to_index (I[$ d])])))
38
- elseif I[d] <: Colon
39
- if d < length (I) || d <= ndims (A)
40
- push! (newaxes, :($ (Axis{names[d]})(A. axes[$ d]. val)))
41
- else
42
- dimname = _defaultdimname (d)
43
- push! (newaxes, :($ (Axis{dimname})(Base. OneTo (Base. trailingsize (A, $ d)))))
44
- end
45
- elseif I[d] <: AbstractArray
46
- for i= 1 : ndims (I[d])
47
- # When we index with non-vector arrays, we *add* dimensions.
48
- push! (newaxes, :($ (Axis{Symbol (names[d], " _" , i)})(indices (I[$ d], $ i))))
49
- end
50
- end
51
- end
52
- quote
53
- ($ (newaxes... ),)
57
+ newaxes
58
+ end
59
+ # And indexing with an AxisArray joins the name and overrides the values
60
+ @generated function _new_axes {name, N} (ax:: Axis{name} , idx: :@compat (AxisArray{<: Any , N}))
61
+ newaxes = Expr (:tuple )
62
+ idxnames = axisnames (idx)
63
+ for i= 1 : N
64
+ push! (newaxes. args, :($ (Axis{Symbol (name, " _" , idxnames[i])})(idx. axes[$ i]. val)))
54
65
end
66
+ newaxes
55
67
end
56
68
57
69
@propagate_inbounds function Base. getindex (A:: AxisArray , idxs:: Idx... )
0 commit comments