Loading...
Searching...
No Matches
apply_all.h
Go to the documentation of this file.
1#ifndef _BBM_APPLY_ALL_H_
2#define _BBM_APPLY_ALL_H_
3
4#include "concepts/util.h"
6#include "util/type_traits.h"
7#include "util/reflection.h"
8#include "util/named.h"
9
10namespace bbm {
11
12 /*** Implementation details ***/
13 namespace detail {
14 template<typename T> struct is_gettable { static constexpr bool value = bbm::concepts::gettable<T>; };
15 template<typename T> struct has_reflection { static constexpr bool value = bbm::concepts::reflection::supported<T>; };
16
17 template<typename T> struct get_size { static constexpr size_t value = 1; };
18 template<typename T> requires bbm::concepts::gettable<T> struct get_size<T> { static constexpr size_t value = std::tuple_size_v<std::decay_t<T>>; };
19 }
20
21 /**********************************************************************/
22 /*! \brief Apply a function
23
24 Applies a function to a series of arguments. The following rules are
25 used to determine the return type:
26
27 + if any type support reflection AND all reflection types are the same AND
28 reflection type supports empty construction, then call func on each
29 reflection element.
30
31 + if any type is gettable AND all gettable types have the same size, then
32 apply func to all gettable elements. Try to keep the return type the
33 same, or return a tuple.
34
35 + else pass on to func directly
36 *********************************************************************/
37 template<typename FUNC, typename... T> requires (
38 !std::is_void_v< find_first<bbm::detail::has_reflection, T...> > || // is reflection type OR
39 !std::is_void_v< find_first<bbm::detail::is_gettable, T...> > || // is gettable type OR
40 requires(const FUNC& func, const T&... t) {{func(value(t)...)};} // supports direct call
41 )
42 inline auto apply_all(const FUNC& func, const T&... t)
43 {
44 // helper functions
45 auto get_if = []<size_t IDX>(auto&& v) // get IDX-th element if v is gettable, otherwise return v
46 {
47 using V = decltype(v);
48 if constexpr (concepts::gettable<V>) return std::get<IDX>(std::forward<V>(v));
49 else return v;
50 };
51
52 auto reflected_if = [](auto&& v) // return attributes if v supports reflection, otherwise return v
53 {
54 using V = decltype(v);
56 else return v;
57 };
58
59 auto call_func = [&]<size_t IDX>() // call 'func' on IDX-th parameters
60 {
61 return apply_all( func, get_if.template operator()<IDX>(t)... );
62 };
63
64 auto call_func_all = [&]<size_t... IDX>(std::index_sequence<IDX...>) // enumerate 'func' over all IDXs' gettable parameters
65 {
66 return std::make_tuple( call_func.template operator()<IDX>()... );
67 };
68
69 // Determine reflection and gettable type
70 using ReflType = find_first< bbm::detail::has_reflection, T...>;
71 using GetType = find_first< bbm::detail::is_gettable, T...>;
72
73 // CASE 1: reflection
74 if constexpr ( !std::is_void_v<ReflType> && std::constructible_from<ReflType> && ((!concepts::reflection::supported<T> || std::same_as<reflection::attributes_t<ReflType>, reflection::attributes_t<T>>) && ...) )
75 {
76 ReflType result;
77 reflection::attributes(result) = apply_all(func, reflected_if(t)...);
78 return result;
79 }
80
81 // CASE 2: gettable
82 else if constexpr ( !std::is_void_v<GetType> && ((bbm::detail::get_size<GetType>::value == bbm::detail::get_size<T>::value || !bbm::concepts::gettable<T>) && ...) )
83 {
84 auto result = call_func_all(std::make_index_sequence<bbm::detail::get_size<GetType>::value>{});
85
86 // try to cast to GetType
87 if constexpr (concepts::constructible_from_tuple<GetType, decltype(result)> && std::same_as<decltype(result), to_tuple_t<GetType>>)
88 {
89 return std::make_from_tuple<GetType>(result);
90 }
91
92 // otherwise return tuple
93 else return result;
94 }
95 // ESLE: direct call
96 else return func(value(t)...);
97 }
98
99} // end bbm namespace
100
101#endif /* _BBM_APPLY_ALL_H_ */
Helper methods for extracting the value of an attribute (according to concepts::attribute).
constructible_from_tuple concept
Definition: util.h:166
std::get supported
Definition: util.h:175
concept to check if a class supports reflections
Definition: reflection.h:58
constexpr decltype(auto) attributes(T &&t)
Definition: reflection.h:200
typename bbm::reflection::detail::attributes_impl< T >::type attributes_t
Definition: reflection.h:206
Definition: aggregatebsdf.h:29
typename bbm::detail::find_first_impl< TRAIT, void, Ts... >::type find_first
Find first type that matches a type_trait.
Definition: type_traits.h:85
auto apply_all(const FUNC &func, const T &... t)
Apply a function.
Definition: apply_all.h:42
decltype(auto) value(T &&t)
return the value of an attribute, or if not an attribute the object
Definition: attribute_value.h:20
decltype(to_tuple(std::declval< T >())) to_tuple_t
type of converting a type that supports std::get to a tuple
Definition: tuple.h:35
constexpr auto value_copy_tuple(const std::tuple< ARGS... > &tup)
Value-copy a tuple.
Definition: tuple.h:61
A wrapper for STL containers such as tuple, pair, and array. These containers force the programmer to...
Compile-time reflection of:
Additional basic helper concepts.