Horizon
slice.hpp
Go to the documentation of this file.
1 // 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 
14 #ifndef RANGES_V3_VIEW_SLICE_HPP
15 #define RANGES_V3_VIEW_SLICE_HPP
16 
17 #include <type_traits>
18 
19 #include <meta/meta.hpp>
20 
21 #include <range/v3/range_fwd.hpp>
22 
31 #include <range/v3/utility/static_const.hpp>
32 #include <range/v3/view/all.hpp>
34 #include <range/v3/view/facade.hpp>
36 #include <range/v3/view/view.hpp>
37 
38 #include <range/v3/detail/prologue.hpp>
39 
40 namespace ranges
41 {
43  namespace detail
44  {
45  template<typename Rng, typename Int>
46  iterator_t<Rng> pos_at_(Rng && rng, Int i, input_range_tag, std::true_type)
47  {
48  RANGES_EXPECT(0 <= i);
49  return next(ranges::begin(rng), i);
50  }
51 
52  template<typename Rng, typename Int>
53  iterator_t<Rng> pos_at_(Rng && rng, Int i, bidirectional_range_tag,
54  std::false_type)
55  {
56  if(0 > i)
57  {
58  // If it's not common and we know the size, faster to count from the front
59  if(RANGES_CONSTEXPR_IF(sized_range<Rng> && !common_range<Rng>))
60  return next(ranges::begin(rng), distance(rng) + i);
61  // Otherwise, probably faster to count from the back.
62  return next(ranges::next(ranges::begin(rng), ranges::end(rng)), i);
63  }
64  return next(ranges::begin(rng), i);
65  }
66 
67  template<typename Rng, typename Int>
68  iterator_t<Rng> pos_at_(Rng && rng, Int i, input_range_tag, std::false_type)
69  {
70  RANGES_EXPECT(i >= 0 || (bool)sized_range<Rng> || (bool)forward_range<Rng>);
71  if(0 > i)
72  return next(ranges::begin(rng), distance(rng) + i);
73  return next(ranges::begin(rng), i);
74  }
75 
76  template<typename Rng, bool IsRandomAccess>
77  struct slice_view_ : view_facade<slice_view<Rng>, finite>
78  {
79  private:
80  friend range_access;
81  Rng rng_;
82  range_difference_t<Rng> from_, count_;
83  detail::non_propagating_cache<iterator_t<Rng>> begin_;
84 
85  iterator_t<Rng> get_begin_()
86  {
87  if(!begin_)
88  begin_ = detail::pos_at_(
89  rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{});
90  return *begin_;
91  }
92 
93  public:
94  slice_view_() = default;
95  constexpr slice_view_(Rng rng, range_difference_t<Rng> from,
96  range_difference_t<Rng> count)
97  : rng_(std::move(rng))
98  , from_(from)
99  , count_(count)
100  {}
101  counted_iterator<iterator_t<Rng>> begin()
102  {
103  return make_counted_iterator(get_begin_(), count_);
104  }
105  default_sentinel_t end()
106  {
107  return {};
108  }
109  auto size() const
110  {
111  return static_cast<detail::iter_size_t<iterator_t<Rng>>>(count_);
112  }
113  Rng base() const
114  {
115  return rng_;
116  }
117  };
118 
119  template<typename Rng>
120  struct slice_view_<Rng, true> : view_interface<slice_view<Rng>, finite>
121  {
122  private:
123  Rng rng_;
124  range_difference_t<Rng> from_, count_;
125 
126  public:
127  slice_view_() = default;
128  constexpr slice_view_(Rng rng, range_difference_t<Rng> from,
129  range_difference_t<Rng> count)
130  : rng_(std::move(rng))
131  , from_(from)
132  , count_(count)
133  {
134  RANGES_EXPECT(0 <= count_);
135  }
136  iterator_t<Rng> begin()
137  {
138  return detail::pos_at_(
139  rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{});
140  }
141  iterator_t<Rng> end()
142  {
143  return detail::pos_at_(
144  rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{}) +
145  count_;
146  }
147  template(typename BaseRng = Rng)(
148  requires range<BaseRng const>)
149  iterator_t<BaseRng const> begin() const
150  {
151  return detail::pos_at_(
152  rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{});
153  }
154  template(typename BaseRng = Rng)(
155  requires range<BaseRng const>)
156  iterator_t<BaseRng const> end() const
157  {
158  return detail::pos_at_(
159  rng_, from_, range_tag_of<Rng>{}, is_infinite<Rng>{}) +
160  count_;
161  }
162  auto size() const
163  {
164  return static_cast<detail::iter_size_t<iterator_t<Rng>>>(count_);
165  }
166  Rng base() const
167  {
168  return rng_;
169  }
170  };
171  } // namespace detail
173 
176  template<typename Rng>
177  struct slice_view : detail::slice_view_<Rng, (bool)random_access_range<Rng>>
178  {
179  using detail::slice_view_<Rng, (bool)random_access_range<Rng>>::slice_view_;
180  };
181 
182  template<typename Rng>
183  RANGES_INLINE_VAR constexpr bool enable_borrowed_range<slice_view<Rng>> = //
184  enable_borrowed_range<Rng>;
185 
186 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
187  template<typename Rng>
188  slice_view(Rng &&, range_difference_t<Rng>, range_difference_t<Rng>)
189  ->slice_view<views::all_t<Rng>>;
190 #endif
191 
192  namespace views
193  {
195  {
196  private:
197  template<typename Rng>
198  static constexpr slice_view<all_t<Rng>> impl_(Rng && rng,
199  range_difference_t<Rng> from,
200  range_difference_t<Rng> count,
202  {
203  return {all(static_cast<Rng &&>(rng)), from, count};
204  }
205  template(typename Rng)(
206  requires borrowed_range<Rng>)
207  static subrange<iterator_t<Rng>> impl_(Rng && rng,
208  range_difference_t<Rng> from,
209  range_difference_t<Rng> count,
211  common_range_tag = {})
212  {
213  auto it =
214  detail::pos_at_(rng, from, range_tag_of<Rng>{}, is_infinite<Rng>{});
215  return {it, it + count};
216  }
217 
218  public:
219  // slice(rng, 2, 4)
220  template(typename Rng)(
221  requires viewable_range<Rng> AND input_range<Rng>)
222  constexpr auto operator()(Rng && rng,
223  range_difference_t<Rng> from,
224  range_difference_t<Rng> to) const
225  {
226  RANGES_EXPECT(0 <= from && from <= to);
227  return slice_base_fn::impl_(
228  static_cast<Rng &&>(rng), from, to - from, range_tag_of<Rng>{});
229  }
230  // slice(rng, 4, end-2)
231  // TODO Support Forward, non-Sized ranges by returning a range that
232  // doesn't know it's size?
233  template(typename Rng)(
234  requires viewable_range<Rng> AND input_range<Rng> AND sized_range<Rng>)
235  auto operator()(Rng && rng,
236  range_difference_t<Rng> from,
237  detail::from_end_of_t<Rng> to) const
238  {
239  static_assert(!is_infinite<Rng>::value,
240  "Can't index from the end of an infinite range!");
241  RANGES_EXPECT(0 <= from);
242  RANGES_ASSERT(from <= distance(rng) + to.dist_);
243  return slice_base_fn::impl_(static_cast<Rng &&>(rng),
244  from,
245  distance(rng) + to.dist_ - from,
246  range_tag_of<Rng>{});
247  }
248  // slice(rng, end-4, end-2)
249  template(typename Rng)(
250  requires viewable_range<Rng> AND
251  (forward_range<Rng> || (input_range<Rng> && sized_range<Rng>)))
252  auto operator()(Rng && rng,
253  detail::from_end_of_t<Rng> from,
254  detail::from_end_of_t<Rng> to) const
255  {
256  static_assert(!is_infinite<Rng>::value,
257  "Can't index from the end of an infinite range!");
258  RANGES_EXPECT(from.dist_ <= to.dist_);
259  return slice_base_fn::impl_(static_cast<Rng &&>(rng),
260  from.dist_,
261  to.dist_ - from.dist_,
262  range_tag_of<Rng>{},
263  common_range_tag_of<Rng>{});
264  }
265  // slice(rng, 4, end)
266  template(typename Rng)(
267  requires viewable_range<Rng> AND input_range<Rng>)
268  auto operator()(Rng && rng, range_difference_t<Rng> from, end_fn) const
269  {
270  RANGES_EXPECT(0 <= from);
271  return ranges::views::drop_exactly(static_cast<Rng &&>(rng), from);
272  }
273  // slice(rng, end-4, end)
274  template(typename Rng)(
275  requires viewable_range<Rng> AND
276  (forward_range<Rng> || (input_range<Rng> && sized_range<Rng>)))
277  auto operator()(Rng && rng,
278  detail::from_end_of_t<Rng> from,
279  end_fn) const
280  {
281  static_assert(!is_infinite<Rng>::value,
282  "Can't index from the end of an infinite range!");
283  return slice_base_fn::impl_(static_cast<Rng &&>(rng),
284  from.dist_,
285  -from.dist_,
286  range_tag_of<Rng>{},
287  common_range_tag_of<Rng>{});
288  }
289  };
290 
292  {
293  using slice_base_fn::operator();
294 
295  // Overloads for the pipe syntax: rng | views::slice(from,to)
296  template(typename Int)(
297  requires detail::integer_like_<Int>)
298  constexpr auto operator()(Int from, Int to) const
299  {
300  return make_view_closure(bind_back(slice_base_fn{}, from, to));
301  }
302  template(typename Int)(
303  requires detail::integer_like_<Int>)
304  constexpr auto operator()(Int from, detail::from_end_<Int> to) const
305  {
306  return make_view_closure(bind_back(slice_base_fn{}, from, to));
307  }
308  template(typename Int)(
309  requires detail::integer_like_<Int>)
310  constexpr auto operator()(detail::from_end_<Int> from,
311  detail::from_end_<Int> to) const
312  {
313  return make_view_closure(bind_back(slice_base_fn{}, from, to));
314  }
315  template(typename Int)(
316  requires detail::integer_like_<Int>)
317  constexpr auto operator()(Int from, end_fn) const
318  {
319  return make_view_closure(
321  }
322  template(typename Int)(
323  requires detail::integer_like_<Int>)
324  constexpr auto operator()(detail::from_end_<Int> from, end_fn to) const
325  {
326  return make_view_closure(bind_back(slice_base_fn{}, from, to));
327  }
328  };
329 
333  } // namespace views
335 } // namespace ranges
336 
337 #include <range/v3/detail/epilogue.hpp>
338 #include <range/v3/detail/satisfy_boost_range.hpp>
339 RANGES_SATISFY_BOOST_RANGE(::ranges::slice_view)
340 
341 #endif
RANGES_INLINE_VARIABLE(detail::to_container_fn< detail::from_range< std::vector >>, to_vector) template< template< typename... > class ContT > auto to(RANGES_HIDDEN_DETAIL(detail
For initializing a container of the specified type with the elements of an Range.
Definition: conversion.hpp:399
defer< bind_back, Fn, Ts... > bind_back
Definition: meta.hpp:994
meta::size_t< L::size()> size
An integral constant wrapper that is the size of the meta::list L.
Definition: meta.hpp:1696
_t< detail::count_< L, T > > count
Count the number of times a type T appears in the list L.
Definition: meta.hpp:2725
Tiny meta-programming library.
Definition: concepts.hpp:305
Definition: concepts.hpp:271
Definition: concepts.hpp:277
Definition: concepts.hpp:268
Definition: slice.hpp:178
Definition: subrange.hpp:196
Definition: drop_exactly.hpp:135
Definition: slice.hpp:195
Definition: slice.hpp:292