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.

312 lines
10KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-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_VIEW_TAKE_HPP
  14. #define RANGES_V3_VIEW_TAKE_HPP
  15. #include <type_traits>
  16. #include <range/v3/range_fwd.hpp>
  17. #include <range/v3/algorithm/min.hpp>
  18. #include <range/v3/functional/bind_back.hpp>
  19. #include <range/v3/iterator/counted_iterator.hpp>
  20. #include <range/v3/iterator/default_sentinel.hpp>
  21. #include <range/v3/range/concepts.hpp>
  22. #include <range/v3/range/traits.hpp>
  23. #include <range/v3/utility/static_const.hpp>
  24. #include <range/v3/view/all.hpp>
  25. #include <range/v3/view/view.hpp>
  26. namespace ranges
  27. {
  28. template<typename Rng>
  29. struct take_view : view_interface<take_view<Rng>, finite>
  30. {
  31. private:
  32. CPP_assert(view_<Rng>);
  33. Rng base_ = Rng();
  34. range_difference_t<Rng> count_ = 0;
  35. template<bool Const>
  36. struct sentinel
  37. {
  38. private:
  39. using Base = detail::if_then_t<Const, Rng const, Rng>;
  40. using CI = counted_iterator<iterator_t<Base>>;
  41. sentinel_t<Base> end_ = sentinel_t<Base>();
  42. public:
  43. sentinel() = default;
  44. constexpr explicit sentinel(sentinel_t<Base> last)
  45. : end_(std::move(last))
  46. {}
  47. CPP_template(bool Other)( //
  48. requires Const && (!Other) &&
  49. convertible_to<sentinel_t<Rng>,
  50. sentinel_t<Base>>) //
  51. constexpr sentinel(sentinel<Other> that)
  52. : end_(std::move(that.end_))
  53. {}
  54. constexpr sentinel_t<Base> base() const
  55. {
  56. return end_;
  57. }
  58. #ifdef RANGES_WORKAROUND_MSVC_756601
  59. template<typename = void>
  60. #endif // RANGES_WORKAROUND_MSVC_756601
  61. friend constexpr bool operator==(sentinel const & x, CI const & y)
  62. {
  63. return y.count() == 0 || y.base() == x.end_;
  64. }
  65. #ifdef RANGES_WORKAROUND_MSVC_756601
  66. template<typename = void>
  67. #endif // RANGES_WORKAROUND_MSVC_756601
  68. friend constexpr bool operator==(CI const & y, sentinel const & x)
  69. {
  70. return y.count() == 0 || y.base() == x.end_;
  71. }
  72. #ifdef RANGES_WORKAROUND_MSVC_756601
  73. template<typename = void>
  74. #endif // RANGES_WORKAROUND_MSVC_756601
  75. friend constexpr bool operator!=(sentinel const & x, CI const & y)
  76. {
  77. return y.count() != 0 && y.base() != x.end_;
  78. }
  79. #ifdef RANGES_WORKAROUND_MSVC_756601
  80. template<typename = void>
  81. #endif // RANGES_WORKAROUND_MSVC_756601
  82. friend constexpr bool operator!=(CI const & y, sentinel const & x)
  83. {
  84. return y.count() != 0 && y.base() != x.end_;
  85. }
  86. };
  87. #if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17
  88. template<typename Take>
  89. static auto begin_random_access_(Take & take, std::true_type)
  90. {
  91. return ranges::begin(take.base_);
  92. }
  93. template<typename Take>
  94. static auto begin_random_access_(Take & take, std::false_type)
  95. {
  96. auto s = static_cast<range_difference_t<Rng>>(take.size());
  97. return make_counted_iterator(ranges::begin(take.base_), s);
  98. }
  99. template<typename Take>
  100. static auto begin_sized_(Take & take, std::true_type)
  101. {
  102. return begin_random_access_(
  103. take, meta::bool_<random_access_range<decltype((take.base_))>>{});
  104. }
  105. template<typename Take>
  106. static auto begin_sized_(Take & take, std::false_type)
  107. {
  108. return make_counted_iterator(ranges::begin(take.base_), take.count_);
  109. }
  110. template<typename Take>
  111. static auto end_random_access_(Take & take, std::true_type)
  112. {
  113. return ranges::begin(take.base_) +
  114. static_cast<range_difference_t<Rng>>(take.size());
  115. }
  116. static auto end_random_access_(detail::ignore_t, std::false_type)
  117. {
  118. return default_sentinel;
  119. }
  120. template<typename Take>
  121. static auto end_sized_(Take & take, std::true_type, std::false_type) // sized
  122. {
  123. return end_random_access_(
  124. take, meta::bool_<random_access_range<decltype((take.base_))>>{});
  125. }
  126. static auto end_sized_(detail::ignore_t, std::false_type,
  127. std::true_type) // infinite
  128. {
  129. return default_sentinel;
  130. }
  131. static auto end_sized_(take_view & take, std::false_type, std::false_type)
  132. {
  133. return sentinel<false>{ranges::end(take.base_)};
  134. }
  135. static auto end_sized_(take_view const & take, std::false_type, std::false_type)
  136. {
  137. return sentinel<true>{ranges::end(take.base_)};
  138. }
  139. #endif
  140. public:
  141. take_view() = default;
  142. constexpr take_view(Rng base, range_difference_t<Rng> cnt)
  143. : base_(std::move(base))
  144. , count_(cnt)
  145. {}
  146. constexpr Rng base() const
  147. {
  148. return base_;
  149. }
  150. CPP_member
  151. constexpr auto CPP_fun(begin)()(requires(!simple_view<Rng>()))
  152. {
  153. #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
  154. if constexpr(sized_range<Rng>)
  155. if constexpr(random_access_range<Rng>)
  156. return ranges::begin(base_);
  157. else
  158. {
  159. // cannot always delegate to size() member on GCC with ConceptsTS
  160. #if defined(__cpp_concepts) && __cpp_concepts <= 201507
  161. auto s = ranges::min(
  162. static_cast<range_difference_t<Rng>>(count_),
  163. static_cast<range_difference_t<Rng>>(ranges::size(base_)));
  164. #else
  165. auto s = static_cast<range_difference_t<Rng>>(size());
  166. #endif
  167. return make_counted_iterator(ranges::begin(base_), s);
  168. }
  169. else
  170. return make_counted_iterator(ranges::begin(base_), count_);
  171. #else
  172. return begin_sized_(*this, meta::bool_<sized_range<Rng>>{});
  173. #endif
  174. }
  175. CPP_member
  176. constexpr auto CPP_fun(begin)()(const requires range<Rng const>)
  177. {
  178. #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
  179. if constexpr(sized_range<Rng const>)
  180. if constexpr(random_access_range<Rng const>)
  181. return ranges::begin(base_);
  182. else
  183. {
  184. auto s = static_cast<range_difference_t<Rng>>(size());
  185. return make_counted_iterator(ranges::begin(base_), s);
  186. }
  187. else
  188. return make_counted_iterator(ranges::begin(base_), count_);
  189. #else
  190. return begin_sized_(*this, meta::bool_<sized_range<Rng const>>{});
  191. #endif
  192. }
  193. CPP_member
  194. constexpr auto CPP_fun(end)()(requires(!simple_view<Rng>()))
  195. {
  196. #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
  197. if constexpr(sized_range<Rng>)
  198. if constexpr(random_access_range<Rng>)
  199. return ranges::begin(base_) +
  200. static_cast<range_difference_t<Rng>>(size());
  201. else
  202. return default_sentinel;
  203. // Not to spec: Infinite ranges:
  204. else if constexpr(is_infinite<Rng>::value)
  205. return default_sentinel;
  206. else
  207. return sentinel<false>{ranges::end(base_)};
  208. #else
  209. return end_sized_(*this, meta::bool_<sized_range<Rng>>{}, is_infinite<Rng>{});
  210. #endif
  211. }
  212. CPP_member
  213. constexpr auto CPP_fun(end)()(const requires range<Rng const>)
  214. {
  215. #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
  216. if constexpr(sized_range<Rng const>)
  217. if constexpr(random_access_range<Rng const>)
  218. return ranges::begin(base_) +
  219. static_cast<range_difference_t<Rng>>(size());
  220. else
  221. return default_sentinel;
  222. // Not to spec: Infinite ranges:
  223. else if constexpr(is_infinite<Rng const>::value)
  224. return default_sentinel;
  225. else
  226. return sentinel<true>{ranges::end(base_)};
  227. #else
  228. return end_sized_(
  229. *this, meta::bool_<sized_range<Rng const>>{}, is_infinite<Rng const>{});
  230. #endif
  231. }
  232. CPP_member
  233. constexpr auto CPP_fun(size)()(requires sized_range<Rng>)
  234. {
  235. auto n = ranges::size(base_);
  236. return ranges::min(n, static_cast<decltype(n)>(count_));
  237. }
  238. CPP_member
  239. constexpr auto CPP_fun(size)()(const requires sized_range<Rng const>)
  240. {
  241. auto n = ranges::size(base_);
  242. return ranges::min(n, static_cast<decltype(n)>(count_));
  243. }
  244. };
  245. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  246. template<typename Rng>
  247. take_view(Rng &&, range_difference_t<Rng>)->take_view<views::all_t<Rng>>;
  248. #endif
  249. namespace views
  250. {
  251. struct take_fn
  252. {
  253. private:
  254. friend view_access;
  255. template<typename Int>
  256. static constexpr auto CPP_fun(bind)(take_fn take, Int n)( //
  257. requires integral<Int>)
  258. {
  259. return make_pipeable(bind_back(take, n));
  260. }
  261. public:
  262. template<typename Rng>
  263. auto operator()(Rng && rng, range_difference_t<Rng> n) const
  264. -> CPP_ret(take_view<all_t<Rng>>)( //
  265. requires viewable_range<Rng>)
  266. {
  267. return {all(static_cast<Rng &&>(rng)), n};
  268. }
  269. };
  270. /// \relates take_fn
  271. /// \ingroup group-views
  272. RANGES_INLINE_VARIABLE(view<take_fn>, take)
  273. } // namespace views
  274. namespace cpp20
  275. {
  276. namespace views
  277. {
  278. using ranges::views::take;
  279. }
  280. CPP_template(typename Rng)( //
  281. requires view_<Rng>) //
  282. using take_view = ranges::take_view<Rng>;
  283. } // namespace cpp20
  284. /// @}
  285. } // namespace ranges
  286. #include <range/v3/detail/satisfy_boost_range.hpp>
  287. RANGES_SATISFY_BOOST_RANGE(::ranges::take_view)
  288. #endif