Created
January 22, 2016 11:10
-
-
Save hidez8891/c9c7acc423f2475a6dec to your computer and use it in GitHub Desktop.
C++ pipe stream
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iterator> | |
#include <type_traits> | |
#include <vector> | |
#include <algorithm> | |
// operator | |
template <typename C, typename F> | |
auto operator| (C c, F f) | |
{ | |
return f(c.begin(), c.end()); | |
} | |
// accumulator | |
template <template <class E, class A = std::allocator<E>> class C> | |
struct to_ | |
{ | |
template <typename Itr, typename T = typename Itr::value_type> | |
C<T> operator() (Itr begin, Itr end) | |
{ | |
C<T> container; | |
std::back_insert_iterator<C<T>> it(container); | |
std::copy(begin, end, it); | |
return container; | |
} | |
}; | |
// accumulator to vector | |
auto to_vec() | |
{ | |
return to_<std::vector>(); | |
} | |
// range :: generator | |
template <typename T> | |
struct range_stream_iterator | |
: public std::iterator<std::input_iterator_tag, T> | |
{ | |
range_stream_iterator(T s, T e) | |
: s(s), e(e) {} | |
range_stream_iterator(const range_stream_iterator& obj) | |
: s(obj.s), e(obj.e) {} | |
auto& operator++() { if(s <= e) ++s; return *this; } | |
auto operator* () { return s; } | |
bool operator== (const range_stream_iterator& obj) { return s == obj.s; } | |
bool operator!= (const range_stream_iterator& obj) { return !(*this == obj); } | |
private: | |
T s, e; | |
}; | |
template <typename T> | |
struct range_stream | |
{ | |
range_stream(T s, T e) | |
: s(s), e(e) {} | |
auto begin() const { return range_stream_iterator<T>(s, e); } | |
auto end() const { return range_stream_iterator<T>(e+1, e); } | |
private: | |
T s, e; | |
}; | |
template <typename T> | |
auto range_(T start, T end) | |
{ | |
return range_stream<T>(start, end); | |
} | |
// map :: partial evaluater | |
template <typename F, typename Itr> | |
struct map_stream_iterator | |
: public std::iterator< | |
std::input_iterator_tag, | |
typename std::result_of<F(typename Itr::value_type)>::type> | |
{ | |
map_stream_iterator(F f, Itr itr1, Itr itr2) | |
: f(f), itr1(itr1), itr2(itr2) {} | |
map_stream_iterator(const map_stream_iterator& obj) | |
: f(obj.f), itr1(obj.itr1), itr2(obj.itr2) {} | |
auto& operator++() { if(itr1 != itr2) ++itr1; return *this; } | |
auto operator* () { return f(*itr1); } | |
bool operator== (const map_stream_iterator& obj) { return itr1 == obj.itr1; } | |
bool operator!= (const map_stream_iterator& obj) { return !(*this == obj); } | |
private: | |
F f; | |
Itr itr1, itr2; | |
}; | |
template <typename F, typename Itr> | |
struct map_stream | |
{ | |
map_stream(F f, Itr itr1, Itr itr2) | |
: f(f), itr1(itr1), itr2(itr2) {} | |
auto begin() const { return map_stream_iterator<F, Itr>(f, itr1, itr2); } | |
auto end() const { return map_stream_iterator<F, Itr>(f, itr2, itr2); } | |
private: | |
F f; | |
Itr itr1, itr2; | |
}; | |
template <typename F> | |
auto map_(F f) | |
{ | |
return [f](auto itr1, auto itr2) { | |
return map_stream<F, decltype(itr1)>(f, itr1, itr2); | |
}; | |
} | |
// select :: partial evaluater | |
template <typename F, typename Itr> | |
struct select_stream_iterator | |
: public std::iterator<std::input_iterator_tag, typename Itr::value_type> | |
{ | |
select_stream_iterator(F f, Itr itr1, Itr itr2) | |
: f(f), itr1(itr1), itr2(itr2) { valid(); } | |
select_stream_iterator(const select_stream_iterator& obj) | |
: f(obj.f), itr1(obj.itr1), itr2(obj.itr2) { valid(); } | |
auto& operator++() { if(itr1 != itr2) { ++itr1; valid(); } return *this; } | |
auto operator* () { return *itr1; } | |
bool operator== (const select_stream_iterator& obj) { return itr1 == obj.itr1; } | |
bool operator!= (const select_stream_iterator& obj) { return !(*this == obj); } | |
void valid() { while (itr1 != itr2 && !f(*itr1)) ++itr1; } | |
private: | |
F f; | |
Itr itr1, itr2; | |
}; | |
template <typename F, typename Itr> | |
struct select_stream | |
{ | |
select_stream(F f, Itr itr1, Itr itr2) | |
: f(f), itr1(itr1), itr2(itr2) {} | |
auto begin() const { return select_stream_iterator<F, Itr>(f, itr1, itr2); } | |
auto end() const { return select_stream_iterator<F, Itr>(f, itr2, itr2); } | |
private: | |
F f; | |
Itr itr1, itr2; | |
}; | |
template <typename F> | |
auto select_(F f) | |
{ | |
return [f](auto itr1, auto itr2) { | |
return select_stream<F, decltype(itr1)>(f, itr1, itr2); | |
}; | |
} | |
// head :: partial evaluater | |
template <typename Itr> | |
struct head_stream | |
{ | |
head_stream(unsigned n, Itr itr1, Itr itr2) | |
: n(n), itr1(itr1), itr2(itr2) {} | |
auto begin() const { return itr1; } | |
auto end() const { | |
auto itr(itr1); | |
for (int i = 0; i < n && itr != itr2; ++i, ++itr); | |
return itr; | |
} | |
private: | |
unsigned n; | |
Itr itr1, itr2; | |
}; | |
auto head_(unsigned n) | |
{ | |
return [n](auto itr1, auto itr2) { | |
return head_stream<decltype(itr1)>(n, itr1, itr2); | |
}; | |
} | |
// take :: partial evaluater | |
auto take_(unsigned n) | |
{ | |
return head_(n); | |
} | |
// take_while :: partial evaluater | |
template <typename F, typename Itr> | |
struct take_while_stream | |
{ | |
take_while_stream(F f, Itr itr1, Itr itr2) | |
: f(f), itr1(itr1), itr2(itr2) {} | |
auto begin() const { return itr1; } | |
auto end() const { | |
auto itr(itr1); | |
while (itr != itr2 && f(*itr)) ++itr; | |
return itr; | |
} | |
private: | |
F f; | |
Itr itr1, itr2; | |
}; | |
template <typename F> | |
auto take_while_(F f) | |
{ | |
return [f](auto itr1, auto itr2) { | |
return take_while_stream<F, decltype(itr1)>(f, itr1, itr2); | |
}; | |
} | |
// drop :: partial evaluater | |
template <typename Itr> | |
struct drop_stream | |
{ | |
drop_stream(unsigned n, Itr itr1, Itr itr2) | |
: n(n), itr1(itr1), itr2(itr2) {} | |
auto begin() const { | |
auto itr(itr1); | |
for (int i = 0; i < n && itr != itr2; ++i, ++itr); | |
return itr; | |
} | |
auto end() const { return itr2; } | |
private: | |
unsigned n; | |
Itr itr1, itr2; | |
}; | |
auto drop_(unsigned n) | |
{ | |
return [n](auto itr1, auto itr2) { | |
return drop_stream<decltype(itr1)>(n, itr1, itr2); | |
}; | |
} | |
// drop_while :: partial evaluater | |
template <typename F, typename Itr> | |
struct drop_while_stream | |
{ | |
drop_while_stream(F f, Itr itr1, Itr itr2) | |
: f(f), itr1(itr1), itr2(itr2) {} | |
auto begin() const { | |
auto itr(itr1); | |
while (itr != itr2 && f(*itr)) ++itr; | |
return itr; | |
} | |
auto end() const { return itr2; } | |
private: | |
F f; | |
Itr itr1, itr2; | |
}; | |
template <typename F> | |
auto drop_while_(F f) | |
{ | |
return [f](auto itr1, auto itr2) { | |
return drop_while_stream<F, decltype(itr1)>(f, itr1, itr2); | |
}; | |
} | |
// tail :: partial evaluater | |
auto tail_(unsigned n) | |
{ | |
return [n](auto itr1, auto itr2) { | |
auto n2 = std::distance(itr1, itr2) - n; | |
if (n2 < 0) n2 = 0; | |
return drop_stream<decltype(itr1)>(n2, itr1, itr2); | |
}; | |
} | |
// each :: whole evaluater | |
template <typename F> | |
auto each_(F f) | |
{ | |
return [f](auto itr1, auto itr2) { | |
std::vector<typename decltype(itr1)::value_type> v(itr1, itr2); | |
std::for_each(v.begin(), v.end(), f); | |
return v; | |
}; | |
} | |
// sort :: whole evaluater | |
auto sort_() | |
{ | |
return [](auto itr1, auto itr2) { | |
std::vector<typename decltype(itr1)::value_type> v(itr1, itr2); | |
std::sort(v.begin(), v.end()); | |
return v; | |
}; | |
} | |
// reverse :: whole evaluater | |
auto reverse_() | |
{ | |
return [](auto itr1, auto itr2) { | |
std::vector<typename decltype(itr1)::value_type> v(itr1, itr2); | |
std::reverse(v.begin(), v.end()); | |
return v; | |
}; | |
} | |
/************************************** | |
test code | |
***************************************/ | |
#include <boost/lambda/lambda.hpp> | |
#include <iostream> | |
using boost::lambda::_1; | |
int main() | |
{ | |
// select odd, take 5 | |
range_(1, 10000) | |
| select_(_1 % 2 == 1) | |
| take_(5) | |
| each_(std::cout << _1 << "\n"); | |
// get 5th - 9th number | |
range_(1, 10000) | |
| map_(_1 * 2) | |
| head_(9) | |
| drop_(4) | |
| each_(std::cout << _1 << "\n"); | |
// use foreach | |
auto r = range_(1, 10000) | |
| map_(_1 * 2) | |
| head_(9) | |
| drop_(4); | |
std::for_each(r.begin(), r.end(), std::cout << _1 << "\n"); | |
// to save vector | |
auto v = r | to_vec(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment