recursive_iterator_traits.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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 <>
  46. struct typeclass_t<typename std::string::iterator> : typeclass_t<void> {};
  47. template <>
  48. struct typeclass_t<typename std::string::const_iterator> : typeclass_t<void> {
  49. };
  50. template <typename T>
  51. struct typeclass_t<T, typename void_t<value_iterator<T>>::type> {
  52. static constexpr typeclass const value{typeclass::CONTAINER};
  53. };
  54. template <typename T>
  55. struct typeclass_t<T, typename void_t<mapped_iterator<T>>::type> {
  56. static constexpr typeclass const value{typeclass::ASSOCIATIVE_CONTAINER};
  57. };
  58. // Accessor templates for invoking std::get
  59. template <std::size_t I, typename It, typename = void> struct accessor;
  60. template <typename It> struct accessor<0, end_aware_iterator<It>> {
  61. using type = end_aware_iterator<It>;
  62. };
  63. template <typename It, typename Rec>
  64. struct accessor<0, recursive_iterator_layer<It, Rec>> {
  65. using type = end_aware_iterator<It>;
  66. };
  67. template <typename It, typename Rec>
  68. struct accessor<0, flatten_iterator_layer<It, Rec>> {
  69. using type = end_aware_iterator<It>;
  70. };
  71. template <typename It> struct accessor<0, It> {
  72. using type = typename accessor<0, typename It::super>::type;
  73. };
  74. template <std::size_t I, typename It>
  75. struct accessor<I, It, typename std::enable_if<I != 0>::type> {
  76. using type = typename accessor<I, typename It::super>::type;
  77. };
  78. template <std::size_t I, typename It, typename Rec>
  79. struct accessor<I, recursive_iterator_layer<It, Rec>,
  80. typename std::enable_if<I != 0>::type> {
  81. using type = typename accessor<I - 1, Rec>::type;
  82. };
  83. template <std::size_t I, typename It, typename Rec>
  84. struct accessor<I, flatten_iterator_layer<It, Rec>,
  85. typename std::enable_if<I != 0>::type> {
  86. using type = typename accessor<I - 1, Rec>::type;
  87. };
  88. }}