1 | // -*- C++ -*- |
---|
2 | /*************************************************************************** |
---|
3 | * blitz/array/map.h Declaration of the ArrayIndexMapping class |
---|
4 | * |
---|
5 | * $Id$ |
---|
6 | * |
---|
7 | * Copyright (C) 1997-2011 Todd Veldhuizen <tveldhui@acm.org> |
---|
8 | * |
---|
9 | * This file is a part of Blitz. |
---|
10 | * |
---|
11 | * Blitz is free software: you can redistribute it and/or modify |
---|
12 | * it under the terms of the GNU Lesser General Public License |
---|
13 | * as published by the Free Software Foundation, either version 3 |
---|
14 | * of the License, or (at your option) any later version. |
---|
15 | * |
---|
16 | * Blitz is distributed in the hope that it will be useful, |
---|
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
19 | * GNU Lesser General Public License for more details. |
---|
20 | * |
---|
21 | * You should have received a copy of the GNU Lesser General Public |
---|
22 | * License along with Blitz. If not, see <http://www.gnu.org/licenses/>. |
---|
23 | * |
---|
24 | * Suggestions: blitz-devel@lists.sourceforge.net |
---|
25 | * Bugs: blitz-support@lists.sourceforge.net |
---|
26 | * |
---|
27 | * For more information, please see the Blitz++ Home Page: |
---|
28 | * https://sourceforge.net/projects/blitz/ |
---|
29 | * |
---|
30 | ****************************************************************************/ |
---|
31 | |
---|
32 | /* |
---|
33 | * ArrayIndexMapping is used to implement tensor array notation. For |
---|
34 | * example: |
---|
35 | * |
---|
36 | * Array<float, 2> A, B; |
---|
37 | * firstIndex i; |
---|
38 | * secondIndex j; |
---|
39 | * thirdIndex k; |
---|
40 | * Array<float, 3> C = A(i,j) * B(j,k); |
---|
41 | * |
---|
42 | * For expression templates purposes, something like B(j,k) is represented |
---|
43 | * by an instance of class ArrayIndexMapping. This class maps an array onto |
---|
44 | * the destination array coordinate system, e.g. B(j,k) -> C(i,j,k) |
---|
45 | */ |
---|
46 | |
---|
47 | #ifndef BZ_ARRAYMAP_H |
---|
48 | #define BZ_ARRAYMAP_H |
---|
49 | |
---|
50 | #include <blitz/blitz.h> |
---|
51 | #include <blitz/prettyprint.h> |
---|
52 | #include <blitz/et-forward.h> |
---|
53 | #include <blitz/tinyvec2.h> |
---|
54 | #include <blitz/array/domain.h> |
---|
55 | |
---|
56 | BZ_NAMESPACE(blitz) |
---|
57 | |
---|
58 | /* |
---|
59 | * _bz_doArrayIndexMapping is a helper class that does the index |
---|
60 | * remapping. It is specialized for ranks 1, 2, 3, ..., 11. |
---|
61 | */ |
---|
62 | |
---|
63 | template<int N_rank> |
---|
64 | struct _bz_doArrayIndexMapping { |
---|
65 | static const int rank=N_rank; |
---|
66 | template<typename T_expr, int N_inputRank> |
---|
67 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
68 | const TinyVector<int,N_inputRank>&, int, int, int, int, int, int, |
---|
69 | int, int, int, int, int) |
---|
70 | { |
---|
71 | // If you try to use an array index mapping on an array with |
---|
72 | // rank greater than 11, then you'll get a precondition failure |
---|
73 | // here. |
---|
74 | BZPRECHECK(0,"Index mappings for containers of rank>11 not implemented"); |
---|
75 | return T_expr::T_numtype(); |
---|
76 | } |
---|
77 | }; |
---|
78 | |
---|
79 | template<> |
---|
80 | struct _bz_doArrayIndexMapping<1> { |
---|
81 | static const int rank=1; |
---|
82 | template<typename T_expr, int N_inputRank> |
---|
83 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
84 | const TinyVector<int,N_inputRank>& index, int i0, int, int, int, int, |
---|
85 | int, int, int, int, int, int) |
---|
86 | { |
---|
87 | // this was the case when it took an array. is it necessary? |
---|
88 | BZPRECHECK(T_expr::rank_==rank, |
---|
89 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
90 | return expr.unwrap()(index[i0]); |
---|
91 | } |
---|
92 | |
---|
93 | template<int N_inputRank> |
---|
94 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
95 | int i0, int, int, int, int, |
---|
96 | int, int, int, int, int, int) |
---|
97 | { |
---|
98 | // this might be slower but unlike Array, FAI doesn't have 11 |
---|
99 | // overloaded moveTo methods. |
---|
100 | const TinyVector<int,rank> newindex(index[i0]); |
---|
101 | return newindex; |
---|
102 | } |
---|
103 | }; |
---|
104 | |
---|
105 | |
---|
106 | template<> |
---|
107 | struct _bz_doArrayIndexMapping<2> { |
---|
108 | static const int rank=2; |
---|
109 | |
---|
110 | template<typename T_expr, int N_inputRank> |
---|
111 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
112 | const TinyVector<int,N_inputRank>& index, int i0, int i1, int, |
---|
113 | int, int, int, int, int, int, int, int) |
---|
114 | { |
---|
115 | // this was the case when it took an array. is it necessary? |
---|
116 | BZPRECHECK(T_expr::rank_==rank, |
---|
117 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
118 | return expr.unwrap()(index[i0], index[i1]); |
---|
119 | } |
---|
120 | |
---|
121 | template<int N_inputRank> |
---|
122 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
123 | int i0, int i1, int, int, int, |
---|
124 | int, int, int, int, int, int) |
---|
125 | { |
---|
126 | return TinyVector<int,rank>(index[i0], index[i1]); |
---|
127 | } |
---|
128 | }; |
---|
129 | |
---|
130 | template<> |
---|
131 | struct _bz_doArrayIndexMapping<3> { |
---|
132 | static const int rank=3; |
---|
133 | |
---|
134 | template<typename T_expr, int N_inputRank> |
---|
135 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
136 | const TinyVector<int,N_inputRank>& index, int i0, int i1, int i2, |
---|
137 | int, int, int, int, int, int, int, int) |
---|
138 | { |
---|
139 | // this was the case when it took an array. is it necessary? |
---|
140 | BZPRECHECK(T_expr::rank_==rank, |
---|
141 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
142 | return expr.unwrap()(index[i0], index[i1], index[i2]); |
---|
143 | } |
---|
144 | |
---|
145 | template<int N_inputRank> |
---|
146 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
147 | int i0, int i1, int i2, int, int, |
---|
148 | int, int, int, int, int, int) |
---|
149 | { |
---|
150 | return TinyVector<int,rank>(index[i0], index[i1], index[i2]); |
---|
151 | } |
---|
152 | }; |
---|
153 | |
---|
154 | template<> |
---|
155 | struct _bz_doArrayIndexMapping<4> { |
---|
156 | static const int rank=4; |
---|
157 | |
---|
158 | template<typename T_expr, int N_inputRank> |
---|
159 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
160 | const TinyVector<int,N_inputRank>& index, int i0, int i1, int i2, |
---|
161 | int i3, int, int, int, int, int, int, int) |
---|
162 | { |
---|
163 | // this was the case when it took an array. is it necessary? |
---|
164 | BZPRECHECK(T_expr::rank_==rank, |
---|
165 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
166 | return expr.unwrap()(index[i0], index[i1], index[i2], index[i3]); |
---|
167 | } |
---|
168 | |
---|
169 | template<int N_inputRank> |
---|
170 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
171 | int i0, int i1, int i2, int i3, int, |
---|
172 | int, int, int, int, int, int) |
---|
173 | { |
---|
174 | return TinyVector<int,rank>(index[i0], index[i1], index[i2], |
---|
175 | index[i3]); |
---|
176 | } |
---|
177 | }; |
---|
178 | |
---|
179 | template<> |
---|
180 | struct _bz_doArrayIndexMapping<5> { |
---|
181 | static const int rank=5; |
---|
182 | |
---|
183 | template<typename T_expr, int N_inputRank> |
---|
184 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
185 | const TinyVector<int,N_inputRank>& index, int i0, int i1, int i2, |
---|
186 | int i3, int i4, int, int, int, int, int, int) |
---|
187 | { |
---|
188 | // this was the case when it took an array. is it necessary? |
---|
189 | BZPRECHECK(T_expr::rank_==rank, |
---|
190 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
191 | return expr.unwrap()(index[i0], index[i1], index[i2], index[i3], index[i4]); |
---|
192 | } |
---|
193 | |
---|
194 | template<int N_inputRank> |
---|
195 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
196 | int i0, int i1, int i2, int i3, int i4, |
---|
197 | int, int, int, int, int, int) |
---|
198 | { |
---|
199 | return TinyVector<int,rank>(index[i0], index[i1], index[i2], |
---|
200 | index[i3], index[i4]); |
---|
201 | } |
---|
202 | }; |
---|
203 | |
---|
204 | template<> |
---|
205 | struct _bz_doArrayIndexMapping<6> { |
---|
206 | static const int rank=6; |
---|
207 | |
---|
208 | template<typename T_expr, int N_inputRank> |
---|
209 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
210 | const TinyVector<int,N_inputRank>& index, int i0, int i1, int i2, |
---|
211 | int i3, int i4, int i5, int, int, int, int, int) |
---|
212 | { |
---|
213 | // this was the case when it took an array. is it necessary? |
---|
214 | BZPRECHECK(T_expr::rank_==rank, |
---|
215 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
216 | return expr.unwrap()(index[i0], index[i1], index[i2], index[i3], index[i4], |
---|
217 | index[i5]); |
---|
218 | } |
---|
219 | |
---|
220 | template<int N_inputRank> |
---|
221 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
222 | int i0, int i1, int i2, int i3, int i4, |
---|
223 | int i5, int, int, int, int, int) |
---|
224 | { |
---|
225 | return TinyVector<int,rank>(index[i0], index[i1], index[i2], |
---|
226 | index[i3], index[i4], index[i5]); |
---|
227 | } |
---|
228 | }; |
---|
229 | |
---|
230 | template<> |
---|
231 | struct _bz_doArrayIndexMapping<7> { |
---|
232 | static const int rank=7; |
---|
233 | |
---|
234 | template<typename T_expr, int N_inputRank> |
---|
235 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
236 | const TinyVector<int,N_inputRank>& index, int i0, int i1, int i2, |
---|
237 | int i3, int i4, int i5, int i6, int, int, int, int) |
---|
238 | { |
---|
239 | // this was the case when it took an array. is it necessary? |
---|
240 | BZPRECHECK(T_expr::rank_==rank, |
---|
241 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
242 | return expr.unwrap()(index[i0], index[i1], index[i2], index[i3], |
---|
243 | index[i4], index[i5], index[i6]); |
---|
244 | } |
---|
245 | |
---|
246 | template<int N_inputRank> |
---|
247 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
248 | int i0, int i1, int i2, int i3, int i4, |
---|
249 | int i5, int i6, int, int, int, int) |
---|
250 | { |
---|
251 | return TinyVector<int,rank>(index[i0], index[i1], index[i2], |
---|
252 | index[i3], index[i4], index[i5], |
---|
253 | index[i6]); |
---|
254 | } |
---|
255 | }; |
---|
256 | |
---|
257 | template<> |
---|
258 | struct _bz_doArrayIndexMapping<8> { |
---|
259 | static const int rank=8; |
---|
260 | |
---|
261 | template<typename T_expr, int N_inputRank> |
---|
262 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
263 | const TinyVector<int,N_inputRank>& index, int i0, int i1, int i2, |
---|
264 | int i3, int i4, int i5, int i6, int i7, int, int, int) |
---|
265 | { |
---|
266 | // this was the case when it took an array. is it necessary? |
---|
267 | BZPRECHECK(T_expr::rank_==rank, |
---|
268 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
269 | return expr.unwrap()(index[i0], index[i1], index[i2], index[i3], |
---|
270 | index[i4], index[i5], index[i6], index[i7]); |
---|
271 | } |
---|
272 | |
---|
273 | template<int N_inputRank> |
---|
274 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
275 | int i0, int i1, int i2, int i3, int i4, |
---|
276 | int i5, int i6, int i7, int, int, int) |
---|
277 | { |
---|
278 | return TinyVector<int,rank>(index[i0], index[i1], index[i2], |
---|
279 | index[i3], index[i4], index[i5], |
---|
280 | index[i6], index[i7]); |
---|
281 | } |
---|
282 | }; |
---|
283 | |
---|
284 | template<> |
---|
285 | struct _bz_doArrayIndexMapping<9> { |
---|
286 | static const int rank=9; |
---|
287 | |
---|
288 | template<typename T_expr, int N_inputRank> |
---|
289 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
290 | const TinyVector<int,N_inputRank>& index, int i0, int i1, int i2, |
---|
291 | int i3, int i4, int i5, int i6, int i7, int i8, int, int) |
---|
292 | { |
---|
293 | // this was the case when it took an array. is it necessary? |
---|
294 | BZPRECHECK(T_expr::rank_==rank, |
---|
295 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
296 | return expr.unwrap()(index[i0], index[i1], index[i2], index[i3], |
---|
297 | index[i4], index[i5], index[i6], index[i7], |
---|
298 | index[i8]); |
---|
299 | } |
---|
300 | |
---|
301 | template<int N_inputRank> |
---|
302 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
303 | int i0, int i1, int i2, int i3, int i4, |
---|
304 | int i5, int i6, int i7, int i8, int, int) |
---|
305 | { |
---|
306 | return TinyVector<int,rank>(index[i0], index[i1], index[i2], |
---|
307 | index[i3], index[i4], index[i5], |
---|
308 | index[i6], index[i7], index[i8]); |
---|
309 | } |
---|
310 | }; |
---|
311 | |
---|
312 | template<> |
---|
313 | struct _bz_doArrayIndexMapping<10> { |
---|
314 | static const int rank=10; |
---|
315 | |
---|
316 | template<typename T_expr, int N_inputRank> |
---|
317 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
318 | const TinyVector<int,N_inputRank>& index, int i0, int i1, int i2, |
---|
319 | int i3, int i4, int i5, int i6, int i7, int i8, int i9, int) |
---|
320 | { |
---|
321 | // this was the case when it took an array. is it necessary? |
---|
322 | BZPRECHECK(T_expr::rank_==rank, |
---|
323 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
324 | return expr.unwrap()(index[i0], index[i1], index[i2], index[i3], |
---|
325 | index[i4], index[i5], index[i6], index[i7], |
---|
326 | index[i8], index[i9]); |
---|
327 | } |
---|
328 | |
---|
329 | template<int N_inputRank> |
---|
330 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
331 | int i0, int i1, int i2, int i3, int i4, |
---|
332 | int i5, int i6, int i7, int i8, int i9, int) |
---|
333 | { |
---|
334 | return TinyVector<int,rank>(index[i0], index[i1], index[i2], |
---|
335 | index[i3], index[i4], index[i5], |
---|
336 | index[i6], index[i7], index[i8], |
---|
337 | index[i9]); |
---|
338 | } |
---|
339 | }; |
---|
340 | |
---|
341 | template<> |
---|
342 | struct _bz_doArrayIndexMapping<11> { |
---|
343 | static const int rank=11; |
---|
344 | |
---|
345 | template<typename T_expr, int N_inputRank> |
---|
346 | static typename T_expr::T_numtype map(const ETBase<T_expr>& expr, |
---|
347 | const TinyVector<int,N_inputRank>& index, int i0, int i1, int i2, |
---|
348 | int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10) |
---|
349 | { |
---|
350 | // this was the case when it took an array. is it necessary? |
---|
351 | BZPRECHECK(T_expr::rank_==rank, |
---|
352 | "Rank confusion in _bz_doArrayIndexMapping"); |
---|
353 | return expr.unwrap()(index[i0], index[i1], index[i2], index[i3], |
---|
354 | index[i4], index[i5], index[i6], index[i7], |
---|
355 | index[i8], index[i9], index[i10]); |
---|
356 | } |
---|
357 | |
---|
358 | template<int N_inputRank> |
---|
359 | static TinyVector<int,rank> map_dims(const TinyVector<int,N_inputRank>& index, |
---|
360 | int i0, int i1, int i2, int i3, int i4, |
---|
361 | int i5, int i6, int i7, int i8, int i9, int i10) |
---|
362 | { |
---|
363 | return TinyVector<int,rank>(index[i0], index[i1], index[i2], |
---|
364 | index[i3], index[i4], index[i5], |
---|
365 | index[i6], index[i7], index[i8], |
---|
366 | index[i9], index[i10]); |
---|
367 | } |
---|
368 | }; |
---|
369 | |
---|
370 | |
---|
371 | // default arguments are defined in the fwd header |
---|
372 | template<typename P_expr, int N_map0, int N_map1, int N_map2, |
---|
373 | int N_map3, int N_map4, int N_map5, int N_map6, int N_map7, |
---|
374 | int N_map8, int N_map9, int N_map10> |
---|
375 | class ArrayIndexMapping { |
---|
376 | public: |
---|
377 | typedef P_expr T_expr; |
---|
378 | typedef typename T_expr::T_numtype T_numtype; |
---|
379 | |
---|
380 | typedef T_numtype T_optype; |
---|
381 | typedef typename asET<T_numtype>::T_wrapped T_typeprop; |
---|
382 | typedef typename unwrapET<T_typeprop>::T_unwrapped T_result; |
---|
383 | |
---|
384 | typedef T_expr T_ctorArg1; |
---|
385 | typedef int T_ctorArg2; // dummy |
---|
386 | typedef ArrayIndexMapping<typename T_expr::T_range_result,N_map0,N_map1,N_map2,N_map3,N_map4,N_map5,N_map6,N_map7,N_map8,N_map9,N_map10> T_range_result; |
---|
387 | |
---|
388 | /* |
---|
389 | * This enum block finds the maximum of the N_map0, N_map1, ..., N_map10 |
---|
390 | * parameters and stores it in maxRank10. The rank of the expression is |
---|
391 | * then maxRank10 + 1, since the IndexPlaceholders start at 0 rather than |
---|
392 | * 1. |
---|
393 | */ |
---|
394 | static const int |
---|
395 | maxRank1 = (N_map0 > N_map1) ? N_map0 : N_map1, |
---|
396 | maxRank2 = (N_map2 > maxRank1) ? N_map2 : maxRank1, |
---|
397 | maxRank3 = (N_map3 > maxRank2) ? N_map3 : maxRank2, |
---|
398 | maxRank4 = (N_map4 > maxRank3) ? N_map4 : maxRank3, |
---|
399 | maxRank5 = (N_map5 > maxRank4) ? N_map5 : maxRank4, |
---|
400 | maxRank6 = (N_map6 > maxRank5) ? N_map6 : maxRank5, |
---|
401 | maxRank7 = (N_map7 > maxRank6) ? N_map7 : maxRank6, |
---|
402 | maxRank8 = (N_map8 > maxRank7) ? N_map8 : maxRank7, |
---|
403 | maxRank9 = (N_map9 > maxRank8) ? N_map9 : maxRank8, |
---|
404 | maxRank10 = (N_map10 > maxRank9) ? N_map10 : maxRank9; |
---|
405 | |
---|
406 | static const int |
---|
407 | numArrayOperands = T_expr::numArrayOperands, |
---|
408 | numTVOperands = T_expr::numTVOperands, |
---|
409 | numTMOperands = T_expr::numTMOperands, |
---|
410 | numIndexPlaceholders = 1, |
---|
411 | minWidth = simdTypes<T_numtype>::vecWidth, |
---|
412 | maxWidth = simdTypes<T_numtype>::vecWidth, |
---|
413 | rank_ = maxRank10 + 1, |
---|
414 | exprRank = T_expr::rank_; |
---|
415 | |
---|
416 | template<int N> struct tvresult { |
---|
417 | typedef FastTV2Iterator<T_numtype, N> Type; |
---|
418 | }; |
---|
419 | |
---|
420 | /* |
---|
421 | ArrayIndexMapping(const Array<T_numtype, rank>& array) |
---|
422 | : iter_(array) |
---|
423 | { |
---|
424 | } |
---|
425 | */ |
---|
426 | |
---|
427 | ArrayIndexMapping(const ArrayIndexMapping<T_expr,N_map0, |
---|
428 | N_map1,N_map2,N_map3,N_map4,N_map5,N_map6,N_map7,N_map8,N_map9, |
---|
429 | N_map10>& z) |
---|
430 | : iter_(z.iter_) |
---|
431 | { |
---|
432 | } |
---|
433 | |
---|
434 | ArrayIndexMapping(BZ_ETPARM(T_expr) a) |
---|
435 | : iter_(a) |
---|
436 | { } |
---|
437 | |
---|
438 | // this is ambiguous with the above |
---|
439 | // ArrayIndexMapping(_bz_typename T_expr::T_ctorArg1 a) |
---|
440 | // : iter_(a) |
---|
441 | // { } |
---|
442 | |
---|
443 | // these bypass the FAI and go directly to the array. That should |
---|
444 | // prevent any performance impact of using the FAI instead of an |
---|
445 | // array directly. |
---|
446 | |
---|
447 | /* Functions for reading. Because they must depend on the result |
---|
448 | * type, they utilize a helper class. |
---|
449 | */ |
---|
450 | |
---|
451 | // For numtypes, apply operator |
---|
452 | template<typename T> struct readHelper { |
---|
453 | static T_result first_value(const T_expr& iter) { |
---|
454 | // is the correct thing to do here to return the index zero value? |
---|
455 | return indexop(iter, TinyVector<int,1>(0)); } |
---|
456 | template<int N_rank> |
---|
457 | #ifdef BZ_ARRAY_EXPR_PASS_INDEX_BY_VALUE |
---|
458 | static T_result indexop(const T_expr& iter, |
---|
459 | const TinyVector<int, N_rank> i) { |
---|
460 | #else |
---|
461 | static T_result indexop(const T_expr& iter, |
---|
462 | const TinyVector<int, N_rank>& i) { |
---|
463 | #endif |
---|
464 | return _bz_doArrayIndexMapping<exprRank>::map(iter/*.array()*/, i, |
---|
465 | N_map0, N_map1, N_map2, N_map3, N_map4, N_map5, N_map6, |
---|
466 | N_map7, N_map8, N_map9, N_map10); |
---|
467 | }; |
---|
468 | }; |
---|
469 | |
---|
470 | // For ET types, bypass operator and create expression |
---|
471 | template<typename T> struct readHelper<ETBase<T> > { |
---|
472 | template<int N_rank> |
---|
473 | #ifdef BZ_ARRAY_EXPR_PASS_INDEX_BY_VALUE |
---|
474 | static T_result indexop(const T_expr& iter, |
---|
475 | const TinyVector<int, N_rank> i) { |
---|
476 | #else |
---|
477 | static T_result indexop(const T_expr& iter, |
---|
478 | const TinyVector<int, N_rank>& i) { |
---|
479 | #endif |
---|
480 | return iter(i); } |
---|
481 | static T_result first_value(const T_expr& iter) { |
---|
482 | // is the correct thing to do here to return the index zero value? |
---|
483 | return indexop(iter, TinyVector<int,1>(0)); } |
---|
484 | }; |
---|
485 | |
---|
486 | template<int N_rank> |
---|
487 | #ifdef BZ_ARRAY_EXPR_PASS_INDEX_BY_VALUE |
---|
488 | T_result operator()(const TinyVector<int, N_rank> i) const { |
---|
489 | #else |
---|
490 | T_result operator()(const TinyVector<int, N_rank>& i) const { |
---|
491 | #endif |
---|
492 | return readHelper<T_typeprop>::indexop(iter_,i); } |
---|
493 | |
---|
494 | T_result first_value() const { |
---|
495 | // unclear how to define "first" value for index expressions. |
---|
496 | BZPRECHECK(0,"Minmax reductions of index expressions not implemented"); |
---|
497 | return readHelper<T_typeprop>::first_value(iter_); } |
---|
498 | |
---|
499 | // find which dimension in mapped expression that corresponds to |
---|
500 | // dimension dim. This works such that dimension dim in this |
---|
501 | // expression corresponds to dimension map_dim(dim) in iter_. |
---|
502 | int map_dim(const int dim) const |
---|
503 | { |
---|
504 | if (N_map0 == dim) |
---|
505 | return 0; |
---|
506 | else if ((N_map1 == dim) && (exprRank > 1)) |
---|
507 | return 1; |
---|
508 | else if ((N_map2 == dim) && (exprRank > 2)) |
---|
509 | return 2; |
---|
510 | else if ((N_map3 == dim) && (exprRank > 3)) |
---|
511 | return 3; |
---|
512 | else if ((N_map4 == dim) && (exprRank > 4)) |
---|
513 | return 4; |
---|
514 | else if ((N_map5 == dim) && (exprRank > 5)) |
---|
515 | return 5; |
---|
516 | else if ((N_map6 == dim) && (exprRank > 6)) |
---|
517 | return 6; |
---|
518 | else if ((N_map7 == dim) && (exprRank > 7)) |
---|
519 | return 7; |
---|
520 | else if ((N_map8 == dim) && (exprRank > 8)) |
---|
521 | return 8; |
---|
522 | else if ((N_map9 == dim) && (exprRank > 9)) |
---|
523 | return 9; |
---|
524 | else if ((N_map10 == dim) && (exprRank > 10)) |
---|
525 | return 10; |
---|
526 | else |
---|
527 | // means dimension is not in this operand |
---|
528 | return -1; |
---|
529 | } |
---|
530 | |
---|
531 | // remaps the dimensions of an index vector so it can be applied to |
---|
532 | // iter_, using the _bz_doArrayIndexMapping helper class. |
---|
533 | template<int N> |
---|
534 | TinyVector<int, exprRank> map_dims(const TinyVector<int, N>& i) const { |
---|
535 | return _bz_doArrayIndexMapping<exprRank>::map_dims |
---|
536 | (i, N_map0, N_map1, N_map2, N_map3, N_map4, N_map5, |
---|
537 | N_map6, N_map7, N_map8, N_map9, N_map10); |
---|
538 | } |
---|
539 | |
---|
540 | int ascending(const int dim) const |
---|
541 | { |
---|
542 | const int d=map_dim(dim); |
---|
543 | const int o = d>=0 ? iter_.ascending(d) : INT_MIN ; |
---|
544 | return o; |
---|
545 | } |
---|
546 | |
---|
547 | int ordering(const int dim) const |
---|
548 | { |
---|
549 | // JCC: ignore ordering result from 1d Array |
---|
550 | if (exprRank == 1) |
---|
551 | return INT_MIN; // tiny(int()); |
---|
552 | |
---|
553 | const int d=map_dim(dim); |
---|
554 | const int o = d>=0 ? iter_.ordering(d) : INT_MIN ; |
---|
555 | return o; |
---|
556 | } |
---|
557 | |
---|
558 | int lbound(const int dim) const |
---|
559 | { |
---|
560 | const int d=map_dim(dim); |
---|
561 | const int o = d>=0 ? iter_.lbound(d) : INT_MIN ; |
---|
562 | return o; |
---|
563 | } |
---|
564 | |
---|
565 | int ubound(const int dim) const |
---|
566 | { |
---|
567 | const int d=map_dim(dim); |
---|
568 | const int o = d>=0 ? iter_.ubound(d) : INT_MAX ; |
---|
569 | return o; |
---|
570 | } |
---|
571 | |
---|
572 | // defer calculation to lbound/ubound |
---|
573 | RectDomain<rank_> domain() const |
---|
574 | { |
---|
575 | TinyVector<int, rank_> lb, ub; |
---|
576 | for(int r=0; r<rank_; ++r) { |
---|
577 | lb[r]=lbound(r); ub[r]=ubound(r); |
---|
578 | } |
---|
579 | return RectDomain<rank_>(lb,ub); |
---|
580 | } |
---|
581 | |
---|
582 | // If you have a precondition failure on this routine, it means |
---|
583 | // you are trying to use stack iteration mode on an expression |
---|
584 | // which contains an index placeholder. You must use index |
---|
585 | // iteration mode instead. |
---|
586 | // (no -- added to support stencils /PJ) |
---|
587 | T_result operator*() const |
---|
588 | { |
---|
589 | return *iter_; |
---|
590 | } |
---|
591 | |
---|
592 | // See operator*() note |
---|
593 | void push(int) |
---|
594 | { |
---|
595 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
596 | } |
---|
597 | |
---|
598 | // See operator*() note |
---|
599 | void pop(int) |
---|
600 | { |
---|
601 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
602 | } |
---|
603 | |
---|
604 | // See operator*() note |
---|
605 | void advance() |
---|
606 | { |
---|
607 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
608 | } |
---|
609 | |
---|
610 | // See operator*() note |
---|
611 | void advance(int) |
---|
612 | { |
---|
613 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
614 | } |
---|
615 | |
---|
616 | // See operator*() note |
---|
617 | void loadStride(int) |
---|
618 | { |
---|
619 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
620 | } |
---|
621 | |
---|
622 | bool isUnitStride(int) const |
---|
623 | { |
---|
624 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
625 | return false; |
---|
626 | } |
---|
627 | |
---|
628 | bool isUnitStride() const |
---|
629 | { |
---|
630 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
631 | return false; |
---|
632 | } |
---|
633 | |
---|
634 | void advanceUnitStride() |
---|
635 | { |
---|
636 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
637 | } |
---|
638 | |
---|
639 | bool canCollapse(int,int) const |
---|
640 | { BZPRECHECK(0,"Can't use stack iteration on an index mapping."); return false; } |
---|
641 | |
---|
642 | T_result operator[](int) |
---|
643 | { |
---|
644 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
645 | return T_result(); |
---|
646 | } |
---|
647 | |
---|
648 | T_result fastRead(int) const |
---|
649 | { |
---|
650 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
651 | return T_result(); |
---|
652 | } |
---|
653 | |
---|
654 | template<int N> |
---|
655 | typename tvresult<N>::Type fastRead_tv(int) const { |
---|
656 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
657 | return TinyVector<T_numtype, N>(); |
---|
658 | } |
---|
659 | |
---|
660 | /** Determining whether the resulting expression is aligned is |
---|
661 | difficult, so to be safe we say no. It shouldn't be attempted |
---|
662 | anyway, though. */ |
---|
663 | bool isVectorAligned(diffType offset) const { |
---|
664 | return false; } |
---|
665 | |
---|
666 | int suggestStride(int) const |
---|
667 | { |
---|
668 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
669 | return 0; |
---|
670 | } |
---|
671 | |
---|
672 | bool isStride(int,int) const |
---|
673 | { |
---|
674 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
675 | return true; |
---|
676 | } |
---|
677 | |
---|
678 | #ifdef BZ_ARRAY_EXPR_PASS_INDEX_BY_VALUE |
---|
679 | template<int N_destrank> |
---|
680 | void moveTo(const TinyVector<int,N_destrank> i) |
---|
681 | { |
---|
682 | iter_.moveTo(map_dims(i)); |
---|
683 | } |
---|
684 | #else |
---|
685 | template<int N_destrank> |
---|
686 | void moveTo(const TinyVector<int,N_destrank>& i) |
---|
687 | { |
---|
688 | iter_.moveTo(map_dims(i)); |
---|
689 | } |
---|
690 | #endif |
---|
691 | |
---|
692 | T_result shift(int offset, int dim) const { |
---|
693 | // need to check if dim is mapped into this expression |
---|
694 | const int d=map_dim(dim); |
---|
695 | if (d<0) |
---|
696 | return *iter_; |
---|
697 | else |
---|
698 | return iter_.shift(offset, d); |
---|
699 | } |
---|
700 | |
---|
701 | T_result shift(int offset1, int dim1,int offset2, int dim2) const { |
---|
702 | // need to check if dims are mapped into this expression |
---|
703 | int d1=map_dim(dim1); |
---|
704 | int d2=map_dim(dim2); |
---|
705 | if (d1<0) //disable offset |
---|
706 | {d1=0;offset1=0;} |
---|
707 | if (d2<0) //disable offset |
---|
708 | {d2=0;offset2=0;} |
---|
709 | return iter_.shift(offset1, d1, offset2, d2); |
---|
710 | } |
---|
711 | |
---|
712 | void _bz_offsetData(sizeType i) { |
---|
713 | BZPRECHECK(0,"Can't use stack iteration on an index mapping."); |
---|
714 | } |
---|
715 | |
---|
716 | template<int N> |
---|
717 | T_range_result operator()(RectDomain<N> d) const |
---|
718 | { // need to reorder dimensions here |
---|
719 | TinyVector<int, exprRank> lb(map_dims(d.lbound())), ub(map_dims(d.ubound())); |
---|
720 | RectDomain<exprRank> newd(lb,ub); |
---|
721 | return T_range_result(iter_(newd)); |
---|
722 | } |
---|
723 | |
---|
724 | void prettyPrint(BZ_STD_SCOPE(string) &str, prettyPrintFormat&) const |
---|
725 | { |
---|
726 | // NEEDS_WORK-- do real formatting for reductions |
---|
727 | str += "map[NEEDS_WORK]"; |
---|
728 | } |
---|
729 | |
---|
730 | template<typename T_shape> |
---|
731 | bool shapeCheck(const T_shape&) const |
---|
732 | { |
---|
733 | // NEEDS_WORK-- do a real shape check (tricky) |
---|
734 | return true; |
---|
735 | } |
---|
736 | |
---|
737 | // sliceinfo for expressions |
---|
738 | template<typename T1, typename T2 = nilArraySection, |
---|
739 | class T3 = nilArraySection, typename T4 = nilArraySection, |
---|
740 | class T5 = nilArraySection, typename T6 = nilArraySection, |
---|
741 | class T7 = nilArraySection, typename T8 = nilArraySection, |
---|
742 | class T9 = nilArraySection, typename T10 = nilArraySection, |
---|
743 | class T11 = nilArraySection> |
---|
744 | class SliceInfo { |
---|
745 | public: |
---|
746 | typedef typename T_expr::template SliceInfo<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::T_slice T_slice1; |
---|
747 | typedef ArrayIndexMapping<T_slice1, N_map0, N_map1, N_map2, |
---|
748 | N_map3, N_map4, N_map5, N_map6, N_map7, |
---|
749 | N_map8, N_map9, N_map10> T_slice; |
---|
750 | }; |
---|
751 | |
---|
752 | template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, |
---|
753 | typename T7, typename T8, typename T9, typename T10, typename T11> |
---|
754 | typename SliceInfo<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11>::T_slice |
---|
755 | operator()(T1 r1, T2 r2, T3 r3, T4 r4, T5 r5, T6 r6, T7 r7, T8 r8, T9 r9, T10 r10, T11 r11) const |
---|
756 | { |
---|
757 | /* Slicing for remapped expressions doesn't work. Because of the |
---|
758 | potential different types (Range vs int) in the expression, |
---|
759 | it would be very awkward to implement. As far as I can see, |
---|
760 | it would require manual coding of the 3^11 calling |
---|
761 | possibilities. /PJ */ |
---|
762 | BZPRECONDITION(0); |
---|
763 | } |
---|
764 | |
---|
765 | private: |
---|
766 | ArrayIndexMapping() : iter_( Array<T_numtype, exprRank>() ) { } |
---|
767 | |
---|
768 | T_expr iter_; |
---|
769 | }; |
---|
770 | |
---|
771 | BZ_NAMESPACE_END |
---|
772 | |
---|
773 | #endif // BZ_ARRAYMAP_H |
---|
774 | |
---|