end_aware_iterator.hpp 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. //
  2. // end_aware_iterator.hpp
  3. // iterator
  4. //
  5. // Created by Sam Jaffe on 2/7/17.
  6. //
  7. #pragma once
  8. #include "iterator_fwd.hpp"
  9. #include <iterator>
  10. namespace iterator {
  11. /**
  12. * @class end_aware_iterator
  13. * @brief An iterator that keeps track of the relative end of the range.
  14. *
  15. * @tparam Iterator The underlying iterator type
  16. */
  17. template <typename Iterator>
  18. class end_aware_iterator {
  19. public:
  20. using iter_type = Iterator;
  21. using value_type = typename std::iterator_traits<iter_type>::value_type;
  22. using reference = typename std::iterator_traits<iter_type>::reference;
  23. using pointer = typename std::iterator_traits<iter_type>::pointer;
  24. using difference_type = typename std::iterator_traits<iter_type>::difference_type;
  25. using iterator_category = std::forward_iterator_tag;
  26. public:
  27. end_aware_iterator() = default;
  28. end_aware_iterator(iter_type it, iter_type end) : curr_(it), end_(end) {}
  29. end_aware_iterator(iter_type end) : curr_(end), end_(end) {}
  30. template <typename I>
  31. end_aware_iterator( end_aware_iterator<I> const & other )
  32. : curr_(other.current()), end_(other.end()) {
  33. }
  34. end_aware_iterator & operator++() {
  35. if ( !done() ) { ++curr_; }
  36. return *this;
  37. }
  38. end_aware_iterator operator++(int) {
  39. end_aware_iterator tmp{*this};
  40. operator++();
  41. return tmp;
  42. }
  43. reference operator*() const { return *curr_; }
  44. pointer operator->() const { return std::addressof(*curr_); }
  45. bool done() const { return curr_ == end_; }
  46. /**
  47. * When comparing iterators that do not point to the same collection/range,
  48. * the result is not specified by the standard. Therefore, as a matter of
  49. * convenience, even if the underlying data is different, all end-aware
  50. * iterators in the done() state are considered equal.
  51. *
  52. * @see done
  53. * @return true if both iterators are done, or if the underlying iterators
  54. * are logically equal
  55. */
  56. bool operator==(end_aware_iterator const & other) const {
  57. return (done() && other.done()) || (curr_ == other.curr_ && end_ == other.end_);
  58. }
  59. bool operator!=(end_aware_iterator const & other) {
  60. return !(operator==(other));
  61. }
  62. iter_type current() const { return curr_; }
  63. iter_type end() const { return end_; }
  64. private:
  65. iter_type curr_, end_;
  66. };
  67. }
  68. template <typename Iter>
  69. iterator::end_aware_iterator<Iter> make_end_aware_iterator(Iter a, Iter b) {
  70. return iterator::end_aware_iterator<Iter>(a, b);
  71. }
  72. template <typename C>
  73. auto make_end_aware_iterator(C & collect) {
  74. return make_end_aware_iterator(std::begin(collect), std::end(collect));
  75. }
  76. template <typename C>
  77. auto make_end_aware_iterator(C const & collect) {
  78. return make_end_aware_iterator(std::begin(collect), std::end(collect));
  79. }