Skip to content

Instantly share code, notes, and snippets.

@xlc
Last active December 30, 2015 10:49
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 xlc/7818599 to your computer and use it in GitHub Desktop.
Save xlc/7818599 to your computer and use it in GitHub Desktop.
#include <vector>
#include <iostream>
#include <utility>
#include <functional>
#include <type_traits>
#include <memory>
namespace xlc
{
template <class TIterator, class TSelectFunc>
class SelectIterator
{
private:
TIterator _it;
TSelectFunc _func;
public:
SelectIterator(TIterator const & it, TSelectFunc const & func)
: _it(it), _func(func) {}
SelectIterator(SelectIterator const &other)
:_it(other._it), _func(other._func) {}
decltype(_func(*_it)) operator*()
{
return _func(*_it);
}
SelectIterator & operator++()
{
++_it;
return *this;
}
bool operator!=(SelectIterator const & other)
{
return _it != other._it;
}
};
template <class TIterator, class TWhereFunc>
class WhereIterator
{
using value_type = typename std::remove_reference<decltype(*TIterator())>::type;
private:
TIterator _it;
TIterator _end;
TWhereFunc _func;
std::unique_ptr<value_type> _val;
public:
WhereIterator(TIterator const & it, TIterator const & end, TWhereFunc const & func)
: _it(it), _end(end), _func(func), _val()
{}
WhereIterator(WhereIterator const &other)
:_it(other._it), _end(other._end), _func(other._func), _val()
{}
value_type operator*()
{
validate();
return *_val;
}
WhereIterator & operator++()
{
++_it;
validate(true);
return *this;
}
bool operator!=(WhereIterator const & other)
{
validate();
return _it != other._it;
}
private:
void validate(bool force = false)
{
if (_val && !force)
return;
while (_it != _end)
{
_val.reset(new value_type(*_it));
if (_func(*_val))
{
break;
}
++_it;
}
}
};
template <class TContainer, class TIteratorBuilder>
class Range
{
private:
TContainer _container;
TIteratorBuilder _builder;
public:
using container_iterator_type = decltype(std::begin(_container));
using iterator_type = typename std::decay< decltype(std::get<0>(_builder(std::tuple<container_iterator_type, container_iterator_type>()))) >::type;
private:
std::unique_ptr<iterator_type> _begin;
std::unique_ptr<iterator_type> _end;
void lazyInit()
{
if (_begin && _end) return;
auto result = _builder(std::make_tuple(std::begin(_container), std::end(_container)));
_begin.reset(new iterator_type(std::get<0>(result)));
_end.reset(new iterator_type(std::get<1>(result)));
}
public:
Range(TContainer && container, TIteratorBuilder && builder)
:_container(std::move(container)), _builder(std::move(builder)), _begin(), _end() {}
iterator_type begin()
{
lazyInit();
return *_begin;
}
iterator_type end()
{
lazyInit();
return *_end;
}
template <class TSelectFunc>
auto select(TSelectFunc const & func)
{
auto builder = _builder;
auto newbuilder = [builder, func](std::tuple<container_iterator_type, container_iterator_type> its) {
auto its2 = builder(its);
auto begin = std::get<0>(its2);
auto end = std::get<1>(its2);
return std::make_tuple(
SelectIterator<iterator_type, TSelectFunc>(begin, func),
SelectIterator<iterator_type, TSelectFunc>(end, func)
);
};
return Range<TContainer, decltype(newbuilder)>{ std::move(_container), std::move(newbuilder) };
}
template <class TWhereFunc>
auto where(TWhereFunc const & func)
{
auto builder = _builder;
auto newbuilder = [builder, func](std::tuple<container_iterator_type, container_iterator_type> its) {
auto its2 = builder(its);
auto begin = std::get<0>(its2);
auto end = std::get<1>(its2);
return std::make_tuple(
WhereIterator<iterator_type, TWhereFunc>(begin, end, func),
WhereIterator<iterator_type, TWhereFunc>(end, end, func)
);
};
return Range<TContainer, decltype(newbuilder)>{ std::move(_container), std::move(newbuilder) };
}
};
template <class TContainer>
auto from(TContainer container)
{
using TIterator = decltype(std::begin(container));
auto builder = [](std::tuple<TIterator, TIterator> its){ return its; };
return Range<TContainer, decltype(builder)>{ std::move(container), std::move(builder) };
}
}
int main()
{
std::vector<int> vec = {1,2,3,4,5};
auto r = xlc::from(vec)
.where([](int i){return i % 2;})
.select([](int i){return i * i;})
.select([](int i){return static_cast<char>(i + 'a');})
;
for(auto i : r)
std::cout << i << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment