tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
visit.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2
3#ifndef TETL_VARIANT_VISIT_HPP
4#define TETL_VARIANT_VISIT_HPP
5
20
21namespace etl {
22
23namespace detail {
24
25template <typename... Ts>
26auto variant_access(variant<Ts...> const* v) -> variant<Ts...>;
27
28template <typename T>
29using variant_access_t = decltype(variant_access(static_cast<decay_t<T>*>(nullptr)));
30
31template <template <typename...> typename, typename = void, typename...>
32struct is_detected_impl : false_type { };
33
34template <template <typename...> typename D, typename... Ts>
35struct is_detected_impl<D, void_t<D<Ts...>>, Ts...> : true_type { };
36
37template <template <typename...> typename D, typename... Ts>
38using is_detected = typename is_detected_impl<D, void, Ts...>::type;
39
40template <template <typename...> typename D, typename... Ts>
41constexpr bool is_detected_v = is_detected<D, Ts...>::value;
42
43template <typename T>
44constexpr bool is_variant_v = is_detected_v<variant_access_t, T>;
45
46template <size_t... I>
47[[nodiscard]] consteval auto sum(index_sequence<I...> /*seq*/) -> size_t
48{
49 return (I + ...);
50}
51
52template <size_t I, size_t... Is>
53[[nodiscard]] consteval auto prepend(index_sequence<Is...> /*seq*/) -> index_sequence<I, Is...>
54{
55 return {};
56}
57
58[[nodiscard]] consteval auto next_seq(index_sequence<> /*i*/, index_sequence<> /*j*/) -> index_sequence<> { return {}; }
59
60template <size_t I, size_t... Is, size_t J, size_t... Js>
61consteval auto next_seq(index_sequence<I, Is...> /*i*/, index_sequence<J, Js...> /*j*/)
62{
63 if constexpr (I + 1 == J) {
64 return prepend<0>(next_seq(index_sequence<Is...>{}, index_sequence<Js...>{}));
65 } else {
66 return index_sequence<I + 1, Is...>{};
67 }
68}
69
70template <typename V>
71consteval auto variant_size() -> size_t
72{
73 if constexpr (is_variant_v<V>) {
75 } else {
76 return 1;
77 }
78}
79
80template <size_t I, typename T>
81constexpr auto get(T&& t) -> decltype(auto)
82{
83 if constexpr (is_variant_v<T>) {
85 } else {
86 static_assert(I == 0);
87 return etl::forward<T>(t);
88 }
89}
90
91template <typename V>
92constexpr auto index(V const& v) -> size_t
93{
94 if constexpr (is_variant_v<V>) {
95 return v.index();
96 } else {
97 return 0;
98 }
99}
100
101template <typename T, size_t I>
102struct indexed_value {
103 static constexpr auto index = index_v<I>;
104
105 constexpr explicit indexed_value(T value)
106 : _value(etl::forward<T>(value))
107 {
108 }
109
110 [[nodiscard]] constexpr auto value() const& -> auto& { return _value; }
111
112 [[nodiscard]] constexpr auto value() && -> auto&& { return etl::forward<T>(_value); }
113
114private:
115 T _value;
116};
117
118template <size_t... Is, size_t... Ms, typename F, typename... Vs>
119constexpr auto visit_with_index(index_sequence<Is...> i, index_sequence<Ms...> m, F&& f, Vs&&... vs)
120{
121 constexpr auto n = next_seq(i, m);
122 if constexpr (sum(n) == 0) {
123 return f(indexed_value<decltype(get<Is>(etl::forward<Vs>(vs))), Is>{get<Is>(etl::forward<Vs>(vs))}...);
124 } else {
125 if (etl::tuple(index(vs)...) == etl::tuple(Is...)) {
126 return f(indexed_value<decltype(get<Is>(etl::forward<Vs>(vs))), Is>{get<Is>(etl::forward<Vs>(vs))}...);
127 }
128 return visit_with_index(n, m, etl::forward<F>(f), etl::forward<Vs>(vs)...);
129 }
130}
131
132template <typename>
133inline constexpr size_t zero = 0;
134
135} // namespace detail
136
148template <typename F, typename... Vs>
149constexpr auto visit_with_index(F&& f, Vs&&... vs)
150{
151 if constexpr (((detail::variant_size<Vs>() == 1) and ...)) {
152 return f(detail::indexed_value<decltype(detail::get<0>(etl::forward<Vs>(vs))), 0>(
153 detail::get<0>(etl::forward<Vs>(vs))
154 )...);
155 } else {
156 return detail::visit_with_index(
157 index_sequence<detail::zero<Vs>...>{},
160 etl::forward<Vs>(vs)...
161 );
162 }
163}
164
176template <typename F, typename... Vs>
177constexpr auto visit(F&& f, Vs&&... vs)
178{
179 return etl::visit_with_index([&](auto... parameter) {
180 return etl::forward<F>(f)(etl::move(parameter).value()...);
181 }, etl::forward<Vs>(vs)...);
182}
183
184} // namespace etl
185
186#endif // TETL_VARIANT_VISIT_HPP
constexpr auto move(InputIt first, InputIt last, OutputIt destination) -> OutputIt
Moves the elements in the range [first, last), to another range beginning at destination,...
Definition move.hpp:26
void void_t
Definition void_t.hpp:10
constexpr auto visit(F &&f, Vs &&... vs)
Applies the visitor vis (Callable that can be called with any combination of types from variants) to ...
Definition visit.hpp:177
constexpr auto visit_with_index(F &&f, Vs &&... vs)
Applies the visitor vis (Callable that can be called with any combination of types from variants) to ...
Definition visit.hpp:149
Definition adjacent_find.hpp:8
constexpr auto variant_size_v
Definition variant_size.hpp:25
typename etl::decay< T >::type decay_t
Definition decay.hpp:32
constexpr auto index_v
Definition index_constant.hpp:15
etl::integer_sequence< etl::size_t, Ints... > index_sequence
Definition index_sequence.hpp:12
constexpr auto unchecked_get(variant< Ts... > &v) -> auto &
bool_constant< true > true_type
Definition bool_constant.hpp:13
bool_constant< false > false_type
Definition bool_constant.hpp:14
constexpr auto forward(remove_reference_t< T > &param) noexcept -> T &&
Forwards lvalues as either lvalues or as rvalues, depending on T. When t is a forwarding reference (a...
Definition forward.hpp:18