You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

275 lines
9.6KB

  1. // Range v3 library
  2. //
  3. // Copyright Eric Niebler 2018-present
  4. //
  5. // Use, modification and distribution is subject to the
  6. // Boost Software License, Version 1.0. (See accompanying
  7. // file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. // Project home: https://github.com/ericniebler/range-v3
  11. //
  12. #ifndef RANGES_V3_STD_ITERATOR
  13. #define RANGES_V3_STD_ITERATOR
  14. #if defined(__GNUC__)
  15. #include_next <iterator>
  16. #elif defined(_MSC_VER)
  17. #include <../include/iterator> // HACKHACK
  18. #else
  19. #error "Cannot use range-v3 STL deep integration on this platform."
  20. #endif
  21. #if RANGES_DEEP_STL_INTEGRATION
  22. #include <range/v3/detail/config.hpp>
  23. #include <std/detail/associated_types.hpp>
  24. namespace ranges
  25. {
  26. template<typename I>
  27. struct incrementable_traits;
  28. template<typename I>
  29. struct readable_traits;
  30. /// \cond
  31. namespace detail
  32. {
  33. template<typename I>
  34. typename incrementable_traits<I>::difference_type cpp17_difference_type_(int);
  35. template<typename I>
  36. void cpp17_difference_type_(long);
  37. template<typename I>
  38. typename I::pointer cpp17_pointer_type_(int);
  39. template<typename I>
  40. auto cpp17_pointer_type_(long, I *pi = nullptr) -> decltype(pi->operator->());
  41. template<typename I>
  42. void cpp17_pointer_type_(...);
  43. template<typename I>
  44. typename I::reference cpp17_reference_type_(int);
  45. template<typename I>
  46. auto cpp17_reference_type_(long, I *pi = nullptr) -> decltype(**pi);
  47. template<typename I>
  48. auto cpp17_iterator_category_4_(long)
  49. {
  50. return std::bidirectional_iterator_tag{};
  51. }
  52. // Satisfies Cpp17RandomAccessIterator?
  53. template<typename I>
  54. auto cpp17_iterator_category_4_(
  55. int,
  56. I *pi = nullptr,
  57. typename incrementable_traits<I>::difference_type d = 0,
  58. always_<
  59. void,
  60. int[RANGES_IS_SAME(decltype(*pi += d), I &)],
  61. int[RANGES_IS_SAME(decltype(*pi -= d), I &)],
  62. int[RANGES_IS_SAME(decltype(*pi + d), I)],
  63. int[RANGES_IS_SAME(decltype(*pi - d), I)],
  64. int[RANGES_IS_SAME(decltype(d + *pi), I)],
  65. int[RANGES_IS_SAME(decltype(*pi - *pi), decltype(d))],
  66. int[RANGES_IS_SAME(decltype((*pi)[d]), decltype(**pi))],
  67. decltype(*pi < *pi ? true : false),
  68. decltype(*pi > *pi ? true : false),
  69. decltype(*pi <= *pi ? true : false),
  70. decltype(*pi >= *pi ? true : false)
  71. > * = nullptr)
  72. {
  73. return std::random_access_iterator_tag{};
  74. }
  75. template<typename I>
  76. auto cpp17_iterator_category_3_(long)
  77. {
  78. return std::forward_iterator_tag{};
  79. }
  80. // Satisfies Cpp17BidirectionalIterator?
  81. template<typename I>
  82. auto cpp17_iterator_category_3_(
  83. int,
  84. I *pi = nullptr,
  85. void (*fn)(I const &) = nullptr,
  86. always_<
  87. void,
  88. decltype(fn((*pi)--)), // i-- convertible to I const &
  89. int[RANGES_IS_SAME(decltype(--*pi), I &)], // --i has type I &
  90. // *i has the same type as *i--
  91. int[RANGES_IS_SAME(decltype(**pi), decltype(*(*pi)--))]
  92. > * = nullptr)
  93. {
  94. return cpp17_iterator_category_4_<I>(0);
  95. }
  96. template<typename I>
  97. auto cpp17_iterator_category_2_(long)
  98. {
  99. return std::input_iterator_tag{};
  100. }
  101. // Satisfies Cpp17ForwardIterator?
  102. template<typename I>
  103. auto cpp17_iterator_category_2_(
  104. int,
  105. I *pi = nullptr,
  106. void (*fn)(I const &) = nullptr,
  107. typename readable_traits<I>::value_type *pv = nullptr,
  108. typename readable_traits<I>::value_type const *pcv = nullptr,
  109. always_<
  110. void,
  111. decltype(I{}), // Default constructible
  112. decltype(fn((*pi)++)), // i++ convertible to I const &
  113. // *i has the same type as *i++
  114. int[RANGES_IS_SAME(decltype(**pi), decltype(*(*pi)++))],
  115. // *i is a real reference to value_type
  116. #ifdef RANGES_WORKAROUND_MSVC_793042
  117. enable_if_t<RANGES_IS_SAME(decltype(**pi), decltype(*pv)) ||
  118. RANGES_IS_SAME(decltype(**pi), decltype(*pcv)) ||
  119. RANGES_IS_SAME(decltype(**pi), typename readable_traits<I>::value_type &&) ||
  120. RANGES_IS_SAME(decltype(**pi), typename readable_traits<I>::value_type const &&)>
  121. #else // ^^^ workaround / no workaround vvv
  122. int[RANGES_IS_SAME(decltype(**pi), decltype(*pv)) ||
  123. RANGES_IS_SAME(decltype(**pi), decltype(*pcv)) ||
  124. RANGES_IS_SAME(decltype(**pi), typename readable_traits<I>::value_type &&) ||
  125. RANGES_IS_SAME(decltype(**pi), typename readable_traits<I>::value_type const &&)]
  126. #endif // RANGES_WORKAROUND_MSVC_793042
  127. > * = nullptr)
  128. {
  129. return cpp17_iterator_category_3_<I>(0);
  130. }
  131. template<typename I>
  132. using cpp17_readable_iterator_category_t =
  133. decltype(detail::cpp17_iterator_category_2_<I>(0));
  134. template<typename I>
  135. auto cpp17_iterator_category_(long)
  136. {
  137. return cpp17_iterator_category_2_<I>(0);
  138. }
  139. // Explicitly declares its category?
  140. template<typename I>
  141. typename I::iterator_category cpp17_iterator_category_(int)
  142. {
  143. return {};
  144. }
  145. template<typename I>
  146. auto std_iterator_traits_impl_2_(long)
  147. {
  148. return std_output_iterator_traits<
  149. decltype(detail::cpp17_difference_type_<I>(0))>{};
  150. }
  151. // Satisfies Cpp17InputIterator?
  152. template<typename I>
  153. auto std_iterator_traits_impl_2_(
  154. int,
  155. I *pi = nullptr,
  156. typename incrementable_traits<I>::difference_type d = 0,
  157. typename readable_traits<I>::value_type const *pcv = nullptr,
  158. always_<
  159. void,
  160. int[decltype(d)(-1) < decltype(d)(0)], // signed difference type
  161. decltype(decltype(*pcv)(**pi)), // sensible reference/value type
  162. decltype(decltype(*pcv)(*(*pi)++)), // sensible post-increment result
  163. decltype(*pi == *pi ? true : false), // equality comparable
  164. decltype(*pi != *pi ? true : false) // " "
  165. > * = nullptr)
  166. {
  167. using D = typename incrementable_traits<I>::difference_type;
  168. struct yes_traits
  169. {
  170. using difference_type = D;
  171. using value_type = typename readable_traits<I>::value_type;
  172. using reference = decltype(cpp17_reference_type_<I>(0));
  173. using pointer = decltype(cpp17_pointer_type_<I>(0));
  174. using iterator_category = decltype(cpp17_iterator_category_<I>(0));
  175. };
  176. struct no_traits
  177. {};
  178. return if_then_t<is_integral_<D>(0), yes_traits, no_traits>{};
  179. }
  180. template<typename I>
  181. nil_ std_iterator_traits_impl_(long)
  182. {
  183. return {};
  184. }
  185. // Satisfies Cpp17Iterator?
  186. template<typename I>
  187. auto std_iterator_traits_impl_(
  188. int,
  189. I *pi = nullptr,
  190. void (*nv)(...) = nullptr,
  191. always_<
  192. void,
  193. decltype(nv(**pi)),
  194. int[RANGES_IS_SAME(decltype(++*pi), I &)],
  195. decltype(nv(*(*pi)++))
  196. > * = nullptr)
  197. {
  198. return std_iterator_traits_impl_2_<I>(0);
  199. }
  200. template<typename T>
  201. constexpr bool has_iterator_typedefs_impl_(
  202. int,
  203. always_<
  204. void,
  205. typename T::difference_type,
  206. typename T::value_type,
  207. typename T::pointer,
  208. typename T::reference,
  209. typename T::iterator_category
  210. > * = nullptr)
  211. {
  212. return true;
  213. }
  214. template<typename T>
  215. constexpr bool has_iterator_typedefs_impl_(long)
  216. {
  217. return false;
  218. }
  219. }
  220. /// \endcond
  221. }
  222. // Hijack the primary std::iterator_traits template from each of the 3 major
  223. // standard library implementations
  224. RANGES_BEGIN_NAMESPACE_STD
  225. RANGES_BEGIN_NAMESPACE_VERSION
  226. #if defined(__GLIBCXX__)
  227. template<typename I>
  228. struct __iterator_traits<
  229. I,
  230. ::ranges::detail::enable_if_t<!::ranges::detail::has_iterator_typedefs_impl_<I>(0)>>
  231. : decltype(::ranges::detail::std_iterator_traits_impl_<I>(0))
  232. {};
  233. #elif defined(_LIBCPP_VERSION)
  234. template<typename I>
  235. struct __iterator_traits<I, false> // doesn't have I::iterator_category
  236. : decltype(::ranges::detail::std_iterator_traits_impl_<I>(0))
  237. {};
  238. #elif defined(_MSVC_STL_VERSION)
  239. template<typename I>
  240. struct _Iterator_traits_base<
  241. I,
  242. #ifdef RANGES_WORKAROUND_MSVC_792338
  243. ::ranges::detail::enable_if_t<decltype(bool_constant<
  244. !::ranges::detail::has_iterator_typedefs_impl_<I>(0)>{})::value>>
  245. #else // ^^^ workaround / no workaround vvv
  246. ::ranges::detail::enable_if_t<!::ranges::detail::has_iterator_typedefs_impl_<I>(0)>>
  247. #endif // RANGES_WORKAROUND_MSVC_792338
  248. : decltype(::ranges::detail::std_iterator_traits_impl_<I>(0))
  249. {};
  250. #endif
  251. RANGES_END_NAMESPACE_VERSION
  252. RANGES_END_NAMESPACE_STD
  253. #endif // RANGES_DEEP_STL_INTEGRATION
  254. #endif // RANGES_V3_STD_ITERATOR