Cuda battery library
Loading...
Searching...
No Matches
variant.hpp
Go to the documentation of this file.
1// Copyright 2021 Pierre Talbot
2// Based on https://gist.github.com/calebh/fd00632d9c616d4b0c14e7c2865f3085
3// and on https://gist.github.com/tibordp/6909880
4
5#ifndef CUDA_BATTERY_VARIANT_HPP
6#define CUDA_BATTERY_VARIANT_HPP
7
8#include <type_traits>
9#include "utility.hpp"
10
11namespace battery {
12
13/// @private
14namespace impl {
15
16template<size_t n, typename... Ts>
17struct variant_helper_rec;
18
19template<size_t n, typename F, typename... Ts>
20struct variant_helper_rec<n, F, Ts...>
21{
22 CUDA inline static void destroy(size_t id, void* data)
23 {
24 if (n == id) {
25 reinterpret_cast<F*>(data)->~F();
26 } else {
27 variant_helper_rec<n + 1, Ts...>::destroy(id, data);
28 }
29 }
30
31 CUDA inline static void move(size_t id, void* from, void* to)
32 {
33 if (n == id) {
34 new (to) F(std::move(*reinterpret_cast<F*>(from)));
35 } else {
36 variant_helper_rec<n + 1, Ts...>::move(id, from, to);
37 }
38 }
39
40 CUDA inline static void copy(size_t id, const void* from, void* to)
41 {
42 if (n == id) {
43 new (to) F(*reinterpret_cast<const F*>(from));
44 } else {
45 variant_helper_rec<n + 1, Ts...>::copy(id, from, to);
46 }
47 }
48
49 CUDA inline static bool equals(size_t id, const void* a, const void* b)
50 {
51 if (n == id) {
52 return *reinterpret_cast<const F*>(a) == *reinterpret_cast<const F*>(b);
53 } else {
54 return variant_helper_rec<n + 1, Ts...>::equals(id, a, b);
55 }
56 }
57
58 CUDA inline static void print(size_t id, const void* a)
59 {
60 if (n == id) {
61 ::battery::print(*reinterpret_cast<const F*>(a));
62 } else {
63 variant_helper_rec<n + 1, Ts...>::print(id, a);
64 }
65 }
66};
67
68template<size_t n> struct variant_helper_rec<n> {
69 CUDA inline static void destroy(size_t id, void* data) { }
70 CUDA inline static void move(size_t old_t, void* from, void* to) { }
71 CUDA inline static void copy(size_t old_t, const void* from, void* to) { }
72 CUDA inline static bool equals(size_t id, const void* a, const void* b) { return false; }
73 CUDA inline static void print(size_t id, const void* a) {}
74};
75
76template<typename... Ts>
77struct variant_helper {
78 CUDA inline static void destroy(size_t id, void* data) {
79 variant_helper_rec<0, Ts...>::destroy(id, data);
80 }
81
82 CUDA inline static void move(size_t id, void* from, void* to) {
83 variant_helper_rec<0, Ts...>::move(id, from, to);
84 }
85
86 CUDA inline static void copy(size_t id, const void* from, void* to) {
87 variant_helper_rec<0, Ts...>::copy(id, from, to);
88 }
89
90 CUDA inline static bool equals(size_t id, const void* a, const void* b) {
91 return variant_helper_rec<0, Ts...>::equals(id, a, b);
92 }
93
94 CUDA inline static void print(size_t id, const void* a) {
95 return variant_helper_rec<0, Ts...>::print(id, a);
96 }
97};
98
99template<> struct variant_helper<> {
100 CUDA inline static void destroy(size_t id, void* data) { }
101 CUDA inline static void move(size_t old_t, void* from, void* to) { }
102 CUDA inline static void copy(size_t old_t, const void* from, void* to) { }
103 CUDA inline static bool equals(size_t id, const void* a, const void* b) { return false; }
104 CUDA inline static void print(size_t id, const void* a) { }
105};
106
107template<typename F>
108struct variant_helper_static;
109
110template<typename F>
111struct variant_helper_static {
112 CUDA inline static void move(void* from, void* to) {
113 new (to) F(std::move(*reinterpret_cast<F*>(from)));
114 }
115
116 CUDA inline static void copy(const void* from, void* to) {
117 new (to) F(*reinterpret_cast<const F*>(from));
118 }
119};
120
121// Given a size_t i, selects the ith type from the list of item types
122template<size_t i, typename... Items>
123struct variant_alternative;
124
125template<typename HeadItem, typename... TailItems>
126struct variant_alternative<0, HeadItem, TailItems...>
127{
128 using type = HeadItem;
129};
130
131template<size_t i, typename HeadItem, typename... TailItems>
132struct variant_alternative<i, HeadItem, TailItems...>
133{
134 using type = typename variant_alternative<i - 1, TailItems...>::type;
135};
136
137} // namespace impl
138
139template<typename... Ts>
140struct variant {
141private:
142 using data_t = typename std::aligned_union<1, Ts...>::type;
143 using helper_t = impl::variant_helper<Ts...>;
144
145 template<size_t i>
146 using alternative = typename impl::variant_alternative<i, Ts...>::type;
147
148 size_t variant_id;
149 data_t data;
150
151 CUDA variant(size_t id) : variant_id(id) {}
152
153 template<size_t i>
154 CUDA alternative<i>& get()
155 {
156 assert(variant_id == i);
157 return *reinterpret_cast<alternative<i>*>(&data);
158 }
159
160 template<size_t i>
161 CUDA const alternative<i>& get() const
162 {
163 assert(variant_id == i);
164 return *reinterpret_cast<const alternative<i>*>(&data);
165 }
166
167public:
168 CUDA variant(): variant_id(0) {
169 new(&data) alternative<0>{};
170 }
171
172 template<size_t i>
173 CUDA NI static variant create(const alternative<i>& value)
174 {
175 variant ret(i);
176 impl::variant_helper_static<alternative<i>>::copy(&value, &ret.data);
177 return ret;
178 }
179
180 template<size_t i>
181 CUDA NI static variant create(alternative<i>&& value) {
182 variant ret(i);
183 impl::variant_helper_static<alternative<i>>::move(&value, &ret.data);
184 return ret;
185 }
186
187 CUDA NI variant(const variant<Ts...>& from) : variant_id(from.variant_id)
188 {
189 helper_t::copy(from.variant_id, &from.data, &data);
190 }
191
192 CUDA NI variant(variant<Ts...>&& from) : variant_id(from.variant_id)
193 {
194 helper_t::move(from.variant_id, &from.data, &data);
195 }
196
198 {
199 helper_t::destroy(variant_id, &data);
200 variant_id = rhs.variant_id;
201 helper_t::copy(rhs.variant_id, &rhs.data, &data);
202 return *this;
203 }
204
206 {
207 helper_t::destroy(variant_id, &data);
208 variant_id = rhs.variant_id;
209 helper_t::move(rhs.variant_id, &rhs.data, &data);
210 return *this;
211 }
212
213 CUDA size_t index() const {
214 return variant_id;
215 }
216
217 template<size_t i>
218 CUDA NI void set(alternative<i>& value)
219 {
220 helper_t::destroy(variant_id, &data);
221 variant_id = i;
222 impl::variant_helper_static<alternative<i>>::copy(&value, &data);
223 }
224
225 template<size_t i>
226 CUDA NI void set(alternative<i>&& value)
227 {
228 helper_t::destroy(variant_id, &data);
229 variant_id = i;
230 impl::variant_helper_static<alternative<i>>::move(&value, &data);
231 }
232
234 helper_t::destroy(variant_id, &data);
235 }
236
237 CUDA NI void print() const {
238 helper_t::print(variant_id, &data);
239 }
240
241 template<typename... Us>
242 CUDA friend bool operator==(const variant<Us...>& lhs, const variant<Us...>& rhs);
243 template<size_t i, typename... Us>
244 CUDA friend typename impl::variant_alternative<i, Us...>::type& get(variant<Us...>& v);
245 template<size_t i, typename... Us>
246 CUDA friend const typename impl::variant_alternative<i, Us...>::type& get(const variant<Us...>& v);
247};
248
249template<size_t i, typename... Ts>
250CUDA typename impl::variant_alternative<i, Ts...>::type& get(variant<Ts...>& v)
251{
252 return v.template get<i>();
253}
254
255template<size_t i, typename... Ts>
256CUDA const typename impl::variant_alternative<i, Ts...>::type& get(const variant<Ts...>& v)
257{
258 return v.template get<i>();
259}
260
261template<typename... Ts>
262CUDA NI bool operator==(const variant<Ts...>& lhs, const variant<Ts...>& rhs) {
263 if(lhs.index() == rhs.index()) {
264 return impl::variant_helper<Ts...>::equals(lhs.index(), &lhs.data, &rhs.data);
265 }
266 else {
267 return false;
268 }
269}
270
271template<typename... Ts>
272CUDA bool operator!=(const variant<Ts...>& lhs, const variant<Ts...>& rhs) {
273 return !(lhs == rhs);
274}
275
276} // namespace battery
277
278#endif
Definition algorithm.hpp:10
CUDA NI void print(const T &t)
Definition utility.hpp:707
CUDA impl::variant_alternative< i, Ts... >::type & get(variant< Ts... > &v)
Definition variant.hpp:250
CUDA bool operator==(const string< Alloc1 > &lhs, const string< Alloc2 > &rhs)
Definition string.hpp:110
Definition variant.hpp:140
CUDA variant()
Definition variant.hpp:168
CUDA friend impl::variant_alternative< i, Us... >::type & get(variant< Us... > &v)
CUDA static NI variant create(const alternative< i > &value)
Definition variant.hpp:173
CUDA NI void set(alternative< i > &&value)
Definition variant.hpp:226
CUDA static NI variant create(alternative< i > &&value)
Definition variant.hpp:181
CUDA friend const impl::variant_alternative< i, Us... >::type & get(const variant< Us... > &v)
CUDA NI variant(variant< Ts... > &&from)
Definition variant.hpp:192
CUDA NI ~variant()
Definition variant.hpp:233
CUDA NI variant< Ts... > & operator=(variant< Ts... > &rhs)
Definition variant.hpp:197
CUDA NI variant(const variant< Ts... > &from)
Definition variant.hpp:187
CUDA size_t index() const
Definition variant.hpp:213
CUDA NI void set(alternative< i > &value)
Definition variant.hpp:218
CUDA NI void print() const
Definition variant.hpp:237
CUDA friend bool operator==(const variant< Us... > &lhs, const variant< Us... > &rhs)
#define CUDA
Definition utility.hpp:59
#define NI
Definition utility.hpp:62