join_iterator.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. //
  2. // join_iterator.h
  3. // iterator
  4. //
  5. // Created by Sam Jaffe on 2/7/17.
  6. //
  7. #pragma once
  8. #include <iterator>
  9. #include <memory>
  10. #include <utility>
  11. #include <iterator/capture_iterator.h>
  12. #include <iterator/end_aware_iterator.h>
  13. #include <iterator/facade.h>
  14. #include <iterator/forwards.h>
  15. #include <iterator/detail/macro.h>
  16. namespace iterator {
  17. template <typename It>
  18. class joining_iterator : public facade<joining_iterator<It>> {
  19. private:
  20. template <typename Ot> friend class joining_iterator;
  21. constexpr static bool requires_caching = detail::is_rvalue_iterator_v<It>;
  22. public:
  23. using sentinel_type = sentinel_t;
  24. using outer_iterator_t =
  25. std::conditional_t<requires_caching,
  26. capture_iterator<end_aware_iterator<It>>,
  27. end_aware_iterator<It>>;
  28. using inner_iterator_t =
  29. end_aware_iterator<detail::iter<DEREF_TYPE(outer_iterator_t)>>;
  30. private:
  31. outer_iterator_t outer_;
  32. inner_iterator_t inner_;
  33. public:
  34. joining_iterator() = default;
  35. template <typename Ot>
  36. joining_iterator(joining_iterator<Ot> const & other) : outer_(other.outer_) {
  37. safely_init_inner_iterator(other.outer_, other.inner_);
  38. }
  39. template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
  40. joining_iterator(C && container) : outer_(FWD(container)) {
  41. update_iterator();
  42. }
  43. joining_iterator(outer_iterator_t outer) : outer_(outer) {
  44. update_iterator();
  45. }
  46. joining_iterator(outer_iterator_t const & outer,
  47. inner_iterator_t const & inner)
  48. : outer_(outer) {
  49. safely_init_inner_iterator(outer, inner);
  50. }
  51. void increment() {
  52. if ((++inner_).at_end()) {
  53. ++outer_;
  54. update_iterator();
  55. }
  56. }
  57. decltype(auto) dereference() const { return *inner_; }
  58. bool at_end() const { return outer_iterator().at_end(); }
  59. bool equal_to(joining_iterator const & other) const {
  60. return outer_iterator() == other.outer_iterator() &&
  61. inner_iterator() == other.inner_iterator();
  62. }
  63. auto const & outer_iterator() const { return outer_; }
  64. auto const & inner_iterator() const { return inner_; }
  65. private:
  66. template <typename OuterIt, typename InnerIt>
  67. void safely_init_inner_iterator(OuterIt const & outer,
  68. InnerIt const & inner) {
  69. if constexpr (requires_caching) {
  70. inner_ = *outer_;
  71. std::advance(inner_, std::distance(InnerIt(*outer), inner));
  72. } else {
  73. inner_ = inner;
  74. }
  75. }
  76. void update_iterator() {
  77. while (!outer_.at_end() && (inner_ = *outer_).at_end()) {
  78. ++outer_;
  79. }
  80. }
  81. };
  82. template <typename C>
  83. joining_iterator(C &&) -> joining_iterator<detail::iter<C>>;
  84. template <typename JI>
  85. joining_iterator(end_aware_iterator<JI>) -> joining_iterator<JI>;
  86. }
  87. MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::joining_iterator);
  88. #include <iterator/detail/undef.h>