Boost logo

Boost :

From: Kresimir Fresl (fresl_at_[hidden])
Date: 2001-08-27 09:57:54


On Monday 27 August 2001 16:12, David Abrahams wrote:

[[ Toon Knapen wrote:
[[ template < int N >
[[ class stride_iterator_policy : public boost::default_iterator_policies
[[...]
[[ static void increment(BaseType& x) { std::advance( x, N ); }

> This is a good idea, but it is common to need to select the stride at
> runtime.

I agree.

AFAIK, in the latest version of iterator_policies increment() is not
a static member function; I think that stride can therefore be a
member of stride_iterator_policy.

> An intersting fact about striding over matrices: to avoid undefined
> behavior you usually need to allocate an extra row (or column) so that
> there's a valid end iterator position.

Here is my strided_iterator which addresses this problem. It was
written before iterator_adaptors were added to boost and
therefore uses iterator helpers from operators.hpp.
Also, it is restricted to random access iterators. But I hope
that some ideas can be helpful.

================================================

  #include <iterator>
  #include <boost/operators.hpp>

  template <typename RndAIt>
  class strided_iterator
    : public boost::random_access_iterator_helper<
      strided_iterator<RndAIt>,
      typename std::iterator_traits<RndAIt>::value_type,
      typename std::iterator_traits<RndAIt>::difference_type,
      typename std::iterator_traits<RndAIt>::pointer,
      typename std::iterator_traits<RndAIt>::reference
> {
  public:

    typedef strided_iterator<RndAIt> self_t;
    typedef RndAIt base_iterator;
    typedef std::random_access_iterator_tag iterator_category;
    typedef typename std::iterator_traits<RndAIt>::difference_type
                                                   difference_type;
    typedef typename std::iterator_traits<RndAIt>::value_type value_type;
    typedef typename std::iterator_traits<RndAIt>::pointer pointer;
    typedef typename std::iterator_traits<RndAIt>::reference reference;

    strided_iterator() {}

    explicit strided_iterator (base_iterator from,
                     difference_type step = 1)
      : first (from), curr (0), strd (step) {}

    reference operator*() const { return first[curr]; }

    self_t& operator++() { curr += strd; return *this; }
    self_t& operator--() { curr -= strd; return *this; }
    self_t& operator+= (difference_type n) {
      curr += n * strd;
      return *this;
    }
    self_t& operator-= (difference_type n) {
      curr -= n * strd;
      return *this;
    }

    friend bool operator== (self_t const& l, self_t const& r) {
      return l.curr == r.curr
        && l.first == r.first
        && l.strd == r.strd;
    }
    friend bool operator< (self_t const& l, self_t const& r) {
      return l.curr < r.curr
        && l.first == r.first
        && l.strd == r.strd;
    }
  
    friend difference_type operator- (self_t const& x, self_t const& y) {
      // if (x.first == y.first && x.strd != y.strd)
      // throw something;
      return (x.curr - y.curr) / x.strd;
    }

    base_iterator base() const { return first+curr; }
    base_iterator base_first() const { return first; }
    difference_type stride() const { return strd; }
    difference_type current() const { return curr; }

  protected:
    base_iterator first;
    difference_type curr, strd;
  };

  // helper functions to construct sequence end:

  // .. n steps after the first, ie. current == n * stride

  template <typename RndAIt>
  strided_iterator<RndAIt> strided_iterator_nth
  (RndAIt from,
   typename std::iterator_traits<RndAIt>::difference_type n,
   typename std::iterator_traits<RndAIt>::difference_type step = 1
   ) {
    strided_iterator<RndAIt> sit (from, step);
    sit += n;
    return sit;
  }

  template <typename RndAIt>
  strided_iterator<RndAIt> strided_iterator_nth
  (strided_iterator<RndAIt> from,
   typename std::iterator_traits<RndAIt>::difference_type n
   ) {
    from += n;
    return from;
  }

  // .. adjust current so that the it has right offset after the
  // .... end of sequence (given by sequence::iterator to)

  template <typename RndAIt>
  strided_iterator<RndAIt> strided_iterator_to
  (RndAIt from,
   RndAIt to,
   typename std::iterator_traits<RndAIt>::difference_type step = 1
   ) {
    typedef typename std::iterator_traits<RndAIt>::difference_type d_t;
    d_t rdist = to - from;
    d_t dist = rdist / step;
    d_t rem = rdist % step;
    // caution: sign (rem) is implementation-defined (ISO 83/4)
    if (rem != 0)
      dist += 1;
    return strided_iterator_nth (from, dist, step);
  }

  template <typename RndAIt>
  strided_iterator<RndAIt>
  strided_iterator_to (strided_iterator<RndAIt> from, RndAIt to) {
    return
      strided_iterator_to (from.base_first(), to, from.stride());
  }


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk