Created
February 6, 2018 03:46
-
-
Save badocelot/f0e36065853f7914489f79ac7b3061d8 to your computer and use it in GitHub Desktop.
Linq-like classes in C++ (exercise)
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 <iostream> | |
#include <string> | |
#include <vector> | |
template <typename InputIt> class From; | |
template <typename InputIt, typename OutType, typename InType> class Select; | |
template <typename InputIt, typename ItemType> class Where; | |
template <typename InputIt, typename OutType, typename InType> | |
class Select | |
{ | |
const InputIt _first; | |
const InputIt _last; | |
const std::function<OutType(InType)> _fn; | |
public: | |
class iterator | |
{ | |
const InputIt& _last; | |
const std::function<OutType(InType)>& _fn; | |
InputIt _current; | |
public: | |
iterator(InputIt current, const InputIt& last, | |
const std::function<OutType(InType)>& fn) | |
: _current{current}, _last{last}, _fn{fn} | |
{ | |
} | |
OutType operator*() | |
{ | |
return _fn(*_current); | |
} | |
iterator& operator++() | |
{ | |
if (_current != _last) | |
{ | |
++_current; | |
} | |
return *this; | |
} | |
iterator operator++(int) | |
{ | |
iterator it{*this}; | |
++(*this); | |
return it; | |
} | |
bool operator==(const iterator& it) | |
{ | |
return _current == it._current; | |
} | |
bool operator!=(const iterator& it) | |
{ | |
return _current != it._current; | |
} | |
}; | |
Select(InputIt first, InputIt last, std::function<OutType(InType)> fn) | |
: _first{first}, _last{last}, _fn{fn} | |
{} | |
iterator begin() { return iterator(_first, _last, _fn); } | |
iterator end() { return iterator(_last, _last, _fn); } | |
template <typename OutType2> | |
auto select(std::function<OutType2(OutType)> fn) | |
{ | |
return Select<iterator, OutType2, OutType>(begin(), end(), fn); | |
} | |
template <typename ItemType> | |
auto where(std::function<bool(ItemType)> fn) const | |
{ | |
return Where<iterator, ItemType>(begin(), end(), fn); | |
} | |
}; | |
template <typename InputIt, typename ItemType> | |
class Where | |
{ | |
const InputIt _first; | |
const InputIt _last; | |
const std::function<bool(ItemType)> _fn; | |
public: | |
class iterator | |
{ | |
const InputIt& _last; | |
const std::function<bool(ItemType)>& _fn; | |
InputIt _current; | |
public: | |
iterator(InputIt current, const InputIt& last, | |
const std::function<bool(ItemType)>& fn) | |
: _current{current}, _last{last}, _fn{fn} | |
{ | |
// move automatically to first value to be served | |
if (!_fn(*_current)) | |
{ | |
++(*this); | |
} | |
} | |
ItemType& operator*() | |
{ | |
return *_current; | |
} | |
iterator& operator++() | |
{ | |
if (_current != _last) | |
{ | |
do | |
{ | |
++_current; | |
} | |
while (_current != _last && !_fn(*_current)); | |
} | |
return *this; | |
} | |
iterator operator++(int) | |
{ | |
iterator it{*this}; | |
++(*this); | |
return it; | |
} | |
bool operator==(const iterator& it) | |
{ | |
return _current == it._current; | |
} | |
bool operator!=(const iterator& it) | |
{ | |
return _current != it._current; | |
} | |
}; | |
Where(InputIt first, InputIt last, std::function<bool(ItemType)> fn) | |
: _first{first}, _last{last}, _fn{fn} | |
{} | |
iterator begin() const { return iterator(_first, _last, _fn); } | |
iterator end() const { return iterator(_last, _last, _fn); } | |
template <typename OutType> | |
auto select(std::function<OutType(ItemType)> fn) | |
{ | |
return Select<iterator, OutType, ItemType>(begin(), end(), fn); | |
} | |
template <typename ItemType2> | |
auto where(std::function<bool(ItemType2)> fn) const | |
{ | |
return Where<iterator, ItemType2>(begin(), end(), fn); | |
} | |
}; | |
template <typename InputIt> | |
class From | |
{ | |
public: | |
using iterator = InputIt; | |
private: | |
const InputIt _first; | |
const InputIt _last; | |
public: | |
From(InputIt first, InputIt last) : _first{first}, _last{last} {} | |
InputIt begin() const { return _first; } | |
InputIt end() const { return _last; } | |
template <typename OutType, typename InType> | |
auto select(std::function<OutType(InType)> fn) | |
{ | |
return Select<iterator, OutType, InType>(begin(), end(), fn); | |
} | |
template <typename ItemType> | |
auto where(std::function<bool(ItemType)> fn) const | |
{ | |
return Where<InputIt, ItemType>(begin(), end(), fn); | |
} | |
}; | |
template <typename InputIt> | |
auto from(InputIt first, InputIt last) | |
{ | |
return From<InputIt>(first, last); | |
} | |
int main() | |
{ | |
std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; | |
auto even_nums = from(v.begin(), v.end()) | |
.where<int>([](int x) { return x % 2 == 0; }); | |
auto messages = even_nums | |
.select<std::string>([](const int& x) { | |
return std::to_string(x) + " is even"; | |
}); | |
for (auto x : even_nums) | |
{ | |
std::cout << x << "\n"; | |
} | |
for (auto x : messages) | |
{ | |
std::cout << x << "\n"; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment