Horizon
Loading...
Searching...
No Matches
slice.hpp
Go to the documentation of this file.
1
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
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
22
31#include <range/v3/utility/static_const.hpp>
32#include <range/v3/view/all.hpp>
37
38#include <range/v3/detail/prologue.hpp>
39
40namespace 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)(
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)(
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
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)(
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
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(
320 bind_back(ranges::views::drop_exactly_base_fn{}, from));
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
332 RANGES_INLINE_VARIABLE(slice_fn, slice)
333 } // namespace views
335} // namespace ranges
336
337#include <range/v3/detail/epilogue.hpp>
338#include <range/v3/detail/satisfy_boost_range.hpp>
339RANGES_SATISFY_BOOST_RANGE(::ranges::slice_view)
340
341#endif
The borrowed_range concept.
The forward_range concept.
The input_range concept.
The random_access_range concept.
The sized_range concept.
The viewable_range concept.
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