libidx
/home/rex/ebltrunk/core/libidx/include/idx.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 IDX_HPP_
00034 #define IDX_HPP_
00035 
00036 namespace ebl {
00037 
00039   // idx memory methods
00040 
00041 #define growstorage() {                                         \
00042   if (storage->growsize(spec.footprint()) < 0)                  \
00043     eblerror("cannot grow storage to " << spec.footprint()      \
00044              << " bytes (probably out of memory)");             \
00045   }
00046 
00047   template <class T> void idx<T>::growstorage_chunk(intg s_chunk){
00048     if (storage->growsize_chunk(spec.footprint(), s_chunk) < 0)
00049       eblerror("cannot grow storage to " << spec.footprint()
00050                << " bytes (probably out of memory)");
00051   }
00052 
00054   // idx basic constructors/destructor
00055 
00056   template <class T> idx<T>::~idx() {
00057     DEBUG_LOW("idx::destructor " << long(this));
00058     storage->unlock();
00059     if (this->pidxdim)
00060       delete this->pidxdim;
00061   }
00062 
00063   // fake constructor called by idxlooper constructor
00064   template <class T> idx<T>::idx(dummyt *dummy) {
00065     spec.dim = NULL;
00066     spec.mod = NULL;
00067     storage = NULL;
00068     pidxdim = NULL;
00069   }
00070 
00071   template <class T> idx<T>::idx(const idx<T>& other)
00072     : spec(other.spec), storage(other.storage), pidxdim(NULL) {
00073     storage->lock();
00074   }
00075 
00078 
00079   template <class T> idx<T>::idx(const T *mat, intg s0, intg s1)
00080     : spec(0, s0, s1), pidxdim(NULL) {
00081     storage = new srg<T>();
00082     growstorage();
00083     storage->lock();
00084     memcpy(idx_ptr(), mat, nelements() * sizeof (T));
00085   }
00086 
00087   template <class T> idx<T>::idx(const T *mat, intg s0, intg s1, intg s2)
00088     : spec(0, s0, s1, s2), pidxdim(NULL) {
00089     storage = new srg<T>();
00090     growstorage();
00091     storage->lock();
00092     memcpy(idx_ptr(), mat, nelements() * sizeof (T));
00093   }
00094 
00096   // specific constructors for each number of dimensions
00097 
00098   template <class T> idx<T>::idx() : spec(0), pidxdim(NULL) {
00099     storage = new srg<T>();
00100     growstorage();
00101     storage->lock();
00102   }
00103 
00104   template <class T> idx<T>::idx(intg size0)
00105   : spec(0,size0), pidxdim(NULL) {
00106     storage = new srg<T>();
00107     growstorage();
00108     storage->lock();
00109   }
00110 
00111   template <class T> idx<T>::idx(intg size0, intg size1)
00112     : spec(0,size0,size1), pidxdim(NULL) {
00113     storage = new srg<T>();
00114     growstorage();
00115     storage->lock();
00116   }
00117 
00118   template <class T> idx<T>::idx(intg size0, intg size1, intg size2)
00119     : spec(0,size0,size1,size2), pidxdim(NULL) {
00120     storage = new srg<T>();
00121     growstorage();
00122     storage->lock();
00123   }
00124 
00125   template <class T>
00126   idx<T>::idx(intg s0, intg s1, intg s2, intg s3, intg s4, intg s5,
00127               intg s6, intg s7)
00128     : spec(0,s0,s1,s2,s3,s4,s5,s6,s7), pidxdim(NULL) {
00129     storage = new srg<T>();
00130     growstorage();
00131     storage->lock();
00132   }
00133 
00134   template <class T> idx<T>::idx(const idxdim &d)
00135     : spec(0, d), pidxdim(NULL) {
00136     storage = new srg<T>();
00137     growstorage();
00138     storage->lock();
00139   }
00140 
00142   // constructors from existing srg and offset
00143 
00144   template <class T>
00145   idx<T>::idx(srg<T> *sg, idxspec &s) : pidxdim(NULL) {
00146     spec = s;
00147     if (sg) // use passed srg if not null
00148       storage = sg;
00149     else // otherwise create new one
00150       storage = new srg<T>();
00151     growstorage();
00152     storage->lock();
00153   }
00154 
00155   template <class T>
00156   idx<T>::idx(srg<T> *sg, intg o, intg n, intg *dims, intg *mods)
00157     : spec(sg ? o : 0, n, dims, mods), pidxdim(NULL) {
00158     if (sg) // use passed srg if not null
00159       storage = sg;
00160     else // otherwise create new one
00161       storage = new srg<T>();
00162     growstorage();
00163     storage->lock();
00164   }
00165 
00166   template <class T>
00167   idx<T>::idx(srg<T> *sg, intg o)
00168     : spec(sg ? o : 0), pidxdim(NULL) {
00169     if (sg) // use passed srg if not null
00170       storage = sg;
00171     else // otherwise create new one
00172       storage = new srg<T>();
00173     growstorage();
00174     storage->lock();
00175   }
00176 
00177   template <class T>
00178   idx<T>::idx(srg<T> *sg, intg o, intg size0)
00179     : spec(sg ? o : 0, size0), pidxdim(NULL) {
00180     if (sg) // use passed srg if not null
00181       storage = sg;
00182     else // otherwise create new one
00183       storage = new srg<T>();
00184     growstorage();
00185     storage->lock();
00186   }
00187 
00188   template <class T>
00189   idx<T>::idx(srg<T> *sg, intg o, intg size0, intg size1)
00190     : spec(sg ? o : 0, size0, size1), pidxdim(NULL) {
00191     if (sg) // use passed srg if not null
00192       storage = sg;
00193     else // otherwise create new one
00194       storage = new srg<T>();
00195     growstorage();
00196     storage->lock();
00197   }
00198 
00199   template <class T>
00200   idx<T>::idx(srg<T> *sg, intg o, intg size0, intg size1, intg size2)
00201     : spec(sg ? o : 0, size0, size1, size2), pidxdim(NULL) {
00202     if (sg) // use passed srg if not null
00203       storage = sg;
00204     else // otherwise create new one
00205       storage = new srg<T>();
00206     growstorage();
00207     storage->lock();
00208   }
00209 
00210   template <class T>
00211   idx<T>::idx(srg<T> *sg, intg o, intg s0, intg s1, intg s2, intg s3,
00212               intg s4, intg s5, intg s6, intg s7)
00213     : spec(sg ? o : 0, s0, s1, s2, s3, s4, s5, s6, s7), pidxdim(NULL) {
00214     if (sg) // use passed sg if not null
00215       storage = sg;
00216     else // otherwise create new one
00217       storage = new srg<T>();
00218     growstorage();
00219     storage->lock();
00220   }
00221 
00222   template <class T>
00223   idx<T>::idx(srg<T> *sg, intg o, const idxdim &d)
00224     : spec(sg ? o : 0, d), pidxdim(NULL) {
00225     if (sg) // use passed srg if not null
00226       storage = sg;
00227     else // otherwise create new one
00228       storage = new srg<T>();
00229     growstorage();
00230     storage->lock();
00231   }
00232 
00234   // operators
00235 
00236   template <class T>
00237   idx<T>& idx<T>::operator=(T other){
00238     eblerror("Forbidden idx assignment: it can only be assigned another idx");
00239     return *this;
00240   }
00241 
00242   template <class T>
00243   idx<T>& idx<T>::operator=(const idx<T>& other) {
00244     if (this != &other) { // protect against invalid self-assignment
00245       srg<T> *tmp = NULL;
00246       if (this->storage != NULL)
00247         tmp = this->storage;
00248       this->storage = other.storage;
00249       this->spec = other.spec;
00250       this->storage->lock();
00251       if (tmp) // unlock previous storage
00252         tmp->unlock();
00253       if (other.pidxdim) this->pidxdim = new idxdim(*other.pidxdim);
00254       else this->pidxdim = NULL;
00255     }
00256     return *this;
00257   }
00258 
00259   template <class T>
00260   idx<T> idx<T>::operator[](const intg i) {
00261     return this->select(0,i);
00262   }
00263 
00265   // resize methods
00266 
00267   template <class T>
00268   intg idx<T>::setoffset(intg o) {
00269     if (o<0) { eblerror("idx::setoffset: offset must be positive"); }
00270     if (o > spec.offset) {
00271       spec.setoffset(o);
00272       growstorage();
00273       return o;
00274     } else {
00275       spec.setoffset(o);
00276       return o;
00277     }
00278   }
00279 
00280   template <class T>
00281   void idx<T>::add_offset(intg o) {
00282     spec.add_offset(o);
00283   }
00284 
00285   template <class T>
00286   void idx<T>::resize(intg s0, intg s1, intg s2, intg s3,
00287                       intg s4, intg s5, intg s6, intg s7) {
00288     if (!same_dim(s0,s1,s2,s3,s4,s5,s6,s7)) { // save some time
00289       spec.resize(s0,s1,s2,s3,s4,s5,s6,s7);
00290       growstorage();
00291     }
00292   }
00293 
00294   template <class T>
00295   void idx<T>::resize(const idxdim &d) {
00296     if (d.order() > spec.ndim)
00297       eblerror("cannot change order of idx in resize while trying to resize "
00298                << " from " << (*this) << " to " << d);
00299     if (!same_dim(d)) { // save some time if dims are same
00300       spec.resize(d);
00301       growstorage();
00302     }
00303   }
00304 
00305   template <class T>
00306   void idx<T>::resize1(intg dimn, intg size) {
00307     if (dimn > spec.ndim) eblerror("cannot change order of idx in resize");
00308     if (spec.dim[dimn] != size) {
00309       spec.resize1(dimn, size);
00310       growstorage();
00311     }
00312   }
00313 
00314   template <class T>
00315   void idx<T>::resize_chunk(intg s_chunk, intg s0, intg s1, intg s2, intg s3,
00316                             intg s4, intg s5, intg s6, intg s7) {
00317     spec.resize(s0,s1,s2,s3,s4,s5,s6,s7);
00318     growstorage_chunk(s_chunk);
00319   }
00320 
00321   // return true if this idx has same order and dimensions as idxdim d.
00322   // i.e. if all their dimensions are equal (regardless of strides).
00323   template <class T>
00324   bool idx<T>::same_dim(const idxdim &d) {
00325     if (spec.ndim != d.order())
00326       return false;
00327     for (int i=0; i < spec.ndim; ++i)
00328       if (spec.dim[i] != d.dim(i))
00329         return false;
00330     return true;
00331   }
00332 
00333   // idx manipulation methods //////////////////////////////////////////////////
00334 
00335   template <class T> idx<T> idx<T>::select(int d, intg i) {
00336     idx<T> r(storage,spec.getoffset());
00337     spec.select_into(&r.spec, d, i);
00338     return r;
00339   }
00340 
00341   template <class T> idx<T> idx<T>::narrow(int d, intg s, intg o) {
00342     idx<T> r(storage,spec.getoffset());
00343     spec.narrow_into(&r.spec, d, s, o);
00344     return r;
00345   }
00346 
00347   template <class T> idx<T> idx<T>::transpose(int d1, int d2) {
00348     idx<T> r(storage,spec.getoffset());
00349     spec.transpose_into(&r.spec, d1, d2);
00350     return r;
00351   }
00352 
00353   template <class T> idx<T> idx<T>::transpose(int *p) {
00354     idx<T> r(storage,spec.getoffset());
00355     spec.transpose_into(&r.spec, p);
00356     return r;
00357   }
00358 
00359   template <class T> idx<T> idx<T>::unfold(int d, intg k, intg s) {
00360     idx<T> r(storage,spec.getoffset());
00361     spec.unfold_into(&r.spec, d, k, s);
00362     return r;
00363   }
00364 
00365   template <class T> idx<T> idx<T>::view_as_order(int n) {
00366     if (n < 0) {
00367       eblerror("view_as_order: input dimension must be positive");
00368       return *this;
00369     }
00370     if (n == spec.ndim)
00371       return *this;
00372     else {
00373       if ((n == 1) && (spec.ndim == 1)) {
00374         // the order is already 1, do nothing and return current idx.
00375         return idx<T>(*this);
00376       }
00377       else if (n == 1) {
00378         // the order is not 1, check that data is contiguous and return
00379         // a 1D idx.
00380         idx_check_contiguous1(*this);
00381         idx<T> r(getstorage(), 0, spec.nelements());
00382         return r;
00383       }
00384       else if (n > spec.ndim) {
00385         intg *ldim = new intg[n];
00386         intg *lmod = new intg[n];
00387         memcpy(ldim, spec.dim, spec.ndim * sizeof (intg));
00388         memcpy(lmod, spec.mod, spec.ndim * sizeof (intg));
00389         for (int i = spec.ndim; i < n; ++i) {
00390           ldim[i] = 1;
00391           lmod[i] = 1;
00392         }
00393         idx<T> r(getstorage(), spec.getoffset(), n, ldim, lmod);
00394         if (ldim) delete[] ldim;
00395         if (lmod) delete[] lmod;
00396         return r;
00397       }
00398       else {
00399         eblerror("view_as_order is not defined when n < current order");
00400         return idx<T>(*this);
00401       }
00402     }
00403   }
00404 
00405   template <class T> idx<T> idx<T>::shift_dim(int d, int pos) {
00406     int tr[MAXDIMS];
00407     for (int i = 0, j = 0; i < spec.ndim; ++i) {
00408       if (i == pos)
00409         tr[i] = d;
00410       else {
00411         if (j == d)
00412           j++;
00413         tr[i] = j++;
00414       }
00415     }
00416     return transpose(tr);
00417   }
00418 
00419   // return true if this idx has same order and dimensions s0 .. s7
00420   // i.e. if all their dimensions are equal (regardless of strides).
00421   template <class T>
00422   bool idx<T>::same_dim(intg s0, intg s1, intg s2, intg s3, intg s4, intg s5,
00423                          intg s6, intg s7) {
00424     if ((s7 >= 0) && (spec.ndim < 8)) return false;
00425     if ((spec.ndim == 8) && (s7 != spec.dim[7])) return false;
00426     if ((s6 >= 0) && (spec.ndim < 7)) return false;
00427     if ((spec.ndim >= 7) && (s6 != spec.dim[6])) return false;
00428     if ((s5 >= 0) && (spec.ndim < 6)) return false;
00429     if ((spec.ndim >= 6) && (s5 != spec.dim[5])) return false;
00430     if ((s4 >= 0) && (spec.ndim < 5)) return false;
00431     if ((spec.ndim >= 5) && (s4 != spec.dim[4])) return false;
00432     if ((s3 >= 0) && (spec.ndim < 4)) return false;
00433     if ((spec.ndim >= 4) && (s3 != spec.dim[3])) return false;
00434     if ((s2 >= 0) && (spec.ndim < 3)) return false;
00435     if ((spec.ndim >= 3) && (s2 != spec.dim[2])) return false;
00436     if ((s1 >= 0) && (spec.ndim < 2)) return false;
00437     if ((spec.ndim >= 2) && (s1 != spec.dim[1])) return false;
00438     if ((s0 >= 0) && (spec.ndim < 1)) return false;
00439     if ((spec.ndim >= 1) && (s0 != spec.dim[0])) return false;
00440     return true;
00441   }
00442 
00443   template <class T> idxdim& idx<T>::get_idxdim() {
00444     // allocating idxdim on the fly creates a memory leak somehow
00445     // we temporarly keep an idxdim around in all idxs (more expensive in mem)
00446     // TODO: change idxdim to be contained in spec, replacing the dims of spec
00447     // this way we don't duplicate this info twice and can keep it around
00448     // at the same cost of current spec.
00449 
00450     // if (!pidxdim)
00451     //   pidxdim = new idxdim();
00452     // pidxdim->setdims(spec);
00453     // return *pidxdim;
00454 
00455     idd.setdims(spec);
00456     return idd;
00457   }
00458 
00459   template <class T> idxdim idx<T>::get_idxdim() const {
00460     idxdim d;
00461     d.setdims(spec);
00462     return d;
00463   }
00464 
00465   // data access methods ///////////////////////////////////////////////////////
00466 
00467   template <class T> T* idx<T>::idx_ptr() {
00468     return storage->data + spec.offset;
00469   }
00470   
00471   template <class T> const T* idx<T>::idx_ptr() const {
00472     return storage->data + spec.offset;
00473   }
00474   
00475   template <class T> intg* idx<T>::mod_ptr() {
00476     return spec.mod;
00477   }
00478 
00479   // pointer access methods ////////////////////////////////////////////////////
00480 
00481   template <class T> T* idx<T>::ptr() {
00482     if (spec.ndim != 0) eblerror("not an idx0");
00483     return storage->data + spec.offset;
00484   }
00485   
00486   // get element of idx1
00487   template <class T> T *idx<T>::ptr(intg i0) {
00488     idx_checkorder1(*this, 1);
00489     if ((i0 < 0) || (i0 >= spec.dim[0])) eblerror("index 0 out of bound");
00490     return storage->data + spec.offset + i0*spec.mod[0];
00491   }
00492 
00493   // get element of idx2
00494   template <class T> T *idx<T>::ptr(intg i0, intg i1) {
00495     idx_checkorder1(*this, 2);
00496     if ((i0 < 0) || (i0 >= spec.dim[0])) eblerror("index 0 out of bound");
00497     if ((i1 < 0) || (i1 >= spec.dim[1])) eblerror("index 1 out of bound");
00498     return storage->data + spec.offset + i0*spec.mod[0] + i1*spec.mod[1];
00499   }
00500 
00501   // get element of idx3
00502   template <class T> T *idx<T>::ptr(intg i0, intg i1, intg i2) {
00503     idx_checkorder1(*this, 3);
00504     if ((i0 < 0) || (i0 >= spec.dim[0])) eblerror("index 0 out of bound");
00505     if ((i1 < 0) || (i1 >= spec.dim[1])) eblerror("index 1 out of bound");
00506     if ((i2 < 0) || (i2 >= spec.dim[2])) eblerror("index 2 out of bound");
00507     return storage->data + spec.offset + i0*spec.mod[0] + i1*spec.mod[1]
00508       + i2*spec.mod[2];
00509   }
00510 
00511   // replacing exception throwing by macro to handle environments without
00512   // macros (e.g. android). this makes the compiled code a bit bigger.
00513 #define PTR_ERROR(v)                                                    \
00514   eblerror("idx::get: (error " << v                                     \
00515            << "wrong number of indices, negative or out of bound index");
00516 
00517   // return a pointer to an element of an idx
00518   // generic function for order>3
00519   template <class T> T *idx<T>::ptr(intg i0, intg i1, intg i2, intg i3,
00520                                     intg i4, intg i5, intg i6, intg i7) {
00521     // check that we passed the right number of indices
00522     // and that they are all positive
00523     switch (spec.ndim) {
00524     case 8: if (i7 < 0) PTR_ERROR(-8);break;
00525     case 7: if ((i6 < 0) || (i7 != -1)) PTR_ERROR(-7);break;
00526     case 6: if ((i5 < 0) || (i6 != -1)) PTR_ERROR(-6);break;
00527     case 5: if ((i4 < 0) || (i5 != -1)) PTR_ERROR(-5);break;
00528     case 4: if ((i3<0)||(i2<0)||(i1<0)||(i0<0)||(i4 != -1)) PTR_ERROR(-4);break;
00529     default:
00530       eblerror("idx::get: number of indices and order are different");
00531     }
00532     // now compute offset, and check that all
00533     // indices are within bounds.
00534     intg k = 0;
00535     switch (spec.ndim) {
00536     case 8: k += spec.mod[7]*i7; if (i7 >= spec.dim[7])  PTR_ERROR(7);
00537     case 7: k += spec.mod[6]*i6; if (i6 >= spec.dim[6])  PTR_ERROR(6);
00538     case 6: k += spec.mod[5]*i5; if (i5 >= spec.dim[5])  PTR_ERROR(5);
00539     case 5: k += spec.mod[4]*i4; if (i4 >= spec.dim[4])  PTR_ERROR(4);
00540     case 4: k += spec.mod[3]*i3; if (i3 >= spec.dim[3])  PTR_ERROR(3);
00541     }
00542     k += spec.mod[2]*i2; if (i2 >= spec.dim[2])  PTR_ERROR(2);
00543     k += spec.mod[1]*i1; if (i1 >= spec.dim[1])  PTR_ERROR(1);
00544     k += spec.mod[0]*i0; if (i0 >= spec.dim[0])  PTR_ERROR(0);
00545     return storage->data + spec.offset + k;
00546   }
00547 
00548   // get methods ///////////////////////////////////////////////////////////////
00549 
00550   // get element of idx0
00551   template <class T> T idx<T>::get() const {
00552 #ifdef __DEBUG__
00553     idx_checkorder1(*this, 0);
00554 #endif
00555     return (storage->data)[spec.offset];
00556   }
00557 
00558   // get element of idx1
00559   template <class T> T& idx<T>::get(intg i0) const {
00560 #ifdef __DEBUG__
00561     idx_checkorder1(*this, 1);
00562     if ((i0 < 0) || (i0 >= spec.dim[0])) {
00563       eblerror("error accessing elt " << i0 << " in " << *this
00564                << ", index out of bound");
00565     }
00566 #endif
00567     return (storage->data)[spec.offset + i0*spec.mod[0]];
00568   }
00569 
00570   // get element of idx2
00571   template <class T> T idx<T>::get(intg i0, intg i1) const {
00572 #ifdef __DEBUG__
00573     idx_checkorder1(*this, 2);
00574     if (((i0 < 0) || (i0 >= spec.dim[0])) ||
00575         ((i1 < 0) || (i1 >= spec.dim[1]))) {
00576       eblerror("error accessing elt " << i0 << "x"
00577                 << i1 << " in " << *this << ", index out of bound");
00578     }
00579 #endif
00580     return (storage->data)[spec.offset + i0*spec.mod[0] + i1*spec.mod[1]];
00581   }
00582 
00583   // get element of idx3
00584   template <class T> T idx<T>::get(intg i0, intg i1, intg i2) const {
00585 #ifdef __DEBUG__
00586     idx_checkorder1(*this, 3);
00587     if (((i0 < 0) || (i0 >= spec.dim[0])) ||
00588         ((i1 < 0) || (i1 >= spec.dim[1])) ||
00589         ((i2 < 0) || (i2 >= spec.dim[2]))) {
00590       eblerror("error accessing elt " << i0 << "x"
00591                << i1 << "x" << i2 << " in " << *this
00592                << ", index out of bound");
00593     }
00594 #endif
00595     return (storage->data)[spec.offset + i0*spec.mod[0] + i1*spec.mod[1]
00596                            + i2*spec.mod[2]];
00597   }
00598 
00599   // get element of an idx of any order
00600   template <class T> T idx<T>::get(intg i0, intg i1, intg i2, intg i3,
00601                                    intg i4, intg i5, intg i6, intg i7) {
00602     return *ptr(i0,i1,i2,i3,i4,i5,i6,i7);
00603   }
00604 
00605   // get element of an idx of any order
00606   template <class T> T idx<T>::gget(intg i0, intg i1, intg i2, intg i3,
00607                                     intg i4, intg i5, intg i6, intg i7) {
00608     switch (spec.ndim) {
00609     case 7: i7 = -1; break ;
00610     case 6: i6 = -1; i7 = -1; break ;
00611     case 5: i5 = -1; i6 = -1; i7 = -1; break ;
00612     case 4: i4 = -1; i5 = -1; i6 = -1; i7 = -1; break ;
00613     case 3: return get(i0, i1, i2);
00614     case 2: return get(i0, i1);
00615     case 1: return get(i0);
00616     case 0: return get();
00617     default: break ;
00618     }
00619     return *ptr(i0,i1,i2,i3,i4,i5,i6,i7);
00620   }
00621 
00623   // set methods
00624 
00625   // set the element of idx0
00626   template <class T> T idx<T>::set(T val) {
00627 #ifdef __DEBUG__
00628     idx_checkorder1(*this, 0);
00629 #endif
00630     return (storage->data)[spec.offset] = val;
00631   }
00632 
00633   // set the element of idx1
00634   template <class T> T idx<T>::set(T val, intg i0) {
00635 #ifdef __DEBUG__
00636     idx_checkorder1(*this, 1);
00637     if ((i0 < 0) || (i0 >= spec.dim[0]))
00638       eblerror("index " << i0 << " in dim 0 out of bound in " << *this);
00639 #endif
00640     return (storage->data)[spec.offset + i0*spec.mod[0]] = val;
00641   }
00642 
00643   // set the element of idx2
00644   template <class T> T idx<T>::set(T val, intg i0, intg i1) {
00645 #ifdef __DEBUG__
00646     idx_checkorder1(*this, 2);
00647     if ((i0 < 0) || (i0 >= spec.dim[0]))
00648       eblerror("index " << i0 << " in dim 0 out of bound in " << *this);
00649     if ((i1 < 0) || (i1 >= spec.dim[1]))
00650       eblerror("index " << i1 << " in dim 1 out of bound in " << *this);
00651 #endif
00652     return (storage->data)[spec.offset + i0*spec.mod[0] + i1*spec.mod[1]] = val;
00653   }
00654 
00655   // set the element of idx3
00656   template <class T> T idx<T>::set(T val, intg i0, intg i1, intg i2) {
00657 #ifdef __DEBUG__
00658     idx_checkorder1(*this, 3);
00659     if ((i0 < 0) || (i0 >= spec.dim[0]))
00660       eblerror("index " << i0 << " in dim 0 out of bound in " << *this);
00661     if ((i1 < 0) || (i1 >= spec.dim[1]))
00662       eblerror("index " << i1 << " in dim 1 out of bound in " << *this);
00663     if ((i2 < 0) || (i2 >= spec.dim[2]))
00664       eblerror("index " << i2 << " in dim 2 out of bound in " << *this);
00665 #endif
00666     return (storage->data)[spec.offset + i0*spec.mod[0] + i1*spec.mod[1]
00667                            + i2*spec.mod[2]] = val;
00668   }
00669 
00670   // set an element of an idx of any order.
00671   template <class T> T idx<T>::set(T val, intg i0, intg i1, intg i2, intg i3,
00672                                    intg i4, intg i5, intg i6, intg i7) {
00673     return *ptr(i0,i1,i2,i3,i4,i5,i6,i7) = val;
00674   }
00675 
00676   // get element of an idx of any order
00677   template <class T> T idx<T>::sset(T val, intg i0, intg i1, intg i2, intg i3,
00678                                     intg i4, intg i5, intg i6, intg i7) {
00679     switch (spec.ndim) {
00680     case 7: i7 = -1; break ;
00681     case 6: i6 = -1; i7 = -1; break ;
00682     case 5: i5 = -1; i6 = -1; i7 = -1; break ;
00683     case 4: i4 = -1; i5 = -1; i6 = -1; i7 = -1; break ;
00684     case 3: return set(val, i0, i1, i2);
00685     case 2: return set(val, i0, i1);
00686     case 1: return set(val, i0);
00687     case 0: return set(val);
00688     default: break ;
00689     }
00690     return *ptr(i0,i1,i2,i3,i4,i5,i6,i7) = val;
00691   }
00692 
00694   // print methods
00695 
00696   template <typename T>
00697   void idx<T>::printElems(std::ostream& out, bool newline) const {
00698     printElems_impl(0, out, newline);
00699     out.flush();
00700   }
00701 
00702   template <typename T>
00703   void idx<T>::printElems(std::string& out, bool newline) const {
00704     printElems_impl(0, out, newline);
00705   }
00706 
00707   template <typename T>
00708   void idx<T>::printElems() const {
00709     this->printElems(std::cout);
00710   }
00711 
00712   template <typename T>
00713   void idx<T>::print() const {
00714     this->printElems(std::cout);
00715     std::cout << "\n";
00716   }
00717 
00718   template <typename T>
00719   std::string idx<T>::str() const {
00720     std::string s;
00721     this->printElems(s, false);
00722     return s;
00723   }
00724 
00725   template<class T> inline T printElems_impl_cast(T val) {
00726     return val;
00727   }
00728 
00729   // specialization for ubyte to print as unsigned integers.
00730   inline unsigned int printElems_impl_cast(ubyte val) {
00731     return (unsigned int) val;
00732   }
00733 
00734   template <typename T> template <class stream>
00735   void idx<T>::printElems_impl(int indent, stream& out, bool newline) const {
00736     static const std::string lbrace = "[";
00737     static const std::string rbrace = "]";
00738     static const std::string sep = " ";
00739     // prepare indentation
00740     std::string tab;
00741     for( unsigned int ii = 0; ii < lbrace.length(); ++ii )
00742       tab << " ";
00743     // printing a 0-dimensional tensor
00744     if (order() == 0)
00745       out << lbrace << "@" << sep << printElems_impl_cast(get()) <<sep<< rbrace;
00746     else if (order() == 1) { // printing a 1-D tensor
00747       out << lbrace << sep;
00748       for (int ii = 0; ii < dim(0); ++ii)
00749         out << printElems_impl_cast(get(ii)) <<sep;
00750       out << rbrace; //<<"\n";
00751       //if (newline) out << "\n";
00752     } else { // printing a multidimensional tensor
00753       out << lbrace; // opening brace
00754       // print subtensors.
00755       idx<T> subtensor(storage, spec.offset);
00756       for(int dimInd = 0; dimInd < dim(0); ++dimInd ){
00757         // only print indent if this isn't the first subtensor.
00758         if (dimInd > 0)
00759           for(int ii = 0; ii < indent + 1; ++ii) out << tab;
00760         // print subtensor
00761         spec.select_into(&subtensor.spec, 0, dimInd);
00762         subtensor.printElems_impl(indent+1, out, newline);
00763         // only print the newline if this isn't the last subtensor.
00764         if (dimInd < dim(0) - 1 && newline) out << "\n";
00765       }
00766       out << rbrace; // closing brace
00767       //if (newline) out << "\n";
00768     }
00769   }
00770 
00771   template <class T> void idx<T>::pretty(FILE *f) const {
00772     fprintf(f,"idx: at address %ld\n",(intg)this);
00773     fprintf(f,"  storage=%ld (size=%ld)\n",(intg)storage,storage->size());
00774     spec.pretty(f);
00775   }
00776 
00777   template <class T> void idx<T>::pretty() const {
00778     pretty(std::cout);
00779   }
00780 
00781   template <class T> void idx<T>::pretty(std::ostream& out) const {
00782     out << "idx: at address " << (intg)this << "\n";
00783     out << "  storage=" <<  (intg)storage << "(size=" << storage->size();
00784     out << "\n";
00785     spec.pretty(out);
00786   }
00787 
00788   template <class T> int idx<T>::fdump(std::ostream &f) {
00789     if (spec.ndim == 0)
00790       f << "[@ " << this->get() << "]" << std::endl;
00791     else if (spec.ndim == 1) {
00792       f << "[";
00793       for (intg i=0; i<dim(0); i += mod(0))
00794         f << (storage->data)[spec.offset + i] << " ";
00795       f << "]\n";
00796     } else {
00797       f << "[";
00798       { idx_bloop1(p,*this,T) { p.fdump(f); } }
00799       f << "]\n";
00800     }
00801     return 0;
00802   }
00803 
00804   // stream printing ///////////////////////////////////////////////////////////
00805 
00806   template <class T>
00807   std::ostream& operator<<(std::ostream& out, const idx<T>& m) {
00808     out << m.spec;
00809     return out;
00810   }
00811 
00812   template <class T>
00813   std::string& operator<<(std::string& out, idx<T>& m) {
00814     out << m.spec;
00815     return out;
00816   }
00817 
00818   template <class T>
00819   std::string& operator<<(std::string& out, idx<T>* m) {
00820     if (!m)
00821       out << "null";
00822     else
00823       out << m->spec;
00824     return out;
00825   }
00826 
00827   template <typename T, class stream>
00828   stream& operator<<(stream& out, midx<T>& m) {
00829     idxdim dmin, dmax;
00830     bool dnull = false, bpos = false;
00831     if (m.order() == 0) {
00832       out << "[empty midx]";
00833       return out;
00834     }
00835     idx_aloopf1(e, ((idx<idx<T>*>&) m), idx<T>*, {
00836         idx<T> *pe = *e;
00837         if (pe) {
00838           idxdim d(*pe);
00839           if (d.nelements() < dmin.nelements() || dmin.empty()) dmin = d;
00840           if (d.nelements() > dmax.nelements()) dmax = d;
00841           bpos = true;
00842         } else
00843           dnull = true;
00844       });
00845     out << "[" << (idx<idx<T>*>&) m << ", ";
00846     if (!bpos)
00847       out << "all empty";
00848     else {
00849       out << "from ";
00850       if (dnull) out << "null";
00851       else out << dmin;
00852       out << " to " << dmax;
00853     }
00854     out << "]";
00855     return out;
00856   }
00857 
00858 //   template <typename T, class stream>
00859 //   stream& operator<<(stream& o, svector<midx<T> >& m) {
00860 //     o << "[ ";
00861 //     for (uint i = 0; i < m.size(); ++i) {
00862 //       midx<T> &e = m[i];
00863 //       o << e << " ";
00864 //     }
00865 //     o << "]";
00866 //     return o;
00867 //   }
00868 
00870 
00871   template <typename T>
00872   std::ostream& operator<<(std::ostream& out, const idxd<T>& d) {
00873     std::string s;
00874     s << d;
00875     out << s;
00876     return out;
00877   }
00878 
00879   template <typename T>
00880   std::string& operator<<(std::string& out, const idxd<T>& d) {
00881     if (d.order() <= 0)
00882       out << "<empty>";
00883     else {
00884       if (d.offsets) {
00885         bool show = false;
00886         for (int i = 0; i < d.order(); ++i)
00887           if (d.offset(i) != 0) {
00888             show = true;
00889             break;
00890           }
00891         if (show) {
00892           out << "(";
00893           out << d.offset(0);
00894           for (int i = 1; i < d.order(); ++i)
00895             out << "," << d.offset(i);
00896           out << ")";
00897         }
00898       }
00899       out << d.dim(0);
00900       for (int i = 1; i < d.order(); ++i)
00901         out << "x" << d.dim(i);
00902     }
00903     return out;
00904   }
00905 
00906   // midx //////////////////////////////////////////////////////////////////////
00907 
00908   template <typename T>
00909   midx<T>::midx(intg size, std::file *fp_, idx<int64> *off)
00910     : idx<idx<T>*>(size), fp(fp_) {
00911     idx_clear(*this);
00912     if (fp) {
00913       if (!off) eblerror("expected an offset matrix");
00914       offsets = *off;
00915       fp->incr_ref();
00916     }
00917   }
00918 
00919   template <typename T>
00920   midx<T>::midx(intg size0, intg size1, std::file *fp_, idx<int64> *off)
00921     : idx<idx<T>*>(size0, size1), fp(fp_) {
00922     idx_clear(*this);
00923     if (fp) {
00924       if (!off) eblerror("expected an offset matrix");
00925       offsets = *off;
00926       fp->incr_ref();
00927     }
00928   }
00929 
00930   template <typename T>
00931   midx<T>::midx(idxdim &d, std::file *fp_, idx<int64> *off)
00932     : idx<idx<T>*>(d), fp(fp_) {
00933     idx_clear(*this);
00934     if (fp) {
00935       if (!off) eblerror("expected an offset matrix");
00936       offsets = *off;
00937       fp->incr_ref();
00938     }
00939   }
00940 
00941   template <typename T>
00942   midx<T>::midx() : idx<idx<T>*>(), fp(NULL) {
00943     idx_clear(*this);
00944   }
00945 
00946   template <typename T>
00947   midx<T>::midx(const midx<T> &o)
00948     //    : idx<idx<T>*>((idx<idx<T>*>&)o), fp(o.fp), offsets(o.offsets) {
00949     : idx<idx<T>*>(o), fp(o.fp), offsets(o.offsets) {
00950     if (fp)
00951       fp->incr_ref(); // signify fp that we're using it
00952     lock_all();
00953   }
00954 
00955   template <typename T>
00956   midx<T>::~midx() {
00957     unlock_all();
00958   }
00959 
00960   template <typename T>
00961   midx<T>& midx<T>::operator=(const midx<T>& other) {
00962     if (this != &other) { // protect against invalid self-assignment
00963       unlock_all();
00964       *((idx<idx<T>*>*)this) = (idx<idx<T>*>&) other;
00965       fp = other.fp;
00966       offsets = other.offsets;
00967       if (fp) fp->incr_ref();
00968       lock_all();
00969     }
00970     return *this;
00971   }
00972 
00973   template <typename T>
00974   void midx<T>::remove(intg i0) {
00975     idx<T> *e = idx<idx<T>*>::get(i0);
00976     if (e) e->unlock();
00977     idx<idx<T>*>::set(NULL, i0);
00978   }
00979 
00980   template <typename T>
00981   void midx<T>::resize(intg i0) {
00982     if (this->dim(0) != i0) {
00983       this->clear();
00984       idx<idx<T>*>::resize(i0);
00985       idx_clear(*this);
00986     }
00987   }
00988 
00989   template <typename T>
00990   void midx<T>::resize(intg i0, intg i1) {
00991     if (this->dim(0) != i0 || this->dim(1) != i1) {
00992       this->clear();
00993       idx<idx<T>*>::resize(i0, i1);
00994       idx_clear(*this);
00995     }
00996   }
00997 
00998   template <typename T>
00999   void midx<T>::resize(midx<T> &other) {
01000     idx_aloopf2(e, ((idx<idx<T>*>&) *this), idx<T>*,
01001                 o, ((idx<idx<T>*>&) other), idx<T>*, {
01002                   idx<T> *pe = *e; idx<T> *po = *o;
01003                   if (pe) pe->resize(po->get_idxdim());
01004                   else {
01005                     pe = new idx<T>(po->get_idxdim());
01006                     pe->lock();
01007                     *e = pe;
01008                   }
01009       });
01010   }
01011 
01012   template <typename T>
01013   void midx<T>::remove(intg i0, intg i1) {
01014     idx<T> *e = idx<idx<T>*>::get(i0, i1);
01015     if (e) e->unlock();
01016     idx<idx<T>*>::set(NULL, i0, i1);
01017   }
01018 
01019   template <typename T>
01020   void midx<T>::clear() {
01021     idx_aloopf1(e, ((idx<idx<T>*>&) *this), idx<T>*, {
01022         idx<T> *pe = *e;
01023         if (pe) pe->unlock();
01024         *e = NULL;
01025       });
01026     if (fp) {
01027       fp->decr_ref();
01028       if (fp->no_references())
01029         delete fp; // close file
01030       fp = NULL;
01031     }
01032   }
01033 
01034   template <typename T>
01035   void midx<T>::set(idx<T> &e, intg pos) {
01036     idx<T> *pe = idx<idx<T>*>::get(pos);
01037     if (pe) pe->unlock();
01038     pe = new idx<T>(e);
01039     pe->lock();
01040     idx<idx<T>*>::set(pe, pos);
01041   }
01042 
01043   template <typename T>
01044   void midx<T>::set(idx<T> &e, intg i0, intg i1) {
01045     idx<T> *pe = idx<idx<T>*>::get(i0, i1);
01046     if (pe) pe->unlock();
01047     pe = new idx<T>(e);
01048     pe->lock();
01049     idx<idx<T>*>::set(pe, i0, i1);
01050   }
01051 
01052   // early definition of load_matrix
01053   template <typename T> idx<T> load_matrix(FILE *fp, idx<T> *out = NULL);
01054 
01055   template <typename T>
01056   idx<T> midx<T>::get(intg i0) {
01057     if (fp) { // on-demand loading
01058       if (fseek(fp->get_fp(), offsets.get(i0), SEEK_SET)) {
01059         fseek(fp->get_fp(), 0, SEEK_END);
01060         fpos_t fppos;
01061         fgetpos(fp->get_fp(), &fppos);
01062 #if defined(__WINDOWS__) || defined(__MAC__)
01063         eblerror("fseek to position " << offsets.get(i0) << " failed, "
01064                  << "file is " << (intg) fppos << " big");
01065 #else
01066         eblerror("fseek to position " << offsets.get(i0) << " failed, "
01067                  << "file is " << (intg) fppos.__pos << " big");
01068 #endif
01069       }
01070       return load_matrix<T>(fp->get_fp());
01071     } else { // all data is already loaded
01072       idx<T> *e = idx<idx<T>*>::get(i0);
01073       if (!e) eblerror("trying to access null element at position " << i0);
01074       idx<T> m(*e);
01075       return m;
01076     }
01077   }
01078 
01079   template <typename T>
01080   idx<T> midx<T>::get(intg i0, intg i1) {
01081     if (fp) { // on-demand loading
01082       if (fseek(fp->get_fp(), offsets.get(i0, i1), SEEK_SET)) {
01083         fseek(fp->get_fp(), 0, SEEK_END);
01084         fpos_t fppos;
01085         fgetpos(fp->get_fp(), &fppos);
01086 #if defined(__WINDOWS__) || defined(__MAC__)
01087         eblerror("fseek to position " << offsets.get(i0, i1) << " failed, "
01088                  << "file is " << (intg) fppos << " big");
01089 #else
01090         eblerror("fseek to position " << offsets.get(i0, i1) << " failed, "
01091                  << "file is " << (intg) fppos.__pos << " big");
01092 #endif
01093       }
01094       return load_matrix<T>(fp->get_fp());
01095     } else { // all data is already loaded
01096       idx<T> *e = idx<idx<T>*>::get(i0, i1);
01097       if (!e)
01098         eblerror("trying to access null element at position ("
01099                  << i0 << ", " << i1 << ")");
01100       idx<T> m(*e);
01101       return m;
01102     }
01103   }
01104 
01105   template <typename T>
01106   midx<T> midx<T>::narrow(int d, intg s, intg o) {
01107     // if same, return a copy
01108     if (o == 0 && this->dim(d) == s) {
01109       midx<T> copy(*this);
01110       return copy;
01111     }
01112     // otherwise narrow it
01113     idx<idx<T>*> tmp = idx<idx<T>*>::narrow(d, s, o);
01114     midx<T> r = *this;
01115     idx<idx<T>*> &rr = ((idx<idx<T>*>&)r);// = (idx<idx<T>*>&) tmp;
01116     rr = tmp;
01117     return r;
01118   }
01119 
01120   template <typename T>
01121   midx<T> midx<T>::select(int d, intg s) {
01122     idx<idx<T>*> tmp = idx<idx<T>*>::select(d, s);
01123     midx<T> r((midx<T>&)tmp);
01124     return r;
01125   }
01126 
01127   template <typename T>
01128   bool midx<T>::exists(intg pos) const {
01129     if (fp) // on-demand loading
01130       return offsets.get(pos) != 0; // check that offset is defined
01131     else { // data already loaded, check if present
01132       idx<T> *e = idx<idx<T>*>::get(pos);
01133       return (e != NULL);
01134     }
01135   }
01136 
01137   template <typename T>
01138   bool midx<T>::exists(intg i0, intg i1) const {
01139     if (fp) // on-demand loading
01140       return offsets.get(i0, i1) != 0; // check that offset is defined
01141     else { // data already loaded, check if present
01142       idx<T> *e = idx<idx<T>*>::get(i0, i1);
01143       return (e != NULL);
01144     }
01145   }
01146 
01147   template <typename T>
01148   idxdim midx<T>::get_maxdim() {
01149     if (fp)
01150       eblerror("get_maxdim should be avoided when loading on-demand"
01151                << " because it would required loading all data");
01152     idxdim dmax;
01153     for (intg i = 0; i < this->dim(0); ++i) {
01154       if (exists(i)) {
01155         idx<T> p = this->get(i);
01156         idxdim d(p);
01157         if (d.nelements() > dmax.nelements()) dmax = d;
01158       }
01159     }
01160     return dmax;
01161   }
01162 
01163   template <typename T>
01164   idx<int64> midx<T>::get_offsets() {
01165     return offsets;
01166   }
01167 
01168   template <typename T>
01169   std::file *midx<T>::get_file_pointer() {
01170     return fp;
01171   }
01172 
01173   template <typename T>
01174   bool midx<T>::same_dim(const midx<T> &other) const {
01175     if (this->get_idxdim() != other.get_idxdim()) return false;
01176     idx_aloopf2(e1, ((idx<idx<T>*>&) *this), idx<T>*,
01177                 e2, ((idx<idx<T>*>&) other), idx<T>*, {
01178                   idx<T> *pe1 = *e1; idx<T> *pe2 = *e2;
01179                   if (pe1 != NULL && pe2 != NULL) {
01180                     if (pe1->get_idxdim() != pe2->get_idxdim())
01181                       return false;
01182                   } else return false;
01183                 });
01184     return true;
01185   }
01186 
01187   template <typename T>
01188   intg midx<T>::nelements_all() const {
01189     intg n = 0;
01190     idx_aloopf1(e, ((idx<idx<T>*>&) *this), idx<T>*, {
01191         idx<T> *pe = *e;
01192         if (pe) n += pe->nelements();
01193       });
01194     return n;
01195   }
01196 
01197   template <typename T>
01198   idx<T> midx<T>::pack() {
01199     // determine size of sub-tensor
01200     idx<T> sub;
01201     intg o = this->order();
01202     if (o == 1) sub = this->get(0);
01203     else if (o == 2) sub = this->get(0, 0);
01204     else eblerror("not implemented");
01205     idxdim d = this->get_idxdim();
01206     idxdim dsub = sub;
01207     for (uint i = 0; i < dsub.order(); ++i)
01208       d.insert_dim(d.order(), dsub.dim(i));
01209     // allocate target tensor
01210     idx<T> all(d);
01211     // empty it
01212     idx_clear(all);
01213     // loop on all sub-tensors and copy them
01214     if (o == 1) {
01215       for (intg i = 0; i < this->dim(0); ++i) {
01216         idx<T> tmp = this->get(i);
01217         if (tmp.get_idxdim() != dsub)
01218           eblerror("can't pack midx containing variable sub-tensor dimensions");
01219         idx<T> tgt = all.select(0, i);
01220         idx_copy(tmp, tgt);
01221       }
01222     } else if (o == 2) {
01223       for (intg i = 0; i < this->dim(0); ++i) {
01224         idx<T> suball = all.select(0, i);
01225         for (intg j = 0; j < this->dim(1); ++j) {
01226           idx<T> tmp = this->get(i, j);
01227           if (tmp.get_idxdim() != dsub)
01228             eblerror("can't pack midx containing variable "
01229                      << "sub-tensor dimensions");
01230           idx<T> tgt = suball.select(0, j);
01231           idx_copy(tmp, tgt);
01232         }
01233       }
01234     } else eblerror("not implemented");
01235     return all;
01236   }
01237 
01238   template <typename T>
01239   void midx<T>::shift_dim_internal(int d, int pos) {
01240     // loop over all elements
01241     idx_aloopf1(e, ((idx<idx<T>*>&) *this), idx<T>*, {
01242         idx<T> *pe = *e;
01243         if (pe) *pe = pe->shift_dim(d, pos);
01244       });
01245   }
01246 
01247   template <typename T>
01248   void midx<T>::pretty() const {
01249     this->pretty(std::cout);
01250   }
01251 
01252   template <typename T> template <class stream>
01253   void midx<T>::pretty(stream &out, bool newline) const {
01254     out << "[ ";
01255     if (this->order() == 0)
01256       out << "empty midx";
01257     else {
01258       idx_aloopf1(e, ((idx<idx<T>*>&) *this), idx<T>*, {
01259           idx<T> *pe = *e;
01260           if (pe) {
01261             idxdim d(*pe);
01262             out << d << " ";
01263           } else
01264             out << "empty ";
01265         });
01266     }
01267     out << "]";
01268     if (newline) out << "\n";
01269   }
01270 
01271   template <typename T>
01272   std::string midx<T>::str() const {
01273     std::string s;
01274     this->pretty(s, false);
01275     return s;
01276   }
01277 
01278   // internal methods //////////////////////////////////////////////////////////
01279 
01280   template <typename T>
01281   void midx<T>::lock_all() {
01282     idx_aloopf1(e, ((idx<idx<T>*>&) *this), idx<T>*, {
01283         idx<T> *pe = *e;
01284         if (pe) pe->lock();
01285       });
01286   }
01287 
01288   template <typename T>
01289   void midx<T>::unlock_all() {
01290     idx_aloopf1(e, ((idx<idx<T>*>&) *this), idx<T>*, {
01291         idx<T> *pe = *e;
01292         if (pe) pe->unlock();
01293       });
01294   }
01295 
01296 } // namespace ebl
01297 
01298 #endif /* IDX_HPP_ */