subArray2D.h

Go to the documentation of this file.
00001 
00015 #ifndef _DLR_SUBARRAY2D_H_
00016 #define _DLR_SUBARRAY2D_H_
00017 
00018 #include <dlrNumeric/array2D.h>
00019 #include <dlrNumeric/slice.h>
00020 
00021 namespace dlr {
00022 
00023   namespace numeric {
00024     
00039     template <class Type>
00040     class SubArray2D {
00041     public:
00048       SubArray2D(const Array2D<Type>& source);
00049 
00065       SubArray2D(const Array2D<Type>& source, const Slice& rowSlice,
00066                  const Slice& columnSlice);
00067 
00076       SubArray2D(const SubArray2D<Type> &other);
00077 
00081       virtual
00082       ~SubArray2D() {}
00083 
00092       operator Array2D<Type>() const;
00093 
00101       inline size_t
00102       rows() const {return this->m_rows;}
00103 
00112       inline size_t
00113       columns() const {return this->m_columns;}
00114 
00123       inline size_t
00124       startRow() const {return this->m_startRow;}
00125 
00134       inline size_t
00135       startColumn() const {return this->m_startColumn;}
00136     
00144       inline size_t
00145       rowStride() const {return this->m_rowStride;}
00146 
00155       inline size_t
00156       columnStride() const {return this->m_columnStride;}
00157 
00166       inline Array2D<Type>
00167       getArray() const {return this->m_source;}
00168   
00179       SubArray2D<Type>&
00180       operator=(const SubArray2D<Type>& other);
00181 
00192       SubArray2D<Type>& operator=(Type value);
00193 
00204       SubArray2D<Type>&
00205       operator+=(const SubArray2D<Type>& other);
00206 
00217       SubArray2D<Type>&
00218       operator-=(const SubArray2D<Type>& other);
00219 
00220     private:
00221 
00230       inline int
00231       abs(int argument) {return (argument >= 0) ? argument : -argument;}
00232     
00233       inline void
00234       checkArray2DSize(const Array2D<Type>& other) const;
00235 
00236       inline void
00237       checkSubArray2DSize(const SubArray2D<Type>& other) const;
00238 
00239       SubArray2D<Type>&
00240       copyColumnMajor(const SubArray2D<Type>& other);
00241 
00242       SubArray2D<Type>&
00243       copyRowMajor(const SubArray2D<Type>& other);
00244 
00245       Array2D<Type> m_source;
00246       int m_startRow;
00247       int m_stopRow;
00248       int m_rowStride;
00250       size_t m_rows;
00251       int m_startColumn;
00252       int m_stopColumn;
00253       int m_columnStride;
00255       size_t m_columns;
00256     };
00257 
00258 
00259     /* Non-member functions */
00260 
00275     template <class Type>
00276     inline SubArray2D<Type>
00277     subArray(const Array2D<Type>& source) {return SubArray2D<Type>(source);}
00278 
00279   
00300     template <class Type>
00301     inline SubArray2D<Type>
00302     subArray(const Array2D<Type>& source,
00303              const Slice& rowSlice,
00304              const Slice& columnSlice) {
00305       return SubArray2D<Type>(source, rowSlice, columnSlice);
00306     }
00307 
00308   
00328     template <class Type>
00329     inline SubArray2D<Type>
00330     subArray(const Array2D<Type>& source,
00331              const int row,
00332              const Slice& columnSlice) {
00333       return SubArray2D<Type>(source, Slice(row, row+1), columnSlice);
00334     }
00335 
00336   
00356     template <class Type>
00357     inline SubArray2D<Type>
00358     subArray(const Array2D<Type>& source,
00359              const Slice& rowSlice,
00360              int column) {
00361       return SubArray2D<Type>(source, rowSlice, Slice(column, column + 1));
00362     }
00363 
00364   
00373     template <class Type>
00374     std::ostream&
00375     operator<<(std::ostream& stream, const SubArray2D<Type>& subArray0);
00376 
00377   } // namespace numeric
00378 
00379 } // namespace dlr
00380 
00381 
00382 /* ======= Declarations to maintain compatibility with legacy code. ======= */
00383 
00384 namespace dlr {
00385 
00386   using numeric::SubArray2D;
00387   using numeric::subArray;
00388 
00389 } // namespace dlr
00390 
00391 
00392 /*******************************************************************
00393  * Function definitions follow.  This would be a .C file
00394  * if SubArray2D weren't templated.
00395  *******************************************************************/
00396 
00397 #include <cmath>
00398 #include <dlrCommon/stridedPointer.h>
00399 
00400 namespace dlr {
00401 
00402   namespace numeric {
00403     
00404     template <class Type>
00405     SubArray2D<Type>::
00406     SubArray2D(const Array2D<Type>& source)
00407       : m_source(source),
00408         m_startRow(0),
00409         m_stopRow(source.rows()),
00410         m_rowStride(1),
00411         m_rows(source.rows()),
00412         m_startColumn(0),
00413         m_stopColumn(source.columns()),
00414         m_columnStride(1),
00415         m_columns(source.columns())
00416     {
00417       // Empty
00418     }
00419 
00420     template <class Type>
00421     SubArray2D<Type>::
00422     SubArray2D(const Array2D<Type>& source, const Slice& rowSlice,
00423                const Slice& columnSlice)
00424       : m_source(source),
00425         m_startRow(rowSlice.start()),
00426         m_stopRow(rowSlice.stop()),
00427         m_rowStride(rowSlice.stride()),
00428         m_rows(0),
00429         m_startColumn(columnSlice.start()),
00430         m_stopColumn(columnSlice.stop()),
00431         m_columnStride(columnSlice.stride()),
00432         m_columns(0)
00433     {
00434       // It's convenient to be able to specify "last row/column" somehow.
00435       // Setting row1/column1 to zero will wrap to source.rows()/source.columns()
00436       // if appropriate.
00437       if((this->m_stopRow == 0) && (this->m_rowStride > 0)) {
00438         this->m_stopRow = static_cast<int>(source.rows());
00439       }
00440       if((this->m_stopColumn == 0) && (this->m_columnStride > 0)) {
00441         this->m_stopColumn = static_cast<int>(source.columns());
00442       }
00443     
00444       // Negative indexing is also super-convenient
00445       while(this->m_startRow < 0) {
00446         this->m_startRow += static_cast<int>(source.rows());
00447       }
00448       while(this->m_stopRow < 0) {
00449         this->m_stopRow += static_cast<int>(source.rows());
00450       }
00451       while(this->m_startColumn < 0) {
00452         this->m_startColumn += static_cast<int>(source.columns());
00453       }
00454       while(this->m_stopColumn < 0) {
00455         this->m_stopColumn += static_cast<int>(source.columns());
00456       }
00457 
00458       // Now compute sizes (yuck).
00459       this->m_rows = ((this->m_stopRow - this->m_startRow)
00460                       / this->m_rowStride); // integer division
00461       if(this->m_rows < 0) {
00462         this->m_rows = 0; 
00463       } else {
00464         // Can't think of a better way to do this.
00465         if(this->abs(static_cast<int>(this->m_rows) * this->m_rowStride)
00466            < this->abs(this->m_stopRow - this->m_startRow)) {
00467           ++this->m_rows;
00468         }
00469       }
00470       this->m_columns = ((this->m_stopColumn - this->m_startColumn)
00471                          / this->m_columnStride); // integer division
00472       if(this->m_columns < 0) {
00473         this->m_columns = 0; 
00474       } else {
00475         // Can't think of a better way to do this.
00476         if(this->abs(static_cast<int>(this->m_columns) * this->m_columnStride)
00477            < this->abs(this->m_stopColumn - this->m_startColumn)) {
00478           ++this->m_columns;
00479         }
00480       }
00481       // Make sure we won't read/write outside of the array.
00482       this->checkArray2DSize(source);
00483     }
00484 
00485     template <class Type>
00486     SubArray2D<Type>::
00487     SubArray2D(const SubArray2D<Type> &other)
00488       : m_source(other.m_source),
00489         m_startRow(other.m_startRow),
00490         m_stopRow(other.m_stopRow),
00491         m_rowStride(other.m_rowStride),
00492         m_rows(other.m_rows),
00493         m_startColumn(other.m_startColumn),
00494         m_stopColumn(other.m_stopColumn),
00495         m_columnStride(other.m_columnStride),
00496         m_columns(other.m_columns)
00497     {
00498       // Empty
00499     }
00500 
00501     template <class Type>
00502     SubArray2D<Type>::operator Array2D<Type>() const
00503     {
00504       Array2D<Type> returnVal(this->rows(), this->columns());
00505       subArray(returnVal) = *this;
00506       return returnVal;
00507     }
00508 
00509     template <class Type>
00510     SubArray2D<Type>& SubArray2D<Type>::
00511     operator=(const SubArray2D<Type>& other)
00512     {
00513       this->checkSubArray2DSize(other);
00514       // if(this->chooseMajorAxis() == 0) {
00515       if(1) {
00516         return this->copyRowMajor(other);
00517       } else {
00518         return this->copyColumnMajor(other);
00519       }
00520     }
00521 
00522     template <class Type>
00523     SubArray2D<Type>& SubArray2D<Type>::
00524     operator=(Type value)
00525     {
00526       int outRow = m_startRow;
00527       while(outRow < m_stopRow) {
00528         StridedPointer<Type>
00529           outPtr0(this->m_source.data(outRow, this->m_startColumn),
00530                   this->m_columnStride);
00531         StridedPointer<Type> outPtr1 = outPtr0 + this->columns();
00532         std::fill(outPtr0, outPtr1, value);
00533         outRow += this->m_rowStride;
00534       }
00535       return *this;
00536     }
00537 
00538     template <class Type>
00539     SubArray2D<Type>& SubArray2D<Type>::
00540     operator+=(const SubArray2D<Type>& other)
00541     {
00542       this->checkSubArray2DSize(other);
00543       int inRow = other.m_startRow;
00544       int outRow = this->m_startRow;
00545       while(inRow < other.m_stopRow) {
00546         StridedPointer<Type>
00547           thisDataPtr0(this->m_source.data(outRow, this->m_startColumn),
00548                        this->m_columnStride);
00549         StridedPointer<Type> thisDataPtr1 = thisDataPtr0 + this->columns();
00550         StridedPointer<const Type>
00551           otherDataPtr0(other.m_source.data(inRow, other.m_startColumn),
00552                         other.m_columnStride);
00553         std::transform(thisDataPtr0, thisDataPtr1, otherDataPtr0, thisDataPtr0,
00554                        std::plus<Type>());
00555         inRow += other.m_rowStride;
00556         outRow += this->m_rowStride;
00557       }
00558       return *this;
00559     }
00560 
00561     template <class Type>
00562     SubArray2D<Type>& SubArray2D<Type>::
00563     operator-=(const SubArray2D<Type>& other)
00564     {
00565       this->checkSubArray2DSize(other);
00566       int inRow = other.m_startRow;
00567       int outRow = this->m_startRow;
00568       while(inRow < other.m_stopRow) {
00569         StridedPointer<Type>
00570           thisDataPtr0(this->m_source.data(outRow, this->m_startColumn),
00571                        this->m_columnStride);
00572         StridedPointer<Type> thisDataPtr1 = thisDataPtr0 + this->columns();
00573         StridedPointer<const Type>
00574           otherDataPtr0(other.m_source.data(inRow, other.m_startColumn),
00575                         other.m_columnStride);
00576         std::transform(thisDataPtr0, thisDataPtr1, otherDataPtr0, thisDataPtr0,
00577                        std::minus<Type>());
00578         inRow += other.m_rowStride;
00579         outRow += this->m_rowStride;
00580       }
00581       return *this;
00582     }
00583   
00584     template <class Type>
00585     inline void SubArray2D<Type>::
00586     checkArray2DSize(const Array2D<Type>& other) const
00587     {
00588 #ifdef _DLRNUMERIC_CHECKBOUNDS_
00589       if((m_startRow < 0) || (m_startRow >= static_cast<int>(other.rows()))) {
00590         std::ostringstream message;
00591         message << "Invalid start row: " << m_startRow << std::endl;
00592         DLR_THROW(IndexException, "SubArray2D::checkArray2DSize()",
00593                   message.str().c_str());
00594       }
00595       if(m_rowStride > 0) {
00596         if(m_stopRow > static_cast<int>(other.rows())) {
00597           std::ostringstream message;
00598           message << "Invalid stop row: " << m_stopRow << std::endl;
00599           DLR_THROW(IndexException, "SubArray2D::checkArray2DSize()",
00600                     message.str().c_str());
00601         }
00602       } else if(m_rowStride < 0) {
00603         if(m_stopRow < -1) {
00604           std::ostringstream message;
00605           message << "Invalid stop row: " << m_stopRow << std::endl;
00606           DLR_THROW(IndexException, "SubArray2D::checkArray2DSize()",
00607                     message.str().c_str());
00608         }
00609       } else {
00610         // m_rowStride == 0
00611         DLR_THROW(IndexException, "SubArray2D::checkArray2DSize()",
00612                   "Invalid row stride: 0\n");
00613       }
00614       if((m_startColumn < 0)
00615          || (m_startColumn >= static_cast<int>(other.columns()))) {
00616         std::ostringstream message;
00617         message << "Invalid start column: " << m_startColumn << std::endl;
00618         DLR_THROW(IndexException, "SubArray2D::checkArray2DSize()",
00619                   message.str().c_str());
00620       }
00621       if(m_columnStride > 0) {
00622         if(m_stopColumn > static_cast<int>(other.columns())) {
00623           std::ostringstream message;
00624           message << "Invalid stop column: " << m_stopColumn << std::endl;
00625           DLR_THROW(IndexException, "SubArray2D::checkArray2DSize()",
00626                     message.str().c_str());
00627         }
00628       } else if(m_columnStride < 0) {
00629         if(m_stopColumn < -1) {
00630           std::ostringstream message;
00631           message << "Invalid stop column: " << m_stopColumn << std::endl;
00632           DLR_THROW(IndexException, "SubArray2D::checkArray2DSize()",
00633                     message.str().c_str());
00634         }
00635       } else {
00636         // m_columnStride == 0
00637         DLR_THROW(IndexException, "SubArray2D::checkArray2DSize()",
00638                   "Invalid column stride: 0\n");
00639       }
00640 #endif
00641     }
00642 
00643     template <class Type>
00644     inline void SubArray2D<Type>::
00645     checkSubArray2DSize(const SubArray2D<Type>& other) const
00646     {
00647 #ifdef _DLRNUMERIC_CHECKBOUNDS_
00648       if(other.rows() != this->rows()) {
00649         std::ostringstream message;
00650         message << "Row mismatch: " << other.rows() << " vs. "
00651                 << this->rows() << std::endl;
00652         DLR_THROW(IndexException, "SubArray2D::checkSubArray2DSize()",
00653                   message.str().c_str());
00654       }
00655       if(other.columns() != this->columns()) {
00656         std::ostringstream message;
00657         message << "Column mismatch: " << other.columns() << " vs. "
00658                 << this->columns() << std::endl;
00659         DLR_THROW(IndexException, "SubArray2D::checkSubArray2DSize()",
00660                   message.str().c_str());
00661       }
00662 #endif
00663     }
00664 
00665     template <class Type>
00666     SubArray2D<Type>& SubArray2D<Type>::
00667     copyColumnMajor(const SubArray2D<Type>& other)
00668     {
00669       int inColumn = other.m_startColumn;
00670       int outColumn = this->m_startColumn;
00671       while(inColumn < other.m_stopColumn) {
00672         StridedPointer<const Type>
00673           inPtr0(other.m_source.data(other.m_startRow, inColumn),
00674                  other.m_rowStride * other.m_source.columns());
00675         StridedPointer<const Type> inPtr1 = inPtr0 + other.rows();
00676         StridedPointer<Type>
00677           outPtr0(this->m_source.data(this->m_startRow, outColumn),
00678                   this->m_rowStride * this->m_source.columns());
00679         std::copy(inPtr0, inPtr1, outPtr0);
00680         inColumn += other.m_columnStride;
00681         outColumn += this->m_columnStride;
00682       }
00683       return *this;
00684     }
00685   
00686     template <class Type>
00687     SubArray2D<Type>& SubArray2D<Type>::
00688     copyRowMajor(const SubArray2D<Type>& other)
00689     {
00690       int inRow = other.m_startRow;
00691       int outRow = this->m_startRow;
00692       while(inRow < other.m_stopRow) {
00693         StridedPointer<const Type>
00694           inPtr0(other.m_source.data(inRow, other.m_startColumn),
00695                  other.m_columnStride);
00696         StridedPointer<const Type> inPtr1 = inPtr0 + other.columns();
00697         StridedPointer<Type>
00698           outPtr0(this->m_source.data(outRow, this->m_startColumn),
00699                   this->m_columnStride);
00700         std::copy(inPtr0, inPtr1, outPtr0);
00701         inRow += other.m_rowStride;
00702         outRow += this->m_rowStride;
00703       }
00704       return *this;
00705     }
00706 
00707     /* Non-member functions */
00708 
00709     template <class Type>
00710     std::ostream& operator<<(std::ostream& stream,
00711                              const SubArray2D<Type>& subArray)
00712     {
00713       Array2D<Type> array(subArray.rows(), subArray.columns());
00714       subArray2D(array) = subArray;
00715       stream << "SubArray2D([[";
00716       for(int row = 0; row < array.rows(); ++row) {
00717         for(int column = 0; column < array.columns() - 1; ++column) {
00718           stream << array(row, column) << ", ";
00719         }
00720         stream << array(row, array.columns() - 1) << "],\n";
00721         if(row != array.rows() - 1) {
00722           stream << "          ";
00723         }
00724       }
00725       stream.flush();
00726       return stream;
00727     }
00728 
00729   } // namespace numeric
00730 
00731 } // namespace dlr
00732 
00733 #endif // #ifdef _DLR_SUBARRAY2D_H_
00734 

Generated on Wed Nov 25 00:42:43 2009 for dlrUtilities Utility Library by  doxygen 1.5.8