// // end_aware_iterator.hpp // iterator // // Created by Sam Jaffe on 2/7/17. // #pragma once #include "iterator_fwd.hpp" #include namespace iterator { /** * @class end_aware_iterator * @brief An iterator that keeps track of the relative end of the range. * * @tparam Iterator The underlying iterator type */ template class end_aware_iterator { public: using iter_type = Iterator; using value_type = typename std::iterator_traits::value_type; using reference = typename std::iterator_traits::reference; using pointer = typename std::iterator_traits::pointer; using difference_type = typename std::iterator_traits::difference_type; using iterator_category = std::forward_iterator_tag; public: end_aware_iterator() = default; end_aware_iterator(iter_type it, iter_type end) : curr_(it), end_(end) {} end_aware_iterator(iter_type end) : curr_(end), end_(end) {} template end_aware_iterator( end_aware_iterator const & other ) : curr_(other.current()), end_(other.end()) { } end_aware_iterator & operator++() { if ( !done() ) { ++curr_; } return *this; } end_aware_iterator operator++(int) { end_aware_iterator tmp{*this}; operator++(); return tmp; } reference operator*() const { return *curr_; } pointer operator->() const { return std::addressof(*curr_); } bool done() const { return curr_ == end_; } /** * When comparing iterators that do not point to the same collection/range, * the result is not specified by the standard. Therefore, as a matter of * convenience, even if the underlying data is different, all end-aware * iterators in the done() state are considered equal. * * @see done * @return true if both iterators are done, or if the underlying iterators * are logically equal */ bool operator==(end_aware_iterator const & other) const { return (done() && other.done()) || (curr_ == other.curr_ && end_ == other.end_); } bool operator!=(end_aware_iterator const & other) { return !(operator==(other)); } iter_type current() const { return curr_; } iter_type end() const { return end_; } private: iter_type curr_, end_; }; } template iterator::end_aware_iterator make_end_aware_iterator(Iter a, Iter b) { return iterator::end_aware_iterator(a, b); } template auto make_end_aware_iterator(C & collect) { return make_end_aware_iterator(std::begin(collect), std::end(collect)); } template auto make_end_aware_iterator(C const & collect) { return make_end_aware_iterator(std::begin(collect), std::end(collect)); }