sparrow 0.3.0
Loading...
Searching...
No Matches
mp_utils.hpp
Go to the documentation of this file.
1// Copyright 2024 Man Group Operations Limited
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <concepts>
18#include <cstdint>
19#include <iterator>
20#include <memory>
21#include <ranges>
22#include <span>
23#include <tuple>
24#include <type_traits>
25
26namespace sparrow::mpl
27{
28
31 template <class... T>
32 struct dependent_false : std::false_type
33 {
34 };
35
36 template <class L, template <class...> class U>
37 struct is_type_instance_of : std::false_type
38 {
39 };
40
41 template <template <class...> class L, template <class...> class U, class... T>
42 requires std::is_same_v<L<T...>, U<T...>>
43 struct is_type_instance_of<L<T...>, U> : std::true_type
44 {
45 };
46
49 template <class T, template <class...> class U>
51
53 template <class... T>
54 struct typelist
55 {
56 };
57
69 template <class... Ts, class... Us>
71 consteval auto append(typelist<Ts...>, Us...)
72 {
73 return typelist<Ts..., Us...>{};
74 }
75
86 template <class... Ts, class... Us>
87 consteval auto append(typelist<Ts...>, typelist<Us...>) // TODO: Handle several typelists
88 {
89 return typelist<Ts..., Us...>{};
90 }
91
92
101 template <class TypeList, class... Us>
103 using append_t = decltype(append(TypeList{}, Us{}...));
104
106 template <class... T>
107 constexpr std::size_t size(typelist<T...> = {})
108 {
109 return sizeof...(T);
110 }
111
116 template <typename TList>
118
119 namespace impl
120 {
121 template <class From, template <class...> class To>
123
124 template <template <class...> class From, template <class...> class To, class... T>
125 struct rename_impl<From<T...>, To>
126 {
127 using type = To<T...>;
128 };
129 }
130
134 template <class From, template <class...> class To>
136
139
141 template <template <class...> class W, class T>
142 concept type_wrapper = std::same_as<W<T>, typelist<T>> or std::same_as<W<T>, std::type_identity_t<T>>;
143
146 template <template <class> class P, class T>
147 concept ct_type_predicate = requires {
148 { P<T>::value } -> std::convertible_to<bool>;
149 };
150
155 template< class P, class T >
156 concept callable_type_predicate = std::semiregular<std::decay_t<P>>
157 and (
158 requires(std::decay_t<P> predicate)
159 {
160 { predicate(typelist<T>{}) } -> std::convertible_to<bool>;
161 }
162 or
163 requires(std::decay_t<P> predicate)
164 {
165 { predicate(std::type_identity_t<T>{}) } -> std::convertible_to<bool>;
166 }
167 )
168 ;
169
172 template <class T, template <class> class P>
174 consteval bool evaluate(P<T>)
175 {
176 return P<T>::value;
177 }
178
181 template <class T, callable_type_predicate<T> P>
182 [[nodiscard]] consteval bool evaluate(P predicate)
183 {
184 if constexpr (requires(std::decay_t<P> p) {
185 { p(typelist<T>{}) } -> std::same_as<bool>;
186 })
187 {
188 return predicate(typelist<T>{});
189 }
190 else
191 {
192 return predicate(std::type_identity_t<T>{});
193 }
194 }
195
196 namespace predicate
197 {
198
205 template <class T>
206 struct same_as
207 {
208 template <template <class...> class W, class X>
209 requires type_wrapper<W, X>
210 consteval bool operator()(W<X>) const
211 {
212 return std::same_as<T, X>;
213 }
214 };
215 }
216
217 template <template <class> class P>
219 {
220 template <template <class...> class W, class T>
222 consteval bool operator()(W<T>) const
223 {
224 return P<T>::value;
225 }
226 };
227
230 template <template <class> class P>
231 consteval auto as_predicate()
232 {
234 };
235
238
242 template <class Predicate, template <class...> class L, class... T>
243 requires any_typelist<L<T...>> and (callable_type_predicate<Predicate, T> && ...)
244 [[nodiscard]] consteval bool any_of(L<T...>, [[maybe_unused]] Predicate predicate = {})
245 {
246 return (evaluate<T>(predicate) || ... || false);
247 }
248
252 template <template <class> class Predicate, template <class...> class L, class... T>
253 requires any_typelist<L<T...>> and (ct_type_predicate<Predicate, T> && ...)
254 [[nodiscard]] consteval bool any_of(L<T...> list)
255 {
256 return any_of(list, as_predicate<Predicate>());
257 }
258
262 template <class Predicate, template <class...> class L, class... T>
263 requires any_typelist<L<T...>> and (callable_type_predicate<Predicate, T> && ...)
264 [[nodiscard]] consteval bool all_of(L<T...>, [[maybe_unused]] Predicate predicate) // predicate is used
265 // but GCC does not
266 // see it, that's why
267 // we use
268 // [[maybe_unused]]
269 {
270 return (evaluate<T>(predicate) && ... && true);
271 }
272
276 template <template <class> class Predicate, template <class...> class L, class... T>
277 requires any_typelist<L<T...>> and (ct_type_predicate<Predicate, T> && ...)
278 [[nodiscard]] consteval bool all_of(L<T...> list)
279 {
280 return all_of(list, as_predicate<Predicate>());
281 }
282
284 template <class V, any_typelist L>
285 [[nodiscard]] consteval bool contains(L list)
286 {
287 return any_of(list, predicate::same_as<V>{});
288 }
289
293 template <class Predicate, template <class...> class L, class... T>
294 requires any_typelist<L<T...>> and (callable_type_predicate<Predicate, T> && ...)
295 [[nodiscard]] consteval std::size_t find_if(L<T...>, Predicate predicate)
296 {
297 std::size_t idx = 0;
298 auto check = [&](bool match_success)
299 {
300 if (match_success)
301 {
302 return true;
303 }
304 else
305 {
306 ++idx;
307 return false;
308 }
309 };
310
311 (check(evaluate<T>(predicate)) || ...);
312
313 return idx;
314 }
315
319 template <template <class> class Predicate, template <class...> class L, class... T>
320 requires any_typelist<L<T...>> and (ct_type_predicate<Predicate, T> && ...)
321 [[nodiscard]] consteval std::size_t find_if(L<T...> list)
322 {
323 return find_if(list, as_predicate<Predicate>());
324 }
325
328 template <class TypeToFind, any_typelist L>
329 [[nodiscard]] consteval std::size_t find(L list)
330 {
332 }
333
334 namespace impl
335 {
336 template <template <class...> class F, class... L>
338 {
339 static_assert(dependent_false<L...>::value, "transform can apply to typelist-like types only");
340 };
341
342 template <template <class...> class F, template <class...> class L, class... T>
343 struct transform_impl<F, L<T...>>
344 {
345 using type = L<F<T>...>;
346 };
347
348 template <template <class...> class F, template <class...> class L1, class... T1, template <class...> class L2, class... T2>
349 struct transform_impl<F, L1<T1...>, L2<T2...>>
350 {
351 using type = L1<F<T1, T2>...>;
352 };
353 }
354
361 template <template <class> class F, class... L>
362 using transform = typename impl::transform_impl<F, L...>::type;
363
366
367 template <class T>
368 struct add_const_lvalue_reference : std::add_lvalue_reference<std::add_const_t<T>>
369 {
370 };
371
372 template <class T>
374
375 template <typename T, bool is_const>
376 struct constify
377 {
378 using type = std::conditional_t<is_const, const T, T>;
379 };
380
381 template <typename T, bool is_const>
382 struct constify<T&, is_const>
383 {
384 using type = std::conditional_t<is_const, const T&, T&>;
385 };
386
387 // `constify_t` is required since `std::add_const_t<T&>`
388 // is not `const T&` but `T&`.
389 template <class T, bool is_const>
391
395 template <class T>
396 using iter_const_reference_t = std::common_reference_t<const std::iter_value_t<T>&&, std::iter_reference_t<T>>;
397
405 template <class T>
406 concept constant_iterator = std::input_iterator<T>
407 && std::same_as<iter_const_reference_t<T>, std::iter_reference_t<T>>;
408
417 template <class T>
418 concept constant_range = std::ranges::input_range<T> && constant_iterator<std::ranges::iterator_t<T>>;
419
425 [[noreturn]] inline void unreachable()
426 {
427 // Uses compiler specific extensions if possible.
428 // Even if no extension is used, undefined behavior is still raised by
429 // an empty function body and the noreturn attribute.
430#if defined(_MSC_VER) && !defined(__clang__) // MSVC
431 __assume(false);
432#else // GCC, Clang
433 __builtin_unreachable();
434#endif
435 }
436
438 template <class BoolRange>
439 concept bool_convertible_range = std::ranges::range<BoolRange>
440 && std::convertible_to<std::ranges::range_value_t<BoolRange>, bool>;
441
444 template <class T>
445 concept boolean_like = std::is_assignable_v<std::add_lvalue_reference_t<std::decay_t<T>>, bool>
446 and requires { static_cast<bool>(std::declval<T>()); };
447
449 template <class From, class To>
450 concept convertible_ranges = std::convertible_to<std::ranges::range_value_t<From>, std::ranges::range_value_t<To>>;
451
452 // Matches any `unique_ptr` instance.
453 template <typename T>
455
456 // Matches any `unique_ptr` or derived instance.
457 template <typename T>
459 || std::derived_from<T, std::unique_ptr<typename T::element_type>>;
460
461 // Matches any `shared_ptr` instance.
462 template <typename T>
464
465 // Matches any `shared_ptr` or derived instance.
466 template <typename T>
468 || std::derived_from<T, std::shared_ptr<typename T::element_type>>;
469
470 // Matches any `unique_ptr` or `shared_ptr` instance.
471 template <typename T>
473
474 // Matches any `unique_ptr` or `shared_ptr` or derived instance.
475 template <typename T>
477
478 // Matches any type that is testable
479 template <class T>
480 concept testable = requires(T t) { t ? true : false; };
481
482 // Fails if the Qualifier is true for Y but not for T.
483 template <typename T, typename Y, template <typename> typename Qualifier>
484 concept T_matches_qualifier_if_Y_is = Qualifier<T>::value || !Qualifier<Y>::value;
485
486 // helper class to exclude copy and move constructors beeing routed
487 // to a constructor with variadic arguments / perfect forwarding
488 template <class CLS, class... ARGS>
490 {
491 static constexpr bool value = true;
492 };
493
494 template <class CLS>
496 {
497 static constexpr bool value = true;
498 };
499
500 template <class CLS, class T>
502 {
503 static constexpr bool value = !std::is_same_v<CLS, std::remove_cvref_t<T>>;
504 };
505
506 template <class CLS, class... ARGS>
507 constexpr bool excludes_copy_and_move_ctor_v = excludes_copy_and_move_ctor<CLS, ARGS...>::value;
508
519 template <typename I, typename T>
520 concept iterator_of_type = std::input_iterator<I>
521 && std::same_as<typename std::iterator_traits<I>::value_type, T>;
522
523
524 // todo...make smth better based on sizeof and is pod
525 template <class T>
526 concept char_like = std::same_as<T, char> || std::same_as<T, std::byte> || std::same_as<T, uint8_t>;
527
528 // Concept for std::array
529 template <typename T>
530 concept std_array = requires {
531 typename std::remove_cvref_t<T>::value_type;
532 requires std::same_as<
533 std::array<typename std::remove_cvref_t<T>::value_type, std::tuple_size<std::remove_cvref_t<T>>::value>,
534 std::remove_cvref_t<T>>;
535 };
536
537 // Concept for fixed-size std::span
538 template <typename T>
539 concept fixed_size_span = requires {
540 typename std::remove_cvref_t<T>::element_type;
541 requires std::tuple_size_v<T> != std::dynamic_extent;
542 requires std::same_as<
543 std::span<typename std::remove_cvref_t<T>::element_type, std::remove_cvref_t<T>::extent>,
544 std::remove_cvref_t<T>>;
545 };
546
547}
Matches any type which is an instance of typelist.
Definition mp_utils.hpp:117
Matches range types whose elements are convertible to bool.
Definition mp_utils.hpp:439
Matches types that can be convertible to and assignable from bool.
Definition mp_utils.hpp:445
Matches types whose instance can be called with an object representing a type to evaluate it.
Definition mp_utils.hpp:156
Represents a constant iterator.
Definition mp_utils.hpp:406
The constant_range concept is a refinement of range for which ranges::begin returns a constant iterat...
Definition mp_utils.hpp:418
Matches range types From whose elements are convertible to elements of range type To.
Definition mp_utils.hpp:450
Matches template types that can be evaluated at compile-time similarly to std::true/false_type This m...
Definition mp_utils.hpp:147
Concept to check if an iterator is of a specific type.
Definition mp_utils.hpp:520
Matches template types which can be used as type-wrappers for evaluation in type-predicates.
Definition mp_utils.hpp:142
consteval bool all_of(L< T... >, Predicate predicate)
Checks that every type in the provided list of is making the provide predicate return true.
Definition mp_utils.hpp:264
consteval bool contains(L list)
Definition mp_utils.hpp:285
consteval bool any_of(L< T... >, Predicate predicate={})
Checks that at least one type in the provided list of is making the provide predicate return true.
Definition mp_utils.hpp:244
consteval bool evaluate(P< T >)
Evaluates the provided compile-time template class predicate P given a type T, if P is of a similar s...
Definition mp_utils.hpp:174
decltype(append(TypeList{}, Us{}...)) append_t
Appends one or more types or typelist to a given TypeList.
Definition mp_utils.hpp:103
std::common_reference_t< const std::iter_value_t< T > &&, std::iter_reference_t< T > > iter_const_reference_t
Computes the const reference type of T.
Definition mp_utils.hpp:396
consteval std::size_t find_if(L< T... >, Predicate predicate)
Definition mp_utils.hpp:295
constexpr std::size_t size(typelist< T... >={})
Definition mp_utils.hpp:107
consteval auto append(typelist< Ts... >, Us...)
Appends the given types to a typelist.
Definition mp_utils.hpp:71
consteval auto as_predicate()
Definition mp_utils.hpp:231
constexpr bool excludes_copy_and_move_ctor_v
Definition mp_utils.hpp:507
constexpr bool is_type_instance_of_v
true if T is a concrete type template instanciation of U which is a type template.
Definition mp_utils.hpp:50
void unreachable()
Invokes undefined behavior.
Definition mp_utils.hpp:425
typename constify< T, is_const >::type constify_t
Definition mp_utils.hpp:390
typename impl::rename_impl< From, To >::type rename
Changes the type of the list to the given type/ Example: static_assert(std::same_as<rename<typelist<i...
Definition mp_utils.hpp:135
consteval std::size_t find(L list)
Definition mp_utils.hpp:329
typename add_const_lvalue_reference< T >::type add_const_lvalue_reference_t
Definition mp_utils.hpp:373
typename impl::transform_impl< F, L... >::type transform
Applies the metafunction F to each tuple of elements in the typelists and returns the corresponding l...
Definition mp_utils.hpp:362
std::conditional_t< is_const, const T &, T & > type
Definition mp_utils.hpp:384
std::conditional_t< is_const, const T, T > type
Definition mp_utils.hpp:378
consteval bool operator()(W< T >) const
Definition mp_utils.hpp:222
Workaround to replace static_assert(false) in template code.
Definition mp_utils.hpp:33
Compile-time type predicate: true if the evaluated type is the same as T.
Definition mp_utils.hpp:207
consteval bool operator()(W< X >) const
Definition mp_utils.hpp:210
A sequence of types, used for meta-programming operations.
Definition mp_utils.hpp:55