#pragma once #include namespace stream::detail { template class source_stream { public: explicit source_stream(C && cont) : source_(std::forward(cont)) {} auto begin() { return iterator(source_.begin()); } auto end() { return iterator(source_.end()); } private: C source_; }; template class range_stream { public: explicit range_stream(It b, It e) : begin_(b), end_(e) {} auto begin() { return iterator(begin_); } auto end() { return iterator(end_); } private: It begin_, end_; }; } namespace stream { /** * Construct a stream out of the given container. If C && is an rvalue * reference, the returned object will take ownership of cont. Otherwise, we * capture cont by reference to maximise performance. */ template auto of(C && cont) -> detail::stream_base { return std::make_shared>(std::forward(cont)); } template detail::stream_base empty() { return std::make_shared>(nullptr, nullptr); } /** * Construct a single element stream containing the pointer given */ template detail::stream_base of(T * ptr) { return std::make_shared>(ptr, ptr + 1); } /** * Construct a stream from input iterators representing the start and end * Requirements: It must be an iterator type that provides the trait * 'reference' */ template detail::stream_base of(It begin, It end) { return std::make_shared>(begin, end); } /** * Construct a stream given certain start and end bounds. * e.g. stream::make_range_stream(0, 10) */ template detail::stream_base range(T start, T const & end) { std::vector vec; vec.reserve(end - start); while (start < end) { vec.emplace_back(start++); } return make_stream(std::move(vec)); } /** * Construct a stream given certain start and end bounds, as well as an * increment amount. e.g. stream::make_range_stream(0, 10, 2) */ template detail::stream_base range(T start, T const & end, T const & increment) { int elems{(end - start) / increment}; if (elems < 0 || end == start) { return {}; } std::vector vec{start}; vec.reserve(elems + 1); while (elems-- > 0) { vec.emplace_back(start += increment); } return make_stream(std::move(vec)); } }