Last active
June 28, 2019 17:21
-
-
Save k06a/293a9582eac542aaf6fe2aa42cbd3714 to your computer and use it in GitHub Desktop.
boolinq3.cpp
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 <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