Skip to content

Instantly share code, notes, and snippets.

@ajakubek
Created October 22, 2016 21:27
Show Gist options
  • Save ajakubek/338807586ea68ef17d011c34d8df3850 to your computer and use it in GitHub Desktop.
Save ajakubek/338807586ea68ef17d011c34d8df3850 to your computer and use it in GitHub Desktop.
#ifndef PRODUCT_ITERATOR_H
#define PRODUCT_ITERATOR_H
#include <cassert>
#include <iterator>
#include <tuple>
#include <utility>
template <typename Iterator1, typename Iterator2>
class product_iterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using first_reference = typename std::iterator_traits<Iterator1>::reference;
using second_reference = typename std::iterator_traits<Iterator2>::reference;
using reference = std::tuple<first_reference, second_reference>;
using first_value_type = typename std::iterator_traits<Iterator1>::value_type;
using second_value_type = typename std::iterator_traits<Iterator2>::value_type;
using value_type = std::tuple<first_value_type, second_value_type>;
using pointer = value_type*;
using difference_type = std::ptrdiff_t;
product_iterator(Iterator1 b1, Iterator1 e1, Iterator2 b2, Iterator2 e2)
: it1(b1), it2(b2), e1(e1), b2(b2), e2(e2)
{
if (b1 == e1 || b2 == e2)
{
it1 = e1;
it2 = e2;
}
}
reference operator*() const
{
return reference(*it1, *it2);
}
product_iterator& operator++()
{
++it2;
if (it2 == e2)
{
++it1;
if (it1 != e1)
it2 = b2;
}
return *this;
}
product_iterator& operator--()
{
if (it1 == e1)
--it1;
if (it2 == b2)
{
--it1;
it2 = e2;
}
--it2;
return *this;
}
product_iterator end_iterator() const
{
product_iterator end = *this;
end.it1 = e1;
end.it2 = e2;
return end;
}
bool operator==(const product_iterator& rhs) const
{
assert(e1 == rhs.e1 && b2 == rhs.b2 && e2 == rhs.e2
&& "Comparison between incompatible iterators");
return it1 == rhs.it1 && it2 == rhs.it2;
}
bool operator!=(const product_iterator& rhs) const
{
return !(*this == rhs);
}
private:
Iterator1 it1;
Iterator2 it2;
Iterator1 e1;
Iterator2 b2;
Iterator2 e2;
};
template <typename Iterator1, typename Iterator2>
product_iterator<Iterator1, Iterator2>
make_product_iterator(Iterator1&& b1, Iterator1&& e1, Iterator2&& b2, Iterator2&& e2)
{
return product_iterator<Iterator1, Iterator2>(std::forward<Iterator1>(b1),
std::forward<Iterator1>(e1),
std::forward<Iterator2>(b2),
std::forward<Iterator2>(e2));
}
#endif // PRODUCT_ITERATOR_H
#include <algorithm>
#include <iostream>
#include <vector>
#include "product_iterator.h"
template <typename T1, typename T2>
void print_product(const std::vector<T1>& vec1, const std::vector<T2>& vec2)
{
std::cout << "Product:\n";
auto it = make_product_iterator(vec1.cbegin(), vec1.cend(), vec2.cbegin(), vec2.cend());
std::for_each(it, it.end_iterator(), [](std::tuple<const int&, const std::string&> x) {
std::cout << std::get<0>(x) << ", " << std::get<1>(x) << '\n';
});
}
template <typename T1, typename T2>
void print_product_reverse(const std::vector<T1>& vec1, const std::vector<T2>& vec2)
{
std::cout << "Reverse product:\n";
auto it = make_product_iterator(vec1.cbegin(), vec1.cend(), vec2.cbegin(), vec2.cend());
std::reverse_iterator<decltype(it)> rbegin(it.end_iterator());
std::reverse_iterator<decltype(it)> rend(it);
std::for_each(rbegin, rend, [](std::tuple<const int&, const std::string&> x) {
std::cout << std::get<0>(x) << ", " << std::get<1>(x) << '\n';
});
}
int main(int argc, const char** argv)
{
print_product(std::vector<int>{1, 2, 3, 4},
std::vector<std::string>{"foo", "bar", "baz"});
print_product_reverse(std::vector<int>{1, 2, 3, 4},
std::vector<std::string>{"foo", "bar", "baz"});
print_product(std::vector<int>{},
std::vector<std::string>{"foo", "bar", "baz"});
print_product_reverse(std::vector<int>{},
std::vector<std::string>{"foo", "bar", "baz"});
print_product(std::vector<int>{1, 2, 3, 4},
std::vector<std::string>{});
print_product_reverse(std::vector<int>{1, 2, 3, 4},
std::vector<std::string>{});
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment