@@ -22,10 +22,12 @@ Base.getindex{T}(A::AxisArray{T,1}, idx::Colon) = A
22
22
23
23
# Linear indexing with an array
24
24
Base. getindex {S<:Int} (A:: AxisArray , idx:: AbstractArray{S} ) = A. data[idx]
25
+ Base. setindex! {S<:Int} (A:: AxisArray , v, idx:: AbstractArray{S} ) = (A. data[idx] = v)
25
26
26
27
# Cartesian iteration
27
28
Base. eachindex (A:: AxisArray ) = eachindex (A. data)
28
29
Base. getindex (A:: AxisArray , idx:: Base.IteratorsMD.CartesianIndex ) = A. data[idx]
30
+ Base. setindex! (A:: AxisArray , v, idx:: Base.IteratorsMD.CartesianIndex ) = (A. data[idx] = v)
29
31
30
32
# More complicated cases where we must create a subindexed AxisArray
31
33
# TODO : do we want to be dogmatic about using views? For the data? For the axes?
@@ -51,15 +53,38 @@ stagedfunction Base.getindex{T,N,D,Ax}(A::AxisArray{T,N,D,Ax}, idxs::Idx...)
51
53
AxisArray (data, $ axes) # TODO : avoid checking the axes here
52
54
end
53
55
end
56
+ # Setindex is so much simpler. Just assign it to the data:
57
+ Base. setindex! (A:: AxisArray , v, idxs:: Idx... ) = (A. data[idxs... ] = v)
54
58
55
59
# ## Fancier indexing capabilities provided only by AxisArrays ###
56
60
57
- # First is the ability to index by named axis.
61
+ # Defining the fallbacks on get/setindex are tricky due to ambiguities with
62
+ # AbstractArray definitions... but they simply punt to to_index to convert the
63
+ # special indexing forms to integers and integer ranges.
64
+ # Even though all these splats look scary, they get inlined and don't allocate.
65
+ Base. getindex (A:: AxisArray , idx:: AbstractArray ) = A[to_index (A,idx)... ]
66
+ Base. setindex! (A:: AxisArray , v, idx:: AbstractArray ) = (A[to_index (A,idx)... ] = v)
67
+ let rargs = Expr[], aargs = Expr[], idxs = Symbol[]
68
+ for i = 1 : 4
69
+ isym = symbol (" i$i " )
70
+ push! (rargs, :($ isym:: Real ))
71
+ push! (aargs, :($ isym:: Any ))
72
+ push! (idxs, isym)
73
+ @eval Base. getindex (A:: AxisArray , $ (rargs... )) = A[to_index (A,$ (idxs... ))... ]
74
+ @eval Base. setindex! (A:: AxisArray , v, $ (rargs... )) = (A[to_index (A,$ (idxs... ))... ] = v)
75
+ @eval Base. getindex (A:: AxisArray , $ (aargs... )) = A[to_index (A,$ (idxs... ))... ]
76
+ @eval Base. setindex! (A:: AxisArray , v, $ (aargs... )) = (A[to_index (A,$ (idxs... ))... ] = v)
77
+ end
78
+ end
79
+ Base. getindex (A:: AxisArray , idxs... ) = A[to_index (A,idxs... )... ]
80
+ Base. setindex! (A:: AxisArray , v, idxs... ) = (A[to_index (A,idxs... )... ] = v)
81
+
82
+ # First is indexing by named axis. We simply sort the axes and re-dispatch.
58
83
# When indexing by named axis the shapes of omitted dimensions are preserved
59
84
# TODO : should we handle multidimensional Axis indexes? It could be interpreted
60
85
# as adding dimensions in the middle of an AxisArray.
61
86
# TODO : should we allow repeated axes? As a union of indices of the duplicates?
62
- stagedfunction Base . getindex {T,N,D,Ax} (A:: AxisArray{T,N,D,Ax} , I:: Axis... )
87
+ stagedfunction to_index {T,N,D,Ax} (A:: AxisArray{T,N,D,Ax} , I:: Axis... )
63
88
dims = Int[axisdim (A, ax) for ax in I]
64
89
idxs = Expr[:(Colon ()) for d = 1 : N]
65
90
names = axisnames (A)
@@ -68,7 +93,8 @@ stagedfunction Base.getindex{T,N,D,Ax}(A::AxisArray{T,N,D,Ax}, I::Axis...)
68
93
idxs[dims[i]] = :(I[$ i]. val)
69
94
end
70
95
71
- return :(A[$ (idxs... )])
96
+ meta = Expr (:meta , :inline )
97
+ return :($ meta; to_index (A, $ (idxs... )))
72
98
end
73
99
74
100
# ## Indexing along values of the axes ###
@@ -93,58 +119,24 @@ function axisindexes{T}(::Type{Categorical}, ax::AbstractVector{T}, idx::Abstrac
93
119
res
94
120
end
95
121
96
- # Defining the fallbacks on getindex are tricky due to ambiguities with
97
- # AbstractArray definitions -
98
- let args = Expr[], idxs = Symbol[]
99
- for i = 1 : 4
100
- isym = symbol (" i$i " )
101
- push! (args, :($ isym:: Real ))
102
- push! (idxs, isym)
103
- @eval Base. getindex {T,N,D,Ax} (A:: AxisArray{T,N,D,Ax} , $ (args... )) = fallback_getindex (A, $ (idxs... ))
104
- end
105
- end
106
- Base. getindex {T,N,D,Ax} (A:: AxisArray{T,N,D,Ax} , idx:: AbstractArray ) = fallback_getindex (A, idx)
107
- Base. getindex {T,N,D,Ax} (A:: AxisArray{T,N,D,Ax} , idxs... ) = fallback_getindex (A, idxs... )
108
-
109
122
# These catch-all methods attempt to convert any axis-specific non-standard
110
- # indexing types to their integer or integer range equivalents using the
111
- # They are separate from the `Base.getindex` function to help alleviate
123
+ # indexing types to their integer or integer range equivalents using axisindexes
124
+ # They are separate from the `Base.getindex` function to help alleviate
112
125
# ambiguity warnings from, e.g., `getindex(::AbstractArray, ::Real...)`.
113
- # TODO : These could be generated with meta-meta-programming
114
- stagedfunction fallback_getindex {T,N,D,Ax} (A:: AxisArray{T,N,D,Ax} , I1)
115
- ex = :(getindex (A))
116
- push! (ex. args, I1 <: Idx || length (Ax) < 1 ? :(I1) : :(axisindexes (A. axes[1 ], I1)))
117
- for _= 2 : N
118
- push! (ex. args, :(Colon ()))
119
- end
120
- ex
121
- end
122
- stagedfunction fallback_getindex {T,N,D,Ax} (A:: AxisArray{T,N,D,Ax} , I1, I2)
123
- ex = :(getindex (A))
124
- push! (ex. args, I1 <: Idx || length (Ax) < 1 ? :(I1) : :(axisindexes (A. axes[1 ], I1)))
125
- push! (ex. args, I2 <: Idx || length (Ax) < 2 ? :(I2) : :(axisindexes (A. axes[2 ], I2)))
126
- for _= 3 : N
127
- push! (ex. args, :(Colon ()))
128
- end
129
- ex
130
- end
131
- stagedfunction fallback_getindex {T,N,D,Ax} (A:: AxisArray{T,N,D,Ax} , I1, I2, I3)
132
- ex = :(getindex (A))
133
- push! (ex. args, I1 <: Idx || length (Ax) < 1 ? :(I1) : :(axisindexes (A. axes[1 ], I1)))
134
- push! (ex. args, I2 <: Idx || length (Ax) < 2 ? :(I2) : :(axisindexes (A. axes[2 ], I2)))
135
- push! (ex. args, I3 <: Idx || length (Ax) < 3 ? :(I3) : :(axisindexes (A. axes[3 ], I3)))
136
- for _= 4 : N
137
- push! (ex. args, :(Colon ()))
138
- end
139
- ex
140
- end
141
- stagedfunction fallback_getindex {T,N,D,Ax} (A:: AxisArray{T,N,D,Ax} , I... )
142
- ex = :(getindex (A))
126
+ stagedfunction to_index {T,N,D,Ax} (A:: AxisArray{T,N,D,Ax} , I... )
127
+ ex = Expr (:tuple )
143
128
for i= 1 : length (I)
144
- push! (ex. args, I[i] <: Idx || length (Ax) < i ? :(I[$ i]) : :(axisindexes (A. axes[$ i], I[$ i])))
129
+ if I[i] <: Idx
130
+ push! (ex. args, :(I[$ i]))
131
+ elseif i <= length (Ax)
132
+ push! (ex. args, :(axisindexes (A. axes[$ i], I[$ i])))
133
+ else
134
+ push! (ex. args, :(error (" dimension " , $ i, " does not have an axis to index" )))
135
+ end
145
136
end
146
137
for _= length (I)+ 1 : N
147
138
push! (ex. args, :(Colon ()))
148
139
end
149
- ex
140
+ meta = Expr (:meta , :inline )
141
+ return :($ meta; $ ex)
150
142
end
0 commit comments