recursive_iterator_traits.hpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #pragma once
  2. #include <iterator>
  3. #include <string>
  4. #include <tuple>
  5. #include <utility>
  6. #include "../iterator_fwd.hpp"
  7. namespace iterator { namespace detail {
  8. template <typename Iterator, typename RecursiveIterator_NextLayer>
  9. class flatten_iterator_layer;
  10. template <typename Iterator, typename RecursiveIterator_NextLayer>
  11. class recursive_iterator_layer;
  12. // Helper struct for dealing with merging output from associative and
  13. // non-associative containers.
  14. // TODO: This seems unnecessarily verbose t.b.h.
  15. struct terminal_layer_tag_t;
  16. struct continue_layer_tag_t;
  17. template <typename V, typename Tag> struct next_layer_type {
  18. using type = std::tuple<V>;
  19. };
  20. template <typename V> struct next_layer_type<V, continue_layer_tag_t> {
  21. using type = V;
  22. };
  23. // Helpers for condensing type deductions
  24. template <typename IterType>
  25. using value_iterator = decltype(std::begin(*std::declval<IterType>()));
  26. template <typename IterType>
  27. using mapped_iterator =
  28. decltype(std::begin(std::declval<IterType>()->second));
  29. // Type trait to identify value_type ~~ std::pair<K const, V>, which is
  30. // a safe bet towards 'this is an associative container type'
  31. template <typename T, typename = void>
  32. struct is_associative : std::false_type {};
  33. template <typename T>
  34. struct is_associative<T, std::enable_if_t<std::is_const<
  35. typename T::value_type::first_type>::value>>
  36. : std::true_type {};
  37. template <typename T>
  38. using is_associative_t = std::enable_if_t<is_associative<T>::value>;
  39. // Type deduction guides for constructing recursive iterators.
  40. enum class typeclass { TERMINAL, CONTAINER, ASSOCIATIVE_CONTAINER };
  41. template <typename> struct void_t { using type = void; };
  42. template <typename T, typename = void> struct typeclass_t {
  43. static constexpr typeclass const value{typeclass::TERMINAL};
  44. };
  45. template <typename T> struct is_string_iterator : std::false_type {};
  46. template <>
  47. struct is_string_iterator<std::string::iterator> : std::true_type {};
  48. template <>
  49. struct is_string_iterator<std::string::const_iterator> : std::true_type {};
  50. template <typename T>
  51. struct typeclass_t<
  52. T, std::enable_if_t<!is_string_iterator<value_iterator<T>>::value>> {
  53. static constexpr typeclass const value{typeclass::CONTAINER};
  54. };
  55. template <typename T>
  56. struct typeclass_t<
  57. T, std::enable_if_t<is_string_iterator<value_iterator<T>>::value>> {
  58. static constexpr typeclass const value{typeclass::TERMINAL};
  59. };
  60. template <typename T>
  61. struct typeclass_t<T, typename void_t<mapped_iterator<T>>::type> {
  62. static constexpr typeclass const value{typeclass::ASSOCIATIVE_CONTAINER};
  63. };
  64. // Accessor templates for invoking std::get
  65. template <std::size_t I, typename It, typename = void> struct accessor;
  66. template <typename It> struct accessor<0, end_aware_iterator<It>> {
  67. using type = end_aware_iterator<It>;
  68. };
  69. template <typename It, typename Rec>
  70. struct accessor<0, recursive_iterator_layer<It, Rec>> {
  71. using type = end_aware_iterator<It>;
  72. };
  73. template <typename It, typename Rec>
  74. struct accessor<0, flatten_iterator_layer<It, Rec>> {
  75. using type = end_aware_iterator<It>;
  76. };
  77. template <typename It> struct accessor<0, It> {
  78. using type = typename accessor<0, typename It::super>::type;
  79. };
  80. template <std::size_t I, typename It>
  81. struct accessor<I, It, typename std::enable_if<I != 0>::type> {
  82. using type = typename accessor<I, typename It::super>::type;
  83. };
  84. template <std::size_t I, typename It, typename Rec>
  85. struct accessor<I, recursive_iterator_layer<It, Rec>,
  86. typename std::enable_if<I != 0>::type> {
  87. using type = typename accessor<I - 1, Rec>::type;
  88. };
  89. template <std::size_t I, typename It, typename Rec>
  90. struct accessor<I, flatten_iterator_layer<It, Rec>,
  91. typename std::enable_if<I != 0>::type> {
  92. using type = typename accessor<I - 1, Rec>::type;
  93. };
  94. }}