#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); } } }