Skip to content

Instantly share code, notes, and snippets.

@badocelot
Created February 6, 2018 03:46
Show Gist options
  • Save badocelot/f0e36065853f7914489f79ac7b3061d8 to your computer and use it in GitHub Desktop.
Save badocelot/f0e36065853f7914489f79ac7b3061d8 to your computer and use it in GitHub Desktop.
Linq-like classes in C++ (exercise)
#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