concepts.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. namespace iterator {
  13. template <typename It>
  14. concept implements_distance_to = requires(It const & it) {
  15. { it.distance_to(it) } -> std::integral;
  16. };
  17. template <typename> struct infer_difference_type {
  18. using type = std::ptrdiff_t;
  19. };
  20. template <implements_distance_to It> struct infer_difference_type<It> {
  21. static const It & _it;
  22. using type = decltype(_it.distance_to(_it));
  23. };
  24. template <typename It>
  25. using infer_difference_type_t = typename infer_difference_type<It>::type;
  26. template <typename D, typename It>
  27. concept difference_type_arg =
  28. std::convertible_to<D, infer_difference_type_t<It>>;
  29. template <typename It> struct infer_value_type {
  30. static const It & _it;
  31. using type = std::remove_cvref_t<decltype(*_it)>;
  32. };
  33. template <typename It>
  34. requires requires { typename It::value_type; }
  35. struct infer_value_type<It> {
  36. using type = typename It::value_type;
  37. };
  38. template <typename It> using infer_value_type_t = infer_value_type<It>::type;
  39. template <typename T, typename U>
  40. concept not_same_as = not std::same_as<T, U>;
  41. template <typename It>
  42. concept has_sentinel = requires(It const & it) {
  43. typename It::sentinel_type;
  44. { it.at_end() } -> std::same_as<bool>;
  45. };
  46. template <typename It, typename S>
  47. concept sentinel_for = has_sentinel<It> && requires(It const & it, S s) {
  48. { s - it } -> std::integral;
  49. };
  50. template <typename It>
  51. concept single_pass = bool(It::single_pass_iterator);
  52. template <typename It>
  53. concept forward = requires(It & it) {
  54. { it.dereference() } -> not_same_as<void>;
  55. { it.equal_to(it) } -> std::same_as<bool>;
  56. { it.increment() } -> std::same_as<void>;
  57. };
  58. template <typename It>
  59. concept bidirectional = forward<It> && requires(It & it) {
  60. { it.decrement() } -> std::same_as<void>;
  61. };
  62. template <typename It>
  63. concept random_access = requires(It & it, infer_difference_type_t<It> offset) {
  64. { it.dereference() } -> not_same_as<void>;
  65. { it.equal_to(it) } -> std::same_as<bool>;
  66. { it.advance(offset) } -> std::same_as<void>;
  67. };
  68. template <typename C>
  69. concept Char = std::same_as<C, char> || std::same_as<C, wchar_t> ||
  70. std::same_as<C, char16_t> || std::same_as<C, char32_t> ||
  71. std::same_as<C, char8_t>;
  72. template <typename S>
  73. concept LegacyString = requires(S const & t) {
  74. { t.c_str() };
  75. };
  76. template <typename S>
  77. concept StringViewCompat =
  78. Char<typename S::value_type> && requires(S const & t) {
  79. { std::basic_string_view{t} };
  80. };
  81. template <typename S>
  82. concept String = LegacyString<S> || StringViewCompat<S>;
  83. template <typename C>
  84. concept Range = (not String<C>) && std::ranges::range<C>;
  85. template <typename V>
  86. concept Assoc = std::is_const_v<typename V::first_type>;
  87. template <typename V>
  88. concept AssocRange = Assoc<V> && Range<typename V::second_type>;
  89. template <typename C>
  90. using iterator_t = decltype(std::begin(std::declval<C &>()));
  91. }