Skip to content

Instantly share code, notes, and snippets.

@ubnt-intrepid
Created July 27, 2014 14:36
Show Gist options
  • Save ubnt-intrepid/17f5ce786cc52a5df29b to your computer and use it in GitHub Desktop.
Save ubnt-intrepid/17f5ce786cc52a5df29b to your computer and use it in GitHub Desktop.
#include <iterator>
#include <tuple>
template <typename Iterator1, typename Iterator2>
struct product2_iterator
{
// [first1, last1), [first2, last2)
// -> (first1,first2), (first1+1,first2), ... , (last1-1, last2-2), (last1-1, last2-1)
private:
typedef product2_iterator<Iterator1, Iterator2> self_type ;
typedef typename std::iterator_traits<Iterator1>::value_type value1_type;
typedef typename std::iterator_traits<Iterator2>::value_type value2_type;
typedef std::tuple<Iterator1, Iterator2> iterators ;
iterators it_ ;
iterators const first_, last_ ;
public:
explicit product2_iterator( iterators it, iterators first, iterators last )
: it_(it), first_(first), last_(last)
{
}
inline void operator++() {
increment() ;
}
inline std::tuple<value1_type&, value2_type&> operator*() {
return dereference() ;
}
inline bool operator!=(self_type const& other) const {
return compare(other) ;
}
private:
// increment
void increment() {
if ( ++ std::get<0>(it_) == std::get<0>(last_) ) {
if ( ++ std::get<1>(it_) != std::get<1>(last_) ) {
std::get<0>(it_) = std::get<0>(first_) ;
}
}
}
// dereference
std::tuple<value1_type&, value2_type&> dereference()
{
return std::tuple<value1_type&, value2_type&>(
*std::get<0>(it_),
*std::get<1>(it_)
);
}
// compare
bool compare(self_type const& other) const {
return std::get<0>(it_) != std::get<0>(other.it_)
|| std::get<1>(it_) != std::get<1>(other.it_) ;
}
};
template <typename Iterator1, typename Iterator2>
product2_iterator<Iterator1, Iterator2>
make_product2_iterator(
Iterator1 it1, Iterator2 it2,
Iterator1 first1, Iterator2 first2,
Iterator1 last1, Iterator2 last2 )
{
return product2_iterator<Iterator1, Iterator2>(
std::make_pair(it1, it2),
std::make_pair(first1, first2),
std::make_pair(last1, last2)
) ;
}
#include <boost/range.hpp>
template <typename Range1, typename Range2>
class product2_range
{
typedef typename boost::range_iterator<Range1>::type iterator1 ;
typedef typename boost::range_iterator<Range2>::type iterator2 ;
typedef product2_iterator<iterator1, iterator2> iterator_type ;
Range1& rng1_ ;
Range2& rng2_ ;
public:
explicit product2_range(Range1& rng1, Range2& rng2)
: rng1_(rng1), rng2_(rng2)
{
}
iterator_type begin() {
return make_product2_iterator(
std::begin(rng1_), std::begin(rng2_),
std::begin(rng1_), std::begin(rng2_),
std::end(rng1_), std::end(rng2_));
}
iterator_type end() {
return make_product2_iterator(
std::end(rng1_), std::end(rng2_),
std::begin(rng1_), std::begin(rng2_),
std::end(rng1_), std::end(rng2_));
}
};
template <typename Range1, typename Range2>
product2_range<Range1, Range2> product2(Range1& rng1, Range2& rng2) {
return product2_range<Range1, Range2>(rng1, rng2) ;
}
#include <iostream>
#include <vector>
#include <boost/assign.hpp>
int main()
{
std::vector<int> a = boost::assign::list_of(1)(2)(3)(4)(5);
std::vector<double> b = boost::assign::list_of(6)(7)(8)(9)(10);
for (auto item : product2(a, b))
{
std::cout << "(" << std::get<0>(item) << ", " << std::get<1>(item) << ")\n" ;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment