// // join_iterator.h // iterator // // Created by Sam Jaffe on 2/7/17. // #pragma once #include #include #include #include #include #include #include #include namespace iterator { template class joining_iterator : public facade> { private: template friend class joining_iterator; constexpr static bool requires_caching = detail::is_rvalue_iterator_v; public: using sentinel_type = sentinel_t; using outer_iterator_t = std::conditional_t>, end_aware_iterator>; using inner_iterator_t = end_aware_iterator>; private: outer_iterator_t outer_; inner_iterator_t inner_; public: joining_iterator() = default; template joining_iterator(joining_iterator const & other) : outer_(other.outer_) { safely_init_inner_iterator(other.outer_, other.inner_); } template )> joining_iterator(C && container) : outer_(FWD(container)) { update_iterator(); } joining_iterator(outer_iterator_t outer) : outer_(outer) { update_iterator(); } joining_iterator(outer_iterator_t const & outer, inner_iterator_t const & inner) : outer_(outer) { safely_init_inner_iterator(outer, inner); } void increment() { if ((++inner_).at_end()) { ++outer_; update_iterator(); } } decltype(auto) dereference() const { return *inner_; } bool at_end() const { return outer_.at_end(); } bool equal_to(joining_iterator const & other) const { return outer_ == other.outer_ && inner_ == other.inner_; } auto outer_iterator() const { return outer_; } auto inner_iterator() const { return inner_; } private: template void safely_init_inner_iterator(OuterIt const & outer, InnerIt const & inner) { if constexpr (requires_caching) { inner_ = *outer_; std::advance(inner_, std::distance(InnerIt(*outer), inner)); } else { inner_ = inner; } } void update_iterator() { while (!outer_.at_end() && (inner_ = *outer_).at_end()) { ++outer_; } } }; template joining_iterator(C &&) -> joining_iterator>; template joining_iterator(end_aware_iterator) -> joining_iterator; } MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::joining_iterator); #include