Skip to content

Instantly share code, notes, and snippets.

@k06a
Last active June 28, 2019 17:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save k06a/293a9582eac542aaf6fe2aa42cbd3714 to your computer and use it in GitHub Desktop.
Save k06a/293a9582eac542aaf6fe2aa42cbd3714 to your computer and use it in GitHub Desktop.
boolinq3.cpp
#include <functional>
#include <iterator>
#include <iostream>
#include <vector>
#include <list>
#include <unordered_set>
//
struct LinqEndException {};
template<typename S, typename T>
class Linq {
std::function<T(S&)> nextFunc;
S storage;
public:
typedef T value_type;
Linq()
: nextFunc()
, storage()
{
}
Linq(S storage, std::function<T(S&)> nextFunc)
: nextFunc(nextFunc)
, storage(storage)
{
}
T next() {
return nextFunc(storage);
}
template<typename SS, typename TTRet>
struct LinqIndex {
Linq<SS,TTRet> linq;
int index;
};
void foreach_i(std::function<void(T,int)> apply) const {
LinqIndex<S,T> storage = {*this, 0};
try {
while (true) {
apply(storage.linq.next(), storage.index++);
}
}
catch (LinqEndException&) {}
}
void foreach(std::function<void(T)> apply) const {
return foreach_i([apply](T && value, int index){return apply(value);});
}
Linq<LinqIndex<S,T>,T> where_i(std::function<bool(T,int)> filter) const {
return Linq<LinqIndex<S,T>,T>(
{*this, 0},
[filter](auto & pair){
while (true) {
T ret = pair.linq.next();
if (filter(ret, pair.index++)) {
return ret;
}
}
}
);
}
Linq<LinqIndex<S,T>,T> where(std::function<bool(T)> filter) const {
return where_i([filter](T && value, int index){return filter(value);});
}
Linq<LinqIndex<S,T>,T> take(int count) const {
return where_i([count](T /*value*/, int i) {
if (i == count) {
throw LinqEndException();
}
return true;
});
}
Linq<LinqIndex<S,T>,T> takeWhile_i(std::function<bool(T,int)> predicate) const {
return where_i([predicate](T && value, int i) {
if(!predicate(value, i)) {
throw LinqEndException();
}
return true;
});
}
Linq<LinqIndex<S,T>,T> takeWhile(std::function<bool(T)> predicate) const {
return takeWhile_i([predicate](T && value, int /*i*/){return predicate(value);});
}
Linq<LinqIndex<S,T>,T> skip(int count) const {
return where_i([count](T && value, int i){return i >= count;});
}
template<typename SS, typename TTRet>
struct LinqIndexFlag : public LinqIndex<SS,TTRet> {
bool flag;
};
Linq<LinqIndexFlag<S,T>,T> skipWhile_i(std::function<bool(T,int)> predicate) const {
return Linq<LinqIndex<S,T>,T>(
{*this, 0, false},
[predicate](auto & tuple){
if (tuple.flag) {
return tuple.linq.next();
}
while (true) {
T ret = tuple.linq.next();
if (predicate(ret, tuple.index++)) {
return ret;
}
}
}
);
}
Linq<LinqIndexFlag<S,T>,T> skipWhile(std::function<bool(T)> predicate) const {
return skipWhile_i([predicate](T && value, int /*i*/){ return predicate(value);});
}
template<typename F>
auto select_i(F apply) const -> Linq<LinqIndex<S,T>,typename std::result_of<F(T,int)>::type> {
typedef typename std::result_of<F(T,int)>::type TRet;
return Linq<LinqIndex<S,T>,TRet>(
{*this,0},
[apply](auto & pair){
return apply(pair.linq.next(), pair.index++);
}
);
}
template<typename F>
auto select(F apply) const -> Linq<LinqIndex<S,T>,typename std::result_of<F(T)>::type> {
return select_i([apply](T && value, int index){return apply(value);});
}
template<typename TRet>
Linq<Linq<S,T>,TRet> cast() const {
return select([](T && value){return TRet(value);});
}
template<typename SS, typename TTRet, typename TCurrent>
struct LinqCurrentIndexFinished {
Linq<SS,TTRet> linq;
TCurrent current;
int index;
bool finished;
};
template<typename F>
auto selectMany_i(F apply) const -> Linq<LinqCurrentIndexFinished<S, T, typename std::result_of<F(T,int)>::type>,typename std::result_of<F(T,int)>::type::value_type> {
typedef typename std::result_of<F(T,int)>::type TCurrent;
typedef typename TCurrent::value_type TRet;
return Linq<LinqCurrentIndexFinished<S,T,TCurrent>,TRet>(
{*this,TCurrent(),0,true},
[apply](auto & tuple){
while (true) {
if (tuple.finished) {
tuple.current = apply(tuple.linq.next(), tuple.index++);
tuple.finished = false;
}
try {
return tuple.current.next();
}
catch(LinqEndException &) {
tuple.finished = true;
}
}
}
);
}
template<typename F>
auto selectMany(F apply) const -> Linq<LinqCurrentIndexFinished<S, T, typename std::result_of<F(T)>::type>,typename std::result_of<F(T)>::type::value_type> {
return selectMany_i([apply](T && value, int index){return apply(value);});
}
template<typename SS, typename TTRet, typename TTRet2>
struct LinqUnorderedSet {
Linq<SS,TTRet> linq;
std::unordered_set<TTRet2> set;
};
template<typename TRet>
Linq<LinqUnorderedSet<S,T,TRet>,T> distinct(std::function<TRet(T)> transform) const {
return Linq<LinqUnorderedSet<S,T,TRet>,T>(
{*this,std::unordered_set<TRet>()},
[transform](auto & tuple) {
while (true) {
T value = tuple.linq.next();
if (tuple.set.insert(transform(value)).second) {
return value;
}
}
}
);
}
Linq<LinqUnorderedSet<S,T,T>,T> distinct() const {
return distinct([](T && value){return value;});
}
template<typename TTRet>
struct StdVectorAndIterator {
std::vector<TTRet> vec;
typename std::vector<TTRet>::iterator it;
};
template<typename F>
Linq<StdVectorAndIterator<T>,T> orderBy(F transform) const {
typedef typename std::vector<T>::iterator TIter;
std::vector<T> items = toStdVector();
std::sort(items.begin(), items.end(), [transform](const T & a, const T & b) {
return transform(a) < transform(b);
});
return Linq<StdVectorAndIterator<T>,T>(
{items,TIter()},
[](auto & tuple){
if (tuple.it == TIter()) {
tuple.it = tuple.vec.begin();
}
if (tuple.it == tuple.vec.end()) {
throw LinqEndException();
}
return *(tuple.it++);
}
);
}
Linq<StdVectorAndIterator<T>,T> orderBy() const {
return orderBy([](T && value){return value;});
}
template<typename TTRet>
struct StdListAndReverseIterator {
std::list<TTRet> list;
typename std::list<TTRet>::reverse_iterator it;
};
Linq<StdListAndReverseIterator<T>,T> reverse() const {
typedef typename std::list<T>::reverse_iterator TIter;
std::list<T> items = toStdList();
return Linq<StdListAndReverseIterator<T>,T>(
{items,TIter()},
[](auto & tuple){
if (tuple.it == TIter()) {
tuple.it = tuple.list.rbegin();
}
if (tuple.it == tuple.list.rend()) {
throw LinqEndException();
}
return *(tuple.it++);
}
);
}
// Aggregators
template<typename TRet>
TRet aggregate(TRet start, std::function<TRet(TRet,T)> accumulate) const {
Linq<S,T> linq = *this;
try
{
while (true) {
start = accumulate(start, linq.next());
}
}
catch (LinqEndException &) {}
return start;
}
template<typename F>
auto sum(F transform) const -> typename std::result_of<F(T,T)>::type {
return aggregate<T>(T(), [transform](T accumulator, T && value){
return accumulator + transform(value);
});
}
template<typename F>
auto avg(F transform) const -> typename std::result_of<F(T,T)>::type {
int count = 0;
T res = sum([transform,&count](T && value){
count++;
return value;
});
return res / count;
}
int count() const {
int index = 0;
foreach([&index](T && /**/a){index++;});
return index;
}
int count(std::function<bool(T)> predicate) const {
return where(predicate).count();
}
int count(const T & item) const {
return count([item](T && value){return item == value;});
}
// Bool aggregators
bool any(std::function<bool(T)> predicate) const {
Linq<S,T> linq = *this;
try {
while (true) {
if (predicate(linq.nextObject()))
return true;
}
}
catch(LinqEndException &) {}
return false;
}
bool any() const {
return any([](T && value){return static_cast<bool>(value);});
}
bool all(std::function<bool(T)> predicate) const {
return !any([predicate](T && value){return !predicate(value);});
}
bool all() const {
return all([](T && value){return static_cast<bool>(value);});
}
bool contains(const T & item) const {
return any([&item](T && value){return value == item;});
}
// Election aggregators
T elect(std::function<T(T,T)> accumulate) const {
Linq<S,T> linq = *this;
T result;
try {
result = linq.next();
while (true) {
result = accumulate(result, linq.next());
}
}
catch(LinqEndException &) {}
return result;
}
template<typename F>
T max(F transform) const {
return elect([transform](const T & a, const T & b){
return (transform(a) < transform(b)) ? b : a;
});
}
T max() const {
return max([](T && value){return value;});
}
template<typename F>
T min(F transform) const {
return elect([transform](const T & a, const T & b){
return (transform(a) < transform(b)) ? a : b;
});
}
T min() const {
return min([](T && value){return value;});
}
// Single object returners
T elementAt(int index) const {
return skip(index - 1).next();
}
T first(std::function<bool(T)> predicate) const {
return where(predicate).next();
}
T first() const {
return next();
}
T firstOrDefault(std::function<bool(T)> predicate) const {
try {
return where(predicate).next();
}
catch(LinqEndException &) {}
return T();
}
T firstOrDefault() const {
firstOrDefault([](T && /*value*/){return true;});
}
T last(std::function<bool(T)> predicate) const {
T res;
foreach([&res](T && value){
res = value;
});
return res;
}
T last() const {
return last([](T && /*value*/){return true;});
}
T lastOrDefault(std::function<bool(T)> predicate) const {
try {
return last(predicate);
}
catch(LinqEndException &) {}
return T();
}
T lastOrDefault() const {
return lastOrDefault([](T && /*value*/){return true;});
}
// Export to containers
std::vector<T> toStdVector() const {
std::vector<T> items;
foreach([&items](T && value){
items.push_back(value);
});
return items;
}
std::list<T> toStdList() const {
std::list<T> items;
foreach([&items](T && value){
items.push_back(value);
});
return items;
}
};
//
template<typename T>
Linq<std::pair<T,T>,typename std::iterator_traits<T>::value_type> make_linq(T begin, T end) {
return Linq<std::pair<T,T>,typename std::iterator_traits<T>::value_type>(
{begin, end},
[](auto & pair) {
if (pair.first < pair.second) {
return *(pair.first++);
}
throw LinqEndException();
}
);
}
template<typename T, int N>
Linq<std::pair<T*,T*>,T> make_linq(T (&array)[N]) {
return make_linq((T*)(&array), (T*)(&array) + N);
}
template<typename T>
Linq<std::pair<T,int>,T> repeat_linq(T value, int count) {
return Linq<std::pair<T,int>,T>(
{value, count},
[](auto & pair) {
if (pair.second > 0) {
pair.second--;
return pair.first;
}
throw LinqEndException();
}
);
}
template<typename T>
Linq<std::pair<std::pair<T,T>,T>,T> range_linq(T start, T count, T step) {
return Linq<std::pair<std::pair<T,T>,T>,T>(
{start, {count, step}},
[](auto & pair) {
if (pair.first.first < pair.first.second) {
return *(pair.first.first += pair.second);
}
throw LinqEndException();
}
);
}
//
template<typename S, typename T>
std::ostream & operator << (std::ostream & stream, Linq<S,T> linq) {
try {
while (true) {
stream << linq.next() << ' ';
}
}
catch(LinqEndException &) {}
return stream;
}
// To execute C++, please define "int main()"
int main() {
std::vector<int> values = { 1,2,3,4,5,6,7,8 };
auto q = make_linq(values.begin(), values.end());
std::cout << repeat_linq(3,3) << std::endl;
std::cout << repeat_linq(7,7) << std::endl;
std::cout << q << std::endl;
std::cout << q
.selectMany([](int a){return repeat_linq(a,a);})
<< std::endl;
std::cout << q
.where([](int a){return a%2==0;})
<< std::endl;
std::cout << q
.where([](int a){return a%2==0;})
.select([](int a){return a/2;})
<< std::endl;
std::cout << q
.where([](int a){return a%2==0;})
.select([](int a){return a/2;})
.orderBy([](int a){return -a;})
<< std::endl;
std::cout << q
.where([](int a){return a%2==0;})
.select([](int a){return a/2;})
.orderBy([](int a){return -a;})
.selectMany([](int a){return repeat_linq(a,a);})
<< std::endl;
std::cout << q
.where([](int a){return a%2==0;})
.select([](int a){return a/2;})
.orderBy([](int a){return -a;})
.selectMany([](int a){return repeat_linq(a,a);})
.reverse()
<< std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment