traits.h 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #pragma once
  2. #include <iterator>
  3. #include <type_traits>
  4. namespace iterator {
  5. struct sentinel_t;
  6. }
  7. namespace iterator::detail {
  8. template <typename C> using iter = decltype(std::begin(std::declval<C>()));
  9. // Type Helper for deducing reference types
  10. template <typename T, typename = void> struct reference_helper {
  11. using type = decltype(*std::declval<T>());
  12. };
  13. template <typename T>
  14. struct reference_helper<T, std::void_t<typename T::reference>> {
  15. using type = typename T::reference;
  16. };
  17. // Type Helper for deducing value types
  18. template <typename T, typename = void> struct value_type_helper {
  19. using reference = typename reference_helper<T>::type;
  20. using type = std::remove_cv_t<std::remove_reference_t<reference>>;
  21. };
  22. template <typename T>
  23. struct value_type_helper<T, std::void_t<typename T::value_type>> {
  24. using type = typename T::value_type;
  25. };
  26. // Type Helper for identifying container-like objects
  27. template <typename C, typename = void> struct is_container : std::false_type {};
  28. template <typename C>
  29. struct is_container<C, std::void_t<iter<C>>> : std::true_type {};
  30. template <typename It, typename = void>
  31. struct has_sentinel_type : std::false_type {};
  32. template <typename It>
  33. struct has_sentinel_type<It, std::void_t<typename It::sentinel_type>>
  34. : std::true_type {};
  35. template <typename T> using value_type = typename value_type_helper<T>::type;
  36. template <typename T> using reference = typename reference_helper<T>::type;
  37. template <typename C> constexpr bool is_container_v = is_container<C>{};
  38. template <typename Iter>
  39. constexpr bool is_rvalue_iterator_v = !std::is_reference_v<reference<Iter>>;
  40. template <typename Iter>
  41. using category = typename std::iterator_traits<Iter>::iterator_category;
  42. template <typename Iter>
  43. constexpr bool is_random_access_v =
  44. std::is_same_v<category<Iter>, std::random_access_iterator_tag>;
  45. template <typename Iter>
  46. constexpr bool is_bidirectional_v =
  47. std::is_same_v<category<Iter>, std::bidirectional_iterator_tag> ||
  48. is_random_access_v<Iter>;
  49. template <typename Iter>
  50. constexpr bool is_forward_v =
  51. std::is_same_v<category<Iter>, std::forward_iterator_tag> ||
  52. is_bidirectional_v<Iter>;
  53. template <typename Iter> constexpr bool is_single_pass_v = !is_forward_v<Iter>;
  54. template <typename It>
  55. constexpr bool has_sentinel_type_v = has_sentinel_type<It>{};
  56. template <typename It, typename S>
  57. using sentinel_type = std::conditional_t<std::is_same_v<It, S>, sentinel_t, S>;
  58. }