Scythe-1.0.3
|
00001 /* 00002 * Scythe Statistical Library Copyright (C) 2000-2002 Andrew D. Martin 00003 * and Kevin M. Quinn; 2002-present Andrew D. Martin, Kevin M. Quinn, 00004 * and Daniel Pemstein. All Rights Reserved. 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify under the terms of the GNU General Public License as 00008 * published by Free Software Foundation; either version 2 of the 00009 * License, or (at your option) any later version. See the text files 00010 * COPYING and LICENSE, distributed with this source code, for further 00011 * information. 00012 * -------------------------------------------------------------------- 00013 * scythestat/matrix_bidirectional_iterator.h 00014 * 00015 * Bidirectional iterators for the matrix class. 00016 * 00017 */ 00018 00035 #ifndef SCYTHE_MATRIX_BIDIRECTIONAL_ITERATOR_H 00036 #define SCYTHE_MATRIX_BIDIRECTIONAL_ITERATOR_H 00037 00038 #include <iterator> 00039 00040 #ifdef SCYTHE_COMPILE_DIRECT 00041 #include "defs.h" 00042 #include "error.h" 00043 #include "matrix.h" 00044 #else 00045 #include "scythestat/defs.h" 00046 #include "scythestat/error.h" 00047 #include "scythestat/matrix.h" 00048 #endif 00049 00050 namespace scythe { 00051 /* convenience typedefs */ 00052 namespace { // local to this file 00053 typedef unsigned int uint; 00054 } 00055 00056 /* forward declaration of the matrix class */ 00057 template <typename T_type, matrix_order ORDER, matrix_style STYLE> 00058 class Matrix; 00059 00074 template <typename T_type, matrix_order ORDER, matrix_order M_ORDER, 00075 matrix_style M_STYLE> 00076 class const_matrix_bidirectional_iterator 00077 : public std::iterator<std::bidirectional_iterator_tag, T_type> 00078 { 00079 public: 00080 /**** TYPEDEFS ***/ 00081 typedef const_matrix_bidirectional_iterator<T_type, ORDER, 00082 M_ORDER, M_STYLE> self; 00083 00084 /* These are a little formal, but useful */ 00085 typedef typename std::iterator_traits<self>::value_type 00086 value_type; 00087 typedef typename std::iterator_traits<self>::iterator_category 00088 iterator_category; 00089 typedef typename std::iterator_traits<self>::difference_type 00090 difference_type; 00091 typedef typename std::iterator_traits<self>::pointer pointer; 00092 typedef typename std::iterator_traits<self>::reference reference; 00093 00094 00095 /**** CONSTRUCTORS ****/ 00096 00097 /* Default constructor */ 00098 const_matrix_bidirectional_iterator () 00099 {} 00100 00101 /* Standard constructor */ 00102 const_matrix_bidirectional_iterator 00103 (const Matrix<value_type, M_ORDER, M_STYLE> &M) 00104 : pos_ (M.getArray()), 00105 matrix_ (&M) 00106 { 00107 SCYTHE_CHECK_30 (pos_ == 0, scythe_null_error, 00108 "Requesting iterator to NULL matrix"); 00109 00110 /* The basic story is: when M_STYLE == Concrete and ORDER == 00111 * M_ORDER, we only need pos_ and iteration will be as fast as 00112 * possible. All other types of iteration need more variables 00113 * to keep track of things and are slower. 00114 */ 00115 00116 00117 if (M_STYLE != Concrete || M_ORDER != ORDER) { 00118 offset_ = 0; 00119 00120 if (ORDER == Col) { 00121 lead_length_ = M.rows(); 00122 lead_inc_ = M.rowstride(); 00123 trail_inc_ = M.colstride(); 00124 } else { 00125 lead_length_ = M.cols(); 00126 lead_inc_ = M.colstride(); 00127 trail_inc_ = M.rowstride(); 00128 } 00129 jump_ = trail_inc_ + (1 - lead_length_) * lead_inc_; 00130 vend_ = pos_ + (lead_length_ - 1) * lead_inc_; 00131 vbegin_ = pos_; 00132 } 00133 #if SCYTHE_DEBUG > 2 00134 size_ = M.size(); 00135 start_ = pos_; 00136 #endif 00137 00138 } 00139 00140 /* Copy constructor */ 00141 const_matrix_bidirectional_iterator (const self &mi) 00142 : pos_ (mi.pos_), 00143 matrix_ (mi.matrix_) 00144 { 00145 if (M_STYLE != Concrete || M_ORDER != ORDER) { 00146 offset_ = mi.offset_; 00147 lead_length_ = mi.lead_length_; 00148 lead_inc_ = mi.lead_inc_; 00149 trail_inc_ = mi.trail_inc_; 00150 vend_ = mi.vend_; 00151 vbegin_ = mi.vbegin_; 00152 jump_ = mi.jump_; 00153 } 00154 00155 #if SCYTHE_DEBUG > 2 00156 size_ = mi.size_; 00157 start_ = mi.start_; 00158 #endif 00159 } 00160 00161 /**** EXTRA MODIFIER ****/ 00162 00163 /* This function lets us grab an end iterator. It is cheap for 00164 * Concrete matrices but somewhat more costly for views. 00165 */ 00166 inline self& set_end () 00167 { 00168 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00169 pos_ = matrix_->getArray() + matrix_->size(); 00170 } else { 00171 if (ORDER == Col) { 00172 vbegin_ += trail_inc_ * matrix_->cols(); 00173 vend_ += trail_inc_ * matrix_->cols(); 00174 } else { // ORDER == Rows 00175 vbegin_ += trail_inc_ * matrix_->rows(); 00176 vend_ += trail_inc_ * matrix_->rows(); 00177 } 00178 00179 pos_ = vbegin_; 00180 offset_ = matrix_->size(); 00181 } 00182 00183 return *this; 00184 } 00185 00186 /**** FORWARD ITERATOR FACILITIES ****/ 00187 00188 inline self& operator= (const self& mi) 00189 { 00190 pos_ = mi.pos_; 00191 matrix_ = mi.matrix_; 00192 00193 if (M_STYLE != Concrete || M_ORDER != ORDER) { 00194 offset_ = mi.offset_; 00195 lead_length_ = mi.lead_length_; 00196 lead_inc_ = mi.lead_inc_; 00197 trail_inc_ = mi.trail_inc_; 00198 vend_ = mi.vend_; 00199 vbegin_ = mi.vbegin_; 00200 jump_ = mi.jump_; 00201 } 00202 #if SCYTHE_DEBUG > 2 00203 size_ = mi.size_; 00204 start_ = mi.start_; 00205 #endif 00206 00207 return *this; 00208 } 00209 00210 inline const reference operator* () const 00211 { 00212 SCYTHE_ITER_CHECK_BOUNDS(); 00213 return *pos_; 00214 } 00215 00216 inline const pointer operator-> () const 00217 { 00218 SCYTHE_ITER_CHECK_BOUNDS(); 00219 return pos_; 00220 } 00221 00222 inline self& operator++ () 00223 { 00224 if (M_STYLE == Concrete && ORDER == M_ORDER) 00225 ++pos_; 00226 else { 00227 if (pos_ == vend_) { 00228 vend_ += trail_inc_; 00229 vbegin_ += trail_inc_; 00230 pos_ += jump_; 00231 } else { 00232 pos_ += lead_inc_; 00233 } 00234 ++offset_; 00235 } 00236 00237 return *this; 00238 } 00239 00240 inline self operator++ (int) 00241 { 00242 self tmp = *this; 00243 ++(*this); 00244 return tmp; 00245 } 00246 00247 /* == is only defined for iterators of the same template type 00248 * that point to the same matrix. Behavior for any other 00249 * comparison is undefined. 00250 * 00251 * Note that we have to be careful about iterator comparisons 00252 * when working with views and cross-grain iterators. 00253 * Specifically, we always have to rely on the offset value. 00254 * Obviously, with <> checks pos_ can jump all over the place in 00255 * cross-grain iterators, but also end iterators point to the 00256 * value after the last in the matrix. In some cases, the 00257 * equation in += and -= will actually put pos_ inside the 00258 * matrix (often in an early position) in this case. 00259 */ 00260 inline bool operator== (const self& x) const 00261 { 00262 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00263 return pos_ == x.pos_; 00264 } else { 00265 return offset_ == x.offset_; 00266 } 00267 } 00268 00269 /* Again, != is only officially defined for iterators over the 00270 * same matrix although the test will be trivially true for 00271 * matrices that don't view the same data, by implementation. 00272 */ 00273 inline bool operator!= (const self &x) const 00274 { 00275 return !(*this == x); 00276 } 00277 00278 /**** BIDIRECTIONAL ITERATOR FACILITES ****/ 00279 inline self& operator-- () 00280 { 00281 if (M_STYLE == Concrete && ORDER == M_ORDER) 00282 --pos_; 00283 else { 00284 if (pos_ == vbegin_) { 00285 vend_ -= trail_inc_; 00286 vbegin_ -= trail_inc_; 00287 pos_ -= jump_; 00288 } else { 00289 pos_ -= lead_inc_; 00290 } 00291 --offset_; 00292 } 00293 00294 return *this; 00295 } 00296 00297 inline self operator-- (int) 00298 { 00299 self tmp = *this; 00300 --(*this); 00301 return tmp; 00302 } 00303 00304 protected: 00305 00306 /**** INSTANCE VARIABLES ****/ 00307 T_type* pos_; // pointer to current position in array 00308 T_type *vend_; // pointer to end of current vector 00309 T_type *vbegin_; // pointer to begin of current vector 00310 00311 uint offset_; // logical offset into matrix 00312 00313 // TODO Some of these can probably be uints 00314 int lead_length_; // Logical length of leading dimension 00315 int lead_inc_; // Memory distance between vectors in ldim 00316 int trail_inc_; // Memory distance between vectors in tdim 00317 int jump_; // Memory distance between end of one ldim vector and 00318 // begin of next 00319 // Pointer used only for set_end. TODO Cleaner impl. 00320 const Matrix<T_type, M_ORDER, M_STYLE>* matrix_; 00321 // Size variable for range checking 00322 #if SCYTHE_DEBUG > 2 00323 uint size_; // Logical matrix size 00324 T_type* start_; // only needed for bounds checking 00325 #endif 00326 }; 00327 00342 template <typename T_type, matrix_order ORDER, matrix_order M_ORDER, 00343 matrix_style M_STYLE> 00344 class matrix_bidirectional_iterator 00345 : public const_matrix_bidirectional_iterator<T_type, ORDER, 00346 M_ORDER, M_STYLE> 00347 { 00348 /**** TYPEDEFS ***/ 00349 typedef matrix_bidirectional_iterator<T_type, ORDER, M_ORDER, 00350 M_STYLE> self; 00351 typedef const_matrix_bidirectional_iterator<T_type, ORDER, 00352 M_ORDER, M_STYLE> Base; 00353 00354 public: 00355 /* These are a little formal, but useful */ 00356 typedef typename std::iterator_traits<Base>::value_type 00357 value_type; 00358 typedef typename std::iterator_traits<Base>::iterator_category 00359 iterator_category; 00360 typedef typename std::iterator_traits<Base>::difference_type 00361 difference_type; 00362 typedef typename std::iterator_traits<Base>::pointer pointer; 00363 typedef typename std::iterator_traits<Base>::reference reference; 00364 00365 00366 /**** CONSTRUCTORS ****/ 00367 00368 /* Default constructor */ 00369 matrix_bidirectional_iterator () 00370 : Base () 00371 {} 00372 00373 /* Standard constructor */ 00374 matrix_bidirectional_iterator (const Matrix<value_type, M_ORDER, 00375 M_STYLE> &M) 00376 : Base(M) 00377 {} 00378 00379 /* Copy constructor */ 00380 matrix_bidirectional_iterator (const self &mi) 00381 : Base (mi) 00382 {} 00383 00384 /**** EXTRA MODIFIER ****/ 00385 inline self& set_end () 00386 { 00387 Base::set_end(); 00388 return *this; 00389 } 00390 00391 /**** FORWARD ITERATOR FACILITIES ****/ 00392 00393 /* We have to override a lot of these to get return values 00394 * right.*/ 00395 inline self& operator= (const self& mi) 00396 { 00397 pos_ = mi.pos_; 00398 matrix_ = mi.matrix_; 00399 00400 if (M_STYLE != Concrete || M_ORDER != ORDER) { 00401 offset_ = mi.offset_; 00402 lead_length_ = mi.lead_length_; 00403 lead_inc_ = mi.lead_inc_; 00404 trail_inc_ = mi.trail_inc_; 00405 vend_ = mi.vend_; 00406 vbegin_ = mi.vbegin_; 00407 jump_ = mi.jump_; 00408 } 00409 #if SCYTHE_DEBUG > 2 00410 size_ = mi.size_; 00411 start_ = mi.start_; 00412 #endif 00413 00414 return *this; 00415 } 00416 00417 inline reference operator* () const 00418 { 00419 SCYTHE_ITER_CHECK_BOUNDS(); 00420 return *pos_; 00421 } 00422 00423 inline pointer operator-> () const 00424 { 00425 SCYTHE_ITER_CHECK_BOUNDS(); 00426 return pos_; 00427 } 00428 00429 inline self& operator++ () 00430 { 00431 Base::operator++(); 00432 return *this; 00433 } 00434 00435 inline self operator++ (int) 00436 { 00437 self tmp = *this; 00438 ++(*this); 00439 return tmp; 00440 } 00441 00442 inline self& operator-- () 00443 { 00444 Base::operator--(); 00445 return *this; 00446 } 00447 00448 inline self operator-- (int) 00449 { 00450 self tmp = *this; 00451 --(*this); 00452 return tmp; 00453 } 00454 00455 private: 00456 /* Get handles to base members. It boggles the mind */ 00457 using Base::pos_; 00458 using Base::vend_; 00459 using Base::vbegin_; 00460 using Base::offset_; 00461 using Base::lead_length_; 00462 using Base::lead_inc_; 00463 using Base::trail_inc_; 00464 using Base::jump_; 00465 using Base::matrix_; 00466 #if SCYTHE_DEBUG > 2 00467 using Base::size_; 00468 using Base::start_; 00469 #endif 00470 }; 00471 00472 } // namespace scythe 00473 00474 #endif /* SCYTHE_MATRIX_BIDIRECTIONAL_ITERATOR_H */