Scythe-1.0.3
matrix_bidirectional_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_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 */