libidx
|
00001 /*************************************************************************** 00002 * Copyright (C) 2008 by Yann LeCun and Pierre Sermanet * 00003 * yann@cs.nyu.edu, pierre.sermanet@gmail.com * 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions are met: 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Redistribution under a license not approved by the Open Source 00014 * Initiative (http://www.opensource.org) must display the 00015 * following acknowledgement in all advertising material: 00016 * This product includes software developed at the Courant 00017 * Institute of Mathematical Sciences (http://cims.nyu.edu). 00018 * * The names of the authors may not be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 00022 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00023 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00024 * DISCLAIMED. IN NO EVENT SHALL ThE AUTHORS BE LIABLE FOR ANY 00025 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00026 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00027 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00028 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00029 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 ***************************************************************************/ 00032 00033 #ifndef IDXITER_HPP_ 00034 #define IDXITER_HPP_ 00035 00036 namespace ebl { 00037 00038 // state_idx error checking macros /////////////////////////////////////////// 00039 00041 #define state_idx_check_different(s1, s2) \ 00042 if (&s1 == &s2) eblerror("in and out state_idx must be different"); 00043 00044 #define state_idx_check_different3(s1, s2, s3) \ 00045 if ((&s1 == &s2) || (&s1 == &s3)) \ 00046 eblerror("in1, in2 and out state_idx must be different"); 00047 00048 // idx error macros ////////////////////////////////////////////////////////// 00049 00051 #define idx_compatibility_error2(idx1, idx2, errmsg) { \ 00052 eblerror(idx1 << " and " << idx2 << " are incompatible: " << errmsg); } 00053 00054 #define idx_compatibility_error3(idx1, idx2, idx3, errmsg) { \ 00055 eblerror(idx1 << ", " << idx2 << " and " << idx3 \ 00056 << " are incompatible: " << errmsg); } 00057 00058 #define idx_compatibility_error4(idx1, idx2, idx3, idx4, errmsg) { \ 00059 eblerror(idx1 << ", " << idx2 << ", " << idx3 << " and " \ 00060 << idx4 << " are incompatible: " << errmsg); } 00061 00062 #define idx_compatibility_error5(idx1, idx2, idx3, idx4, idx5, errmsg) { \ 00063 eblerror("error: " << idx1 << ", " << idx2 << ", " << idx3 << ", " << idx4 \ 00064 << " and " << idx5 << " are incompatible: " << errmsg); } 00065 00066 #define idx_compatibility_error6(idx1, idx2, idx3, idx4, idx5, idx6, errmsg) { \ 00067 eblerror("error: " << idx1 << ", " << idx2 << ", " << idx3 << ", " << idx4 \ 00068 << ", " << idx5 << " and " << idx6 \ 00069 << " are incompatible: " << errmsg); } 00070 00071 // idx elements and dimensions error checking macros ///////////////////////// 00072 00073 #ifdef __DEBUG__ 00074 #define DEBUG_CHECK_SAME_DIMS(m1, m2) \ 00075 if (m1.get_idxdim() != m2.get_idxdim()) \ 00076 eblerror("expected same dimensions but got " << m1 << " and " << m2); 00077 00078 #else 00079 #define DEBUG_CHECK_SAME_DIMS(m1, m2) 00080 #endif 00081 00083 #define idx_check_contiguous1(src0) \ 00084 if (!(src0).contiguousp()) eblerror("idx must be contiguous"); 00085 00086 #define idx_check_contiguous2(src0, src1) \ 00087 if (!(src0).contiguousp() || !(src1).contiguousp()) \ 00088 eblerror("idx must be contiguous"); 00089 00090 #define idx_check_contiguous3(src0, src1, src2) \ 00091 if (!(src0).contiguousp() || !(src1).contiguousp() || !(src2.contiguousp())) \ 00092 eblerror("idx must be contiguous"); 00093 00094 #define idx_checknelems2_all(src0, src1) \ 00095 if ((src0).nelements() != (src1).nelements()) { \ 00096 eblerror(src0 << " and " << src1 << \ 00097 " should have the same number of elements"); } 00098 00099 00100 #define idx_checknelems3_all(src0, src1, src2) \ 00101 if (((src0).nelements() != (src1).nelements()) || \ 00102 ((src0).nelements() != (src2).nelements())) { \ 00103 eblerror(src0 << ", " << src1 << " and " << src2 \ 00104 << " should have the same number of elements"); } 00105 00106 00107 #define idx_checknelems4_all(src0, src1, src2, src3) \ 00108 if (((src0).nelements() != (src1).nelements()) || \ 00109 ((src0).nelements() != (src2).nelements()) || \ 00110 ((src0).nelements() != (src3).nelements())) { \ 00111 eblerror(src0 << ", " << src1 << " and " << src2 << " and " << src3 \ 00112 << " should have the same number of elements"); } 00113 00114 #define idx_checkorder1(src0, o0) \ 00115 if ((src0).order() != o0) { \ 00116 eblerror(src0 << " does not have order " << o0); } 00117 00118 #define idx_checkorder2(src0, o0, src1, o1) \ 00119 if (((src0).order() != o0) || ((src1).order() != o1)) { \ 00120 std::string err; \ 00121 if ((src0).order() != o0) err << src0 <<" should have order "<< o0<<". "; \ 00122 if ((src1).order() != o1) err << src1 <<" should have order "<< o1<<". "; \ 00123 eblerror("incompatible orders: " << err); } 00124 00125 #define idx_checkorder3(src0, o0, src1, o1, src2, o2) \ 00126 if (((src0).order() != o0) || ((src1).order() != o1) \ 00127 || ((src2).order() != o2)) { \ 00128 std::string err; \ 00129 if ((src0).order() != o0) err << src0 <<" should have order "<< o0<<". "; \ 00130 if ((src1).order() != o1) err << src1 <<" should have order "<< o1<<". "; \ 00131 if ((src2).order() != o2) err << src2 <<" should have order "<< o2<<". "; \ 00132 eblerror("incompatible orders: " << err); } 00133 00134 #define idx_checkorder2_all(src0, src1) \ 00135 if ((src0).order() != (src1).order()) \ 00136 idx_compatibility_error2(src0, src1, "idx have incompatible orders"); 00137 00138 #define idx_checkorder3_all(src0, src1, src2) \ 00139 if (((src0).order() != (src1).order()) \ 00140 || ((src0).order() != (src2).order())) \ 00141 idx_compatibility_error3(src0, src1, src2, "idx have incompatible orders"); 00142 00143 #define idx_checkdim1(src0, d0, e0) \ 00144 if ((src0).dim(d0) != e0) \ 00145 eblerror("expected dim " << d0 << " to be " << e0 << " in " << src0); 00146 00147 #define idx_checkdim2(src0, d0, e0, src1, d1, e1) \ 00148 if ((src0).dim(d0) != e0) \ 00149 eblerror("expected dim " << d0 << " to be " << e0 << " in " << src0); \ 00150 if ((src1).dim(d1) != e1) \ 00151 eblerror("expected dim " << d1 << " to be " << e1 << " in " << src1); 00152 00153 #define idx_checkdim2_all(src0, src1, d) \ 00154 if ((src0).dim(d) != (src1).dim(d)) \ 00155 idx_compatibility_error2(src0, src1,"expected same sizes in dimension "<<d); 00156 00157 #define idx_checkdim3_all(src0, src1, src2, d) \ 00158 if ((src0.order() != 0) && (((src0).dim(d) != (src1).dim(d)) || \ 00159 ((src0).dim(d) != (src2).dim(d)))) \ 00160 idx_compatibility_error3(src0,src1,src2, \ 00161 "expected same sizes in dimension "<<d); 00162 00163 00164 #define idx_checkdim4_all(src0, src1, src2, src3, d) \ 00165 if (((src0).dim(d) != (src1).dim(d)) || \ 00166 ((src0).dim(d) != (src2).dim(d)) || \ 00167 ((src0).dim(d) != (src3).dim(d))) \ 00168 idx_compatibility_error4(src0,src1,src2,src3, \ 00169 "expected same sizes in dimension "<<d); 00170 00171 00172 #define idx_checkdim5_all(src0, src1, src2, src3, src4, d) \ 00173 if (((src0).dim(d) != (src1).dim(d)) || \ 00174 ((src0).dim(d) != (src2).dim(d)) || \ 00175 ((src0).dim(d) != (src3).dim(d)) || \ 00176 ((src0).dim(d) != (src4).dim(d))) \ 00177 idx_compatibility_error5(src0,src1,src2,src3,src4, \ 00178 "expected same sizes in dimension "<<d); 00179 00180 00181 #define idx_checkdim6_all(src0, src1, src2, src3, src4, src5, d) \ 00182 if (((src0).dim(d) != (src1).dim(d)) || \ 00183 ((src0).dim(d) != (src2).dim(d)) || \ 00184 ((src0).dim(d) != (src3).dim(d)) || \ 00185 ((src0).dim(d) != (src4).dim(d)) || \ 00186 ((src0).dim(d) != (src5).dim(d))) \ 00187 idx_compatibility_error6(src0,src1,src2,src3,src4,src5, \ 00188 "expected same sizes in dimension "<<d); 00189 00190 // looping macros //////////////////////////////////////////////////////////// 00191 00212 #define cidx1_bloop1(i,p0,src0) \ 00213 if ((src0).order() < 1) eblerror("idx has wrong order"); \ 00214 intg _n0 = (src0).dim(0), _m0 = (src0).mod(0); \ 00215 for (i=0, p0=(src0).idx_ptr(); i<_n0; i++, p0+=_m0) 00216 00217 #define cidx1_bloop2(i,p0,src0,p1,src1) \ 00218 if (((src0).order() < 1)||((src1).order() < 1)) \ 00219 eblerror("idx has wrong order"); \ 00220 intg _n0 = (src0).dim(0), _m0 = (src0).mod(0); _m1 = (src1).mod(0); \ 00221 idx_checkdim2_all(src0,src1,0) \ 00222 for (i=0, p0=(src0).idx_ptr(), p1=(src1).idx_ptr(); \ 00223 i<_n0; \ 00224 i++, p0+=_m0, p1+=_m1) 00225 00226 #define cidx1_bloop3(i,p0,src0,p1,src1,p2,src2) \ 00227 intg _n0 = (src0).dim(0), _m0 = (src0).mod(0); \ 00228 intg _m1 = (src1).mod(0), _m2 = (src2).mod(0); \ 00229 idx_checkdim3_all(src0,src1,src2,0) \ 00230 for (i=0, p0=(src0).idx_ptr(), p1=(src1).idx_ptr(), p2=(src2).idx_ptr();\ 00231 i<_n0; \ 00232 i++, p0+=_m0, p1+=_m1, p2+=_m2) 00233 00234 #define cidx1_bloop4(i,p0,src0,p1,src1,p2,src2,p3,src3) \ 00235 intg _n0 = (src0).dim(0), _m0 = (src0).mod(0), _m1 = (src1).mod(0); \ 00236 intg _m2 = (src2).mod(0), _m3 = (src3).mod(0); \ 00237 idx_checkdim4_all(src0,src1,src2,src3,0) \ 00238 for (i=0, p0=(src0).idx_ptr(), p1=(src1).idx_ptr(), \ 00239 p2=(src2).idx_ptr(), p3=(src3).idx_ptr(); \ 00240 i<_n0; \ 00241 i++, p0+=_m0, p1+=_m1, p2+=_m2, p3+=_m3) 00242 00243 #define cidx2_bloop1(i,j,p0,src0) \ 00244 if ((src0).order() < 2) eblerror("idx has wrong order"); \ 00245 intg _n00 = (src0).dim(0), _m00 = (src0).mod(0); \ 00246 intg _n01 = (src0).dim(1), _m01 = (src0).mod(1); \ 00247 for (i=0, p0=(src0).idx_ptr(); i<_n00; i++, p0+=_m00-_n01*_m01) \ 00248 for (j=0; i<_n01; j++, p0+=_m01) 00249 00250 #define cidx2_bloop2(i,j,p0,src0,p1,src1) \ 00251 if ((src0).order() < 2) eblerror("idx has wrong order"); \ 00252 intg _n00 = (src0).dim(0), _m00 = (src0).mod(0); \ 00253 intg _n01 = (src0).dim(1), _m01 = (src0).mod(1); \ 00254 intg _n10 = (src1).dim(0), _m10 = (src1).mod(0); \ 00255 intg _n11 = (src1).dim(1), _m11 = (src1).mod(1); \ 00256 idx_checkdim2_all(src0,src1,0) \ 00257 idx_checkdim2_all(src0,src1,1) \ 00258 for (i=0, p0=(src0).idx_ptr(), p1=(src1).idx_ptr(); \ 00259 i<_n00; \ 00260 i++, p0+=_m00-_n01*_m01, p1+=_m10-_n11*_m11) \ 00261 for (j=0; i<_n01; j++, p0+=_m01, p1+=_m11) 00262 00263 #define cidx2_bloop3(i,j,p0,src0,p1,src1,p2,src2) \ 00264 if ((src0).order() < 2) eblerror("idx has wrong order"); \ 00265 intg _n00 = (src0).dim(0), _m00 = (src0).mod(0); \ 00266 intg _n01 = (src0).dim(1), _m01 = (src0).mod(1); \ 00267 intg _n10 = (src1).dim(0), _m10 = (src1).mod(0); \ 00268 intg _n11 = (src1).dim(1), _m11 = (src1).mod(1); \ 00269 intg _n20 = (src2).dim(0), _m20 = (src2).mod(0); \ 00270 intg _n21 = (src2).dim(1), _m21 = (src2).mod(1); \ 00271 idx_checkdim3_all(src0,src1,src2,0) \ 00272 idx_checkdim3_all(src0,src1,src2,1) \ 00273 for (i=0, p0=(src0).idx_ptr(), p1=(src1).idx_ptr(), p2=(src2).idx_ptr(); \ 00274 i<_n00; \ 00275 i++, p0+=_m00-_n01*_m01, p1+=_m10-_n11*_m11, p2+=_m20-_n21*_m21) \ 00276 for (j=0; i<_n01; j++, p0+=_m01, p1+=_m11, p2+=_m21) 00277 00279 00287 00288 // bloop/eloop macros 00289 00290 // Okay, either C++ really suxx0rz or I'm a really st00pid Lisp-head. 00291 // Why can't we define syntax-changing macros like in Lisp? Basically, 00292 // I can't encapsulate the allocation 00293 // of temporary variable for a loop inside the macro, unless 00294 // I define a "begin" macro and an "end" macro. I would like 00295 // to define idx_bloop so I can do: 00296 // idx_bloop2(lm, m, lv, v) { idx_dot(lm,lm,v); } 00297 // but I can't do that because I have to allocate lm and lv 00298 // inside the macro, hence I need to know the type. 00299 // Now the call would be: 00300 // idx_bloop2(lm, m, double, lv, v, double) { idx_dot(lm,lm,v); } 00301 // But that still doesn't quite work because if I declare lm and lv 00302 // then I can't reuse the same symbols for another loop in the same 00303 // scope. The only way out is to force the user to encase every 00304 // bloop call inside braces, or to not reuse the same synbol twice 00305 // for a looping idx. I thought about generating a mangled name 00306 // but couldn't find a way to make it useful. 00307 // If a macro could define its own scope that would be great. 00308 00309 #define idx_bloop1(dst0,src0,type0) \ 00310 idxlooper<type0> dst0(src0,0); \ 00311 for ( ; dst0.notdone(); dst0.next()) 00312 00313 #define idx_bloop2(dst0,src0,type0,dst1,src1,type1) \ 00314 idx_checkdim2_all(src0, src1, 0); \ 00315 idxlooper<type0> dst0(src0,0); \ 00316 idxlooper<type1> dst1(src1,0); \ 00317 for ( ; dst0.notdone(); dst0.next(), dst1.next()) 00318 00319 #define idx_bloop3(dst0,src0,type0,dst1,src1,type1,dst2,src2,type2) \ 00320 idx_checkdim3_all(src0, src1, src2, 0); \ 00321 idxlooper<type0> dst0(src0,0); \ 00322 idxlooper<type1> dst1(src1,0); \ 00323 idxlooper<type2> dst2(src2,0); \ 00324 for ( ; dst0.notdone(); dst0.next(), dst1.next(), dst2.next()) 00325 00326 #define idx_bloop4(dst0,src0,type0,dst1,src1,type1,dst2,src2,type2, \ 00327 dst3,src3,type3) \ 00328 idx_checkdim4_all(src0, src1, src2, src3, 0); \ 00329 idxlooper<type0> dst0(src0,0); \ 00330 idxlooper<type1> dst1(src1,0); \ 00331 idxlooper<type2> dst2(src2,0); \ 00332 idxlooper<type3> dst3(src3,0); \ 00333 for ( ; dst0.notdone(); dst0.next(), dst1.next(), dst2.next(), dst3.next()) 00334 00335 #define idx_bloop5(dst0,src0,type0,dst1,src1,type1,dst2,src2,type2, \ 00336 dst3,src3,type3,dst4,src4,type4) \ 00337 idx_checkdim5_all(src0, src1, src2, src3, src4, 0); \ 00338 idxlooper<type0> dst0(src0,0); \ 00339 idxlooper<type1> dst1(src1,0); \ 00340 idxlooper<type2> dst2(src2,0); \ 00341 idxlooper<type3> dst3(src3,0); \ 00342 idxlooper<type4> dst4(src4,0); \ 00343 for ( ; dst0.notdone(); \ 00344 dst0.next(), dst1.next(), dst2.next(), dst3.next(), dst4.next()) 00345 00346 #define idx_bloop6(dst0,src0,type0,dst1,src1,type1,dst2,src2,type2, \ 00347 dst3,src3,type3,dst4,src4,type4,dst5,src5,type5) \ 00348 idx_checkdim6_all(src0, src1, src2, src3, src4, src5, 0); \ 00349 idxlooper<type0> dst0(src0,0); \ 00350 idxlooper<type1> dst1(src1,0); \ 00351 idxlooper<type2> dst2(src2,0); \ 00352 idxlooper<type3> dst3(src3,0); \ 00353 idxlooper<type4> dst4(src4,0); \ 00354 idxlooper<type5> dst5(src5,0); \ 00355 for ( ; dst0.notdone(); \ 00356 dst0.next(), dst1.next(), dst2.next(), dst3.next(), dst4.next(), \ 00357 dst5.next()) 00358 00359 // 1loop macros: loop on all but the 1st dimension 00360 00361 #define idx_1loop2(dst0,src0,type0,dst1,src1,type1,code) { \ 00362 uint src0o = src0.order(); \ 00363 if (src0o == 1) { \ 00364 idx<type0> dst0 = src0; \ 00365 idx<type1> dst1 = src1; \ 00366 code \ 00367 } else if (src0o == 2) { \ 00368 idxlooper<type0> dst0(src0, 1); \ 00369 idxlooper<type1> dst1(src1, 1); \ 00370 for ( ; dst0.notdone(); dst0.next(), dst1.next()) { \ 00371 code \ 00372 } \ 00373 } else if (src0o == 3) { \ 00374 idxlooper<type0> src00(src0, 2); \ 00375 idxlooper<type1> src11(src1, 2); \ 00376 for ( ; src00.notdone(); src00.next(), src11.next()) { \ 00377 idxlooper<type0> dst0(src00, 1); \ 00378 idxlooper<type1> dst1(src11, 1); \ 00379 for ( ; dst0.notdone(); dst0.next(), dst1.next()) { \ 00380 code \ 00381 } \ 00382 } \ 00383 } else \ 00384 eblerror("order " << src0o << " not implemented"); \ 00385 } 00386 00387 // eloop macros 00388 00389 #define idx_eloop1(dst0,src0,type0) \ 00390 idxlooper<type0> dst0(src0,src0.order()-1); \ 00391 for ( ; dst0.notdone(); dst0.next()) 00392 00393 #define idx_eloop2(dst0,src0,type0,dst1,src1,type1) \ 00394 if ((src0).dim((src0).order() - 1) != (src1).dim((src1).order() - 1)) \ 00395 eblerror("incompatible idxs for eloop\n"); \ 00396 idxlooper<type0> dst0(src0,(src0).order()-1); \ 00397 idxlooper<type1> dst1(src1,(src1).order()-1); \ 00398 for ( ; dst0.notdone(); dst0.next(), dst1.next()) 00399 00400 #define idx_eloop3(dst0,src0,type0,dst1,src1,type1,dst2,src2,type2)\ 00401 if (((src0).dim((src0).order() - 1) != (src1).dim((src1).order() - 1)) \ 00402 || ((src0).dim((src0).order() - 1) != (src2).dim((src2).order() - 1))) \ 00403 eblerror("incompatible idxs for eloop\n"); \ 00404 idxlooper<type0> dst0(src0,(src0).order()-1); \ 00405 idxlooper<type1> dst1(src1,(src1).order()-1); \ 00406 idxlooper<type2> dst2(src2,(src2).order()-1); \ 00407 for ( ; dst0.notdone(); dst0.next(), dst1.next(), dst2.next()) 00408 00409 #define idx_eloop4(dst0,src0,type0,dst1,src1,type1, \ 00410 dst2,src2,type2,dst3,src3,type3) \ 00411 if (((src0).dim((src0).order() - 1) != (src1).dim((src1).order() - 1)) \ 00412 || ((src0).dim((src0).order() - 1) != (src2).dim((src2).order() - 1)) \ 00413 || ((src0).dim((src0).order() - 1) != (src3).dim((src3).order() - 1))) \ 00414 eblerror("incompatible idxs for eloop\n"); \ 00415 idxlooper<type0> dst0(src0,(src0).order()-1); \ 00416 idxlooper<type1> dst1(src1,(src1).order()-1); \ 00417 idxlooper<type2> dst2(src2,(src2).order()-1); \ 00418 idxlooper<type3> dst3(src3,(src3).order()-1); \ 00419 for ( ; dst0.notdone(); dst0.next(), dst1.next(), dst2.next(), dst3.next()) 00420 00422 // aloop macros: loop over all elements 00423 00424 // Loops over all elements of an idx. This takes a pointer to 00425 // the data type of idx elements, and a blank idxiter object: 00426 // idx_aloop1(data_pointer,idxiter,&idx) { do_stuff(data_pointer); } 00427 // Example of use: add 1 to all element of m: 00428 // idx<double> m(3,4); 00429 // idxiter<double> p; 00430 // idx_aloop1(p,&m) { *p += 1; } 00431 #define idx_aloop1_on(itr0,src0) \ 00432 for ( itr0.init(src0); itr0.notdone(); itr0.next()) 00433 00434 // this loops simultaneously over all elements of 2 idxs. 00435 // The two idxs can have different structures as long as they have 00436 // the same total number of elements. 00437 #define idx_aloop2_on(itr0,src0,itr1,src1) \ 00438 idx_checknelems2_all(src0, src1); \ 00439 for ( itr0.init(src0), itr1.init(src1); \ 00440 itr0.notdone(); \ 00441 itr0.next(), itr1.next()) 00442 00443 #define idx_aloop3_on(itr0,src0,itr1,src1,itr2,src2) \ 00444 idx_checknelems3_all(src0, src1, src2); \ 00445 for (itr0.init(src0), itr1.init(src1), itr2.init(src2); \ 00446 itr0.notdone(); \ 00447 itr0.next(), itr1.next(), itr2.next()) 00448 00449 // high level aloop macros. 00450 // These should be enclosed in braces, to avoid name clashes 00451 #define idx_aloop1(itr0,src0,type0) \ 00452 idxiter<type0> itr0; \ 00453 idx_aloop1_on(itr0,src0) 00454 00455 #define idx_aloop2(itr0,src0,type0,itr1,src1,type1) \ 00456 idxiter<type0> itr0; \ 00457 idxiter<type1> itr1; \ 00458 idx_checknelems2_all(src0, src1); \ 00459 for (itr0.init(src0), itr1.init(src1); \ 00460 itr0.notdone(); \ 00461 itr0.next(), itr1.next()) 00462 00463 #define idx_aloop3(itr0,src0,type0,itr1,src1,type1,itr2,src2,type2) \ 00464 idxiter<type0> itr0; \ 00465 idxiter<type1> itr1; \ 00466 idxiter<type2> itr2; \ 00467 idx_checknelems3_all(src0, src1, src2); \ 00468 for (itr0.init(src0), itr1.init(src1), itr2.init(src2); \ 00469 itr0.notdone(); \ 00470 itr0.next(), itr1.next(), itr2.next()) 00471 00472 #define idx_aloop4(itr0,src0,type0,itr1,src1,type1,itr2,src2,type2, \ 00473 itr3,src3,type3) \ 00474 idxiter<type0> itr0; \ 00475 idxiter<type1> itr1; \ 00476 idxiter<type2> itr2; \ 00477 idxiter<type3> itr3; \ 00478 idx_checknelems4_all(src0, src1, src2, src3); \ 00479 for (itr0.init(src0), itr1.init(src1), itr2.init(src2), itr3.init(src3); \ 00480 itr0.notdone(); \ 00481 itr0.next(), itr1.next(), itr2.next(), itr3.next()) 00482 00484 // an idxlooper is an iterator for midx. 00485 // It is actually a subclass of idx. 00486 // These are not C++ iterators in the classical sense. 00487 00488 class dummyt { bool someunk; }; 00489 00490 template <class T> 00491 idxlooper<T>::idxlooper(idx<T> &m, int ld) : idx<T>((dummyt*)0) { 00492 if (m.order() == 0) // TODO: allow looping once on 0-order idx 00493 eblerror("cannot loop on idx with order 0. idx is: " << m); 00494 i = 0; 00495 dimd = m.spec.dim[ld]; 00496 modd = m.spec.mod[ld]; 00497 m.spec.select_into(&(this->spec), ld, i); 00498 this->storage = m.storage; 00499 this->storage->lock(); 00500 } 00501 00502 // like ++ 00503 // CAUTION: this doesn't do array bound checking 00504 // because we coudn't use a for loop if it did. 00505 template <class T> T *idxlooper<T>::next() { 00506 i++; 00507 this->spec.offset += modd; 00508 return this->storage->data + this->spec.offset; 00509 } 00510 00511 // return true when done. 00512 template <class T> bool idxlooper<T>::notdone() { return ( i < dimd ); } 00513 00515 // a pointer that loops over all elements 00516 // of an idx 00517 00518 // empty constructor; 00519 template <class T> idxiter<T>::idxiter() { } 00520 00521 template <class T> T *idxiter<T>::init(const idx<T> &m) { 00522 iterand = &m; 00523 i = 0; 00524 j = iterand->spec.ndim; 00525 data = iterand->storage->data + iterand->spec.offset; 00526 n = iterand->spec.nelements(); 00527 if (iterand->spec.contiguousp()) { 00528 d[0] = -1; 00529 } else { 00530 for(int i=0; i < iterand->spec.ndim; i++) { d[i] = 0; } 00531 } 00532 return data; 00533 } 00534 00535 template <class T> T *idxiter<T>::next() { 00536 i++; 00537 if (d[0] < 0) { 00538 // contiguous idx 00539 data++; 00540 } else { 00541 // non-contiguous idx 00542 j--; 00543 do { 00544 if (j<0) { 00545 break; 00546 } 00547 if (++d[j] < iterand->spec.dim[j]) { 00548 data += iterand->spec.mod[j]; 00549 j++; 00550 } else { 00551 data -= iterand->spec.dim[j] * iterand->spec.mod[j]; 00552 d[j--] = -1; 00553 } 00554 } while (j < iterand->spec.ndim); 00555 } 00556 return data; 00557 } 00558 00559 //template <class T> bool idxiter<T>::notdone() { return done; } 00560 template <class T> bool idxiter<T>::notdone() { return (i < n); } 00561 00562 } // end namespace ebl 00563 00564 #endif /* IDXITER_HPP_*/