concepts.h 2.8 KB

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