|
14 | 14 |
|
15 | 15 | #include <iris/x4/traits/substitution.hpp> |
16 | 16 |
|
17 | | -#include <boost/variant/variant_fwd.hpp> // TODO: remove this |
18 | | - |
19 | | -#include <boost/mpl/find.hpp> // TODO: remove this |
20 | | -#include <boost/mpl/deref.hpp> // TODO: remove this |
21 | | -#include <boost/mpl/find_if.hpp> // TODO: remove this |
22 | | -#include <boost/mpl/eval_if.hpp> // TODO: remove this |
23 | | -#include <boost/mpl/begin_end.hpp> // TODO: remove this |
| 17 | +#include <iris/rvariant/variant_helper.hpp> |
24 | 18 |
|
25 | 19 | #include <type_traits> |
26 | 20 |
|
27 | 21 | namespace iris::x4::traits { |
28 | 22 |
|
29 | | -// TODO: define a legit concept for determining variant-like types |
30 | | - |
31 | 23 | template<class T> |
32 | 24 | struct is_variant : std::false_type {}; |
33 | 25 |
|
34 | 26 | template<class T> |
35 | 27 | constexpr bool is_variant_v = is_variant<T>::value; |
36 | 28 |
|
37 | | -// By declaring a nested struct named `adapted_variant_tag` in |
38 | | -// your class, you tell X4 that it is regarded as a variant type. |
39 | | -// The minimum required interface for such a variant is that it has |
40 | | -// constructors for various types supported by your variant and |
41 | | -// `::types` which is an mpl sequence of the contained types. |
42 | | -// Note (2025): The above spec is obsolete and will change in the near future. |
43 | | -// |
44 | | -// This is an intrusive interface. For a non-intrusive interface, |
45 | | -// specialize the is_variant trait. |
46 | | -template<class T> |
47 | | - requires requires { |
48 | | - typename T::adapted_variant_tag; |
49 | | - } |
50 | | -struct is_variant<T> : std::true_type |
51 | | -{}; |
| 29 | +// `std::variant` is not supported, as it does can't handle recursive types |
52 | 30 |
|
53 | | -template<BOOST_VARIANT_ENUM_PARAMS(typename T)> |
54 | | -struct is_variant<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>> |
55 | | - : std::true_type |
56 | | -{}; |
| 31 | +template<class... Ts> |
| 32 | +struct is_variant<iris::rvariant<Ts...>> : std::true_type {}; |
| 33 | + |
| 34 | + |
| 35 | +namespace detail { |
57 | 36 |
|
| 37 | +template<class Attr, class... Ts> |
| 38 | +struct variant_find_substitute_impl; |
58 | 39 |
|
59 | | -template<class Variant, X4Attribute T> |
60 | | -struct variant_find_substitute |
| 40 | +template<class Attr> |
| 41 | +struct variant_find_substitute_impl<Attr> |
61 | 42 | { |
62 | | - // Get the type from the Variant that can be a substitute for T. |
63 | | - // If none is found, just return T |
64 | | - |
65 | | - using variant_type = Variant; |
66 | | - using types = typename variant_type::types; |
67 | | - using end = typename boost::mpl::end<types>::type; |
68 | | - |
69 | | - using iter_1 = typename boost::mpl::find<types, T>::type; |
70 | | - |
71 | | - using iter = typename boost::mpl::eval_if< |
72 | | - std::is_same<iter_1, end>, |
73 | | - boost::mpl::find_if<types, is_substitute<T, boost::mpl::_1>>, |
74 | | - std::type_identity<iter_1> |
75 | | - >::type; |
76 | | - |
77 | | - using type = typename boost::mpl::eval_if< |
78 | | - std::is_same<iter, end>, |
79 | | - std::type_identity<T>, |
80 | | - boost::mpl::deref<iter> |
81 | | - >::type; |
| 43 | + using type = Attr; |
82 | 44 | }; |
83 | 45 |
|
84 | | -template<class Variant, X4Attribute T> |
85 | | -using variant_find_substitute_t = typename variant_find_substitute<Variant, T>::type; |
86 | | - |
87 | | -template<class Variant> |
88 | | -struct variant_find_substitute<Variant, Variant> |
| 46 | +template<class Attr, class First, class... Rest> |
| 47 | +struct variant_find_substitute_impl<Attr, First, Rest...> |
89 | 48 | { |
90 | | - using type = Variant; |
| 49 | + using type = std::conditional_t< |
| 50 | + is_substitute_v<Attr, iris::unwrap_recursive_t<First>>, |
| 51 | + |
| 52 | + // TODO |
| 53 | + // Given some type `T`, when both `T` and `recursive_wrapper<T>` is seen |
| 54 | + // during attribute resolution, X4 should ideally materialize the latter |
| 55 | + // because: |
| 56 | + // - It means that the user has supplied at least one explicit type |
| 57 | + // (possibly a rule attribute type) that is `recursive_wrapper<T>`, |
| 58 | + // - Constructing `T` and then moving it to `recursive_wrapper<T>` |
| 59 | + // involves copying from stack to heap. |
| 60 | + // |
| 61 | + // This is to-do because the above optimization is currently not |
| 62 | + // implementable in a straightforward way. We need to add |
| 63 | + // `unwrap_recursive(attr)` to every places where any parser attempts |
| 64 | + // to modify the content. |
| 65 | + iris::unwrap_recursive_t<First>, |
| 66 | + |
| 67 | + typename variant_find_substitute_impl<Attr, Rest...>::type |
| 68 | + >; |
91 | 69 | }; |
92 | 70 |
|
| 71 | +} // detail |
93 | 72 |
|
94 | | -namespace detail { |
95 | 73 |
|
96 | | -template<class Variant, X4Attribute T> |
97 | | -struct variant_has_substitute_impl |
98 | | -{ |
99 | | - // Find a type from the Variant that can be a substitute for T. |
100 | | - // return true_ if one is found, else false_ |
| 74 | +template<class Variant, X4Attribute Attr> |
| 75 | +struct variant_find_substitute; |
101 | 76 |
|
102 | | - using variant_type = Variant; |
103 | | - using types = typename variant_type::types; |
104 | | - using end = typename boost::mpl::end<types>::type; |
105 | | - using iter_1 = typename boost::mpl::find<types, T>::type; |
| 77 | +template<class Variant, X4Attribute Attr> |
| 78 | +using variant_find_substitute_t = typename variant_find_substitute<Variant, Attr>::type; |
106 | 79 |
|
107 | | - using iter = typename boost::mpl::eval_if< |
108 | | - std::is_same<iter_1, end>, |
109 | | - boost::mpl::find_if<types, is_substitute<T, boost::mpl::_1>>, |
110 | | - std::type_identity<iter_1> |
111 | | - >::type; |
| 80 | +template<X4Attribute Attr> |
| 81 | +struct variant_find_substitute<Attr, Attr> |
| 82 | +{ |
| 83 | + using type = Attr; |
| 84 | +}; |
112 | 85 |
|
113 | | - using type = std::bool_constant<!std::is_same_v<iter, end>>; |
| 86 | +// Recursively find the first type from the variant that can be a substitute for `Attr`. |
| 87 | +// If none is found, returns `Attr`. |
| 88 | +template<X4Attribute Attr, class... Ts> |
| 89 | + requires (!std::same_as<iris::rvariant<Ts...>, Attr>) |
| 90 | +struct variant_find_substitute<iris::rvariant<Ts...>, Attr> |
| 91 | +{ |
| 92 | + using type = typename detail::variant_find_substitute_impl<Attr, Ts...>::type; |
114 | 93 | }; |
115 | 94 |
|
116 | | -} // detail |
117 | 95 |
|
118 | 96 | template<class Variant, X4Attribute Attr> |
119 | | -struct variant_has_substitute |
120 | | - : detail::variant_has_substitute_impl<Variant, Attr>::type |
121 | | -{}; |
| 97 | +struct variant_has_substitute; |
122 | 98 |
|
123 | 99 | template<class Variant, X4Attribute Attr> |
124 | 100 | constexpr bool variant_has_substitute_v = variant_has_substitute<Variant, Attr>::value; |
125 | 101 |
|
126 | 102 | template<X4Attribute Attr> |
127 | | -struct variant_has_substitute<unused_type, Attr> : std::true_type {}; |
| 103 | +struct variant_has_substitute<Attr, Attr> |
| 104 | + : std::true_type |
| 105 | +{}; |
128 | 106 |
|
129 | 107 | template<X4Attribute Attr> |
130 | | -struct variant_has_substitute<unused_type const, Attr> : std::true_type {}; |
| 108 | +struct variant_has_substitute<unused_type, Attr> |
| 109 | + : std::true_type |
| 110 | +{}; |
| 111 | + |
| 112 | +template<X4Attribute Attr> |
| 113 | +struct variant_has_substitute<unused_type const, Attr> |
| 114 | + : std::true_type |
| 115 | +{}; |
| 116 | + |
| 117 | +// Recursively find the first type from the variant that can be a substitute for `T`. |
| 118 | +// Returns boolean value whether it was found. |
| 119 | +template<X4Attribute Attr, class... Ts> |
| 120 | + requires (!std::same_as<iris::rvariant<Ts...>, Attr>) |
| 121 | +struct variant_has_substitute<iris::rvariant<Ts...>, Attr> |
| 122 | + : std::disjunction<is_substitute<Attr, Ts>...> |
| 123 | +{}; |
131 | 124 |
|
132 | 125 | } // iris::x4::traits |
133 | 126 |
|
|
0 commit comments