#pragma once #include #include #include #include #include #include "iterator.hpp" namespace stream::detail { template class stream_base_pointer_impl {}; template class stream_base_pointer_impl< T, std::enable_if_t>> { 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 >> C & collect(C & coll) const { std::copy(begin(), end(), std::inserter(coll, coll.end())); return coll; } std::optional first() const { return begin() != end() ? std::optional(*begin()) : std::nullopt; } template bool none(F && pred) const { return std::none_of(begin(), end(), pred); } template bool all(F && pred) const { return std::all_of(begin(), end(), pred); } template bool any(F && pred) const { return std::any_of(begin(), end(), pred); } template value_type accumulate(F && fold, value_type const & accum) const { return std::accumulate(begin(), end(), accum, fold); } template >> std::optional accumulate(F && fold) const { if (empty()) { return std::nullopt; } value_type first = *begin(); return std::accumulate(++begin(), end(), first, 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 &; auto keys() const & { return map([](auto & kv) -> decltype(auto) { return kv.first; }); } auto values() const & { return map([](auto & kv) -> decltype(auto) { return kv.second; }); } 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}; }; }