halcheck 1.0
Loading...
Searching...
No Matches
range.hpp
1#ifndef HALCHECK_LIB_ITERATOR_RANGES_HPP
2#define HALCHECK_LIB_ITERATOR_RANGES_HPP
3
4// IWYU pragma: private, include <halcheck/lib/iterator.hpp>
5
6#include <halcheck/lib/iterator/base.hpp>
7#include <halcheck/lib/iterator/type_traits.hpp>
8#include <halcheck/lib/pp.hpp>
9#include <halcheck/lib/type_traits.hpp>
10
11#include <cstddef>
12
13namespace halcheck { namespace lib {
14
20template<class R>
22
23inline namespace begin_cpo {
24
38private:
39 template<typename T>
40 using member = lib::iterator<decltype(std::declval<T &>().begin())>;
41
42 template<typename T>
43 using free = lib::iterator<decltype(begin(std::declval<T &>()))>;
44
45public:
46 template<typename T, std::size_t N>
47 constexpr T *operator()(T (&value)[N]) const { // NOLINT
48 return value + 0;
49 };
50
51 template<typename T, std::size_t N>
52 constexpr const T *operator()(const T (&value)[N]) const { // NOLINT
53 return value + 0;
54 };
55
56 template<typename T, std::size_t N>
57 constexpr T *operator()(T *value) const { // NOLINT
58 return value;
59 };
60
61 template<typename T, std::size_t N>
62 constexpr const T *operator()(const T *value) const { // NOLINT
63 return value;
64 };
65
66 template<
67 typename T,
68 HALCHECK_REQUIRE(std::is_lvalue_reference<T>() || lib::enable_borrowed_range<T>()),
69 HALCHECK_REQUIRE(lib::is_detected<member, T>())>
70 constexpr auto operator()(T &&value) const -> decltype(value.begin()) {
71 return value.begin();
72 }
73
74 template<
75 typename T,
76 HALCHECK_REQUIRE(std::is_lvalue_reference<T>() || lib::enable_borrowed_range<T>()),
77 HALCHECK_REQUIRE(!lib::is_detected<member, T>()),
78 HALCHECK_REQUIRE(lib::is_detected<free, T>())>
79 constexpr auto operator()(T &&value) const -> decltype(begin(value)) {
80 return begin(value);
81 }
83
84} // namespace begin_cpo
85
91template<typename T>
92using iterator_t = decltype(lib::begin(std::declval<T &>()));
93
94inline namespace end_cpo {
95
109private:
110 template<typename T>
111 using member = lib::iterator<decltype(std::declval<T &&>().end())>;
112
113 template<typename T>
114 using free = lib::iterator<decltype(end(std::declval<T &&>()))>;
115
116public:
117 template<typename T, std::size_t N>
118 constexpr T *operator()(T (&value)[N]) const { // NOLINT
119 return value + N;
120 };
121
122 template<typename T, std::size_t N>
123 constexpr const T *operator()(const T (&value)[N]) const { // NOLINT
124 return value + N;
125 };
126
127 template<
128 typename T,
131 constexpr auto operator()(T &&value) const -> decltype(value.end()) {
132 return value.end();
133 }
134
135 template<
136 typename T,
140 constexpr auto operator()(T &&value) const -> decltype(end(value)) {
141 return end(value);
142 }
144
145} // namespace end_cpo
146
148template<typename T>
149using range = lib::same<lib::iterator_t<T>, decltype(lib::end(std::declval<T &>()))>;
150
157template<typename T>
158struct is_range : lib::is_detected<lib::range, T> {};
159
160struct view_base {};
161
162template<typename T>
163struct enable_view : std::integral_constant<bool, std::is_base_of<lib::view_base, T>{}> {};
164
165template<typename T>
166using view = lib::void_t<lib::range<T>, lib::movable<T>, lib::enable_if_t<lib::enable_view<T>{}>>;
167
168template<typename T>
169struct is_view : lib::is_detected<lib::view, T> {};
170
171// See https://en.cppreference.com/w/cpp/ranges/input_range
172
174template<typename T>
175using input_range = lib::void_t<lib::range<T>, lib::input_iterator<lib::iterator_t<T>>>;
176
182template<typename T>
183struct is_input_range : lib::is_detected<lib::input_range, T> {};
184
186template<typename T>
187using forward_range = lib::void_t<lib::range<T>, lib::forward_iterator<lib::iterator_t<T>>>;
188
194template<typename T>
195struct is_forward_range : lib::is_detected<lib::forward_range, T> {};
196
198template<typename T>
199using bidirectional_range = lib::void_t<lib::range<T>, lib::bidirectional_iterator<lib::iterator_t<T>>>;
200
206template<typename T>
207struct is_bidirectional_range : lib::is_detected<lib::bidirectional_range, T> {};
208
210template<typename T>
211using random_access_range = lib::void_t<lib::range<T>, lib::random_access_iterator<lib::iterator_t<T>>>;
212
218template<typename T>
219struct is_random_access_range : lib::is_detected<lib::random_access_range, T> {};
220
228template<typename T>
230
244private:
245 template<typename T>
247
248 template<typename T>
250
251public:
252 template<typename T>
253 constexpr void operator()(T *) const = delete; // NOLINT
254
255 template<typename T, std::size_t N>
256 constexpr std::size_t operator()(T (&)[N]) const noexcept { // NOLINT
257 return N;
258 }
259
260 template<typename T, std::size_t N>
261 constexpr std::size_t operator()(const T (&)[N]) const noexcept { // NOLINT
262 return N;
263 }
264
265 template<
266 typename T,
267 HALCHECK_REQUIRE(!lib::disable_sized_range<lib::remove_cvref_t<T>>()),
268 HALCHECK_REQUIRE(lib::is_detected<member, T>())>
269 constexpr auto operator()(T &&value) const noexcept(noexcept(value.size())) -> decltype(value.size()) {
270 return value.size();
271 }
272
273 template<
274 typename T,
275 HALCHECK_REQUIRE(!lib::is_detected<member, T>()),
277 HALCHECK_REQUIRE(!lib::disable_sized_range<lib::remove_cvref_t<T>>()),
278 HALCHECK_REQUIRE(lib::is_detected<free, T>())>
279 constexpr auto operator()(T &&value) const noexcept(noexcept(size(value))) -> decltype(size(value)) {
280 return size(value);
281 }
282
283 template<
284 typename T,
285 HALCHECK_REQUIRE(!lib::is_detected<member, T>()),
286 HALCHECK_REQUIRE(!lib::is_detected<free, T>()),
287 HALCHECK_REQUIRE(lib::is_random_access_range<T>()),
288 HALCHECK_REQUIRE(!lib::disable_sized_range<lib::remove_cvref_t<T>>()),
289 HALCHECK_REQUIRE(lib::is_detected<
291 decltype(lib::end(std::declval<T &>()) - lib::begin(std::declval<T &>()))>())>
292 constexpr auto operator()(T &&value) const noexcept(noexcept(lib::end(value) - lib::begin(value)))
293 -> decltype(lib::end(value) - lib::begin(value)) {
294 return lib::end(value) - lib::begin(value);
295 }
297
299template<typename R>
300using sized_range = lib::void_t<lib::range<R>, decltype(lib::size(std::declval<R &>()))>;
301
307template<typename R>
308struct is_sized_range : lib::is_detected<lib::sized_range, R> {};
309
315template<typename R, HALCHECK_REQUIRE(lib::is_sized_range<R>())>
317
323template<typename R, HALCHECK_REQUIRE(lib::is_range<R>())>
325
331template<typename R, HALCHECK_REQUIRE(lib::is_range<R>())>
333
339template<typename R, HALCHECK_REQUIRE(lib::is_range<R>())>
341
355private:
356 template<typename T>
358
359public:
360 template<typename T, HALCHECK_REQUIRE(lib::is_detected<member, T>())>
361 constexpr bool operator()(T &&value) const noexcept(noexcept(bool(value.empty()))) {
362 return bool(value.empty());
363 }
364
365 template<typename T, HALCHECK_REQUIRE(!lib::is_detected<member, T>()), HALCHECK_REQUIRE(lib::is_sized_range<T>())>
366 constexpr auto operator()(T &&value) const noexcept(noexcept(lib::size(value) == 0))
367 -> decltype(lib::size(value) == 0) {
368 return lib::size(value) == 0;
369 }
370
371 template<
372 typename T,
376 constexpr bool operator()(T &&value) const noexcept(noexcept(bool(lib::end(value) == lib::begin(value)))) {
377 return bool(lib::end(value) == lib::begin(value));
378 }
380
382template<typename R>
383using insertable_range = lib::void_t<
384 lib::range<R>,
385 lib::same<
386 decltype(std::declval<R &>().insert(
389
400template<typename R>
401struct is_insertable_range : lib::is_detected<lib::insertable_range, R> {};
402
403}} // namespace halcheck::lib
404
405#endif
T declval(T... args)
lib::iter_value_t< lib::iterator_t< R > > range_value_t
The type of element contained in a range.
Definition range.hpp:332
decltype(lib::size(std::declval< R & >())) range_size_t
The type of value returned by lib::size.
Definition range.hpp:316
decltype(lib::begin(std::declval< T & >())) iterator_t
Obtains the iterator type of a range type.
Definition range.hpp:92
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@26 empty
Determines if a range is empty.
typename std::iterator_traits< I >::value_type iter_value_t
The type of value pointed to by an iterator.
Definition base.hpp:16
typename std::iterator_traits< I >::difference_type iter_difference_t
The return type of operator- for an iterator.
Definition base.hpp:32
typename std::iterator_traits< I >::reference iter_reference_t
The return type of operator* for an iterator.
Definition base.hpp:24
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@25 size
Obtains the size of a range.
lib::iter_reference_t< lib::iterator_t< R > > range_reference_t
The type returned by operator* for a range type's iterators.
Definition range.hpp:340
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::end_cpo::@28 end
Gets an iterator to past the end of a range.
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::begin_cpo::@27 begin
Gets an iterator to the first element of a range.
lib::iter_difference_t< lib::iterator_t< R > > range_difference_t
The type of value returned by operator- for a range type's iterators.
Definition range.hpp:324
#define HALCHECK_INLINE_CONSTEXPR
A backwards-compatible substitute for inline constexpr.
Definition pp.hpp:70
typename std::remove_cv< typename std::remove_reference< T >::type >::type remove_cvref_t
An implementation of std::remove_cvref_t.
Definition type_traits.hpp:141
typename std::enable_if< Cond, T >::type enable_if_t
An implementation of std::enable_if_t.
Definition type_traits.hpp:93
typename std::make_unsigned< T >::type make_unsigned_t
An implementation of std::make_unsigned_t.
Definition type_traits.hpp:125
void void_t
An implementation of std::void_t.
Definition type_traits.hpp:43
#define HALCHECK_REQUIRE(...)
Expands to a template argument that is only valid if the given argument evaluates to true.
Definition type_traits.hpp:24
Indicates whether lib::size should be disabled for a type.
Definition range.hpp:229
An implementation of std::ranges::enable_borrowed_range.
Definition range.hpp:21
Determines whether a type is a range whose iterators satisfy lib::is_bidirectional_iterator.
Definition range.hpp:207
An implementation of std::experimental::is_detected.
Definition type_traits.hpp:247
Determines whether a type is a range whose iterators satisfy lib::is_forward_iterator.
Definition range.hpp:195
Determines whether a type is a range whose iterators satisfy lib::is_input_iterator.
Definition range.hpp:183
Determines whether a range is insertable.
Definition range.hpp:401
Determines whether a type is a range whose iterators satisfy lib::is_random_access_iterator.
Definition range.hpp:219
Determines whether the given type is a range.
Definition range.hpp:158
Determines whether a range type supports the lib::size operation.
Definition range.hpp:308