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.

325 lines
12KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2014-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_RANGE_PRIMITIVES_HPP
  14. #define RANGES_V3_RANGE_PRIMITIVES_HPP
  15. #include <concepts/concepts.hpp>
  16. #include <range/v3/range_fwd.hpp>
  17. #include <range/v3/iterator/concepts.hpp>
  18. #include <range/v3/range/access.hpp>
  19. #include <range/v3/utility/addressof.hpp>
  20. #include <range/v3/utility/static_const.hpp>
  21. namespace ranges
  22. {
  23. /// \addtogroup group-range
  24. // Specialize this if the default is wrong.
  25. template<typename T>
  26. RANGES_INLINE_VAR constexpr bool disable_sized_range = false;
  27. /// \cond
  28. namespace _size_
  29. {
  30. template<typename T>
  31. void size(T &&) = delete;
  32. #ifdef RANGES_WORKAROUND_MSVC_895622
  33. void size();
  34. #endif
  35. struct fn
  36. {
  37. private:
  38. template<typename R>
  39. using member_size_t = decltype(+(std::declval<R>()).size());
  40. template<typename R>
  41. using non_member_size_t = decltype(+size(std::declval<R>()));
  42. template<typename R, std::size_t N>
  43. static constexpr std::size_t impl_(R (&)[N], int) noexcept
  44. {
  45. return N;
  46. }
  47. template<typename R, std::size_t N>
  48. static constexpr std::size_t impl_(R(&&)[N], int) noexcept
  49. {
  50. return N;
  51. }
  52. // Prefer member if it returns integral.
  53. template<typename R>
  54. static constexpr auto impl_(R && r, int) noexcept(noexcept(((R &&) r).size()))
  55. -> CPP_ret(member_size_t<R>)( //
  56. requires integral<member_size_t<R>> &&
  57. (!disable_sized_range<uncvref_t<R>>))
  58. {
  59. return ((R &&) r).size();
  60. }
  61. // Use ADL if it returns integral.
  62. template<typename R>
  63. static constexpr auto impl_(R && r, long) noexcept(noexcept(size((R &&) r)))
  64. -> CPP_ret(non_member_size_t<R>)( //
  65. requires integral<non_member_size_t<R>> &&
  66. (!disable_sized_range<uncvref_t<R>>))
  67. {
  68. return size((R &&) r);
  69. }
  70. template<typename R>
  71. static constexpr auto impl_(R && r, ...)
  72. -> CPP_ret(detail::iter_size_t<_begin_::_t<R>>)( //
  73. requires forward_iterator<_begin_::_t<R>> &&
  74. sized_sentinel_for<_end_::_t<R>, _begin_::_t<R>>)
  75. {
  76. using size_type = detail::iter_size_t<_begin_::_t<R>>;
  77. return static_cast<size_type>(ranges::end((R &&) r) -
  78. ranges::begin((R &&) r));
  79. }
  80. public:
  81. template<typename R>
  82. constexpr auto operator()(R && r) const
  83. noexcept(noexcept(fn::impl_((R &&) r, 0)))
  84. -> decltype(fn::impl_((R &&) r, 0))
  85. {
  86. return fn::impl_((R &&) r, 0);
  87. }
  88. template<typename T, typename Fn = fn>
  89. RANGES_DEPRECATED(
  90. "Using a reference_wrapper as a Range is deprecated. Use views::ref "
  91. "instead.")
  92. constexpr auto
  93. operator()(std::reference_wrapper<T> ref) const
  94. noexcept(noexcept(Fn{}(ref.get()))) -> decltype(Fn{}(ref.get()))
  95. {
  96. return Fn{}(ref.get());
  97. }
  98. template<typename T, typename Fn = fn>
  99. RANGES_DEPRECATED(
  100. "Using a reference_wrapper as a Range is deprecated. Use views::ref "
  101. "instead.")
  102. constexpr auto
  103. operator()(ranges::reference_wrapper<T> ref) const
  104. noexcept(noexcept(Fn{}(ref.get()))) -> decltype(Fn{}(ref.get()))
  105. {
  106. return Fn{}(ref.get());
  107. }
  108. };
  109. } // namespace _size_
  110. /// \endcond
  111. /// \ingroup group-range
  112. /// \return For a given expression `E` of type `T`, `ranges::size(E)` is equivalent
  113. /// to:
  114. /// * `+extent_v<T>` if `T` is an array type.
  115. /// * Otherwise, `+E.size()` if it is a valid expression and its type `I` models
  116. /// `integral` and `disable_sized_range<std::remove_cvref_t<T>>` is false.
  117. /// * Otherwise, `+size(E)` if it is a valid expression and its type `I` models
  118. /// `integral` with overload resolution performed in a context that includes the
  119. /// declaration:
  120. /// \code
  121. /// template<class T> void size(T&&) = delete;
  122. /// \endcode
  123. /// and does not include a declaration of `ranges::size`, and
  124. /// `disable_sized_range<std::remove_cvref_t<T>>` is false.
  125. /// * Otherwise, `static_cast<U>(ranges::end(E) - ranges::begin(E))` where `U` is
  126. /// `std::make_unsigned_t<iter_difference_t<iterator_t<T>>>` if
  127. /// `iter_difference_t<iterator_t<T>>` satisfies `integral` and
  128. /// `iter_difference_t<iterator_t<T>>` otherwise; except that `E` is
  129. /// evaluated once, if it is a valid expression and the types `I` and `S` of
  130. /// `ranges::begin(E)` and `ranges::end(E)` model `sized_sentinel_for<S, I>` and
  131. /// `forward_iterator<I>`.
  132. /// * Otherwise, `ranges::size(E)` is ill-formed.
  133. RANGES_DEFINE_CPO(_size_::fn, size)
  134. // Customization point data
  135. /// \cond
  136. namespace _data_
  137. {
  138. struct fn
  139. {
  140. private:
  141. template<typename R>
  142. using member_data_t = detail::decay_t<decltype(std::declval<R>().data())>;
  143. template<typename R>
  144. static constexpr auto impl_(R & r, detail::priority_tag<2>) noexcept(
  145. noexcept(r.data())) -> CPP_ret(member_data_t<R &>)( //
  146. requires std::is_pointer<member_data_t<R &>>::value)
  147. {
  148. return r.data();
  149. }
  150. template<typename R>
  151. static constexpr auto impl_(R && r, detail::priority_tag<1>) noexcept(
  152. noexcept(ranges::begin((R &&) r))) -> CPP_ret(_begin_::_t<R>)( //
  153. requires std::is_pointer<_begin_::_t<R>>::value)
  154. {
  155. return ranges::begin((R &&) r);
  156. }
  157. template<typename R>
  158. static constexpr auto impl_(R && r, detail::priority_tag<0>) noexcept(
  159. noexcept(ranges::begin((R &&) r) == ranges::end((R &&) r)
  160. ? nullptr
  161. : detail::addressof(*ranges::begin((R &&) r))))
  162. -> CPP_ret(decltype(detail::addressof(*ranges::begin((R &&) r))))( //
  163. requires contiguous_iterator<_begin_::_t<R>>)
  164. {
  165. return ranges::begin((R &&) r) == ranges::end((R &&) r)
  166. ? nullptr
  167. : detail::addressof(*ranges::begin((R &&) r));
  168. }
  169. public:
  170. template<typename charT, typename Traits, typename Alloc>
  171. constexpr charT * operator()(
  172. std::basic_string<charT, Traits, Alloc> & s) const noexcept
  173. {
  174. // string doesn't have non-const data before C++17
  175. return const_cast<charT *>(detail::as_const(s).data());
  176. }
  177. template<typename R>
  178. constexpr auto operator()(R && r) const
  179. noexcept(noexcept(fn::impl_((R &&) r, detail::priority_tag<2>{})))
  180. -> decltype(fn::impl_((R &&) r, detail::priority_tag<2>{}))
  181. {
  182. return fn::impl_((R &&) r, detail::priority_tag<2>{});
  183. }
  184. };
  185. template<typename R>
  186. using _t = decltype(fn{}(std::declval<R>()));
  187. } // namespace _data_
  188. /// \endcond
  189. RANGES_INLINE_VARIABLE(_data_::fn, data)
  190. /// \cond
  191. namespace _cdata_
  192. {
  193. struct fn
  194. {
  195. template<typename R>
  196. constexpr _data_::_t<R const &> operator()(R const & r) const
  197. noexcept(noexcept(ranges::data(r)))
  198. {
  199. return ranges::data(r);
  200. }
  201. template<typename R>
  202. constexpr _data_::_t<R const> operator()(R const && r) const
  203. noexcept(noexcept(ranges::data((R const &&)r)))
  204. {
  205. return ranges::data((R const &&)r);
  206. }
  207. };
  208. } // namespace _cdata_
  209. /// \endcond
  210. /// \ingroup group-range
  211. /// \param r
  212. /// \return The result of calling `ranges::data` with a const-qualified
  213. /// (lvalue or rvalue) reference to `r`.
  214. RANGES_INLINE_VARIABLE(_cdata_::fn, cdata)
  215. /// \cond
  216. namespace _empty_
  217. {
  218. struct fn
  219. {
  220. private:
  221. // Prefer member if it is valid.
  222. template<typename R>
  223. static constexpr auto impl_(R && r, detail::priority_tag<2>) noexcept(
  224. noexcept(bool(((R &&) r).empty()))) -> decltype(bool(((R &&) r).empty()))
  225. {
  226. return bool(((R &&) r).empty());
  227. }
  228. // Fall back to size == 0.
  229. template<typename R>
  230. static constexpr auto impl_(R && r, detail::priority_tag<1>) noexcept(
  231. noexcept(bool(ranges::size((R &&) r) == 0)))
  232. -> decltype(bool(ranges::size((R &&) r) == 0))
  233. {
  234. return bool(ranges::size((R &&) r) == 0);
  235. }
  236. // Fall further back to begin == end.
  237. template<typename R>
  238. static constexpr auto impl_(R && r, detail::priority_tag<0>) noexcept(
  239. noexcept(bool(ranges::begin((R &&) r) == ranges::end((R &&) r))))
  240. -> CPP_ret(decltype(bool(ranges::begin((R &&) r) ==
  241. ranges::end((R &&) r))))( //
  242. requires forward_iterator<_begin_::_t<R>>)
  243. {
  244. return bool(ranges::begin((R &&) r) == ranges::end((R &&) r));
  245. }
  246. public:
  247. template<typename R>
  248. constexpr auto operator()(R && r) const
  249. noexcept(noexcept(fn::impl_((R &&) r, detail::priority_tag<2>{})))
  250. -> decltype(fn::impl_((R &&) r, detail::priority_tag<2>{}))
  251. {
  252. return fn::impl_((R &&) r, detail::priority_tag<2>{});
  253. }
  254. template<typename T, typename Fn = fn>
  255. RANGES_DEPRECATED(
  256. "Using a reference_wrapper as a Range is deprecated. Use views::ref "
  257. "instead.")
  258. constexpr auto
  259. operator()(std::reference_wrapper<T> ref) const
  260. noexcept(noexcept(Fn{}(ref.get()))) -> decltype(Fn{}(ref.get()))
  261. {
  262. return Fn{}(ref.get());
  263. }
  264. template<typename T, typename Fn = fn>
  265. RANGES_DEPRECATED(
  266. "Using a reference_wrapper as a Range is deprecated. Use views::ref "
  267. "instead.")
  268. constexpr auto
  269. operator()(ranges::reference_wrapper<T> ref) const
  270. noexcept(noexcept(Fn{}(ref.get()))) -> decltype(Fn{}(ref.get()))
  271. {
  272. return Fn{}(ref.get());
  273. }
  274. };
  275. } // namespace _empty_
  276. /// \endcond
  277. /// \ingroup group-range
  278. /// \return true if and only if range contains no elements.
  279. RANGES_INLINE_VARIABLE(_empty_::fn, empty)
  280. namespace cpp20
  281. {
  282. // Specialize this is namespace ranges::
  283. using ranges::cdata;
  284. using ranges::data;
  285. using ranges::disable_sized_range;
  286. using ranges::empty;
  287. using ranges::size;
  288. } // namespace cpp20
  289. } // namespace ranges
  290. #endif