C:/programs/SCPPNT/src/include/slice_pointer.h

Go to the documentation of this file.
00001 /*! \file slice_pointer.h
00002  \brief Definition of the generalized pointer class slice_pointer_base.
00003  
00004  Contains definition of the slice_pointer_base class that is
00005  a generalization of a normal pointer allowing
00006  consecutive elements to be stored non-consecutively in memory
00007  (consecutive elements are separated from one another by a constant distance).
00008 
00009  */
00010 
00011 /*
00012  Simple C++ Numerical Toolkit (SCPPNT)
00013  http://www.smallwaters.com/software/cpp/scppnt.html
00014  This release updates original work contributed by 
00015  Brad Hanson (http://www.b-a-h.com/) in 2001.
00016 
00017  */
00018 
00019 #ifndef SCPPNT_SLICE_POINTER_H
00020 #define SCPPNT_SLICE_POINTER_H
00021 
00022 #ifdef SCPPNT_NO_DIR_PREFIX
00023 #include "scppnt.h"
00024 #include "scppnt_error.h"
00025 #else
00026 #include "scppnt/scppnt.h"
00027 #include "scppnt/scppnt_error.h"
00028 #endif
00029 
00030 #include <iterator> // for struct random_access_iterator_category
00031 namespace SCPPNT
00032 {
00033 
00034   /*! 
00035    \brief Acts like T* but allows consecutive elements to be stored non-consecutively in memory.
00036    
00037    This class is a generalization of a normal pointer that allows 
00038    consecutive elements to be stored non-consecutively in memory
00039    (consecutive elements are separated from one another by a constant distance).
00040    
00041    \param T Type of elements pointed to.
00042    \param PTR Type of pointer to element (T* or const T*)
00043    \param REF Type of reference to element (T& or const T&)
00044    
00045    The PTR and REF template parameters allow both constant and non-constant types 
00046    to be defined using one class. This technique is described in
00047    
00048    Austern, Matt (1999). Generic programming and the STL.
00049    Reading, MA: Addison-Wesley.
00050    
00051    A slice_pointer_base<T, T*, T&> with a distance of 1 separating consecutive elements
00052    should have the same behavior as type T*, and a slice_pointer_base<T, const T*, const T&> 
00053    with a distance of 1 separating consecutive elements should have the same behavior
00054    as type const T*.
00055    
00056    An example of the use of a slice_pointer_base is to allow iterators over column
00057    elements in row-major matrices stored in one contiguous block of memory,
00058    where the matrix has M rows and two consecutive elements in a column
00059    are separated by M-1 elements.
00060    
00061    This class does not manage the memory it points to. In other words,
00062    slice_pointer_base objects are initialized with pointers
00063    that point to allocated areas of memory, and the memory pointed to is not
00064    released when slice_pointer_base objects are destroyed.
00065    
00066    The techinique used for logical comparison operators that allow
00067    constant types to be compared with non-constant types is described
00068    in:
00069    
00070    Austern, Matt (2001, January). Defining iterators and const iterators. 
00071    C/C++ Users Journal (www.cuj.com), 74-79.
00072    
00073    */
00074   template<class T, class PTR, class REF> class slice_pointer_base
00075   {
00076 
00077 public:
00078 
00079     // Types needed for iterator_traits
00080     typedef T value_type; //!< Type pointed to
00081     typedef PTR pointer; //!< Pointer to type
00082     typedef REF reference; //!< Reference to type pointed to
00083     typedef std::random_access_iterator_tag iterator_category; //!< This is a random access iterator
00084     typedef Subscript difference_type; //!< Type for number of elements separating two iterators
00085 
00086     //! default constructor
00087     slice_pointer_base() :
00088       current(0), span(0)
00089     {
00090     }
00091 
00092     /*! \brief Constructor that initializes the slice_pointer_base
00093      
00094      \param first Pointer to first element.
00095      
00096      \param span Distance between consecutive elements (i-th element is given
00097      by first + (i-1) * span. If span == 1 then the object behaves the same as a T*.
00098      
00099      \param size Number of elements pointed to. 
00100      This argument is only used when bounds checking is enabled.
00101      */
00102     slice_pointer_base(pointer first, Subscript span, Subscript size)
00103     {
00104       set(first, span, size);
00105     }
00106 
00107     //! Copy constructor for non-const type, and construction of const type from non-const type.
00108 #ifdef SCPPNT_BOUNDS_CHECK
00109     slice_pointer_base(const slice_pointer_base<T, T*, T&> &p)
00110     {
00111       set(p.get_first(), p.get_span(), p.get_size());
00112       current = p.get_current();
00113     }
00114 #else
00115     slice_pointer_base(const slice_pointer_base<T, T*, T&> &p)
00116     {
00117       set(p.get_current(), p.get_span(), 0);
00118     }
00119 #endif
00120 
00121     /*! \brief Set values of slice_pointer_base members.
00122      
00123      \param first Pointer to first element.
00124      
00125      \param span Distance between consecutive elements (i-th element is given
00126      by first + (i-1) * span. If span == 1 then behavior is the same as T*.
00127      
00128      \param size Number of elements pointed to. 
00129      This argument is only used when bounds checking is enabled.
00130      */
00131 #ifdef SCPPNT_BOUNDS_CHECK
00132     void set(pointer first, Subscript span, Subscript size)
00133 #else
00134     void set(pointer first, Subscript span, Subscript)
00135     // Prevents warning message about unused argument when size not used
00136 #endif
00137     {
00138       current = first;
00139       this->span = span;
00140 #ifdef SCPPNT_BOUNDS_CHECK
00141       this->first = first;
00142       last = first + (size-1) * span;
00143 #endif
00144     }
00145 
00146     // Access functions.
00147 
00148     //! Return pointer to current element
00149     pointer get_current() const
00150     {
00151       return current;
00152     }
00153 
00154     //! Return distance separating consecutive elements
00155     Subscript get_span() const
00156     {
00157       return span;
00158     }
00159 
00160 #ifdef SCPPNT_BOUNDS_CHECK
00161     //! Set number of elements pointed from current element through last element
00162     void set_size(Subscript size)
00163     {
00164       last = current + (size-1) * span;
00165       first = current;
00166     }
00167 
00168     //! Return number of elements pointed to
00169     Subscript get_size() const
00170     {
00171       return last-first+1;
00172     }
00173 
00174     //! Return pointer to first element.
00175     pointer get_first() const
00176     {
00177       return first;
00178     }
00179 #endif
00180 
00181     //! Return current element pointed to.
00182     reference operator*() const
00183     {
00184 #ifdef SCPPNT_BOUNDS_CHECK
00185       if (!current || current < first || current > last)
00186 throw        BoundsError("SCPPNT::slice_pointer_base::operator*");
00187 #endif
00188         return *current;
00189       }
00190 
00191       //! Dereference
00192       pointer operator->() const
00193       {
00194 #ifdef SCPPNT_BOUNDS_CHECK
00195         if (!current || current < first || current > last)
00196         throw BoundsError("SCPPNT::const_slice_pointer_base::operator->");
00197 #endif
00198         return current;
00199       }
00200 
00201       //! zero-offset subscripting
00202       reference operator[](Subscript i) const
00203       {
00204 #ifdef SCPPNT_BOUNDS_CHECK
00205         if (!current || (current+i) < first || (current+i) > last)
00206         throw BoundsError("SCPPNT::slice_pointer_base::operator[]");
00207 #endif
00208         return current[i];
00209       }
00210 
00211       //! Increment to point to next element and return modified slice_pointer_base (preincrement)
00212       slice_pointer_base& operator++()
00213       {
00214         current += span;
00215         return *this;
00216       }
00217 
00218       //! Increment to point to next element and return new slice_pointer_base pointing to original element (postincrement)
00219       slice_pointer_base operator++(int)
00220       {
00221         slice_pointer_base t(*this);
00222         current += span;
00223         return t;
00224       }
00225 
00226       //! Decrement to point to previous element and return modified slice_pointer_base (predecrement)
00227       slice_pointer_base& operator--()
00228       {
00229         current -= span;
00230         return *this;
00231       }
00232 
00233       //! Decrement to point to previous element and return new slice_pointer_base pointing to original element (postdecrement)
00234       slice_pointer_base operator--(int)
00235       {
00236         slice_pointer_base t(*this);
00237         current -= span;
00238         return t;
00239       }
00240 
00241       //! Increment to point to element that is i elements greater than current element.
00242       slice_pointer_base& operator+=(Subscript i)
00243       {
00244         current += span*i;
00245         return *this;
00246       }
00247 
00248       //! Decrement to point to element that is i elements less than current element.
00249       slice_pointer_base& operator-=(Subscript i)
00250       {
00251         current -= span*i;
00252         return *this;
00253       }
00254 
00255       //! Return new slice_pointer_base that points to i elements greater than the current element
00256       slice_pointer_base operator+(Subscript i) const
00257       {
00258         return slice_pointer_base<T,PTR,REF>(*this) += i;
00259       }
00260 
00261       //! Return new slice_pointer_base that points to i elements less than the current element
00262       slice_pointer_base operator-(Subscript i) const
00263       {
00264         return slice_pointer_base<T,PTR,REF>(*this) -= i;
00265       }
00266 
00267 #ifdef SCPPNT_MEMBER_COMPARISONS
00268 
00269       //! Return number of elements separating current elements pointed to by lhs and rhs
00270       Subscript operator-(const slice_pointer_base<T,PTR,REF> &rhs)
00271       {
00272         if (get_span() != rhs.get_span())
00273         throw InvalidArgument("Mismatching spans", "SCPPNT::slice_pointer_base::operator-()");
00274         return (get_current() - rhs.get_current()) / lhs.get_span();
00275       }
00276 
00277       //! Returns true if two slice_pointer_base objects point to the same element
00278       bool operator==(const slice_pointer_base<T,PTR,REF> &rhs)
00279       {
00280         return current == rhs.current;
00281       }
00282 
00283       //! Returns true if two slice_pointer_base objects point to the different elements
00284       bool operator!=(const slice_pointer_base<T,PTR,REF> &rhs)
00285       {
00286         return current != rhs.current;
00287       }
00288 
00289       //! Returns true if lhs points to an element greater than the element pointed to by rhs
00290       bool operator>(const slice_pointer_base<T,PTR,REF> &rhs)
00291       {
00292         return current > rhs.current;
00293       }
00294 
00295       //! Returns true if lhs points to an element greater than or equal to the element pointed to by rhs
00296       bool operator>=(const slice_pointer_base<T,PTR,REF> &rhs)
00297       {
00298         return current >= rhs.current;
00299       }
00300 
00301       //! Returns true if lhs points to an element less than the element pointed to by rhs
00302       bool operator<(const slice_pointer_base<T,PTR,REF> &rhs)
00303       {
00304         return current < rhs.current;
00305       }
00306 
00307       //! Returns true if lhs points to an element less than or equal to the element pointed to by rhs
00308       bool operator<=(const slice_pointer_base<T,PTR,REF> &rhs)
00309       {
00310         return current <= rhs.current;
00311       }
00312 
00313 #else
00314 
00315       //! Return number of elements separating current elements pointed to by lhs and rhs
00316       friend Subscript operator-(const slice_pointer_base<T,PTR,REF> &lhs, const slice_pointer_base<T,PTR,REF> &rhs)
00317       {
00318         if (lhs.get_span() != rhs.get_span())
00319         throw InvalidArgument("Mismatching spans", "SCPPNT::slice_pointer_base::operator-()");
00320         return (lhs.get_current() - rhs.get_current()) / lhs.get_span();
00321       }
00322 
00323       //! Returns true if two slice_pointer_base objects point to the same element
00324       friend bool operator==(const slice_pointer_base<T,PTR,REF> &lhs, const slice_pointer_base<T,PTR,REF> &rhs)
00325       {
00326         return lhs.current == rhs.current;
00327       }
00328 
00329       //! Returns true if two slice_pointer_base objects point to the different elements
00330       friend bool operator!=(const slice_pointer_base<T,PTR,REF> &lhs, const slice_pointer_base<T,PTR,REF> &rhs)
00331       {
00332         return lhs.current != rhs.current;
00333       }
00334 
00335       //! Returns true if lhs points to an element greater than the element pointed to by rhs
00336       friend bool operator>(const slice_pointer_base<T,PTR,REF> &lhs, const slice_pointer_base<T,PTR,REF> &rhs)
00337       {
00338         return lhs.current > rhs.current;
00339       }
00340 
00341       //! Returns true if lhs points to an element greater than or equal to the element pointed to by rhs
00342       friend bool operator>=(const slice_pointer_base<T,PTR,REF> &lhs, const slice_pointer_base<T,PTR,REF> &rhs)
00343       {
00344         return lhs.current >= rhs.current;
00345       }
00346 
00347       //! Returns true if lhs points to an element less than the element pointed to by rhs
00348       friend bool operator<(const slice_pointer_base<T,PTR,REF> &lhs, const slice_pointer_base<T,PTR,REF> &rhs)
00349       {
00350         return lhs.current < rhs.current;
00351       }
00352 
00353       //! Returns true if lhs points to an element less than or equal to the element pointed to by rhs
00354       friend bool operator<=(const slice_pointer_base<T,PTR,REF> &lhs, const slice_pointer_base<T,PTR,REF> &rhs)
00355       {
00356         return lhs.current <= rhs.current;
00357       }
00358 
00359 #endif
00360 
00361     private:
00362 
00363       //! Pointer to current element.
00364       pointer current;
00365 
00366       //! Distance separating consecutive elements. For a normal pointer the distance 1.
00367       Subscript span;
00368 
00369 #ifdef SCPPNT_BOUNDS_CHECK
00370       pointer first; //!< pointer to first valid element
00371       pointer last; //!< pointer to last valid element
00372 #endif
00373 
00374     };
00375 
00376   } // namespace SCPPNT
00377 
00378 #endif // SCPPNT_SLICE_POINTER_H

Generated on Tue Dec 18 23:34:06 2007 for SCPPNT by  doxygen 1.5.4