join_iterator.hpp 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. //
  2. // join_iterator.hpp
  3. // iterator
  4. //
  5. // Created by Sam Jaffe on 2/7/17.
  6. //
  7. #pragma once
  8. #include <iterator>
  9. #include <utility>
  10. #include <iterator/end_aware_iterator.hpp>
  11. #include <iterator/facade.h>
  12. #include <iterator/iterator_fwd.hpp>
  13. namespace iterator {
  14. template <typename MetaIterator>
  15. class joining_iterator : public facade<joining_iterator<MetaIterator>> {
  16. public:
  17. using join_iter = MetaIterator;
  18. using joinable_type = typename join_iter::value_type;
  19. using iter_type = decltype(std::begin(*std::declval<join_iter>()));
  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. explicit joining_iterator() = default;
  28. template <typename I>
  29. joining_iterator(joining_iterator<I> const & other)
  30. : joiner_(other.join_iterator()), iterator_(other.element_iterator()) {}
  31. template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
  32. joining_iterator(C && container)
  33. : joining_iterator(end_aware_iterator(std::forward<C>(container))) {}
  34. joining_iterator(end_aware_iterator<join_iter> join)
  35. : joining_iterator(join, {}, true) {}
  36. joining_iterator(end_aware_iterator<join_iter> join,
  37. end_aware_iterator<iter_type> elem, bool update = false)
  38. : joiner_(join), iterator_(elem) {
  39. if (update) { update_iterator(); }
  40. }
  41. void increment() {
  42. if ((iterator_++).at_end()) {
  43. ++joiner_;
  44. update_iterator();
  45. }
  46. }
  47. decltype(auto) dereference() const { return *iterator_; }
  48. bool equal_to(joining_iterator const & other) const {
  49. return joiner_ == other.joiner_ && iterator_ == other.iterator_;
  50. }
  51. end_aware_iterator<join_iter> join_iterator() const { return joiner_; }
  52. end_aware_iterator<iter_type> element_iterator() const { return iterator_; }
  53. private:
  54. void update_iterator() {
  55. while (!joiner_.at_end() && end_aware_iterator(*joiner_).at_end()) {
  56. ++joiner_;
  57. }
  58. if (!joiner_.at_end()) { iterator_ = end_aware_iterator(*joiner_); }
  59. }
  60. end_aware_iterator<join_iter> joiner_;
  61. end_aware_iterator<iter_type> iterator_;
  62. };
  63. template <typename C> joining_iterator(C &&) -> joining_iterator<iter<C>>;
  64. template <typename JI>
  65. joining_iterator(end_aware_iterator<JI>) -> joining_iterator<JI>;
  66. template <typename JI, typename IT>
  67. joining_iterator(end_aware_iterator<JI>, end_aware_iterator<IT>)
  68. -> joining_iterator<JI>;
  69. }
  70. MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::joining_iterator);