source.hpp 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #pragma once
  2. #include <iterator>
  3. namespace stream::detail {
  4. template <typename C> class source_stream {
  5. public:
  6. explicit source_stream(C && cont) : source_(std::forward<C>(cont)) {}
  7. auto begin() { return iterator(source_.begin()); }
  8. auto end() { return iterator(source_.end()); }
  9. private:
  10. C source_;
  11. };
  12. template <typename It> class range_stream {
  13. public:
  14. explicit range_stream(It b, It e) : begin_(b), end_(e) {}
  15. auto begin() { return iterator(begin_); }
  16. auto end() { return iterator(end_); }
  17. private:
  18. It begin_, end_;
  19. };
  20. }
  21. namespace stream {
  22. /**
  23. * Construct a stream out of the given container. If C && is an rvalue
  24. * reference, the returned object will take ownership of cont. Otherwise, we
  25. * capture cont by reference to maximise performance.
  26. */
  27. template <typename C>
  28. auto of(C && cont) -> detail::stream_base<decltype(*cont.begin())> {
  29. return std::make_shared<detail::source_stream<C>>(std::forward<C>(cont));
  30. }
  31. template <typename T> detail::stream_base<T &> empty() {
  32. return std::make_shared<detail::range_stream<T *>>(nullptr, nullptr);
  33. }
  34. /**
  35. * Construct a single element stream containing the pointer given
  36. */
  37. template <typename T> detail::stream_base<T &> of(T * ptr) {
  38. return std::make_shared<detail::range_stream<T *>>(ptr, ptr + 1);
  39. }
  40. /**
  41. * Construct a stream from input iterators representing the start and end
  42. * Requirements: It must be an iterator type that provides the trait
  43. * 'reference'
  44. */
  45. template <typename It>
  46. detail::stream_base<typename It::reference> of(It begin, It end) {
  47. return std::make_shared<detail::range_stream<It>>(begin, end);
  48. }
  49. /**
  50. * Construct a stream given certain start and end bounds.
  51. * e.g. stream::make_range_stream(0, 10)
  52. */
  53. template <typename T> detail::stream_base<T &> range(T start, T const & end) {
  54. std::vector<T> vec;
  55. vec.reserve(end - start);
  56. while (start < end) {
  57. vec.emplace_back(start++);
  58. }
  59. return make_stream(std::move(vec));
  60. }
  61. /**
  62. * Construct a stream given certain start and end bounds, as well as an
  63. * increment amount. e.g. stream::make_range_stream(0, 10, 2)
  64. */
  65. template <typename T>
  66. detail::stream_base<T &> range(T start, T const & end, T const & increment) {
  67. int elems{(end - start) / increment};
  68. if (elems < 0 || end == start) { return {}; }
  69. std::vector<T> vec{start};
  70. vec.reserve(elems + 1);
  71. while (elems-- > 0) {
  72. vec.emplace_back(start += increment);
  73. }
  74. return make_stream(std::move(vec));
  75. }
  76. }