/** * @file * @author Navneet Dalal * @brief Defines DomainIterator for Rectangular Domain. * * @warning This class has nothing to do with RectDomain. * It just provides iterator functionality on a Rectangular Domain. */ #ifndef _DOMAIN_ITER_H_ #define _DOMAIN_ITER_H_ #include #include #include "tvmutils.h" BZ_NAMESPACE(blitz) /** * DomainIter class. Can be used to create index iterators over an array range * * Stride here has unusual meaning. In blitz array class, strides are used to * increment data pointer but not indices (see iter.h file in blitz repository). * Here we use stride to increment indices. With this, user can create an * iterator which provides access to (for example) every odd element. * * \warning Currently, DomainIter works only with ascending order indices. * Also, use of blitz iterators or DomainIter is always a bit slower when * compared to explicit for loops. However, explicit for loops over each * dimension are complicated and error prone. So if efficiency is not the * prime goal, use DomainIter class. Also, if one is writing template classes * using array dimension as template argument, explicit for loops does not work. * In these situations, one is forced to use DomainIter. */ /* * Though it is not difficult to extend it to descending indices, but * I am unable to think how can we do it without putting any * penalty on ascendingOrder case. */ template class DomainIter { public: enum {Rank = N}; typedef TinyVector IndexType; DomainIter( const IndexType& lbound_, const IndexType& ubound_, const IndexType& strides_, const IndexType& order_): lbound_(lbound_), ubound_(ubound_), strides_(strides_), order_(order_) { init();} DomainIter( const IndexType& lbound_, const IndexType& ubound_, const IndexType& strides_): lbound_(lbound_), ubound_(ubound_), strides_(strides_) { // set the ordering first for (int i= 0; i() const { return pos_; } DomainIter& operator++(); void operator++(int) { ++(*this); } /** * Compare two iterators based on their current indices. * Returns true if and only if all two indices are equal for all N elements */ bool operator==(const DomainIter& x) const { return isEqual(pos_, x.pos_); } /** * Compare two iterators based on their current indices. * Returns true if and only if all two indices are less than for all N elements */ bool operator< (const DomainIter& x) const { return isLess(pos_, x.pos_); } /** * Compare two iterators based on their current indices. * Returns true if and only if all two indices are less than or equal to for all N elements */ bool operator<=(const DomainIter& x) const { return isLessEqual(pos_, x.pos_); } /** * Compare two iterators based on their current indices. * Returns true if and only if all two indices are greater than for all N elements */ bool operator> (const DomainIter& x) const { return isGreater(pos_, x.pos_); } /** * Compare two iterators based on their current indices. * Returns true if and only if all two indices are greater than or equal to for all N elements */ bool operator>= (const DomainIter& x) const { return isGreaterEqual(pos_, x.pos_); } /** * Compare two iterators based on their current indices. * Returns false if and only if all two indices are equal for all N elements */ bool operator!=(const DomainIter& x) const { return isNotEqual(pos_, x.pos_); } /** * This function is provided for efficiency reasons. * To iterate till ubound in for loops, it is more * efficient to use DomainIter<0> as end iterator. */ inline bool operator==(const DomainIter<0>& x) const { return !static_cast(*this); } /** * This function is provided for efficiency reasons. * To iterate till ubound in for loops, it is more * efficient to use DomainIter<0> as end iterator. */ inline bool operator!=(const DomainIter<0>& x) const { return static_cast(*this); } /** * Returns true if and only if all elements of current iterator index and argument index satisfies the condition. * These functions are provided as an extension. Though not standard for iterators. * * \warning It is not recommended to use these functions in for/while loops for efficiency reasons. Use the bool() operator or end iterator. */ // @{ bool operator==(const IndexType& x) const { return isEqual(pos_, x); } bool operator< (const IndexType& x) const { return isLess(pos_, x); } bool operator<=(const IndexType& x) const { return isLessEqual(pos_, x); } bool operator> (const IndexType& x) const { return isGreater(pos_, x); } bool operator>= (const IndexType& x) const { return isGreaterEqual(pos_, x); } bool operator!=(const IndexType& x) const { return isNotEqual(pos_, x); } // @} /** * Return true as long as iterator has more elements. * This function is provided for efficiency reasons. * To iterate till ubound in for loops, it is more * efficient to use this function instead of comparison with end iterator. */ operator bool() const { return isValid_; } /// Return a copy of this iterator inline DomainIter begin() { return *this; } /// Return DomainIter<0> as end iterator. This is done for efficiency reason inline static const DomainIter<0> end() { return DomainIter<0>(); } private: DomainIter() { } void init() { pos_ = lbound_; maxRank_ = order_(0); stride_ = strides_(maxRank_); // if ubound_ < lbound_, then isValid = false; if (sum((ubound_ - lbound_) <0) >0) isValid_ = false; else isValid_ = true; } protected: const IndexType lbound_, ubound_; const IndexType strides_; IndexType order_; int stride_; int maxRank_; bool isValid_; IndexType pos_; }; /** * Specialize DomainIter. When N ==0, this indicates to * loop till end of the bounds in the DomainIter. This will * be much more efficient than comparing two bounds. */ class DomainIter<0> { public: // no accidental loops inline bool operator==(const DomainIter<0>& x) const { return false; } // no accidental loops inline bool operator!=(const DomainIter<0>& x) const { return false; } /** * This function is provided for efficiency reasons. * To iterate till ubound in for loops, it is more * efficient to use DomainIter<0> as end iterator. */ template inline bool operator==(const DomainIter& x) const { return !static_cast(x); } /** * This function is provided for efficiency reasons. * To iterate till ubound in for loops, it is more * efficient to use DomainIter<0> as end iterator. */ template inline bool operator!=(const DomainIter& x) const { return static_cast(x); } // }}} }; template DomainIter& DomainIter::operator++() { BZPRECHECK(isValid_, "Attempted to iterate past the end of an array."); pos_[maxRank_] += stride_; // We hit this case almost all the time. if (pos_[maxRank_] <= ubound_[maxRank_]) { return *this; } // We've hit the end of a row/column/whatever. Need to // increment one of the loops over another dimension. int j = 1; for (; j < N; ++j) { const int r = order_(j); pos_[r] += strides_[r]; if (pos_[r] <= ubound_[r]) break; } // All done? if (j == N) { // Setting isValid_ to 0 indicates the end of the array has // been reached, and will match the end iterator. isValid_ = false; --j;// we donot want to reset the position for the largest // stride back to lower bounds below. } // Now reset all the last pointers for (--j; j >= 0; --j) { const int r = order_(j); pos_[r] = lbound_[r]; } return *this; } BZ_NAMESPACE_END #endif // _DOMAIN_ITER_H_