traits.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #pragma once
  2. #include <algorithm>
  3. #include <iterator>
  4. #include <type_traits>
  5. #include <iterator/forwards.h>
  6. #include <iterator/detail/macro.h>
  7. // Section: Non-Dependant Typedef Helpers
  8. namespace iterator::detail {
  9. template <typename Iter>
  10. using category_t = typename std::iterator_traits<Iter>::iterator_category;
  11. template <typename C> using iter = decltype(std::begin(std::declval<C>()));
  12. }
  13. namespace iterator::detail {
  14. // Type Helper for identifying container-like objects
  15. template <typename C, typename = void> struct is_container : std::false_type {};
  16. template <typename C>
  17. struct is_container<C, std::void_t<iter<C>>> : std::true_type {};
  18. template <typename It, typename = void>
  19. struct sentinel_type {
  20. using type = void;
  21. };
  22. template <typename It>
  23. struct sentinel_type<It, std::void_t<typename It::sentinel_type>> {
  24. using type = typename It::sentinel_type;
  25. };
  26. }
  27. // Mappings between iterator::category enum and iterator_category tags
  28. namespace iterator::detail {
  29. template <typename Tag, category Limit = static_cast<category>(~0)>
  30. struct category_for {
  31. constexpr static category value = category::single_pass;
  32. };
  33. template <category Limit>
  34. struct category_for<std::forward_iterator_tag, Limit> {
  35. constexpr static category value = std::min(category::forward, Limit);
  36. };
  37. template <category Limit>
  38. struct category_for<std::bidirectional_iterator_tag, Limit> {
  39. constexpr static category value = std::min(category::bidirectional, Limit);
  40. };
  41. template <category Limit>
  42. struct category_for<std::random_access_iterator_tag, Limit> {
  43. constexpr static category value = std::min(category::random_access, Limit);
  44. };
  45. template <category> struct tag_for;
  46. template <> struct tag_for<category::single_pass> {
  47. using type = std::input_iterator_tag;
  48. };
  49. template <category> struct tag_for;
  50. template <> struct tag_for<category::forward> {
  51. using type = std::forward_iterator_tag;
  52. };
  53. template <category> struct tag_for;
  54. template <> struct tag_for<category::bidirectional> {
  55. using type = std::bidirectional_iterator_tag;
  56. };
  57. template <category> struct tag_for;
  58. template <> struct tag_for<category::random_access> {
  59. using type = std::random_access_iterator_tag;
  60. };
  61. }
  62. namespace iterator::detail {
  63. template <typename C> constexpr bool is_container_v = is_container<C>{};
  64. template <typename Iter>
  65. constexpr bool is_rvalue_iterator_v = !std::is_reference_v<DEREF_TYPE(Iter)>;
  66. template <typename It>
  67. constexpr bool has_sentinel_type_v = !std::is_void_v<typename sentinel_type<It>::type>;
  68. template <typename It, typename S>
  69. constexpr bool is_sentinel_v = std::is_same_v<typename sentinel_type<It>::type, S>;
  70. template <typename It, category Limit = static_cast<category>(~0)>
  71. constexpr auto category_for_v = category_for<category_t<It>, Limit>::value;
  72. template <typename It>
  73. using tag_for_t = typename tag_for<It::category_enum>::type;
  74. }
  75. #include <iterator/detail/undef.h>