end_aware_iterator.hpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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> class end_aware_iterator {
  18. public:
  19. using iter_type = Iterator;
  20. using value_type = typename std::iterator_traits<iter_type>::value_type;
  21. using reference = typename std::iterator_traits<iter_type>::reference;
  22. using pointer = typename std::iterator_traits<iter_type>::pointer;
  23. using difference_type =
  24. 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. end_aware_iterator & operator++() {
  34. if (!done()) { ++curr_; }
  35. return *this;
  36. }
  37. end_aware_iterator operator++(int) {
  38. end_aware_iterator tmp{*this};
  39. operator++();
  40. return tmp;
  41. }
  42. reference operator*() const { return *curr_; }
  43. pointer operator->() const { return std::addressof(*curr_); }
  44. bool done() const { return curr_ == end_; }
  45. /**
  46. * When comparing iterators that do not point to the same collection/range,
  47. * the result is not specified by the standard. Therefore, as a matter of
  48. * convenience, even if the underlying data is different, all end-aware
  49. * iterators in the done() state are considered equal.
  50. *
  51. * @see done
  52. * @return true if both iterators are done, or if the underlying iterators
  53. * are logically equal
  54. */
  55. bool operator==(end_aware_iterator const & other) const {
  56. return (done() && other.done()) ||
  57. (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> auto make_end_aware_iterator(C & collect) {
  73. return make_end_aware_iterator(std::begin(collect), std::end(collect));
  74. }
  75. template <typename C> auto make_end_aware_iterator(C const & collect) {
  76. return make_end_aware_iterator(std::begin(collect), std::end(collect));
  77. }