libidx
/home/rex/ebltrunk/core/libidx/include/idxiter.hpp
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_*/