libidx
/home/rex/ebltrunk/core/libidx/include/idxiter.h
00001 /***************************************************************************
00002  *   Copyright (C) 2011 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_H_
00034 #define IDXITER_H_
00035 
00036 namespace ebl {
00037   
00038   // forward declarations
00039   template <typename T> class idx;
00040   
00042   // idx Iterators are a subclass of idx
00043 
00048   template <class T> class idxlooper : public idx<T> {
00049   public:
00051     idxlooper(idx<T> &m, int ld);
00053     bool notdone();
00055     T *next();
00056     void operator++();
00057   protected:
00058     intg i;  // loop index
00059     intg dimd;  // number of elements to iterated upon
00060     intg modd; // stride in dimension being iterated upon
00061   };
00062 
00064   // idx Iterators: gives you a pointer to the actual data,
00065   // unlike idxlooper which gives you another idx.
00066 
00081   template <class T> class idxiter {
00082   public:
00084     idxiter();
00087     T *init(const idx<T> &m);
00089     bool notdone();
00091     T *next();
00093     T& operator*() { return *data; }
00094   protected:
00095     T *data; 
00096     intg i; 
00097     intg n; 
00098     int j; 
00099     intg d[MAXDIMS]; 
00100     const idx<T> *iterand; 
00101   };
00102 
00103   template <class T> class contiguous_idxiter {
00104   public:
00105     inline contiguous_idxiter() {}
00106     inline contiguous_idxiter(idx<T> & m)
00107       :current(m.storage->data + m.spec.offset), end(NULL) {
00108 #ifdef __DEBUG__
00109       if (!m.contiguousp())
00110         eblerror("this idx should be contiguous");
00111 #endif
00112       end = current + (unsigned)m.nelements();
00113     }
00114     //inline intg i ();
00115     inline bool notdone () const {return current < end;}
00116     inline void next() {++current;}
00117     inline T& operator * () {return *current;}
00118     inline void operator += (intg i) {current += i;}
00119   protected: // members
00120     T *current, *end;
00121   };
00122 
00123   template <class T> class noncontiguous_idxiter {
00124   public:
00125     T* data;
00126     intg d[MAXDIMS];
00127     intg i, n;
00128     int j, jmax;
00129     idx<T>* iterand;
00130     inline noncontiguous_idxiter() {}
00131     inline noncontiguous_idxiter(idx<T> & m)
00132       :data(m.storage->data + m.spec.offset), i(0), n(m.spec.nelements()),
00133       j(m.spec.ndim - 1), jmax(m.spec.ndim - 1), iterand(&m) {
00134       memset(d, 0, MAXDIMS * sizeof(intg));
00135     }
00136     inline bool notdone () const {return i < n;}
00137     inline void next () {
00138       ++i;
00139       while (j >= 0) {
00140         if (++d[j] >= iterand->spec.dim[j]) {
00141           data -= iterand->spec.dim[j] * iterand->spec.mod[j]; //TODO precalculate?
00142           d[j--] = -1;
00143           continue;
00144         }
00145         data += iterand->spec.mod[j];
00146         if (j != jmax)
00147           j++;
00148         else
00149           return;
00150       }
00151     }
00152     inline T& operator * () {return *data;}
00153     inline void operator += (intg k) {
00154       if (k + i >= n) {
00155         i = n;
00156         return;
00157       }
00158       i += k;
00159       intg m = 1;
00160       intg t;
00161       while ((t = (iterand->spec.dim[j] - d[j]) * m) < k) {
00162         k += d[j];
00163         d[j] = 0;
00164         data -= d[j] * iterand->spec.mod[j];
00165         m *= iterand->spec.dim[j];
00166         --j;
00167       }
00168       for(;;) {
00169         t = k/m;
00170         d[j] += t;
00171         data += iterand->spec.mod[j] * t;
00172         if (j == jmax)
00173           return;
00174         ++j;
00175         k -= t*m;
00176         m /= iterand->spec.dim[j];
00177       }
00178     }
00179   };
00180 
00181 #define new_fast_idxiter(itr, src, type, code)          \
00182   if (src.contiguousp()) {                              \
00183     contiguous_idxiter<type> itr (src);                 \
00184     code                                                \
00185   } else {                                              \
00186     noncontiguous_idxiter<type> itr (src);              \
00187     code                                                \
00188   }
00189 
00190 #define idx_aloopf1(itr0, src0, type0, code)                            \
00191   if (src0.contiguousp()) {                                             \
00192     for (contiguous_idxiter<type0> itr0 (src0); itr0.notdone();         \
00193          itr0.next())                                                   \
00194       code                                                              \
00195   } else {                                                              \
00196     for (noncontiguous_idxiter<type0> itr0 (src0); itr0.notdone();      \
00197          itr0.next())                                                   \
00198       code                                                              \
00199   }
00200 
00201 #define idx_aloopf2(itr0, src0, type0, itr1, src1, type1, code)         \
00202   if (src0.contiguousp()) {                                             \
00203     if (src1.contiguousp()) {                                           \
00204       contiguous_idxiter<type0> itr0 (src0);                            \
00205       contiguous_idxiter<type1> itr1 (src1);                            \
00206       for (; itr0.notdone(); itr0.next(), itr1.next())                  \
00207         code                                                            \
00208     } else {                                                            \
00209       contiguous_idxiter<type0> itr0 (src0);                            \
00210       noncontiguous_idxiter<type1> itr1 (src1);                         \
00211       for (; itr0.notdone(); itr0.next(), itr1.next())                  \
00212         code                                                            \
00213     }                                                                   \
00214   } else {                                                              \
00215     if (src1.contiguousp()) {                                           \
00216       noncontiguous_idxiter<type0> itr0 (src0);                         \
00217       contiguous_idxiter<type1> itr1 (src1);                            \
00218       for (; itr0.notdone(); itr0.next(), itr1.next())                  \
00219         code                                                            \
00220     } else {                                                            \
00221       noncontiguous_idxiter<type0> itr0 (src0);                         \
00222       noncontiguous_idxiter<type1> itr1 (src1);                         \
00223       for (; itr0.notdone(); itr0.next(), itr1.next())                  \
00224         code                                                            \
00225     }                                                                   \
00226   }
00227 
00228 #define idx_aloopf3(itr0, src0, type0, itr1, src1, type1, itr2, src2,   \
00229                     type2, code)                                        \
00230   new_fast_idxiter(itr0, src0, type0, {                                 \
00231     new_fast_idxiter(itr1, src1, type1, {                               \
00232       new_fast_idxiter(itr2, src2, type1, {                             \
00233         for (; itr0.notdone(); itr0.next(), itr1.next(), itr2.next())   \
00234           code                                                          \
00235       })                                                                \
00236     })                                                                  \
00237   })
00238 
00239 } // end namespace ebl
00240 
00241 #include "idxiter.hpp"
00242 
00243 #endif /* IDXITER_H_ */