concepts.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. //
  2. // concepts.h
  3. // iterator
  4. //
  5. // Created by Sam Jaffe on 9/20/25.
  6. // Copyright © 2025 Sam Jaffe. All rights reserved.
  7. //
  8. #pragma once
  9. #include <concepts>
  10. #include <ranges>
  11. #include <string_view>
  12. #include <tuple>
  13. #include <type_traits>
  14. namespace iterator {
  15. template <typename It>
  16. concept implements_distance_to = requires(It const & it) {
  17. { it.distance_to(it) } -> std::integral;
  18. };
  19. template <typename> struct infer_difference_type {
  20. using type = std::ptrdiff_t;
  21. };
  22. template <implements_distance_to It> struct infer_difference_type<It> {
  23. static const It & _it;
  24. using type = decltype(_it.distance_to(_it));
  25. };
  26. template <typename It>
  27. using infer_difference_type_t = typename infer_difference_type<It>::type;
  28. template <typename D, typename It>
  29. concept difference_type_arg =
  30. std::convertible_to<D, infer_difference_type_t<It>>;
  31. template <typename It> struct infer_value_type {
  32. static const It & _it;
  33. using type = std::remove_cvref_t<decltype(*_it)>;
  34. };
  35. template <typename It>
  36. requires requires { typename It::value_type; }
  37. struct infer_value_type<It> {
  38. using type = typename It::value_type;
  39. };
  40. template <typename It> using infer_value_type_t = infer_value_type<It>::type;
  41. template <typename T, typename U>
  42. concept not_same_as = not std::same_as<T, U>;
  43. template <typename It>
  44. concept has_sentinel = requires(It const & it) {
  45. typename It::sentinel_type;
  46. { it.at_end() } -> std::same_as<bool>;
  47. };
  48. template <typename It, typename S>
  49. concept sentinel_for = has_sentinel<It> && requires(It const & it, S s) {
  50. { s - it } -> std::integral;
  51. };
  52. template <typename It>
  53. concept single_pass = bool(It::single_pass_iterator);
  54. template <typename It>
  55. concept forward = requires(It & it) {
  56. { it.dereference() } -> not_same_as<void>;
  57. { it.equal_to(it) } -> std::same_as<bool>;
  58. { it.increment() } -> std::same_as<void>;
  59. };
  60. template <typename It>
  61. concept bidirectional = forward<It> && requires(It & it) {
  62. { it.decrement() } -> std::same_as<void>;
  63. };
  64. template <typename It>
  65. concept random_access = requires(It & it, infer_difference_type_t<It> offset) {
  66. { it.dereference() } -> not_same_as<void>;
  67. { it.equal_to(it) } -> std::same_as<bool>;
  68. { it.advance(offset) } -> std::same_as<void>;
  69. };
  70. template <typename C>
  71. concept Char = std::same_as<C, char> || std::same_as<C, wchar_t> ||
  72. std::same_as<C, char16_t> || std::same_as<C, char32_t> ||
  73. std::same_as<C, char8_t>;
  74. template <typename S>
  75. concept LegacyString = requires(S const & t) {
  76. { t.c_str() };
  77. };
  78. template <typename S>
  79. concept StringViewCompat =
  80. Char<typename S::value_type> && requires(S const & t) {
  81. { std::basic_string_view{t} };
  82. };
  83. template <typename S>
  84. concept String = LegacyString<S> || StringViewCompat<S>;
  85. template <typename C>
  86. concept Range = (not String<C>) && std::ranges::range<C>;
  87. template <typename V>
  88. concept Assoc =
  89. std::is_const_v<std::remove_reference_t<std::tuple_element_t<0, V>>>;
  90. template <typename V>
  91. concept AssocRange = Assoc<V> && (std::tuple_size_v<V> == 2) &&
  92. Range<std::decay_t<std::tuple_element_t<1, V>>>;
  93. template <typename C>
  94. using iterator_t = decltype(std::begin(std::declval<C &>()));
  95. template <typename... Ts>
  96. using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...));
  97. }