join_iterator.h 2.6 KB

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