#include <tuple>
// basic sequences
template<unsigned...> struct seq {};
template<unsigned max, unsigned...s> struct make_seq:make_seq<max-1, max-1, s...> {};
template<unsigned...s> struct make_seq<0,s...>:seq<s...> {};
#define RETURNS(x) ->decltype(x) { return (x); }
template<typename Iterator>
struct simple_range {
Iterator begin;
Iterator end;
typedef Iterator iterator;
};
template<typename Iterator>
auto begin( simple_range<Iterator> r )
RETURNS( r.begin )
template<typename Iterator>
auto end( simple_range<Iterator> r )
RETURNS( r.end )
template<typename... Ranges>
struct cartesian_range {
std::tuple<Ranges...> ranges;
};
// TODO: wrap this in boost iterator fascade:
template<typename... Ranges>
struct cartesian_iterator {
cartesian_range<Ranges...> ranges;
std::tuple<typename Ranges::iterator...> iterators;
explicit cartesian_iterator( typename Ranges::iterator... its ):
iterators(its...)
{}
template<unsigned...s>
auto dereference_helper(seq<s...>)
RETURNS( std::make_tuple( *std::get<s>(iterators)... ) )
auto dereference()
RETURNS( dereference_helper( make_seq<sizeof...(Ranges)>() ) )
bool is_equal( cartesian_iterator<Ranges...> const& o ) {
return iterators == o.iterators;
}
void advance_helper(seq<>) {}
template<unsigned s0, unsigned...s>
void advance_helper(seq<s0, s...>) {
++std::get<s0>(iterators);
auto it0 = std::get<s0>( iterators );
auto end0 = end(std::get<s0>(ranges));
if (it0 == end0)
{
auto begin0 = begin( std::get<s0>(ranges) );
std::get<s0>(iterators) = begin0;
advance_helper( seq<s...>() );
}
}
void advance() {
advance_helper( make_seq<sizeof...(Ranges)>() );
}
};
template<typename... Iterators>
cartesian_iterator<simple_range<Iterators>...> make_cartesian_iterator( Iterators... its )
{
return {its...};
}
template<unsigned... s, typename... Ranges>
auto begin_helper( seq<s...>, cartesian_range<Ranges...> r )
RETURNS( make_cartesian_iterator( begin(std::get<s>(r))... ) )
template<unsigned... s, typename... Ranges>
auto end_helper( seq<s...>, cartesian_range<Ranges...> r )
RETURNS( make_cartesian_iterator( end(std::get<s>(r))... ) )
template<typename... Ranges>
auto begin( cartesian_range<Ranges...> r )
RETURNS( begin_helper( make_seq<sizeof...(Ranges)>(), r ) )
template<typename... Ranges>
auto end( cartesian_range<Ranges...> r )
RETURNS( end_helper( make_seq<sizeof...(Ranges)>(), r ) )