// // join_iterator.h // iterator // // Created by Sam Jaffe on 2/7/17. // #pragma once #include #include #include #include #include #include #include namespace iterator::joining { template class iterator { protected: using inner_t = DEREF_TYPE(Iter); public: iterator() = default; template iterator(iterator const & other) : iterator(other.joiner_, other.element_) {} template >> iterator(C && container) : iterator(end_aware_iterator(std::forward(container))) {} iterator(end_aware_iterator join) : iterator(join, {}, true) {} iterator(end_aware_iterator join, end_aware_iterator> elem, bool update = false) : joiner_(join), element_(elem) { if (update) { update_iterator(); } } protected: void update_iterator() { while (!joiner_.at_end() && (element_ = end_aware_iterator(*joiner_)).at_end()) { ++joiner_; } } protected: template friend class iterator; end_aware_iterator joiner_; end_aware_iterator> element_; }; template class iterator>> { protected: using inner_t = DEREF_TYPE(Iter); public: iterator() = default; template >> iterator(C && container) : joiner_(std::forward(container)) { update_iterator(); } iterator(end_aware_iterator join) : joiner_(join) { update_iterator(); } protected: void update_iterator() { while (!joiner_.at_end() && sync().at_end()) { ++joiner_; } } private: end_aware_iterator> const & sync() { if (joiner_.at_end()) { return element_ = {}; } cache_ = std::make_shared(*joiner_); element_ = end_aware_iterator(*cache_); return element_; } protected: end_aware_iterator joiner_; std::shared_ptr cache_; end_aware_iterator> element_; }; } namespace iterator { template class joining_iterator : public facade>, public joining::iterator { public: using super_t = joining::iterator; using sentinel_type = sentinel_t; public: using super_t::super_t; template >> joining_iterator(C && container) : super_t(std::forward(container)) {} joining_iterator(end_aware_iterator join) : super_t(join) {} void increment() { if ((++super_t::element_).at_end()) { ++super_t::joiner_; super_t::update_iterator(); } } decltype(auto) dereference() const { return *super_t::element_; } bool at_end() const { return join_iterator().at_end(); } bool equal_to(joining_iterator const & other) const { return join_iterator() == other.join_iterator() && element_iterator() == other.element_iterator(); } auto const & join_iterator() const { return super_t::joiner_; } auto const & element_iterator() const { return super_t::element_; } }; template joining_iterator(C &&) -> joining_iterator>; template joining_iterator(end_aware_iterator) -> joining_iterator; } MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::joining_iterator); #include