Question

Background
Large application with a bundle of code, I can't change the storage mechanism.

I would like to create an iterator over a set of multi-dimensional data stored in parallel arrays so we can start using std algorithms & containers.

Any ideas on how to make this work correctly?

#include <boost/iterator/iterator_facade.hpp>

#include <iostream>
#include <algorithm>

class curve_point_iterator;

const int curve_size = 10;

class curve
{
public:
  curve()
  {
    std::fill( x, &x[curve_size], 0.0 );
    std::fill( y, &y[curve_size], 0.0 );
  }

  double x[curve_size];
  double y[curve_size];

  curve_point_iterator begin();
  curve_point_iterator end();
};

class point_reference
{
public:
  point_reference( double& x_, double& y_ )
    : x( x_ )
    , y( y_ )
  {
  }

  point_reference& operator = ( point_reference& other )
  {
    x = other.x;
    y = other.y;

    return *this;
  }

  double & x;
  double & y;
};

class curve_point_iterator 
  : public boost::iterator_facade< 
          curve_point_iterator
        , point_reference
        , boost::random_access_traversal_tag >
{
public:
  curve_point_iterator()
    : index(0)
    , curve_(nullptr)
  {}

  explicit curve_point_iterator( curve* curve_in, size_t index_ = 0 )
    : index( index_ )
    , curve_( curve_in )
  {}

private:
  friend class boost::iterator_core_access;

  void increment()
  {
    ++index;
  }

  void decrement()
  {
    --index;
  }

  void advance( size_t n )
  {
    index += n;
  }

  difference_type distance_to( curve_point_iterator const& other ) const
  {
    return other.index - this->index;
  }

  bool equal(curve_point_iterator const& other) const
  {
      return this->index == other.index && this->curve_ == other.curve_;
  }

  point_reference& dereference() const
  {
    auto pt_ref = new( point_reference_buffer ) point_reference(  curve_->x[index]
                                                                , curve_->y[index] );
    return *pt_ref;
  }

  size_t index;
  mutable char point_reference_buffer[sizeof(point_reference)];
  curve* curve_;
};


curve_point_iterator curve::begin()
{
  return curve_point_iterator( this );
}

curve_point_iterator curve::end()
{
  return curve_point_iterator( this, curve_size+1 );
}


int main(int argc, char* argv[])
{
  curve crv;

  crv.x[1] = 20;
  crv.x[2] = 10;

  std::sort( crv.begin(), crv.end(), []( point_reference const& a, point_reference const& b )
  {
    return a.x < b.x;
  });

  for( auto i = 0; i < curve_size; ++i )
  {
    std::cout << crv.x[i] << std::endl;
  }

  return 0;
}

Output
0
20
20
20
20
20
20
20
20
20

After changing to

class point_reference
{
  ... ( all the other stuff )
  double x; // no longer reference
  double y; // no longer reference
};

Output
0
20
10
0
0
0
0
0
0

Was it helpful?

Solution

Okay, what you need to do is to introduce a point type (which has value semantics) in addition to point_reference, which has the reference semantics you're looking for. You need the value semantics so that operations such as swap act as the standard expects. You can use the fourth argument of iterator_facade to allow this. Also, this way there is no need to use that mutable buffer, since the point_reference itself is returned by value.

Also, your curve::end() used the wrong index, and should use curve_size as its index.

#include <boost/iterator/iterator_facade.hpp>

#include <iostream>
#include <algorithm>

class curve_point_iterator;

const int curve_size = 10;

class curve
{
public:
  curve()
  {
    std::fill( x, &x[curve_size], 0.0 );
    std::fill( y, &y[curve_size], 0.0 );
  }

  double x[curve_size];
  double y[curve_size];

  curve_point_iterator begin();
  curve_point_iterator end();
};

class point
{
public:
  point( const double& x_, const double& y_ )
    : x( x_ )
    , y( y_ )
  {
  }

  double x;
  double y;
};


class point_reference
{
public:
  point_reference( double& x_, double& y_ )
    : x( x_ ),
      y( y_ )
  {
  }

  point_reference& operator = ( const point& other )
  {
    x = other.x;
    y = other.y;

    return *this;
  }

  operator point() const
  {
    return point(x, y);
  }

  double & x;
  double & y;

  point_reference& operator=(const point_reference& other)
  {
    x = other.x;
    y = other.y;
  }

  point_reference* operator->()
  {
     return this;
  }

  point_reference* operator->() const
  {
     return this;
  }


};

class curve_point_iterator 
  : public boost::iterator_facade< 
          curve_point_iterator
  , point
  , boost::random_access_traversal_tag
  , point_reference>
{
public:
  curve_point_iterator()
    : index(0)
    , curve_(nullptr)
  {}

  explicit curve_point_iterator( curve* curve_in, size_t index_ = 0 )
    : index( index_ )
    , curve_( curve_in )
  {}

  point_reference operator->() const
  {
     return dereference();
  }

private:
  friend class boost::iterator_core_access;

  void increment()
  {
    ++index;
  }

  void decrement()
  {
    --index;
  }

  void advance( size_t n )
  {
    index += n;
  }

  difference_type distance_to( curve_point_iterator const& other ) const
  {
    return other.index - this->index;
  }

  bool equal(curve_point_iterator const& other) const
  {
    return this->index == other.index && this->curve_ == other.curve_;
  }

  point_reference dereference() const
  {
    //    auto pt_ref = new( point_reference_buffer ) point_reference(  curve_->x[index]
    //                                , curve_->y[index] );
    //    return *pt_ref;
    return point_reference(curve_->x[index], curve_->y[index]);
  }

  size_t index;
  curve* curve_;
};


curve_point_iterator curve::begin()
{
  return curve_point_iterator( this );
}

curve_point_iterator curve::end()
{
  return curve_point_iterator( this, curve_size );
}


int main(int argc, char* argv[])
{
  curve crv;

  crv.x[1] = 20;
  crv.x[2] = 10;

  std::sort( crv.begin(), crv.end(), []( point const& a, point const& b )
         {
           return a.x < b.x;
         });

  for( auto i = 0; i < curve_size; ++i )
    {
      std::cout << crv.x[i] << std::endl;
    }

  return 0;
}

Output:

0
0
0
0
0
0
0
0
10
20
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top