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// SPDX-FileCopyrightText: Copyright (C) 2021 Tobias Hienzsch
3
4#ifndef TETL_VARIANT_VISIT_HPP
5#define TETL_VARIANT_VISIT_HPP
6
7#include <etl/_cstddef/size_t.hpp>
8#include <etl/_tuple/tuple.hpp>
9#include <etl/_type_traits/add_rvalue_reference.hpp>
10#include <etl/_type_traits/bool_constant.hpp>
11#include <etl/_type_traits/conditional.hpp>
12#include <etl/_type_traits/decay.hpp>
13#include <etl/_type_traits/is_lvalue_reference.hpp>
14#include <etl/_type_traits/is_reference.hpp>
15#include <etl/_type_traits/is_rvalue_reference.hpp>
16#include <etl/_type_traits/remove_reference.hpp>
17#include <etl/_type_traits/void_t.hpp>
18#include <etl/_utility/forward.hpp>
19#include <etl/_utility/index_sequence.hpp>
20#include <etl/_variant/variant_fwd.hpp>
21
22namespace etl {
23
24namespace detail {
25
26template <typename... Ts>
27auto variant_access(variant<Ts...> const* v) -> variant<Ts...>;
28
29template <typename T>
30using variant_access_t = decltype(variant_access(static_cast<decay_t<T>*>(nullptr)));
31
32template <template <typename...> typename, typename = void, typename...>
33struct is_detected_impl : false_type { };
34
35template <template <typename...> typename D, typename... Ts>
36struct is_detected_impl<D, void_t<D<Ts...>>, Ts...> : true_type { };
37
38template <template <typename...> typename D, typename... Ts>
39using is_detected = typename is_detected_impl<D, void, Ts...>::type;
40
41template <template <typename...> typename D, typename... Ts>
42constexpr bool is_detected_v = is_detected<D, Ts...>::value;
43
44template <typename T>
45constexpr bool is_variant_v = is_detected_v<variant_access_t, T>;
46
47template <size_t... I>
48[[nodiscard]] consteval auto sum(index_sequence<I...> /*seq*/) -> size_t
49{
50 return (I + ...);
51}
52
53template <size_t I, size_t... Is>
54[[nodiscard]] consteval auto prepend(index_sequence<Is...> /*seq*/) -> index_sequence<I, Is...>
55{
56 return {};
57}
58
59[[nodiscard]] consteval auto next_seq(index_sequence<> /*i*/, index_sequence<> /*j*/) -> index_sequence<>
60{
61 return {};
62}
63
64template <size_t I, size_t... Is, size_t J, size_t... Js>
65consteval auto next_seq(index_sequence<I, Is...> /*i*/, index_sequence<J, Js...> /*j*/)
66{
67 if constexpr (I + 1 == J) {
68 return prepend<0>(next_seq(index_sequence<Is...>{}, index_sequence<Js...>{}));
69 } else {
70 return index_sequence<I + 1, Is...>{};
71 }
72}
73
74template <typename V>
75consteval auto variant_size() -> size_t
76{
77 if constexpr (is_variant_v<V>) {
78 return variant_size_v<variant_access_t<V>>;
79 } else {
80 return 1;
81 }
82}
83
84template <size_t I, typename T>
85constexpr auto get(T&& t) -> decltype(auto)
86{
87 if constexpr (is_variant_v<T>) {
88 return etl::unchecked_get<I>(etl::forward<T>(t));
89 } else {
90 static_assert(I == 0);
91 return etl::forward<T>(t);
92 }
93}
94
95template <typename V>
96constexpr auto index(V const& v) -> size_t
97{
98 if constexpr (is_variant_v<V>) {
99 return v.index();
100 } else {
101 return 0;
102 }
103}
104
105template <typename T, size_t I>
106struct indexed_value {
107 static constexpr auto index = index_v<I>;
108
109 constexpr explicit indexed_value(T value)
110 : _value(etl::forward<T>(value))
111 {
112 }
113
114 [[nodiscard]] constexpr auto value() const& -> auto&
115 {
116 return _value;
117 }
118
119 [[nodiscard]] constexpr auto value() && -> auto&&
120 {
121 return etl::forward<T>(_value);
122 }
123
124private:
125 T _value;
126};
127
128template <size_t... Is, size_t... Ms, typename F, typename... Vs>
129constexpr auto visit_with_index(index_sequence<Is...> i, index_sequence<Ms...> m, F&& f, Vs&&... vs)
130{
131 constexpr auto n = next_seq(i, m);
132 if constexpr (sum(n) == 0) {
133 return f(indexed_value<decltype(get<Is>(etl::forward<Vs>(vs))), Is>{get<Is>(etl::forward<Vs>(vs))}...);
134 } else {
135 if (etl::tuple(index(vs)...) == etl::tuple(Is...)) {
136 return f(indexed_value<decltype(get<Is>(etl::forward<Vs>(vs))), Is>{get<Is>(etl::forward<Vs>(vs))}...);
137 }
138 return visit_with_index(n, m, etl::forward<F>(f), etl::forward<Vs>(vs)...);
139 }
140}
141
142template <typename>
143inline constexpr size_t zero = 0;
144
145} // namespace detail
146
147/// Applies the visitor vis (Callable that can be called with any
148/// combination of types from variants) to the variants vars.
149///
150/// Every type in etl::remove_reference_t<Variants>... may be a
151/// (possibly const-qualified) specialization of etl::variant.
152///
153/// - Access index as `v.index`
154/// - Access value as `v.value()`
155///
156/// \relates variant
157/// \ingroup variant
158template <typename F, typename... Vs>
159constexpr auto visit_with_index(F&& f, Vs&&... vs)
160{
161 if constexpr (((detail::variant_size<Vs>() == 1) and ...)) {
162 return f(
163 detail::indexed_value<decltype(detail::get<0>(etl::forward<Vs>(vs))), 0>(
164 detail::get<0>(etl::forward<Vs>(vs))
165 )...
166 );
167 } else {
168 return detail::visit_with_index(
169 index_sequence<detail::zero<Vs>...>{},
170 index_sequence<detail::variant_size<Vs>()...>{},
171 etl::forward<F>(f),
172 etl::forward<Vs>(vs)...
173 );
174 }
175}
176
177/// Applies the visitor vis (Callable that can be called with any
178/// combination of types from variants) to the variants vars.
179///
180/// Every type in etl::remove_reference_t<Variants>... may be a
181/// (possibly const-qualified) specialization of etl::variant.
182///
183/// - Copied from https://github.com/rollbear/visit
184/// - https://github.com/rollbear/visit/blob/master/LICENSE.txt
185///
186/// \relates variant
187/// \ingroup variant
188template <typename F, typename... Vs>
189constexpr auto visit(F&& f, Vs&&... vs)
190{
191 return etl::visit_with_index([&](auto... parameter) {
192 return etl::forward<F>(f)(etl::move(parameter).value()...);
193 }, etl::forward<Vs>(vs)...);
194}
195
196} // namespace etl
197
198#endif // TETL_VARIANT_VISIT_HPP
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:189
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:159
Definition adjacent_find.hpp:9
Definition tuple.hpp:114
Definition variant.hpp:99