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.

332 lines
13KB

  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_SLICE_HPP
  14. #define RANGES_V3_VIEW_SLICE_HPP
  15. #include <type_traits>
  16. #include <meta/meta.hpp>
  17. #include <range/v3/range_fwd.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/iterator/operations.hpp>
  22. #include <range/v3/iterator/traits.hpp>
  23. #include <range/v3/range/concepts.hpp>
  24. #include <range/v3/range/traits.hpp>
  25. #include <range/v3/utility/optional.hpp>
  26. #include <range/v3/utility/static_const.hpp>
  27. #include <range/v3/view/all.hpp>
  28. #include <range/v3/view/drop_exactly.hpp>
  29. #include <range/v3/view/facade.hpp>
  30. #include <range/v3/view/subrange.hpp>
  31. #include <range/v3/view/view.hpp>
  32. namespace ranges
  33. {
  34. /// \cond
  35. namespace detail
  36. {
  37. template<typename Rng, typename Int>
  38. iterator_t<Rng> pos_at_(Rng && rng, Int i, input_range_tag, std::true_type)
  39. {
  40. RANGES_EXPECT(0 <= i);
  41. return next(ranges::begin(rng), i);
  42. }
  43. template<typename Rng, typename Int>
  44. iterator_t<Rng> pos_at_(Rng && rng, Int i, bidirectional_range_tag,
  45. std::false_type)
  46. {
  47. if(0 > i)
  48. {
  49. // If it's not common and we know the size, faster to count from the front
  50. if(RANGES_CONSTEXPR_IF(sized_range<Rng> && !common_range<Rng>))
  51. return next(ranges::begin(rng), distance(rng) + i);
  52. // Otherwise, probably faster to count from the back.
  53. return next(ranges::next(ranges::begin(rng), ranges::end(rng)), i);
  54. }
  55. return next(ranges::begin(rng), i);
  56. }
  57. template<typename Rng, typename Int>
  58. iterator_t<Rng> pos_at_(Rng && rng, Int i, input_range_tag, std::false_type)
  59. {
  60. RANGES_EXPECT(i >= 0 || (bool)sized_range<Rng> || (bool)forward_range<Rng>);
  61. if(0 > i)
  62. return next(ranges::begin(rng), distance(rng) + i);
  63. return next(ranges::begin(rng), i);
  64. }
  65. template<typename Rng, bool IsRandomAccess>
  66. struct slice_view_ : view_facade<slice_view<Rng>, finite>
  67. {
  68. private:
  69. friend range_access;
  70. Rng rng_;
  71. range_difference_t<Rng> from_, count_;
  72. detail::non_propagating_cache<iterator_t<Rng>> begin_;
  73. iterator_t<Rng> get_begin_()
  74. {
  75. if(!begin_)
  76. begin_ = detail::pos_at_(
  77. rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{});
  78. return *begin_;
  79. }
  80. public:
  81. slice_view_() = default;
  82. constexpr slice_view_(Rng rng, range_difference_t<Rng> from,
  83. range_difference_t<Rng> count)
  84. : rng_(std::move(rng))
  85. , from_(from)
  86. , count_(count)
  87. {}
  88. counted_iterator<iterator_t<Rng>> begin()
  89. {
  90. return make_counted_iterator(get_begin_(), count_);
  91. }
  92. default_sentinel_t end()
  93. {
  94. return {};
  95. }
  96. auto size() const
  97. {
  98. return static_cast<detail::iter_size_t<iterator_t<Rng>>>(count_);
  99. }
  100. Rng base() const
  101. {
  102. return rng_;
  103. }
  104. };
  105. template<typename Rng>
  106. struct slice_view_<Rng, true> : view_interface<slice_view<Rng>, finite>
  107. {
  108. private:
  109. Rng rng_;
  110. range_difference_t<Rng> from_, count_;
  111. public:
  112. slice_view_() = default;
  113. constexpr slice_view_(Rng rng, range_difference_t<Rng> from,
  114. range_difference_t<Rng> count)
  115. : rng_(std::move(rng))
  116. , from_(from)
  117. , count_(count)
  118. {
  119. RANGES_EXPECT(0 <= count_);
  120. }
  121. iterator_t<Rng> begin()
  122. {
  123. return detail::pos_at_(
  124. rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{});
  125. }
  126. iterator_t<Rng> end()
  127. {
  128. return detail::pos_at_(
  129. rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{}) +
  130. count_;
  131. }
  132. template<typename BaseRng = Rng>
  133. auto begin() const -> CPP_ret(iterator_t<BaseRng const>)( //
  134. requires range<BaseRng const>)
  135. {
  136. return detail::pos_at_(
  137. rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{});
  138. }
  139. template<typename BaseRng = Rng>
  140. auto end() const -> CPP_ret(iterator_t<BaseRng const>)( //
  141. requires range<BaseRng const>)
  142. {
  143. return detail::pos_at_(
  144. rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{}) +
  145. count_;
  146. }
  147. auto size() const
  148. {
  149. return static_cast<detail::iter_size_t<iterator_t<Rng>>>(count_);
  150. }
  151. Rng base() const
  152. {
  153. return rng_;
  154. }
  155. };
  156. } // namespace detail
  157. /// \endcond
  158. /// \addtogroup group-views
  159. /// @{
  160. template<typename Rng>
  161. struct slice_view : detail::slice_view_<Rng, (bool)random_access_range<Rng>>
  162. {
  163. using detail::slice_view_<Rng, (bool)random_access_range<Rng>>::slice_view_;
  164. };
  165. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  166. template<typename Rng>
  167. slice_view(Rng &&, range_difference_t<Rng>, range_difference_t<Rng>)
  168. ->slice_view<views::all_t<Rng>>;
  169. #endif
  170. namespace views
  171. {
  172. struct slice_fn
  173. {
  174. private:
  175. friend view_access;
  176. template<typename Rng>
  177. constexpr static slice_view<all_t<Rng>> impl_(Rng && rng,
  178. range_difference_t<Rng> from,
  179. range_difference_t<Rng> count,
  180. input_range_tag, range_tag = {})
  181. {
  182. return {all(static_cast<Rng &&>(rng)), from, count};
  183. }
  184. template<typename Rng>
  185. static auto impl_(Rng && rng, range_difference_t<Rng> from,
  186. range_difference_t<Rng> count, random_access_range_tag,
  187. common_range_tag = {})
  188. -> CPP_ret(subrange<iterator_t<Rng>>)( //
  189. requires forwarding_range_<Rng>)
  190. {
  191. auto it =
  192. detail::pos_at_(rng, from, range_tag_of<Rng>{}, is_infinite<Rng>{});
  193. return {it, it + count};
  194. }
  195. // Overloads for the pipe syntax: rng | views::slice(from,to)
  196. template<typename Int>
  197. static constexpr auto CPP_fun(bind)(slice_fn slice, Int from, Int to)( //
  198. requires detail::integer_like_<Int>)
  199. {
  200. return make_pipeable(bind_back(slice, from, to));
  201. }
  202. template<typename Int>
  203. static constexpr auto CPP_fun(bind)(slice_fn slice, Int from,
  204. detail::from_end_<Int> to)( //
  205. requires detail::integer_like_<Int>)
  206. {
  207. return make_pipeable(bind_back(slice, from, to));
  208. }
  209. template<typename Int>
  210. static constexpr auto CPP_fun(bind)(slice_fn slice,
  211. detail::from_end_<Int> from,
  212. detail::from_end_<Int> to)( //
  213. requires detail::integer_like_<Int>)
  214. {
  215. return make_pipeable(bind_back(slice, from, to));
  216. }
  217. template<typename Int>
  218. static constexpr auto CPP_fun(bind)(slice_fn, Int from, end_fn)( //
  219. requires detail::integer_like_<Int>)
  220. {
  221. return make_pipeable(bind_back(ranges::views::drop_exactly, from));
  222. }
  223. template<typename Int>
  224. static constexpr auto CPP_fun(bind)(slice_fn slice,
  225. detail::from_end_<Int> from,
  226. end_fn to)( //
  227. requires detail::integer_like_<Int>)
  228. {
  229. return make_pipeable(bind_back(slice, from, to));
  230. }
  231. public:
  232. // slice(rng, 2, 4)
  233. template<typename Rng>
  234. constexpr auto CPP_fun(operator())( //
  235. Rng && rng, range_difference_t<Rng> from, range_difference_t<Rng> to)(
  236. const requires viewable_range<Rng> && input_range<Rng>)
  237. {
  238. RANGES_EXPECT(0 <= from && from <= to);
  239. return slice_fn::impl_(
  240. static_cast<Rng &&>(rng), from, to - from, range_tag_of<Rng>{});
  241. }
  242. // slice(rng, 4, end-2)
  243. // TODO Support Forward, non-Sized ranges by returning a range that
  244. // doesn't know it's size?
  245. template<typename Rng>
  246. auto CPP_fun(operator())( //
  247. Rng && rng, range_difference_t<Rng> from,
  248. detail::from_end_of_t<Rng> to)(const requires viewable_range<Rng> &&
  249. input_range<Rng> && sized_range<Rng>)
  250. {
  251. static_assert(!is_infinite<Rng>::value,
  252. "Can't index from the end of an infinite range!");
  253. RANGES_EXPECT(0 <= from);
  254. RANGES_ASSERT(from <= distance(rng) + to.dist_);
  255. return slice_fn::impl_(static_cast<Rng &&>(rng),
  256. from,
  257. distance(rng) + to.dist_ - from,
  258. range_tag_of<Rng>{});
  259. }
  260. // slice(rng, end-4, end-2)
  261. template<typename Rng>
  262. auto CPP_fun(operator())( //
  263. Rng && rng, detail::from_end_of_t<Rng> from,
  264. detail::from_end_of_t<Rng> to)(const requires viewable_range<Rng> &&
  265. (forward_range<Rng> ||
  266. (input_range<Rng> && sized_range<Rng>)))
  267. {
  268. static_assert(!is_infinite<Rng>::value,
  269. "Can't index from the end of an infinite range!");
  270. RANGES_EXPECT(from.dist_ <= to.dist_);
  271. return slice_fn::impl_(static_cast<Rng &&>(rng),
  272. from.dist_,
  273. to.dist_ - from.dist_,
  274. range_tag_of<Rng>{},
  275. common_range_tag_of<Rng>{});
  276. }
  277. // slice(rng, 4, end)
  278. template<typename Rng>
  279. auto CPP_fun(operator())(Rng && rng, range_difference_t<Rng> from, end_fn)(
  280. const requires viewable_range<Rng> && input_range<Rng>)
  281. {
  282. RANGES_EXPECT(0 <= from);
  283. return ranges::views::drop_exactly(static_cast<Rng &&>(rng), from);
  284. }
  285. // slice(rng, end-4, end)
  286. template<typename Rng>
  287. auto CPP_fun(operator())(Rng && rng, detail::from_end_of_t<Rng> from,
  288. end_fn)(const requires viewable_range<Rng> &&
  289. (forward_range<Rng> ||
  290. (input_range<Rng> && sized_range<Rng>)))
  291. {
  292. static_assert(!is_infinite<Rng>::value,
  293. "Can't index from the end of an infinite range!");
  294. return slice_fn::impl_(static_cast<Rng &&>(rng),
  295. from.dist_,
  296. -from.dist_,
  297. range_tag_of<Rng>{},
  298. common_range_tag_of<Rng>{});
  299. }
  300. };
  301. /// \relates _slice_fn
  302. /// \ingroup group-views
  303. RANGES_INLINE_VARIABLE(view<slice_fn>, slice)
  304. } // namespace views
  305. /// @}
  306. } // namespace ranges
  307. #include <range/v3/detail/satisfy_boost_range.hpp>
  308. RANGES_SATISFY_BOOST_RANGE(::ranges::slice_view)
  309. #endif