Last active
December 30, 2015 10:49
-
-
Save xlc/7818599 to your computer and use it in GitHub Desktop.
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 <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