Horizon
interface.hpp
Go to the documentation of this file.
1 // 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_VIEW_INTERFACE_HPP
14 #define RANGES_V3_VIEW_INTERFACE_HPP
15 
16 #include <iosfwd>
17 
18 #include <meta/meta.hpp>
19 
20 #include <concepts/concepts.hpp>
21 
22 #include <range/v3/range_fwd.hpp>
23 
30 
31 #include <range/v3/detail/prologue.hpp>
32 
33 #if defined(RANGES_WORKAROUND_GCC_91525)
34 #define CPP_template_gcc_workaround CPP_template_sfinae
35 #else
36 #define CPP_template_gcc_workaround template
37 #endif
38 
39 namespace ranges
40 {
42  namespace detail
43  {
44  template<typename From, typename To = From>
45  struct slice_bounds
46  {
47  From from;
48  To to;
49  template(typename F, typename T)(
50  requires convertible_to<F, From> AND convertible_to<T, To>)
51  constexpr slice_bounds(F f, T t)
52  : from(static_cast<From>(f))
53  , to(static_cast<To>(t))
54  {}
55  };
56 
57  template<typename Int>
58  struct from_end_
59  {
60  Int dist_;
61 
62  constexpr explicit from_end_(Int dist)
63  : dist_(dist)
64  {}
65 
66  template(typename Other)(
67  requires integer_like_<Other> AND explicitly_convertible_to<Other, Int>)
68  constexpr operator from_end_<Other>() const
69  {
70  return from_end_<Other>{static_cast<Other>(dist_)};
71  }
72  };
73 
74  template<typename Rng>
75  using from_end_of_t = from_end_<range_difference_t<Rng>>;
76 
77  // clang-format off
80  template<typename Rng>
81  CPP_requires(_can_empty_,
82  requires(Rng & rng) //
83  (
84  ranges::empty(rng)
85  ));
88  template<typename Rng>
89  CPP_concept can_empty_ = //
90  CPP_requires_ref(detail::_can_empty_, Rng);
91  // clang-format on
92 
93  template<cardinality C>
94  RANGES_INLINE_VAR constexpr bool has_fixed_size_ = (C >= 0 || C == infinite);
95 
96  template<bool>
97  struct dependent_
98  {
99  template<typename T>
100  using invoke = T;
101  };
102 
103  template<typename Stream, typename Rng>
104  Stream & print_rng_(Stream & sout, Rng & rng)
105  {
106  sout << '[';
107  auto it = ranges::begin(rng);
108  auto const e = ranges::end(rng);
109  if(it != e)
110  {
111  for(;;)
112  {
113  sout << *it;
114  if(++it == e)
115  break;
116  sout << ',';
117  }
118  }
119  sout << ']';
120  return sout;
121  }
122  } // namespace detail
124 
127  template<typename Derived, cardinality Cardinality /* = finite*/>
128  struct view_interface : basic_view<Cardinality>
129  {
130  protected:
131  template<bool B>
132  using D = meta::invoke<detail::dependent_<B>, Derived>;
133 
134  constexpr Derived & derived() noexcept
135  {
136  CPP_assert(derived_from<Derived, view_interface>);
137  return static_cast<Derived &>(*this);
138  }
140  constexpr Derived const & derived() const noexcept
141  {
142  CPP_assert(derived_from<Derived, view_interface>);
143  return static_cast<Derived const &>(*this);
144  }
145 
146  public:
147  view_interface() = default;
148  view_interface(view_interface &&) = default;
149  view_interface(view_interface const &) = default;
150  view_interface & operator=(view_interface &&) = default;
151  view_interface & operator=(view_interface const &) = default;
153  CPP_member
154  constexpr auto empty() const noexcept //
155  -> CPP_ret(bool)(
156  requires (detail::has_fixed_size_<Cardinality>))
157  {
158  return Cardinality == 0;
159  }
161  template(bool True = true)(
162  requires True AND (Cardinality < 0) AND (Cardinality != infinite) AND
163  (!forward_range<D<True>>) AND sized_range<D<True>>)
164  constexpr bool empty() //
165  noexcept(noexcept(bool(ranges::size(std::declval<D<True> &>()) == 0)))
166  {
167  return ranges::size(derived()) == 0;
168  }
170  template(bool True = true)(
171  requires True AND (Cardinality < 0) AND (Cardinality != infinite) AND
172  (!forward_range<D<True> const>) AND sized_range<D<True> const>)
173  constexpr bool empty() const //
174  noexcept(noexcept(bool(ranges::size(std::declval<D<True> const &>()) == 0)))
175  {
176  return ranges::size(derived()) == 0;
177  }
179  template(bool True = true)(
180  requires True AND (!detail::has_fixed_size_<Cardinality>) AND
181  forward_range<D<True>>)
182  constexpr bool empty() noexcept(
183  noexcept(bool(ranges::begin(std::declval<D<True> &>()) ==
184  ranges::end(std::declval<D<True> &>()))))
185  {
186  return bool(ranges::begin(derived()) == ranges::end(derived()));
187  }
189  template(bool True = true)(
190  requires True AND (!detail::has_fixed_size_<Cardinality>) AND
191  forward_range<D<True> const>)
192  constexpr bool empty() const
193  noexcept(noexcept(bool(ranges::begin(std::declval<D<True> const &>()) ==
194  ranges::end(std::declval<D<True> const &>()))))
195  {
196  return bool(ranges::begin(derived()) == ranges::end(derived()));
197  }
198  CPP_template_gcc_workaround(bool True = true)(
199  requires True && detail::can_empty_<D<True>>) // clang-format off
200  constexpr explicit operator bool()
201  noexcept(noexcept(ranges::empty(std::declval<D<True> &>())))
202  {
203  return !ranges::empty(derived());
204  }
205  // clang-format on
207  CPP_template_gcc_workaround(bool True = true)(
208  requires True && detail::can_empty_<D<True> const>) // clang-format off
209  constexpr explicit operator bool() const
210  noexcept(noexcept(ranges::empty(std::declval<D<True> const &>())))
211  {
212  return !ranges::empty(derived());
213  }
214  // clang-format on
217  template(bool True = true, int = 42)(
218  requires True AND (Cardinality >= 0)) //
219  static constexpr std::size_t size() noexcept
220  {
221  return static_cast<std::size_t>(Cardinality);
222  }
226  template(bool True = true)(
227  requires True AND (Cardinality < 0) AND
228  sized_sentinel_for<sentinel_t<D<True>>, iterator_t<D<True>>> AND
229  forward_range<D<True>>)
230  constexpr detail::iter_size_t<iterator_t<D<True>>> size()
231  {
232  using size_type = detail::iter_size_t<iterator_t<D<True>>>;
233  return static_cast<size_type>(derived().end() - derived().begin());
234  }
236  template(bool True = true)(
237  requires True AND (Cardinality < 0) AND
238  sized_sentinel_for<sentinel_t<D<True> const>,
239  iterator_t<D<True> const>> AND
240  forward_range<D<True> const>)
241  constexpr detail::iter_size_t<iterator_t<D<True>>> size() const //
242  {
243  using size_type = detail::iter_size_t<iterator_t<D<True>>>;
244  return static_cast<size_type>(derived().end() - derived().begin());
245  }
247  template(bool True = true)(
248  requires True AND forward_range<D<True>>)
249  constexpr range_reference_t<D<True>> front()
250  {
251  return *derived().begin();
252  }
254  template(bool True = true)(
255  requires True AND forward_range<D<True> const>)
256  constexpr range_reference_t<D<True> const> front() const
257  {
258  return *derived().begin();
259  }
261  template(bool True = true)(
262  requires True AND common_range<D<True>> AND bidirectional_range<D<True>>)
263  constexpr range_reference_t<D<True>> back()
264  {
265  return *prev(derived().end());
266  }
268  template(bool True = true)(
269  requires True AND common_range<D<True> const> AND
270  bidirectional_range<D<True> const>)
271  constexpr range_reference_t<D<True> const> back() const
272  {
273  return *prev(derived().end());
274  }
276  template(bool True = true)(
277  requires True AND random_access_range<D<True>>)
278  constexpr range_reference_t<D<True>> operator[](range_difference_t<D<True>> n)
279  {
280  return derived().begin()[n];
281  }
283  template(bool True = true)(
284  requires True AND random_access_range<D<True> const>)
285  constexpr range_reference_t<D<True> const> //
286  operator[](range_difference_t<D<True>> n) const
287  {
288  return derived().begin()[n];
289  }
292  template(bool True = true)(
293  requires True AND contiguous_iterator<iterator_t<D<True>>>)
294  constexpr std::add_pointer_t<range_reference_t<D<True>>> data() //
295  {
296  return std::addressof(*ranges::begin(derived()));
297  }
299  template(bool True = true)(
300  requires True AND contiguous_iterator<iterator_t<D<True> const>>)
301  constexpr std::add_pointer_t<range_reference_t<D<True> const>> data() const //
302  {
303  return std::addressof(*ranges::begin(derived()));
304  }
307  template(bool True = true)(
308  requires True AND random_access_range<D<True>> AND sized_range<D<True>>)
309  constexpr range_reference_t<D<True>> at(range_difference_t<D<True>> n)
310  {
311  using size_type = range_size_t<Derived>;
312  if(n < 0 || size_type(n) >= ranges::size(derived()))
313  {
314  throw std::out_of_range("view_interface::at");
315  }
316  return derived().begin()[n];
317  }
319  template(bool True = true)(
320  requires True AND random_access_range<D<True> const> AND
321  sized_range<D<True> const>)
322  constexpr range_reference_t<D<True> const> at(range_difference_t<D<True>> n) const
323  {
324  using size_type = range_size_t<Derived const>;
325  if(n < 0 || size_type(n) >= ranges::size(derived()))
326  {
327  throw std::out_of_range("view_interface::at");
328  }
329  return derived().begin()[n];
330  }
332  // rng[{4,6}]
333  template(bool True = true, typename Slice = views::slice_fn)(
334  requires True AND input_range<D<True> &>)
335  constexpr auto
336  operator[](detail::slice_bounds<range_difference_t<D<True>>> offs) &
337  {
338  return Slice{}(derived(), offs.from, offs.to);
339  }
341  template(bool True = true, typename Slice = views::slice_fn)(
342  requires True AND input_range<D<True> const &>)
343  constexpr auto
344  operator[](detail::slice_bounds<range_difference_t<D<True>>> offs) const &
345  {
346  return Slice{}(derived(), offs.from, offs.to);
347  }
349  template(bool True = true, typename Slice = views::slice_fn)(
350  requires True AND input_range<D<True>>)
351  constexpr auto
352  operator[](detail::slice_bounds<range_difference_t<D<True>>> offs) &&
353  {
354  return Slice{}(detail::move(derived()), offs.from, offs.to);
355  }
356  // rng[{4,end-2}]
358  template(bool True = true, typename Slice = views::slice_fn)(
359  requires True AND input_range<D<True> &> AND sized_range<D<True> &>)
360  constexpr auto //
361  operator[](detail::slice_bounds<range_difference_t<D<True>>,
362  detail::from_end_of_t<D<True>>> offs) &
363  {
364  return Slice{}(derived(), offs.from, offs.to);
365  }
367  template(bool True = true, typename Slice = views::slice_fn)(
368  requires True AND input_range<D<True> const &> AND
369  sized_range<D<True> const &>)
370  constexpr auto //
371  operator[](detail::slice_bounds<range_difference_t<D<True>>,
372  detail::from_end_of_t<D<True>>> offs) const &
373  {
374  return Slice{}(derived(), offs.from, offs.to);
375  }
377  template(bool True = true, typename Slice = views::slice_fn)(
378  requires True AND input_range<D<True>> AND sized_range<D<True>>)
379  constexpr auto //
380  operator[](detail::slice_bounds<range_difference_t<D<True>>,
381  detail::from_end_of_t<D<True>>> offs) &&
382  {
383  return Slice{}(detail::move(derived()), offs.from, offs.to);
384  }
385  // rng[{end-4,end-2}]
387  template(bool True = true, typename Slice = views::slice_fn)(
388  requires True AND (forward_range<D<True> &> ||
389  (input_range<D<True> &> && sized_range<D<True> &>))) //
390  constexpr auto //
391  operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>,
392  detail::from_end_of_t<D<True>>> offs) &
393  {
394  return Slice{}(derived(), offs.from, offs.to);
395  }
397  template(bool True = true, typename Slice = views::slice_fn)(
398  requires True AND
399  (forward_range<D<True> const &> ||
400  (input_range<D<True> const &> && sized_range<D<True> const &>))) //
401  constexpr auto //
402  operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>,
403  detail::from_end_of_t<D<True>>> offs) const &
404  {
405  return Slice{}(derived(), offs.from, offs.to);
406  }
408  template(bool True = true, typename Slice = views::slice_fn)(
409  requires True AND
410  (forward_range<D<True>> ||
411  (input_range<D<True>> && sized_range<D<True>>))) //
412  constexpr auto //
413  operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>,
414  detail::from_end_of_t<D<True>>> offs) &&
415  {
416  return Slice{}(detail::move(derived()), offs.from, offs.to);
417  }
418  // rng[{4,end}]
420  template(bool True = true, typename Slice = views::slice_fn)(
421  requires True AND input_range<D<True> &>)
422  constexpr auto //
423  operator[](detail::slice_bounds<range_difference_t<D<True>>, end_fn> offs) &
424  {
425  return Slice{}(derived(), offs.from, offs.to);
426  }
428  template(bool True = true, typename Slice = views::slice_fn)(
429  requires True AND input_range<D<True> const &>)
430  constexpr auto //
431  operator[](detail::slice_bounds<range_difference_t<D<True>>, end_fn> offs) const &
432  {
433  return Slice{}(derived(), offs.from, offs.to);
434  }
436  template(bool True = true, typename Slice = views::slice_fn)(
437  requires True AND input_range<D<True>>)
438  constexpr auto //
439  operator[](detail::slice_bounds<range_difference_t<D<True>>, end_fn> offs) &&
440  {
441  return Slice{}(detail::move(derived()), offs.from, offs.to);
442  }
443  // rng[{end-4,end}]
445  template(bool True = true, typename Slice = views::slice_fn)(
446  requires True AND
447  (forward_range<D<True> &> ||
448  (input_range<D<True> &> && sized_range<D<True> &>))) //
449  constexpr auto //
450  operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>, end_fn> offs) &
451  {
452  return Slice{}(derived(), offs.from, offs.to);
453  }
455  template(bool True = true, typename Slice = views::slice_fn)(
456  requires True AND
457  (forward_range<D<True> const &> ||
458  (input_range<D<True> const &> && sized_range<D<True> const &>))) //
459  constexpr auto //
460  operator[](
461  detail::slice_bounds<detail::from_end_of_t<D<True>>, end_fn> offs) const &
462  {
463  return Slice{}(derived(), offs.from, offs.to);
464  }
466  template(bool True = true, typename Slice = views::slice_fn)(
467  requires True AND
468  (forward_range<D<True>> ||
469  (input_range<D<True>> && sized_range<D<True>>))) //
470  constexpr auto //
471  operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>, end_fn> offs) &&
472  {
473  return Slice{}(detail::move(derived()), offs.from, offs.to);
474  }
475  private:
476 #ifndef RANGES_V3_DISABLE_IO
478  template<bool True = true>
479  friend auto operator<<(std::ostream & sout, Derived const & rng)
480  -> CPP_broken_friend_ret(std::ostream &)(
481  requires True && input_range<D<True> const>)
482  {
483  return detail::print_rng_(sout, rng);
484  }
486  template<bool True = true>
487  friend auto operator<<(std::ostream & sout, Derived & rng)
488  -> CPP_broken_friend_ret(std::ostream &)(
489  requires True && (!range<D<True> const>) && input_range<D<True>>)
490  {
491  return detail::print_rng_(sout, rng);
492  }
494  template<bool True = true>
495  friend auto operator<<(std::ostream & sout, Derived && rng)
496  -> CPP_broken_friend_ret(std::ostream &)(
497  requires True && (!range<D<True> const>) && input_range<D<True>>)
498  {
499  return detail::print_rng_(sout, rng);
500  }
501 #endif
502  };
503  namespace cpp20
504  {
505  template(typename Derived)(
506  requires std::is_class<Derived>::value AND
507  same_as<Derived, meta::_t<std::remove_cv<Derived>>>)
509  }
511 } // namespace ranges
512 
513 #include <range/v3/detail/epilogue.hpp>
514 
515 #endif
CPP_concept contiguous_iterator
\concept contiguous_iterator
Definition: concepts.hpp:435
CPP_concept sized_range
\concept sized_range
Definition: concepts.hpp:208
CPP_concept bidirectional_range
\concept bidirectional_range
Definition: concepts.hpp:127
CPP_concept common_range
\concept common_range
Definition: concepts.hpp:180
CPP_concept forward_range
\concept forward_range
Definition: concepts.hpp:115
CPP_concept input_range
\concept input_range
Definition: concepts.hpp:103
CPP_concept random_access_range
\concept random_access_range
Definition: concepts.hpp:140
decltype(begin(declval(Rng &))) iterator_t
Definition: access.hpp:698
std::integral_constant< std::size_t, N > size_t
An integral constant wrapper for std::size_t.
Definition: meta.hpp:163
typename T::type _t
Type alias for T::type.
Definition: meta.hpp:141
typename Fn::template invoke< Args... > invoke
Evaluate the invocable Fn with the arguments Args.
Definition: meta.hpp:541
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::back_< L > > back
Return the last element in meta::list L.
Definition: meta.hpp:2103
at_c< L, N::type::value > at
Return the N th element in the meta::list L.
Definition: meta.hpp:1969
_t< detail::front_< L > > front
Return the first element in meta::list L.
Definition: meta.hpp:2070
bool_< 0==size< L >::type::value > empty
An Boolean integral constant wrapper around true if L is an empty type list; false,...
Definition: meta.hpp:2231
Tiny meta-programming library.
Definition: range_fwd.hpp:549
Definition: interface.hpp:129
constexpr Derived const & derived() const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: interface.hpp:140
constexpr CPP_member auto empty() const noexcept -> CPP_ret(bool)(requires(detail::has_fixed_size_< Cardinality >))
Test whether a range can be empty:
Definition: interface.hpp:154