// // join_iterator.hpp // iterator // // Created by Sam Jaffe on 2/7/17. // #pragma once #include #include #include #include #include #include namespace iterator::joining { template class iterator { protected: using inner_t = decltype(*std::declval()); protected: iterator() = default; template iterator(iterator const & other) : iterator(other.join_iterator(), other.element_iterator()) {} 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(); } } void update_iterator() { while (!joiner_.at_end() && (element_ = end_aware_iterator(*joiner_)).at_end()) { ++joiner_; } } protected: end_aware_iterator joiner_; end_aware_iterator> element_; }; template class iterator>> { protected: using inner_t = decltype(*std::declval()); protected: iterator() = default; template >> iterator(C && container) : joiner_(std::forward(container)) { update_iterator(); } iterator(end_aware_iterator join) : joiner_(join) { update_iterator(); } iterator(iterator const &other) { *this = other; } iterator(iterator &&other) { *this = std::move(other); } iterator &operator=(iterator const &other) { joiner_ = other.joiner_; sync(std::distance(end_aware_iterator(cache_.get()), element_)); return *this; } iterator &operator=(iterator &&other) { joiner_ = std::move(joiner_); sync(std::distance(end_aware_iterator(cache_.get()), element_)); return *this; } void update_iterator() { while (!joiner_.at_end() && sync().at_end()) { ++joiner_; } } private: end_aware_iterator> const & sync(size_t n = 0) { if (joiner_.at_end()) { return element_ = {}; } cache_ = *joiner_; element_ = end_aware_iterator(cache_.get()); std::advance(element_, n); return element_; } protected: end_aware_iterator joiner_; detail::value_proxy())> cache_; end_aware_iterator> element_; }; } namespace iterator { template class joining_iterator : public facade>, public joining::iterator { public: using super_t = joining::iterator; 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 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);