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_random_access_iterator.h 00014 * 00015 * Random access iterators for the matrix class. 00016 * 00017 */ 00018 00035 #ifndef SCYTHE_MATRIX_RANDOM_ACCESS_ITERATOR_H 00036 #define SCYTHE_MATRIX_RANDOM_ACCESS_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 /* The const_matrix_iterator and matrix_iterator classes are 00051 * essentially identical, except for the return types of the *, ->, 00052 * and [] operators. matrix_iterator extends const_matrix_iterator, 00053 * overriding most of its members. */ 00054 00055 /* TODO Current setup uses template argument based branches to 00056 * handle views and cross-grained orderings differently than simple 00057 * in-order concrete matrices. The work for this gets done at 00058 * compile time, but we end with a few unused instance variables in 00059 * the concrete case. It might be better to specialize the entire 00060 * class, although this will lead to a lot of code duplication. We 00061 * should bench the difference down the road and see if it is worth 00062 * the maintenance hassle. 00063 * 00064 * At the moment this is looking like it won't be worth it. 00065 * Iterator-based operations on concretes provide comparable 00066 * performance to element-access based routines in previous versions 00067 * of the library, indicating little performance penalty. 00068 */ 00069 00070 namespace scythe { 00071 /* convenience typedefs */ 00072 namespace { // local to this file 00073 typedef unsigned int uint; 00074 } 00075 00076 /* forward declaration of the matrix class */ 00077 template <typename T_type, matrix_order ORDER, matrix_style STYLE> 00078 class Matrix; 00079 00094 template <typename T_type, matrix_order ORDER, matrix_order M_ORDER, 00095 matrix_style M_STYLE> 00096 class const_matrix_random_access_iterator 00097 : public std::iterator<std::random_access_iterator_tag, T_type> 00098 { 00099 public: 00100 /**** TYPEDEFS ***/ 00101 typedef const_matrix_random_access_iterator<T_type, ORDER, 00102 M_ORDER, M_STYLE> self; 00103 00104 /* These are a little formal, but useful */ 00105 typedef typename std::iterator_traits<self>::value_type 00106 value_type; 00107 typedef typename std::iterator_traits<self>::iterator_category 00108 iterator_category; 00109 typedef typename std::iterator_traits<self>::difference_type 00110 difference_type; 00111 typedef typename std::iterator_traits<self>::pointer pointer; 00112 typedef typename std::iterator_traits<self>::reference reference; 00113 00114 00115 /**** CONSTRUCTORS ****/ 00116 00117 /* Default constructor */ 00118 const_matrix_random_access_iterator () 00119 {} 00120 00121 /* Standard constructor */ 00122 const_matrix_random_access_iterator 00123 ( const Matrix<value_type, M_ORDER, M_STYLE> &M) 00124 : start_ (M.getArray()) 00125 { 00126 SCYTHE_CHECK_30 (start_ == 0, scythe_null_error, 00127 "Requesting iterator to NULL matrix"); 00128 pos_ = start_; 00129 00130 /* The basic story is: when M_STYLE == Concrete and ORDER == 00131 * M_ORDER, we only need pos_ and start_ and iteration will be 00132 * as fast as possible. All other types of iteration need 00133 * more variables to keep track of things and are slower. 00134 */ 00135 00136 if (M_STYLE != Concrete || M_ORDER != ORDER) { 00137 offset_ = 0; 00138 00139 if (ORDER == Col) { 00140 lead_length_ = M.rows(); 00141 lead_inc_ = M.rowstride(); 00142 trail_inc_ = M.colstride(); 00143 } else { 00144 lead_length_ = M.cols(); 00145 lead_inc_ = M.colstride(); 00146 trail_inc_ = M.rowstride(); 00147 } 00148 jump_ = trail_inc_ + (1 - lead_length_) * lead_inc_; 00149 } 00150 00151 #if SCYTHE_DEBUG > 2 00152 size_ = M.size(); 00153 #endif 00154 } 00155 00156 /* Copy constructor */ 00157 const_matrix_random_access_iterator (const self &mi) 00158 : start_ (mi.start_), 00159 pos_ (mi.pos_) 00160 { 00161 if (M_STYLE != Concrete || M_ORDER != ORDER) { 00162 offset_ = mi.offset_; 00163 lead_length_ = mi.lead_length_; 00164 lead_inc_ = mi.lead_inc_; 00165 trail_inc_ = mi.trail_inc_; 00166 jump_ = mi.jump_; 00167 } 00168 #if SCYTHE_DEBUG > 2 00169 size_ = mi.size_; 00170 #endif 00171 } 00172 00173 /**** FORWARD ITERATOR FACILITIES ****/ 00174 00175 inline self& operator= (const self& mi) 00176 { 00177 start_ = mi.start_; 00178 pos_ = mi.pos_; 00179 00180 if (M_STYLE != Concrete || M_ORDER != ORDER) { 00181 offset_ = mi.offset_; 00182 lead_length_ = mi.lead_length_; 00183 lead_inc_ = mi.lead_inc_; 00184 trail_inc_ = mi.trail_inc_; 00185 jump_ = mi.jump_; 00186 } 00187 #if SCYTHE_DEBUG > 2 00188 size_ = mi.size_; 00189 #endif 00190 00191 return *this; 00192 } 00193 00194 inline const reference operator* () const 00195 { 00196 SCYTHE_ITER_CHECK_BOUNDS(); 00197 return *pos_; 00198 } 00199 00200 inline const pointer operator-> () const 00201 { 00202 SCYTHE_ITER_CHECK_BOUNDS(); 00203 return pos_; 00204 } 00205 00206 inline self& operator++ () 00207 { 00208 if (M_STYLE == Concrete && ORDER == M_ORDER) 00209 ++pos_; 00210 else if (++offset_ % lead_length_ == 0) 00211 pos_ += jump_; 00212 else 00213 pos_ += lead_inc_; 00214 00215 return *this; 00216 } 00217 00218 inline self operator++ (int) 00219 { 00220 self tmp = *this; 00221 ++(*this); 00222 return tmp; 00223 } 00224 00225 /* == is only defined for iterators of the same template type 00226 * that point to the same matrix. Behavior for any other 00227 * comparison is undefined. 00228 * 00229 * Note that we have to be careful about iterator comparisons 00230 * when working with views and cross-grain iterators. 00231 * Specifically, we always have to rely on the offset value. 00232 * Obviously, with <> checks pos_ can jump all over the place in 00233 * cross-grain iterators, but also end iterators point to the 00234 * value after the last in the matrix. In some cases, the 00235 * equation in += and -= will actually put pos_ inside the 00236 * matrix (often in an early position) in this case. 00237 */ 00238 inline bool operator== (const self& x) const 00239 { 00240 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00241 return pos_ == x.pos_; 00242 } else { 00243 return offset_ == x.offset_; 00244 } 00245 } 00246 00247 /* Again, != is only officially defined for iterators over the 00248 * same matrix although the test will be trivially true for 00249 * matrices that don't view the same data, by implementation. 00250 */ 00251 inline bool operator!= (const self &x) const 00252 { 00253 return !(*this == x); 00254 } 00255 00256 /**** BIDIRECTIONAL ITERATOR FACILITIES ****/ 00257 00258 inline self& operator-- () 00259 { 00260 if (M_STYLE == Concrete && ORDER == M_ORDER) 00261 --pos_; 00262 else if (offset_-- % lead_length_ == 0) 00263 pos_ -= jump_; 00264 else 00265 pos_ -= lead_inc_; 00266 00267 return *this; 00268 } 00269 00270 inline self operator-- (int) 00271 { 00272 self tmp = *this; 00273 --(*this); 00274 return tmp; 00275 } 00276 00277 /**** RANDOM ACCESS ITERATOR FACILITIES ****/ 00278 00279 inline const reference operator[] (difference_type n) const 00280 { 00281 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00282 SCYTHE_ITER_CHECK_OFFSET_BOUNDS(start_ + n); 00283 return *(start_ + n); 00284 } else { 00285 uint trailing = n / lead_length_; 00286 uint leading = n % lead_length_; 00287 00288 T_type* place = start_ + leading * lead_inc_ 00289 + trailing * trail_inc_; 00290 00291 SCYTHE_ITER_CHECK_POINTER_BOUNDS(place); 00292 return *place; 00293 } 00294 } 00295 00296 inline self& operator+= (difference_type n) 00297 { 00298 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00299 pos_ += n; 00300 } else { 00301 offset_ += n; 00302 uint trailing = offset_ / lead_length_; 00303 uint leading = offset_ % lead_length_; 00304 00305 pos_ = start_ + leading * lead_inc_ 00306 + trailing * trail_inc_; 00307 } 00308 00309 return *this; 00310 } 00311 00312 inline self& operator-= (difference_type n) 00313 { 00314 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00315 pos_ -= n; 00316 } else { 00317 offset_ -= n; 00318 uint trailing = offset_ / lead_length_; 00319 uint leading = offset_ % lead_length_; 00320 00321 pos_ = start_ + leading * lead_inc_ 00322 + trailing * trail_inc_; 00323 } 00324 00325 return *this; 00326 } 00327 00328 /* + and - difference operators are outside the class */ 00329 00330 inline difference_type operator- (const self& x) const 00331 { 00332 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00333 return pos_ - x.pos_; 00334 } else { 00335 return offset_ - x.offset_; 00336 } 00337 } 00338 00339 inline difference_type operator< (const self& x) const 00340 { 00341 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00342 return pos_ < x.pos_; 00343 } else { 00344 return offset_ < x.offset_; 00345 } 00346 } 00347 00348 inline difference_type operator> (const self& x) const 00349 { 00350 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00351 return pos_ > x.pos_; 00352 } else { 00353 return offset_ > x.offset_; 00354 } 00355 } 00356 00357 inline difference_type operator<= (const self& x) const 00358 { 00359 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00360 return pos_ <= x.pos_; 00361 } else { 00362 return offset_ <= x.offset_; 00363 } 00364 } 00365 00366 inline difference_type operator>= (const self& x) const 00367 { 00368 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00369 return pos_ >= x.pos_; 00370 } else { 00371 return offset_ >= x.offset_; 00372 } 00373 } 00374 00375 protected: 00376 00377 /**** INSTANCE VARIABLES ****/ 00378 T_type* start_; // pointer to beginning of data array 00379 T_type* pos_; // pointer to current position in array 00380 00381 uint offset_; // Logical offset into matrix 00382 00383 // TODO Some of these can probably be uints 00384 int lead_length_; // Logical length of leading dimension 00385 int lead_inc_; // Memory distance between vectors in ldim 00386 int trail_inc_; // Memory distance between vectors in tdim 00387 int jump_; // Memory distance between end of one ldim vector and 00388 // begin of next 00389 00390 // Size variable for range checking 00391 #if SCYTHE_DEBUG > 2 00392 uint size_; // Logical matrix size 00393 #endif 00394 00395 }; 00396 00410 template <typename T_type, matrix_order ORDER, matrix_order M_ORDER, 00411 matrix_style M_STYLE> 00412 class matrix_random_access_iterator 00413 : public const_matrix_random_access_iterator<T_type, ORDER, 00414 M_ORDER, M_STYLE> 00415 { 00416 /**** TYPEDEFS ***/ 00417 typedef matrix_random_access_iterator<T_type, ORDER, M_ORDER, 00418 M_STYLE> self; 00419 typedef const_matrix_random_access_iterator<T_type, ORDER, 00420 M_ORDER, M_STYLE> Base; 00421 00422 public: 00423 /* These are a little formal, but useful */ 00424 typedef typename std::iterator_traits<Base>::value_type 00425 value_type; 00426 typedef typename std::iterator_traits<Base>::iterator_category 00427 iterator_category; 00428 typedef typename std::iterator_traits<Base>::difference_type 00429 difference_type; 00430 typedef typename std::iterator_traits<Base>::pointer pointer; 00431 typedef typename std::iterator_traits<Base>::reference reference; 00432 00433 00434 /**** CONSTRUCTORS ****/ 00435 00436 /* Default constructor */ 00437 matrix_random_access_iterator () 00438 : Base () 00439 {} 00440 00441 /* Standard constructor */ 00442 matrix_random_access_iterator (const Matrix<value_type, M_ORDER, 00443 M_STYLE> &M) 00444 : Base(M) 00445 {} 00446 00447 /* Copy constructor */ 00448 matrix_random_access_iterator (const self &mi) 00449 : Base (mi) 00450 {} 00451 00452 /**** FORWARD ITERATOR FACILITIES ****/ 00453 00454 /* We have to override a lot of these to get return values 00455 * right.*/ 00456 inline self& operator= (const self& mi) 00457 { 00458 start_ = mi.start_; 00459 pos_ = mi.pos_; 00460 00461 if (M_STYLE != Concrete || M_ORDER != ORDER) { 00462 offset_ = mi.offset_; 00463 lead_length_ = mi.lead_length_; 00464 lead_inc_ = mi.lead_inc_; 00465 trail_inc_ = mi.trail_inc_; 00466 jump_ = mi.jump_; 00467 } 00468 #if SCYTHE_DEBUG > 2 00469 size_ = mi.size_; 00470 #endif 00471 00472 return *this; 00473 } 00474 00475 inline reference operator* () const 00476 { 00477 SCYTHE_ITER_CHECK_BOUNDS(); 00478 return *pos_; 00479 } 00480 00481 inline pointer operator-> () const 00482 { 00483 SCYTHE_ITER_CHECK_BOUNDS(); 00484 return pos_; 00485 } 00486 00487 inline self& operator++ () 00488 { 00489 Base::operator++(); 00490 return *this; 00491 } 00492 00493 inline self operator++ (int) 00494 { 00495 self tmp = *this; 00496 ++(*this); 00497 return tmp; 00498 } 00499 00500 /**** BIDIRECTIONAL ITERATOR FACILITIES ****/ 00501 00502 inline self& operator-- () 00503 { 00504 Base::operator--(); 00505 return *this; 00506 } 00507 00508 inline self operator-- (int) 00509 { 00510 self tmp = *this; 00511 --(*this); 00512 return tmp; 00513 } 00514 00515 /**** RANDOM ACCESS ITERATOR FACILITIES ****/ 00516 00517 inline reference operator[] (difference_type n) const 00518 { 00519 if (M_STYLE == Concrete && ORDER == M_ORDER) { 00520 SCYTHE_ITER_CHECK_POINTER_BOUNDS(start_ + n); 00521 return *(start_ + n); 00522 } else { 00523 uint trailing = n / lead_length_; 00524 uint leading = n % lead_length_; 00525 00526 T_type* place = start_ + leading * lead_inc_ 00527 + trailing * trail_inc_; 00528 00529 SCYTHE_ITER_CHECK_POINTER_BOUNDS(place); 00530 return *place; 00531 } 00532 } 00533 00534 inline self& operator+= (difference_type n) 00535 { 00536 Base::operator+=(n); 00537 return *this; 00538 } 00539 00540 inline self& operator-= (difference_type n) 00541 { 00542 Base::operator-= (n); 00543 return *this; 00544 } 00545 00546 /* + and - difference_type operators are outside the class */ 00547 00548 private: 00549 /* Get handles to base members. It boggles the mind */ 00550 using Base::start_; 00551 using Base::pos_; 00552 using Base::offset_; 00553 using Base::lead_length_; 00554 using Base::lead_inc_; 00555 using Base::trail_inc_; 00556 using Base::jump_; 00557 #if SCYTHE_DEBUG > 2 00558 using Base::size_; 00559 #endif 00560 }; 00561 00562 template <class T_type, matrix_order ORDER, matrix_order M_ORDER, 00563 matrix_style STYLE> 00564 inline 00565 const_matrix_random_access_iterator<T_type, ORDER, M_ORDER, STYLE> 00566 operator+ (const_matrix_random_access_iterator<T_type, ORDER, M_ORDER, STYLE> x, int n) 00567 { 00568 x += n; 00569 return x; 00570 } 00571 00572 template <class T_type, matrix_order ORDER, matrix_order M_ORDER, 00573 matrix_style STYLE> 00574 inline 00575 const_matrix_random_access_iterator<T_type, ORDER, M_ORDER, STYLE> 00576 operator+ (int n, const_matrix_random_access_iterator<T_type, ORDER, 00577 M_ORDER, 00578 STYLE> x) 00579 { 00580 x += n; 00581 return x; 00582 } 00583 00584 template <class T_type, matrix_order ORDER, matrix_order M_ORDER, 00585 matrix_style STYLE> 00586 inline 00587 const_matrix_random_access_iterator<T_type, ORDER, M_ORDER, STYLE> 00588 operator- (const_matrix_random_access_iterator<T_type, ORDER, M_ORDER, STYLE> x, int n) 00589 { 00590 x -= n; 00591 return x; 00592 } 00593 00594 template <class T_type, matrix_order ORDER, matrix_order M_ORDER, 00595 matrix_style STYLE> 00596 inline matrix_random_access_iterator<T_type, ORDER, M_ORDER, STYLE> 00597 operator+ (matrix_random_access_iterator<T_type, ORDER, M_ORDER, 00598 STYLE> x, int n) 00599 { 00600 x += n; 00601 return x; 00602 } 00603 00604 template <class T_type, matrix_order ORDER, matrix_order M_ORDER, 00605 matrix_style STYLE> 00606 inline matrix_random_access_iterator<T_type, ORDER, M_ORDER, STYLE> 00607 operator+ (int n, matrix_random_access_iterator<T_type, ORDER, 00608 M_ORDER, STYLE> x) 00609 { 00610 x += n; 00611 return x; 00612 } 00613 00614 template <class T_type, matrix_order ORDER, matrix_order M_ORDER, 00615 matrix_style STYLE> 00616 inline matrix_random_access_iterator<T_type, ORDER, M_ORDER, STYLE> 00617 operator- (matrix_random_access_iterator<T_type, ORDER, M_ORDER, 00618 STYLE> x, int n) 00619 { 00620 x -= n; 00621 return x; 00622 } 00623 00624 } // namespace scythe 00625 00626 #endif /* SCYTHE_MATRIX_ITERATOR_H */