recursive_iterator.hpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. //
  2. // recursive_iterator.hpp
  3. // iterator
  4. //
  5. // Created by Sam Jaffe on 2/17/17.
  6. //
  7. #pragma once
  8. #include <tuple>
  9. #include "iterator_fwd.hpp"
  10. #include "recursive/impl.hpp"
  11. #include "recursive/traits.hpp"
  12. namespace iterator {
  13. /**
  14. * @class recursive_iterator
  15. * @brief An iterator type for nested collections, allowing you to treat it as
  16. * a single-layer collection.
  17. *
  18. * In order to provide a simple interface, if an associative container is used
  19. * in the chain, the type returned by operator*() is a tuple. If multiple
  20. * associative containers are nested, then the tuple will be of the form
  21. * std::tuple<key1, key2, ..., keyN, value>. To avoid copies, and allow
  22. * editting of underlying values, the tuple contains references.
  23. *
  24. * @tparam Iterator The iterator type of the top-level collection.
  25. */
  26. template <typename Iterator>
  27. class recursive_iterator : public recursive::impl<Iterator> {
  28. public:
  29. using super = recursive::impl<Iterator>;
  30. using reference = decltype(*std::declval<super>());
  31. using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
  32. using pointer = decltype(std::declval<super>().operator->());
  33. using difference_type = std::ptrdiff_t;
  34. using iterator_category = std::forward_iterator_tag;
  35. public:
  36. using super::super;
  37. recursive_iterator() = default;
  38. recursive_iterator & operator++() {
  39. (void)super::next();
  40. return *this;
  41. }
  42. recursive_iterator operator++(int) {
  43. recursive_iterator tmp{*this};
  44. (void)super::next();
  45. return tmp;
  46. }
  47. bool operator!=(recursive_iterator const & other) const {
  48. return !(static_cast<super const &>(*this) == other);
  49. }
  50. };
  51. /**
  52. * @class recursive_iterator_n
  53. * @copydoc recursive_iterator
  54. * This object has bounded recursive depth, so that it can be used to get
  55. * sub-collections, which may be used in other functions.
  56. *
  57. * For Example:
  58. * @code
  59. * using map_type = std::map<std::string, std::map<std::string,
  60. * std::vector<Data> > >;
  61. * ...
  62. * recursive_iterator_n<map_type::iterator, 2> iter{ ... };
  63. * std::vector<Data> & data = std::get<2>(*iter);
  64. * reload_data_from_file( std::get<1>(*iter), data );
  65. * @endcode
  66. *
  67. * @tparam N The maximum depth to recurse into the object
  68. */
  69. template <typename Iterator, std::size_t N>
  70. class recursive_iterator_n : public recursive::bounded_impl<Iterator, 1, N> {
  71. public:
  72. using super = recursive::bounded_impl<Iterator, 1, N>;
  73. using reference = decltype(*std::declval<super>());
  74. using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
  75. using pointer = decltype(std::declval<super>().operator->());
  76. using difference_type = std::ptrdiff_t;
  77. using iterator_category = std::forward_iterator_tag;
  78. public:
  79. using super::super;
  80. recursive_iterator_n() = default;
  81. recursive_iterator_n & operator++() {
  82. (void)super::next();
  83. return *this;
  84. }
  85. recursive_iterator_n operator++(int) {
  86. recursive_iterator_n tmp{*this};
  87. (void)super::next();
  88. return tmp;
  89. }
  90. bool operator!=(recursive_iterator_n const & other) const {
  91. return !(static_cast<super const &>(*this) == other);
  92. }
  93. };
  94. }
  95. namespace std {
  96. template <std::size_t I, typename It>
  97. auto get(::iterator::recursive_iterator<It> const & iter) ->
  98. typename ::iterator::recursive::accessor<
  99. I, ::iterator::recursive_iterator<It>>::type {
  100. return iter;
  101. }
  102. template <std::size_t I, typename It, std::size_t N>
  103. auto get(::iterator::recursive_iterator_n<It, N> const & iter) ->
  104. typename ::iterator::recursive::accessor<
  105. I, ::iterator::recursive_iterator_n<It, N>>::type {
  106. static_assert(I < N, "Cannot get past bounding level");
  107. return iter;
  108. }
  109. }
  110. template <typename C>
  111. auto make_recursive_iterator(C & collect)
  112. -> iterator::recursive_iterator<decltype(std::begin(collect))> {
  113. return iterator::recursive_iterator<decltype(std::begin(collect))>{
  114. make_end_aware_iterator(collect)};
  115. }
  116. template <typename C>
  117. auto make_recursive_iterator(C const & collect)
  118. -> iterator::recursive_iterator<decltype(std::begin(collect))> {
  119. return iterator::recursive_iterator<decltype(std::begin(collect))>{
  120. make_end_aware_iterator(collect)};
  121. }
  122. template <std::size_t Max, typename C>
  123. auto make_recursive_iterator(C & collect)
  124. -> iterator::recursive_iterator_n<decltype(std::begin(collect)), Max> {
  125. return iterator::recursive_iterator_n<decltype(std::begin(collect)), Max>{
  126. make_end_aware_iterator(collect)};
  127. }
  128. template <std::size_t Max, typename C>
  129. auto make_recursive_iterator(C const & collect)
  130. -> iterator::recursive_iterator_n<decltype(std::begin(collect)), Max> {
  131. return iterator::recursive_iterator_n<decltype(std::begin(collect)), Max>{
  132. make_end_aware_iterator(collect)};
  133. }