facade.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #pragma once
  2. #include <iterator>
  3. #include <type_traits>
  4. #include <iterator/detail/arrow_proxy.h>
  5. #include <iterator/detail/traits.h>
  6. #include <iterator/detail/macro.h>
  7. namespace iterator::detail {
  8. template <typename, typename = void> struct distance_to {
  9. using type = std::ptrdiff_t;
  10. };
  11. template <typename T>
  12. struct distance_to<T, EXISTS(VAL(T).distance_to(VAL(T)))> {
  13. using type = decltype(VAL(T).distance_to(VAL(T)));
  14. };
  15. template <typename T> using distance_to_t = typename distance_to<T>::type;
  16. }
  17. namespace iterator {
  18. template <typename D, typename T>
  19. using difference_type_arg_t =
  20. std::enable_if_t<std::is_convertible_v<D, detail::distance_to_t<T>>>;
  21. template <typename CRTP, category C> class facade {
  22. private:
  23. using self_type = CRTP;
  24. public:
  25. constexpr static auto category_enum = C;
  26. public:
  27. decltype(auto) operator*() const { return self().dereference(); }
  28. decltype(auto) operator->() const {
  29. if constexpr (std::is_reference<decltype(**this)>{}) {
  30. return std::addressof(**this);
  31. } else {
  32. return detail::arrow_proxy{**this};
  33. }
  34. }
  35. template <typename D, typename = difference_type_arg_t<D, self_type>,
  36. REQUIRES(DEFER(D) && C == category::random_access)>
  37. decltype(auto) operator[](D off) const {
  38. return *(self() + off);
  39. }
  40. self_type & operator++() {
  41. if constexpr (C == category::random_access) {
  42. self() += 1;
  43. } else {
  44. self().increment();
  45. }
  46. return self();
  47. }
  48. auto operator++(int) {
  49. if constexpr (C == category::single_pass) {
  50. ++*this;
  51. } else {
  52. auto tmp = self();
  53. ++*this;
  54. return tmp;
  55. }
  56. }
  57. SFINAE(C >= category::bidirectional)
  58. self_type & operator--() {
  59. if constexpr (C == category::random_access) {
  60. self() -= 1;
  61. } else {
  62. self().decrement();
  63. }
  64. return self();
  65. }
  66. SFINAE(C >= category::bidirectional)
  67. self_type operator--(int) {
  68. auto tmp = self();
  69. --*this;
  70. return tmp;
  71. }
  72. template <typename D, typename = difference_type_arg_t<D, self_type>,
  73. REQUIRES(DEFER(D) && C == category::random_access)>
  74. friend self_type & operator+=(self_type & self, D off) {
  75. self.advance(off);
  76. return self;
  77. }
  78. template <typename D, typename = difference_type_arg_t<D, self_type>,
  79. REQUIRES(DEFER(D) && C == category::random_access)>
  80. friend self_type & operator-=(self_type & self, D off) {
  81. self.advance(-off);
  82. return self;
  83. }
  84. template <typename D, typename = difference_type_arg_t<D, self_type>,
  85. REQUIRES(DEFER(D) && C == category::random_access)>
  86. friend auto operator+(self_type self, D off) {
  87. return self += off;
  88. }
  89. template <typename D, typename = difference_type_arg_t<D, self_type>,
  90. REQUIRES(DEFER(D) && C == category::random_access)>
  91. friend auto operator+(D off, self_type self) {
  92. return self += off;
  93. }
  94. template <typename D, typename = difference_type_arg_t<D, self_type>,
  95. REQUIRES(DEFER(D) && C == category::random_access)>
  96. friend auto operator-(self_type self, D off) {
  97. return self -= off;
  98. }
  99. SFINAE(C == category::random_access)
  100. friend auto operator-(self_type const & left, self_type const & right) {
  101. return right.distance_to(left);
  102. }
  103. friend bool operator==(self_type const & left, self_type const & right) {
  104. if constexpr (C == category::random_access) {
  105. return (left - right) == 0;
  106. } else {
  107. return left.equal_to(right);
  108. }
  109. }
  110. friend bool operator!=(self_type const & left, self_type const & right) {
  111. return !(left == right);
  112. }
  113. SFINAE(C == category::random_access)
  114. friend bool operator<(self_type const & left, self_type const & right) {
  115. return (left - right) < 0;
  116. }
  117. SFINAE(C == category::random_access)
  118. friend bool operator<=(self_type const & left, self_type const & right) {
  119. return (left - right) <= 0;
  120. }
  121. SFINAE(C == category::random_access)
  122. friend bool operator>(self_type const & left, self_type const & right) {
  123. return (left - right) > 0;
  124. }
  125. SFINAE(C == category::random_access)
  126. friend bool operator>=(self_type const & left, self_type const & right) {
  127. return (left - right) >= 0;
  128. }
  129. protected:
  130. self_type & self() { return *static_cast<self_type *>(this); }
  131. self_type const & self() const {
  132. return *static_cast<self_type const *>(this);
  133. }
  134. };
  135. }
  136. // In C++20, a concept/requires could be used to eschew the need for the below
  137. // macros.
  138. #define MAKE_ITERATOR_FACADE_TYPEDEFS_T(Iter) \
  139. template <typename... T> struct std::iterator_traits<Iter<T...>> { \
  140. using type = Iter<T...>; \
  141. using reference = decltype(*std::declval<type>()); \
  142. using value_type = std::decay_t<reference>; \
  143. using pointer = decltype(std::declval<type>().operator->()); \
  144. using difference_type = ::iterator::detail::distance_to_t<type>; \
  145. using iterator_category = ::iterator::detail::tag_for_t<type>; \
  146. }
  147. #include <iterator/detail/undef.h>