// // stream_helpers.h // stream // // Created by Sam Jaffe on 4/4/23. // #pragma once #include #include #include namespace ranges = stream::ranges; namespace views = stream::ranges::views; #include #define SELF() (*static_cast(this)) /** * There are the following types of iterators/containers that we are interested * in: * - Does the object use common iterators or sentinel iterators * - Does the object have a size/empty */ template class remaining_iterator : public iterator::end_aware_iterator { public: using super_t = iterator::end_aware_iterator; public: using super_t::super_t; friend auto operator-(remaining_iterator const & it, iterator::sentinel_t) { return std::distance(super_t::impl(), super_t::end()); } }; MAKE_ITERATOR_FACADE_TYPEDEFS_T(remaining_iterator); template struct Sized { size_t size() const { return SELF().impl().size(); } bool empty() const { return SELF().impl().size() == 0; } }; template struct Common { auto begin() const { return SELF().impl().begin(); } auto end() const { return SELF().impl().end(); } }; template struct Sentinel { auto begin() const { return iterator::end_aware_iterator(SELF().impl()); } auto end() const { return iterator::sentinel; } }; template struct SizedSentinel { auto begin() const { return remaining_iterator(SELF().impl()); } auto end() const { return iterator::sentinel; } }; template class... Traits> class Range : public Traits>... { private: C impl_; public: Range() = default; Range(C impl) : impl_(std::move(impl)) {} template Range(std::initializer_list init) : impl_(init) {} auto & impl() const { return impl_; } }; #include