#include <cstdio>
#include <cassert>
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template<class RangeType>
struct range_iterator
{
RangeType* _range;
bool operator!=(const range_iterator<RangeType>& that) const {
assert(_range == that._range);
return !_range->empty();
}
void operator++() {
_range->popFront();
}
typename RangeType::value_type operator*() const {
return _range->front();
}
};
template<class T>
struct iota
{
typedef T value_type;
T first;
T last;
iota(T first, T last)
: first(first), last(last) {}
T front() const {
return first;
}
void popFront() {
++first;
}
bool empty() const {
return first == last;
}
typedef range_iterator<iota<T>> iterator;
iterator begin() { return iterator{this}; }
iterator end() { return iterator{this}; }
template<template<class InputRange> class RTy, class... Args>
RTy<iota<T>> to(Args... args) {
return RTy<iota<T>>(*this, args...);
}
};
template<class R>
struct take
{
typedef typename R::value_type value_type;
R r;
int count;
take(R r, int count)
: r(r), count(count){}
value_type front() const {
return r.front();
}
void popFront() {
--count;
r.popFront();
}
bool empty() const {
return r.empty() || count == 0;
}
typedef range_iterator<take<R>> iterator;
iterator begin() { return iterator{this}; }
iterator end() { return iterator{this}; }
template<template<class InputRange> class RTy, class... Args>
RTy<take<R>> to(Args... args) {
return RTy<take<R>>(*this, args...);
}
};
template<class R>
struct filter
{
typedef typename R::value_type value_type;
R r;
function<bool(value_type)> pred;
filter(R r, const function<bool(value_type)> &pred)
: r(r), pred(pred)
{
while(!r.empty() && !pred(r.front())) {
r.popFront();
}
}
value_type front() const {
return r.front();
}
void popFront() {
r.popFront();
while(!r.empty() && !pred(r.front())) {
r.popFront();
}
}
bool empty() const {
return r.empty();
}
typedef range_iterator<filter<R>> iterator;
iterator begin() { return iterator{this}; }
iterator end() { return iterator{this}; }
};
int main(int argc, const char * argv[])
{
auto r = iota<int>(0, 10)
.to<take>(6)
.to<filter>([](int x){ return !(x % 2); });
for(int x : r)
printf("%d ", x);
return 0;
}