#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(); } ~iterator() {} 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 stream_impl { public: template filter_stream(F&& func, stream_base const& sb) : pred_(func), source_(sb) {} ~filter_stream() override {} iterator begin() override { return {filter::iterator{pred_, source_.begin(), source_.end()}}; } iterator end() override { return {filter::iterator{pred_, source_.end(), source_.end()}}; } private: std::function pred_; stream_base source_; }; template template auto stream_base::filter(F&& pred) const -> stream_base { using impl_t = filter_stream; return {std::make_shared(pred, *this)}; } } }