join_iterator.h 2.4 KB

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