recursive_iterator_base.hpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. #pragma once
  2. #include "../end_aware_iterator.hpp"
  3. #include "recursive_iterator_traits.hpp"
  4. namespace iterator { namespace detail {
  5. template <typename Iterator, typename = void> class recursive_iterator_base;
  6. /**
  7. * @class recursive_iterator_base
  8. * @brief A thin wrapper around end_aware_iterator for the purposes of
  9. * template metaprogramming.
  10. */
  11. template <typename Iterator, typename>
  12. class recursive_iterator_base : public end_aware_iterator<Iterator> {
  13. public:
  14. using super = end_aware_iterator<Iterator>;
  15. protected:
  16. using recursive_category = terminal_layer_tag_t;
  17. using reference = decltype(*std::declval<super>());
  18. using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
  19. using pointer = decltype(std::declval<super>().operator->());
  20. public:
  21. using super::super;
  22. recursive_iterator_base(super const & iter) : super(iter) {}
  23. recursive_iterator_base(super && iter) : super(std::move(iter)) {}
  24. recursive_iterator_base() = default;
  25. protected:
  26. decltype(auto) get() const { return super::operator*(); }
  27. };
  28. /**
  29. * @class recursive_iterator_base
  30. * @brief An SFINAE specialization of recursive_iterator_base for associative
  31. * containers
  32. *
  33. * Because it is possible for recursive iterator to step over multiple layers
  34. * of associative containers, the return type is made into a tuple, so that
  35. * the caller does not need to write something like
  36. * `it->second.second.second'. Instead, the return type is a tuple of
  37. * references, so that the caller can write code like `std::get<3>(*it)'.
  38. *
  39. * For example, the ref type for std::map<int, std::map<float, double> >
  40. * with this would be std::tuple<int const&, float const&, double &>.
  41. */
  42. template <typename Iterator>
  43. class recursive_iterator_base<Iterator, is_associative_t<Iterator>>
  44. : public end_aware_iterator<Iterator> {
  45. public:
  46. using super = end_aware_iterator<Iterator>;
  47. using first_type = decltype((std::declval<Iterator>()->first));
  48. using second_type = decltype((std::declval<Iterator>()->second));
  49. protected:
  50. using recursive_category = continue_layer_tag_t;
  51. public:
  52. using value_type = std::tuple<first_type, second_type>;
  53. using reference = std::tuple<first_type &, second_type &>;
  54. public:
  55. using super::super;
  56. recursive_iterator_base(super const & iter) : super(iter) {}
  57. recursive_iterator_base(super && iter) : super(std::move(iter)) {}
  58. recursive_iterator_base() = default;
  59. // TODO: Get rid of this again
  60. reference operator*() const { return get(); }
  61. protected:
  62. /**
  63. * An alternative function to operator*(), which allows single layer
  64. * recursive iterators (on associative containers) to return the
  65. * underlying value/reference type, and nested containers to propogate
  66. * a tuple or a pair as necessary.
  67. */
  68. reference get() const {
  69. auto & pair = super::operator*();
  70. return std::tie(pair.first, pair.second);
  71. }
  72. };
  73. }}