#pragma once #include #include #include #include #define DELEGATE_ITERATOR_IMPL_BASE(impl) \ bool operator==(iterator const & other) const { return impl == other.impl; } #define DELEGATE_ITERATOR_IMPL(impl) \ DELEGATE_ITERATOR_IMPL_BASE(impl) \ iterator & operator++() { \ ++impl; \ return *this; \ } namespace stream { #define STREAM_ITERATOR_COPY() \ copy(other.copy), dereference(other.dereference), compare(other.compare), \ destroy(other.destroy), advance(other.advance), type_(other.type_) template class iterator { public: using value_type = typename std::remove_reference::type; using reference = value_type &; using pointer = value_type *; using difference_type = std::ptrdiff_t; using iterator_category = std::forward_iterator_tag; public: iterator() = default; template iterator(Iter impl) { copy = [](void * p) { return (void *)new Iter(*(Iter *)(p)); }; dereference = [](void * p) -> T { return **((Iter *)p); }; compare = [](void * l, void * r) { return *((Iter *)l) == *((Iter *)r); }; destroy = [](void * p) { delete (Iter *)(p); }; advance = [](void * p) { ++(*(Iter *)(p)); }; type_ = typeid(Iter).name(); impl_ = copy(&impl); } iterator(iterator const & other) : STREAM_ITERATOR_COPY(), impl_(copy(other.impl_)) {} iterator(iterator && other) : STREAM_ITERATOR_COPY(), impl_(other.impl_) { other.impl_ = nullptr; } iterator & operator=(iterator const & other) { return *this = iterator{other}; } iterator & operator=(iterator && other) { swap(*this, other); return *this; } ~iterator() { if (destroy) destroy(impl_); } T operator*() const { return dereference(impl_); } iterator & operator++() { advance(impl_); return *this; } bool operator==(iterator const & other) const { if (strcmp(type_, other.type_)) { return false; } return compare(impl_, other.impl_); } bool operator!=(iterator const & other) const { if (strcmp(type_, other.type_)) { return false; } return !compare(impl_, other.impl_); } private: friend void swap(iterator & lhs, iterator & rhs) { using std::swap; swap(lhs.copy, rhs.copy); swap(lhs.dereference, rhs.dereference); swap(lhs.compare, rhs.compare); swap(lhs.destroy, rhs.destroy); swap(lhs.advance, rhs.advance); swap(lhs.type_, rhs.type_); swap(lhs.impl_, rhs.impl_); } using delegate = void (*)(void *); void * (*copy)(void *){nullptr}; T (*dereference)(void *){nullptr}; bool (*compare)(void *, void *){nullptr}; delegate destroy{nullptr}, advance{nullptr}; char const * type_{nullptr}; void * impl_{nullptr}; }; namespace detail { template class stream_base_pointer_impl {}; template class stream_base_pointer_impl< T, typename std::enable_if::value>::type> { private: using self_t = stream_base; using pointer = typename std::remove_reference::type; using element_type = typename std::pointer_traits::element_type; public: auto deref() const & -> stream_base { return static_cast(this)->map( [](T const & p) -> element_type & { return *p; }); } auto deref() && -> stream_base { return static_cast(*this).map( [](T const & p) -> element_type & { return *p; }); } }; template class stream_base : public stream_base_pointer_impl { private: using value_type = typename std::decay::type; public: template stream_base(std::shared_ptr && impl) { do_begin = [](std::shared_ptr p) -> iterator { return std::static_pointer_cast(p)->begin(); }; do_end = [](std::shared_ptr p) -> iterator { return std::static_pointer_cast(p)->end(); }; impl_ = std::static_pointer_cast(impl); } ::stream::iterator begin() const { return do_begin(impl_); } ::stream::iterator end() const { return do_end(impl_); } bool empty() const { return begin() == end(); } std::vector collect() const { std::vector coll; collect(coll); return coll; } template ::value, void>::type> C & collect(C & coll) const { std::copy(begin(), end(), std::inserter(coll, coll.end())); return coll; } template value_type accumulate(F && fold, value_type const & accum) const { return std::accumulate(begin(), end(), accum, fold); } value_type accumulate(value_type const & accum) const { return std::accumulate(begin(), end(), accum); } template void each(F && consumer) const { std::for_each(begin(), end(), consumer); } template stream_base> map(F && func) const &; template stream_base filter(F && func) const &; template stream_base> flatmap(F && func) const &; template stream_base> map(F && func) &&; template stream_base filter(F && func) &&; template stream_base> flatmap(F && func) &&; template stream_base cast() const & { return map([](T const & p) -> Cast const & { return p; }); } template stream_base cast() && { return std::move(*this).map( [](T const & p) -> Cast const & { return p; }); } template > stream_base> map(F && memvar) const & { return map(map_member_object{memvar}); } template > stream_base> map(F && memvar) const & { return map(map_member_function{memvar}); } template > stream_base> map(F && memvar) && { return std::move(*this).map(map_member_object{memvar}); } template > stream_base> map(F && memvar) && { return std::move(*this).map(map_member_function{memvar}); } private: iterator (*do_begin)(std::shared_ptr){nullptr}; iterator (*do_end)(std::shared_ptr){nullptr}; std::shared_ptr impl_{nullptr}; }; } }