Scythe-1.0.3
matrix_random_access_iterator.h
Go to the documentation of this file.
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 */