Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
variant.hpp
Go to the documentation of this file.
1#pragma once
2
3// temporarily use exceptions
4#include <sysio/vm/exceptions.hpp>
5
6#include <cstddef>
7#include <cstdint>
8#include <algorithm>
9#include <limits>
10#include <tuple>
11#include <type_traits>
12#include <variant>
13#include <utility>
14
15namespace sysio { namespace vm {
16
17 // forward declaration
18 template <typename... Alternatives>
19 class variant;
20
21 // implementation details
22 namespace detail {
23
24 template <typename... Ts>
25 constexpr std::size_t max_layout_size_v = std::max({sizeof(Ts)...});
26
27 template <typename... Ts>
28 constexpr std::size_t max_alignof_v = std::max({alignof(Ts)...});
29
30 template <typename T, typename... Alternatives>
31 constexpr bool is_valid_alternative_v = (... + (std::is_same_v<T, Alternatives>?1:0)) != 0;
32
33 template <typename T, typename Alternative, typename... Alternatives>
34 constexpr std::size_t get_alternatives_index_v =
35 std::is_same_v<T, Alternative> ? 0 : get_alternatives_index_v<T, Alternatives...> + 1;
36
37 template <typename T, typename Alternative>
39
40 template <std::size_t I, typename... Alternatives>
41 using get_alternative_t = std::tuple_element_t<I, std::tuple<Alternatives...>>;
42
43 template <bool Valid, typename Ret>
44 struct dispatcher;
45
46 template <typename Ret>
47 struct dispatcher<false, Ret> {
48 template <std::size_t I, typename Vis, typename Var>
49 static constexpr Ret _case(Vis&&, Var&&) {
50 throw wasm_interpreter_exception("variant visit shouldn't be here");
51 }
52 template <std::size_t I, typename Vis, typename Var>
53 static constexpr Ret _switch(Vis&&, Var&&) {
54 throw wasm_interpreter_exception("variant visit shouldn't be here");
55 }
56 };
57
58 template <typename Ret>
59 struct dispatcher<true, Ret> {
60 template <std::size_t I, typename Vis, typename Var>
61 static constexpr Ret _case(Vis&& vis, Var&& var) {
62 return std::invoke(std::forward<Vis>(vis), std::forward<Var>(var).template get<I>());
63 }
64
65 template <std::size_t I, typename Vis, typename Var>
66 static constexpr Ret _switch(Vis&& vis, Var&& var) {
67 constexpr std::size_t sz = std::decay_t<Var>::variant_size();
68 switch (var.index()) {
69 case I + 0: {
70 return dispatcher<I + 0 < sz, Ret>::template _case<I + 0>(std::forward<Vis>(vis),
71 std::forward<Var>(var));
72 }
73 case I + 1: {
74 return dispatcher<I + 1 < sz, Ret>::template _case<I + 1>(std::forward<Vis>(vis),
75 std::forward<Var>(var));
76 }
77 case I + 2: {
78 return dispatcher<I + 2 < sz, Ret>::template _case<I + 2>(std::forward<Vis>(vis),
79 std::forward<Var>(var));
80 }
81 case I + 3: {
82 return dispatcher<I + 3 < sz, Ret>::template _case<I + 3>(std::forward<Vis>(vis),
83 std::forward<Var>(var));
84 }
85 default: {
86 return dispatcher<I + 4 < sz, Ret>::template _switch<I + 4>(std::forward<Vis>(vis),
87 std::forward<Var>(var));
88 }
89 }
90 }
91 };
92
93#define V_ELEM(N) \
94 T##N _t##N; \
95 constexpr variant_storage(T##N& arg) : _t##N(arg) {} \
96 constexpr variant_storage(T##N&& arg) : _t##N(std::move(arg)) {} \
97 constexpr variant_storage(const T##N& arg) : _t##N(arg) {} \
98 constexpr variant_storage(const T##N&& arg) : _t##N(std::move(arg)) {}
99
100#define V0 variant_storage() = default;
101#define V1 V0 V_ELEM(0)
102#define V2 V1 V_ELEM(1)
103#define V3 V2 V_ELEM(2)
104#define V4 V3 V_ELEM(3)
105
106 template<typename... T>
107 union variant_storage;
108 template<typename T0, typename T1, typename T2, typename T3, typename... T>
109 union variant_storage<T0, T1, T2, T3, T...> {
110 V4
111 template<typename A>
112 constexpr variant_storage(A&& arg) : _tail{static_cast<A&&>(arg)} {}
114 };
115 template<typename T0>
116 union variant_storage<T0> {
117 V1
118 };
119 template<typename T0, typename T1>
120 union variant_storage<T0, T1> {
121 V2
122 };
123 template<typename T0, typename T1, typename T2>
124 union variant_storage<T0, T1, T2> {
125 V3
126 };
127 template<typename T0, typename T1, typename T2, typename T3>
128 union variant_storage<T0, T1, T2, T3> {
129 V4
130 };
131
132#undef V4
133#undef V3
134#undef V2
135#undef V1
136#undef V0
137#undef V_ELEM
138
139 template<int I, typename Storage>
140 constexpr decltype(auto) variant_storage_get(Storage&& val) {
141 if constexpr (I == 0) {
142 return (static_cast<Storage&&>(val)._t0);
143 } else if constexpr (I == 1) {
144 return (static_cast<Storage&&>(val)._t1);
145 } else if constexpr (I == 2) {
146 return (static_cast<Storage&&>(val)._t2);
147 } else if constexpr (I == 3) {
148 return (static_cast<Storage&&>(val)._t3);
149 } else {
150 return detail::variant_storage_get<I - 4>(static_cast<Storage&&>(val)._tail);
151 }
152 }
153 } // namespace detail
154
155 template <class Visitor, typename Variant>
156 constexpr auto visit(Visitor&& vis, Variant&& var) {
157 using Ret = decltype(std::invoke(std::forward<Visitor>(vis), var.template get<0>()));
158 return detail::dispatcher<true, Ret>::template _switch<0>(std::forward<Visitor>(vis), std::forward<Variant>(var));
159 }
160
161 template <typename... Alternatives>
162 class variant {
163 static_assert(sizeof...(Alternatives) <= std::numeric_limits<uint8_t>::max()+1,
164 "sysio::vm::variant can only accept 256 alternatives");
165 static_assert((... && (std::is_trivially_copy_constructible_v<Alternatives> && std::is_trivially_move_constructible_v<Alternatives> &&
166 std::is_trivially_copy_assignable_v<Alternatives> && std::is_trivially_move_assignable_v<Alternatives> &&
167 std::is_trivially_destructible_v<Alternatives>)), "Variant requires trivial types");
168
169 public:
170 variant() = default;
171 variant(const variant& other) = default;
172 variant(variant&& other) = default;
173
174 variant& operator=(const variant& other) = default;
175 variant& operator=(variant&& other) = default;
176
177 template <typename T, typename = std::enable_if_t<detail::is_valid_alternative_v<std::decay_t<T>, Alternatives...>>>
178 constexpr variant(T&& alt) :
179 _which(detail::get_alternatives_index_v<std::decay_t<T>, Alternatives...>),
180 _storage(static_cast<T&&>(alt)) {
181 }
182
183 template <typename T,
184 typename = std::enable_if_t<detail::is_valid_alternative_v<std::decay_t<T>, Alternatives...>>>
185 constexpr variant& operator=(T&& alt) {
186#if (defined(__GNUC__) && !defined(__clang__))
187#pragma GCC diagnostic push
188#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
189 _storage = static_cast<T&&>(alt);
190#pragma GCC diagnostic pop
191#else
192 _storage = static_cast<T&&>(alt);
193#endif
194 _which = detail::get_alternatives_index_v<std::decay_t<T>, Alternatives...>;
195 return *this;
196 }
197
198 static inline constexpr size_t variant_size() { return sizeof...(Alternatives); }
199 inline constexpr uint16_t index() const { return _which; }
200
201 template <size_t Index>
202 inline constexpr auto&& get_check() {
203 // TODO add outcome stuff
204 return 3;
205 }
206
207 template <size_t Index>
208 inline constexpr const auto& get() const & {
209 return detail::variant_storage_get<Index>(_storage);
210 }
211
212 template <typename Alt>
213 inline constexpr const Alt& get() const & {
214 return detail::variant_storage_get<detail::get_alternatives_index_v<Alt, Alternatives...>>(_storage);
215 }
216
217 template <size_t Index>
218 inline constexpr const auto&& get() const && {
219 return detail::variant_storage_get<Index>(std::move(_storage));
220 }
221
222 template <typename Alt>
223 inline constexpr const Alt&& get() const && {
224 return detail::variant_storage_get<detail::get_alternatives_index_v<Alt, Alternatives...>>(std::move(_storage));
225 }
226
227 template <size_t Index>
228 inline constexpr auto&& get() && {
229 return detail::variant_storage_get<Index>(std::move(_storage));
230 }
231
232 template <typename Alt>
233 inline constexpr Alt&& get() && {
234 return detail::variant_storage_get<detail::get_alternatives_index_v<Alt, Alternatives...>>(std::move(_storage));
235 }
236
237 template <size_t Index>
238 inline constexpr auto& get() & {
239 return detail::variant_storage_get<Index>(_storage);
240 }
241
242 template <typename Alt>
243 inline constexpr Alt& get() & {
244 return detail::variant_storage_get<detail::get_alternatives_index_v<Alt, Alternatives...>>(_storage);
245 }
246
247 template <typename Alt>
248 inline constexpr bool is_a() const {
249 return _which == detail::get_alternatives_index_v<Alt, Alternatives...>;
250 }
251 inline constexpr void toggle_exiting_which() { _which ^= 0x100; }
252 inline constexpr void clear_exiting_which() { _which &= 0xFF; }
253 inline constexpr void set_exiting_which() { _which |= 0x100; }
254
255 private:
256 static constexpr size_t _sizeof = detail::max_layout_size_v<Alternatives...>;
257 static constexpr size_t _alignof = detail::max_alignof_v<Alternatives...>;
258 uint16_t _which = 0;
259 detail::variant_storage<Alternatives...> _storage;
260 };
261
262}} // namespace sysio::vm
Binary< NodeType::alt > Alt
Definition Regexp.cpp:54
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition variant.hpp:191
constexpr void clear_exiting_which()
Definition variant.hpp:252
constexpr void toggle_exiting_which()
Definition variant.hpp:251
constexpr const auto & get() const &
Definition variant.hpp:208
constexpr auto && get_check()
Definition variant.hpp:202
static constexpr size_t variant_size()
Definition variant.hpp:198
constexpr auto & get() &
Definition variant.hpp:238
variant & operator=(const variant &other)=default
constexpr auto && get() &&
Definition variant.hpp:228
constexpr void set_exiting_which()
Definition variant.hpp:253
constexpr bool is_a() const
Definition variant.hpp:248
constexpr variant(T &&alt)
Definition variant.hpp:178
constexpr const Alt && get() const &&
Definition variant.hpp:223
constexpr uint16_t index() const
Definition variant.hpp:199
constexpr Alt && get() &&
Definition variant.hpp:233
variant(const variant &other)=default
constexpr const Alt & get() const &
Definition variant.hpp:213
variant & operator=(variant &&other)=default
constexpr variant & operator=(T &&alt)
Definition variant.hpp:185
constexpr const auto && get() const &&
Definition variant.hpp:218
constexpr Alt & get() &
Definition variant.hpp:243
variant(variant &&other)=default
Definition name.hpp:106
std::tuple_element_t< I, std::tuple< Alternatives... > > get_alternative_t
Definition variant.hpp:41
constexpr decltype(auto) variant_storage_get(Storage &&val)
Definition variant.hpp:140
constexpr std::size_t max_layout_size_v
Definition variant.hpp:25
constexpr std::size_t max_alignof_v
Definition variant.hpp:28
constexpr std::size_t get_alternatives_index_v< T, Alternative >
Definition variant.hpp:38
constexpr bool is_valid_alternative_v
Definition variant.hpp:31
constexpr std::size_t get_alternatives_index_v
Definition variant.hpp:34
constexpr auto visit(Visitor &&vis, Variant &&var)
Definition variant.hpp:156
#define T(meth, val, expected)
unsigned short uint16_t
Definition stdint.h:125
static constexpr Ret _case(Vis &&, Var &&)
Definition variant.hpp:49
static constexpr Ret _switch(Vis &&, Var &&)
Definition variant.hpp:53
static constexpr Ret _switch(Vis &&vis, Var &&var)
Definition variant.hpp:66
static constexpr Ret _case(Vis &&vis, Var &&var)
Definition variant.hpp:61
#define V2
Definition variant.hpp:102
#define V1
Definition variant.hpp:101
#define V3
Definition variant.hpp:103
#define V4
Definition variant.hpp:104