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 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_ */