recursive_iterator_traits.hpp 3.8 KB

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