filter.hpp 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #pragma once
  2. namespace stream { namespace detail {
  3. template <typename T>
  4. struct ref_or_val {
  5. ref_or_val operator=(T && val) { value = std::move(val); return *this; }
  6. operator T const &() const { return value; }
  7. T value;
  8. };
  9. template <typename T>
  10. struct ref_or_val<T&> {
  11. ref_or_val operator=(T & val) { value = &val; return *this; }
  12. operator T &() const { return *value; }
  13. T * value;
  14. };
  15. namespace filter {
  16. template <typename T>
  17. class iterator : public iterator_impl<T> {
  18. public:
  19. typedef iterator_impl<T> super;
  20. iterator(std::function<bool(T const&)> f, ::stream::iterator<T>&& impl, ::stream::iterator<T>&& end)
  21. : pred_(f)
  22. , impl_(std::forward<::stream::iterator<T>>(impl))
  23. , end_(std::forward<::stream::iterator<T>>(end)) {
  24. advance();
  25. }
  26. ~iterator() {}
  27. T operator*() override { return mem_; }
  28. super& operator++() override {
  29. ++impl_;
  30. advance();
  31. return *this;
  32. }
  33. DELEGATE_ITERATOR_IMPL_BASE(impl_)
  34. private:
  35. void advance() {
  36. while (impl_ != end_ && !pred_(mem_ = *impl_)) {
  37. ++impl_;
  38. }
  39. }
  40. std::function<bool(T const&)> pred_;
  41. ref_or_val<T> mem_; // To avoid re-calcs, we store this
  42. ::stream::iterator<T> impl_, end_;
  43. };
  44. }
  45. template <typename T>
  46. class filter_stream : public stream_impl<T> {
  47. public:
  48. template <typename F>
  49. filter_stream(F&& func, stream_base<T> const& sb) : pred_(func), source_(sb) {}
  50. ~filter_stream() override {}
  51. iterator<T> begin() override {
  52. return {new filter::iterator<T>{pred_, source_.begin(), source_.end()}};
  53. }
  54. iterator<T> end() override {
  55. return {new filter::iterator<T>{pred_, source_.end(), source_.end()}};
  56. }
  57. private:
  58. std::function<bool(T const&)> pred_;
  59. stream_base<T> source_;
  60. };
  61. template <typename T>
  62. template <typename F>
  63. auto stream_base<T>::filter(F&& pred) const -> stream_base<T> {
  64. using impl_t = filter_stream<T>;
  65. return {std::make_shared<impl_t>(pred, *this)};
  66. }
  67. } }