JVApen
JVApen

Reputation: 11317

Iterator for all combinations of 2 ranges

Is it possible to use the boost::iterators library to create iterators that show the combined results of 2 ranges? Note that for usage, we need the output to be iterators. Nor do we expect to first manually create a vector of all combinations. (Note: We compile with C++17)

A contrived example:

auto v = std::vector<int>({1,2,3});
auto s = std::set<double>({0.5, 1.5});
auto range = combineElements(v.begin(), v.end(), s.begin(), s.end(), [](int i, double d){ return std::pair{i, d}; });
for (auto [i, d] : range)
   std::cout << std::to_string(i) << ',' <<std::to_string(d) << ";";
// Expected output: 1,0.5;1,1.5;2,0.5;2,1.5;3,0.5;3,1.5;

I've checked the documentation of boost::iterators and found:

Am I correct to conclude that in this situation the only option is to write customer iterator by hand?

Upvotes: 4

Views: 327

Answers (1)

Caleth
Caleth

Reputation: 63152

Am I correct to conclude that in this situation the only option is to write customer iterator by hand?

Pretty much yes. You might want to decompose it into an iterator adaptor that repeats each element N times, and one that repeats the whole range M times, which would allow you to zip the pair of those.

template <class Iterator>
class repeat_iterator
  : public boost::iterator::iterator_adaptor< repeat_iterator<Iterator>, Iterator > 
{
  typedef boost::iterator::iterator_adaptor< repeat_iterator<Iterator>, Iterator > super_t;
  friend class boost::iterator::iterator_core_access;
  size_t len = 1;
  size_t curr = 0;

public:
  repeat_iterator() {}

  explicit repeat_iterator(Iterator x, size_t len, curr = 0)
      : super_t(x), len(len), curr(curr) {}

private:
  void increment() { 
      if (++curr == len) { 
          curr = 0;
          ++base_reference(); 
      }
  }
  void decrement() {
      if (curr-- == 0) {
          curr = len - 1;
          --base_reference(); 
      } 
  }
  void advance(typename super_t::difference_type n)
  {
      n += curr;
      base_reference() += n / len;
      curr = n % len;
  }
  template <class OtherIterator>
  typename super_t::difference_type
  distance_to(unstride_iterator<OtherIterator> const& y) const
  {
      return ((base() - y.base()) * len) + (curr - y.curr);
  }
};

template <class Iterator>
class cycle_iterator
  : public boost::iterator::iterator_adaptor< cycle_iterator<Iterator>, Iterator > 
{
  typedef boost::iterator::iterator_adaptor< cycle_iterator<Iterator>, Iterator > super_t;
  friend class boost::iterator::iterator_core_access;
  Iterator first;
  Iterator last;

public:
  cycle_iterator() {}

  explicit cycle_iterator(Iterator first, Iterator last)
      : super_t(first), first(first), last(last) {}

private:
  void increment() { 
      if (++base_reference() == last) { 
          base_reference() = first; 
      }
  }
  void decrement() {
      if (base_reference() == first) {
          base_reference() = last - 1; 
      } 
  }
  void advance(typename super_t::difference_type n)
  {
      n += std::distance(first, base_reference());
      n %= std::distance(first, last);
      base_reference() = first + n;
  }
};

Upvotes: 1

Related Questions