#pragma once namespace stream { namespace detail { namespace filter { template class iterator { public: iterator(std::function f, ::stream::iterator && impl, ::stream::iterator && end) : pred_(f), impl_(std::forward<::stream::iterator>(impl)), end_(std::forward<::stream::iterator>(end)) { advance(); } T operator*() { return mem_; } iterator & operator++() { ++impl_; advance(); return *this; } DELEGATE_ITERATOR_IMPL_BASE(impl_) private: void advance() { while (impl_ != end_ && !pred_(mem_ = *impl_)) { ++impl_; } } std::function pred_; ref_or_val mem_; // To avoid re-calcs, we store this ::stream::iterator impl_, end_; }; } template class filter_stream { public: template filter_stream(F && func, stream_base const & sb) : pred_(func), source_(sb) {} iterator begin() { return {filter::iterator{pred_, source_.begin(), source_.end()}}; } iterator end() { return {filter::iterator{pred_, source_.end(), source_.end()}}; } private: std::function pred_; stream_base source_; }; template template auto stream_base::filter(F && pred) && -> stream_base { return std::make_shared>(pred, std::move(*this)); } template template auto stream_base::filter(F && pred) const & -> stream_base { return std::make_shared>(pred, *this); } }}