Last active
November 22, 2015 05:43
-
-
Save jcmoyer/4305fb700cc40c9bfb20 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef STASHING_REVERSE_ITERATOR_HPP | |
| #define STASHING_REVERSE_ITERATOR_HPP | |
| #include <iterator> | |
| // This is an implementation of `std::reverse_iterator` that uses an auxiliary | |
| // member to store the iterator obtained by calling `operator*`. The standard | |
| // specifies that `reverse_iterator::operator*` has a const qualifier; | |
| // therefore it must return a reference to a local copy of a decremented | |
| // current iterator. If this reference points to data inside that local copy, | |
| // it will be dangling when the function returns. | |
| // | |
| // `stashing_reverse_iterator` can be used in such cases where the underlying | |
| // iterator owns the data that it produces. | |
| template <class Iterator> | |
| class stashing_reverse_iterator : | |
| public std::iterator< | |
| typename std::iterator_traits<Iterator>::iterator_category, | |
| typename std::iterator_traits<Iterator>::value_type, | |
| typename std::iterator_traits<Iterator>::difference_type, | |
| typename std::iterator_traits<Iterator>::pointer, | |
| typename std::iterator_traits<Iterator>::reference | |
| > { | |
| typedef std::iterator_traits<Iterator> traits_type; | |
| public: | |
| typedef Iterator iterator_type; | |
| typedef typename traits_type::difference_type difference_type; | |
| typedef typename traits_type::reference reference; | |
| typedef typename traits_type::pointer pointer; | |
| stashing_reverse_iterator() : current() {} | |
| explicit stashing_reverse_iterator(Iterator x) : current(x) {} | |
| template <class U> | |
| stashing_reverse_iterator(const stashing_reverse_iterator<U>& u) : current(u.current) {} | |
| template <class U> | |
| stashing_reverse_iterator& operator=(const stashing_reverse_iterator<U>& u) { | |
| current = u.base(); | |
| return *this; | |
| } | |
| Iterator base() const { | |
| return current; | |
| } | |
| // differs from reverse_iterator::operator*: | |
| // 1. const qualifier removed | |
| // 2. current iterator is stored in a member field to ensure references are | |
| // always valid after this function returns | |
| reference operator*() { | |
| deref_tmp = current; | |
| --deref_tmp; | |
| return *deref_tmp; | |
| } | |
| pointer operator->() const { | |
| return std::addressof(operator*()); | |
| } | |
| stashing_reverse_iterator& operator++() { | |
| --current; | |
| return *this; | |
| } | |
| stashing_reverse_iterator operator++(int) { | |
| stashing_reverse_iterator tmp = *this; | |
| --current; | |
| return tmp; | |
| } | |
| stashing_reverse_iterator& operator--() { | |
| ++current; | |
| return *this; | |
| } | |
| stashing_reverse_iterator operator--(int) { | |
| stashing_reverse_iterator tmp = *this; | |
| ++current; | |
| return tmp; | |
| } | |
| stashing_reverse_iterator operator+ (difference_type n) const { | |
| return stashing_reverse_iterator(current - n); | |
| } | |
| stashing_reverse_iterator& operator+=(difference_type n) { | |
| current -= n; | |
| return *this; | |
| } | |
| stashing_reverse_iterator operator- (difference_type n) const { | |
| return stashing_reverse_iterator(current + n); | |
| } | |
| stashing_reverse_iterator& operator-=(difference_type n) { | |
| current += n; | |
| return *this; | |
| } | |
| // differs from reverse_iterator::operator[]: | |
| // 1. const qualifier removed because this function makes use of operator* | |
| reference operator[](difference_type n) { | |
| return *(*this + n); | |
| } | |
| protected: | |
| Iterator current; | |
| private: | |
| Iterator deref_tmp; | |
| }; | |
| template <class Iterator1, class Iterator2> | |
| bool operator==( | |
| const stashing_reverse_iterator<Iterator1>& x, | |
| const stashing_reverse_iterator<Iterator2>& y) | |
| { return x.base() == y.base(); } | |
| template <class Iterator1, class Iterator2> | |
| bool operator<( | |
| const stashing_reverse_iterator<Iterator1>& x, | |
| const stashing_reverse_iterator<Iterator2>& y) | |
| { return x.base() > y.base(); } | |
| template <class Iterator1, class Iterator2> | |
| bool operator!=( | |
| const stashing_reverse_iterator<Iterator1>& x, | |
| const stashing_reverse_iterator<Iterator2>& y) | |
| { return !(x.base() == y.base()); } | |
| template <class Iterator1, class Iterator2> | |
| bool operator>( | |
| const stashing_reverse_iterator<Iterator1>& x, | |
| const stashing_reverse_iterator<Iterator2>& y) | |
| { return x.base() < y.base(); } | |
| template <class Iterator1, class Iterator2> | |
| bool operator>=( | |
| const stashing_reverse_iterator<Iterator1>& x, | |
| const stashing_reverse_iterator<Iterator2>& y) | |
| { return x.base() <= y.base(); } | |
| template <class Iterator1, class Iterator2> | |
| bool operator<=( | |
| const stashing_reverse_iterator<Iterator1>& x, | |
| const stashing_reverse_iterator<Iterator2>& y) | |
| { return x.base() >= y.base(); } | |
| template <class Iterator1, class Iterator2> | |
| auto operator-( | |
| const stashing_reverse_iterator<Iterator1>& x, | |
| const stashing_reverse_iterator<Iterator2>& y) -> decltype(y.base() - x.base()) | |
| { return y.base() - x.base(); } | |
| template <class Iterator> | |
| stashing_reverse_iterator<Iterator> operator+( | |
| typename stashing_reverse_iterator<Iterator>::difference_type n, | |
| const stashing_reverse_iterator<Iterator>& x) | |
| { return stashing_reverse_iterator<Iterator>(x.base() - n); } | |
| template <class Iterator> | |
| stashing_reverse_iterator<Iterator> make_stashing_reverse_iterator(Iterator i) | |
| { return stashing_reverse_iterator<Iterator>(i); } | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment