Embedded Template Library 1.0
Loading...
Searching...
No Matches
ranges_mini_variant.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2026 BMW AG
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_RANGES_MINI_VARIANT_INCLUDED
32#define ETL_RANGES_MINI_VARIANT_INCLUDED
33
34#include "../platform.h"
35#include "../error_handler.h"
36#include "../utility.h"
37
38#if ETL_USING_CPP17
39
40namespace etl
41{
42 namespace ranges
43 {
44 namespace private_ranges
45 {
46 //*********************************************************************
50 //*********************************************************************
51
52 // Helper: get the I-th type from a parameter pack.
53 template <size_t I, typename... Ts>
54 struct type_at_index;
55
56 template <size_t I, typename Head, typename... Tail>
57 struct type_at_index<I, Head, Tail...> : type_at_index<I - 1, Tail...>
58 {
59 };
60
61 template <typename Head, typename... Tail>
62 struct type_at_index<0, Head, Tail...>
63 {
64 using type = Head;
65 };
66
67 template <size_t I, typename... Ts>
68 using type_at_index_t = typename type_at_index<I, Ts...>::type;
69
70 // Helper: maximum of sizeof... values
71 template <typename... Ts>
72 struct max_size;
73
74 template <typename T>
75 struct max_size<T>
76 {
77 static constexpr size_t value = sizeof(T);
78 };
79
80 template <typename T, typename... Ts>
81 struct max_size<T, Ts...>
82 {
83 static constexpr size_t value = (sizeof(T) > max_size<Ts...>::value) ? sizeof(T) : max_size<Ts...>::value;
84 };
85
86 // Helper: maximum of alignof... values
87 template <typename... Ts>
88 struct max_align;
89
90 template <typename T>
91 struct max_align<T>
92 {
93 static constexpr size_t value = alignof(T);
94 };
95
96 template <typename T, typename... Ts>
97 struct max_align<T, Ts...>
98 {
99 static constexpr size_t value = (alignof(T) > max_align<Ts...>::value) ? alignof(T) : max_align<Ts...>::value;
100 };
101
102 // Index value representing "no active alternative"
103 inline constexpr size_t mini_variant_npos = ~size_t(0);
104
105 // Detection trait: is a single type equality-comparable?
106 template <typename T, typename = void>
107 struct is_equality_comparable : etl::false_type
108 {
109 };
110
111 template <typename T>
112 struct is_equality_comparable< T, etl::void_t<decltype(etl::declval<const T&>() == etl::declval<const T&>())>> : etl::true_type
113 {
114 };
115
116 // Conjunction: all types in the pack are equality-comparable
117 template <typename... Ts>
118 struct all_equality_comparable : etl::bool_constant<(is_equality_comparable<Ts>::value && ...)>
119 {
120 };
121
122 // Detection trait: is a single type nothrow-move-constructible?
123 template <typename T>
124 struct is_nothrow_move_constructible
125 {
126 private:
127
128 template <typename U>
129 static auto test(int) -> etl::bool_constant<noexcept(U(etl::declval<U&&>()))>;
130
131 template <typename>
132 static etl::false_type test(...);
133
134 public:
135
136 static constexpr bool value = decltype(test<T>(0))::value;
137 };
138
139 // Conjunction: all types in the pack are nothrow-move-constructible
140 template <typename... Ts>
141 struct all_nothrow_move_constructible : etl::bool_constant<(is_nothrow_move_constructible<Ts>::value && ...)>
142 {
143 };
144
145 // Detection trait: is a single type nothrow-destructible?
146 template <typename T>
147 struct is_nothrow_destructible
148 {
149 private:
150
151 template <typename U>
152 static auto test(int) -> etl::bool_constant<noexcept(etl::declval<U&>().~U())>;
153
154 template <typename>
155 static etl::false_type test(...);
156
157 public:
158
159 static constexpr bool value = decltype(test<T>(0))::value;
160 };
161
162 // Conjunction: all types in the pack are nothrow-destructible
163 template <typename... Ts>
164 struct all_nothrow_destructible : etl::bool_constant<(is_nothrow_destructible<Ts>::value && ...)>
165 {
166 };
167
168 template <typename... Ts>
169 class mini_variant
170 {
171 static_assert(sizeof...(Ts) > 0, "mini_variant requires at least one type");
172
173 static constexpr size_t storage_size = max_size<Ts...>::value;
174 static constexpr size_t storage_align = max_align<Ts...>::value;
175
176 alignas(storage_align) unsigned char _storage[storage_size];
177 size_t _index;
178
179 // ---- Destruction dispatch table ----
180 using destroy_fn = void (*)(void*);
181
182 template <size_t I>
183 static void destroy_impl(void* ptr)
184 {
185 using T = type_at_index_t<I, Ts...>;
186 static_cast<T*>(ptr)->~T();
187 }
188
189 template <size_t... Is>
190 static const destroy_fn* make_destroy_table(etl::index_sequence<Is...>)
191 {
192 static const destroy_fn table[] = {&destroy_impl<Is>...};
193 return table;
194 }
195
196 static const destroy_fn* destroy_table()
197 {
198 static const destroy_fn* t = make_destroy_table(etl::make_index_sequence<sizeof...(Ts)>{});
199 return t;
200 }
201
202 // ---- Copy dispatch table ----
203 using copy_fn = void (*)(void* /*dst*/, const void* /*src*/);
204
205 template <size_t I>
206 static void copy_impl(void* dst, const void* src)
207 {
208 using T = type_at_index_t<I, Ts...>;
209 ::new (dst) T(*static_cast<const T*>(src));
210 }
211
212 template <size_t... Is>
213 static const copy_fn* make_copy_table(etl::index_sequence<Is...>)
214 {
215 static const copy_fn table[] = {&copy_impl<Is>...};
216 return table;
217 }
218
219 static const copy_fn* copy_table()
220 {
221 static const copy_fn* t = make_copy_table(etl::make_index_sequence<sizeof...(Ts)>{});
222 return t;
223 }
224
225 // ---- Move dispatch table ----
226 using move_fn = void (*)(void* /*dst*/, void* /*src*/);
227
228 template <size_t I>
229 static void move_impl(void* dst, void* src)
230 {
231 using T = type_at_index_t<I, Ts...>;
232 ::new (dst) T(etl::move(*static_cast<T*>(src)));
233 }
234
235 template <size_t... Is>
236 static const move_fn* make_move_table(etl::index_sequence<Is...>)
237 {
238 static const move_fn table[] = {&move_impl<Is>...};
239 return table;
240 }
241
242 static const move_fn* move_table()
243 {
244 static const move_fn* t = make_move_table(etl::make_index_sequence<sizeof...(Ts)>{});
245 return t;
246 }
247
248 // ---- Equality dispatch table ----
249 using equal_fn = bool (*)(const void* /*lhs*/, const void* /*rhs*/);
250
251 template <size_t I>
252 static bool equal_impl(const void* lhs, const void* rhs)
253 {
254 using T = type_at_index_t<I, Ts...>;
255 return *static_cast<const T*>(lhs) == *static_cast<const T*>(rhs);
256 }
257
258 template <size_t... Is>
259 static const equal_fn* make_equal_table(etl::index_sequence<Is...>)
260 {
261 static const equal_fn table[] = {&equal_impl<Is>...};
262 return table;
263 }
264
265 static const equal_fn* equal_table()
266 {
267 static const equal_fn* t = make_equal_table(etl::make_index_sequence<sizeof...(Ts)>{});
268 return t;
269 }
270
271 void destroy_current()
272 {
273 if (_index != mini_variant_npos)
274 {
275 destroy_table()[_index](&_storage);
276 _index = mini_variant_npos;
277 }
278 }
279
280 public:
281
282 mini_variant()
283 : _index{mini_variant_npos}
284 {
285 }
286
287 mini_variant(const mini_variant& other)
288 : _index{mini_variant_npos}
289 {
290 if (other._index != mini_variant_npos)
291 {
292 copy_table()[other._index](&_storage, &other._storage);
293 _index = other._index;
294 }
295 }
296
297 mini_variant& operator=(const mini_variant& other)
298 {
299 if (this != &other)
300 {
301 destroy_current();
302 if (other._index != mini_variant_npos)
303 {
304 copy_table()[other._index](&_storage, &other._storage);
305 _index = other._index;
306 }
307 }
308 return *this;
309 }
310
311 mini_variant(mini_variant&& other) noexcept(all_nothrow_move_constructible<Ts...>::value && all_nothrow_destructible<Ts...>::value)
312 : _index{mini_variant_npos}
313 {
314 if (other._index != mini_variant_npos)
315 {
316 move_table()[other._index](&_storage, &other._storage);
317 _index = other._index;
318 other.destroy_current();
319 }
320 }
321
322 mini_variant& operator=(mini_variant&& other) noexcept(all_nothrow_move_constructible<Ts...>::value && all_nothrow_destructible<Ts...>::value)
323 {
324 if (this != &other)
325 {
326 destroy_current();
327 if (other._index != mini_variant_npos)
328 {
329 move_table()[other._index](&_storage, &other._storage);
330 _index = other._index;
331 other.destroy_current();
332 }
333 }
334 return *this;
335 }
336
337 ~mini_variant() noexcept(all_nothrow_destructible<Ts...>::value)
338 {
339 destroy_current();
340 }
341
342 template <size_t I, typename... Args>
343 void emplace(Args&&... args)
344 {
345 static_assert(I < sizeof...(Ts), "Index out of range");
346 using T = type_at_index_t<I, Ts...>;
347 destroy_current();
348 ::new (&_storage) T(etl::forward<Args>(args)...);
349 _index = I;
350 }
351
352 constexpr size_t index() const
353 {
354 return _index;
355 }
356
357 template <size_t I>
358 type_at_index_t<I, Ts...>& get_ref()
359 {
360 static_assert(I < sizeof...(Ts), "Index out of range");
361 ETL_ASSERT(_index == I, ETL_ERROR_GENERIC("mini_variant: bad index"));
362 using T = type_at_index_t<I, Ts...>;
363 return *reinterpret_cast<T*>(&_storage);
364 }
365
366 template <size_t I>
367 const type_at_index_t<I, Ts...>& get_ref() const
368 {
369 static_assert(I < sizeof...(Ts), "Index out of range");
370 ETL_ASSERT(_index == I, ETL_ERROR_GENERIC("mini_variant: bad index"));
371 using T = type_at_index_t<I, Ts...>;
372 return *reinterpret_cast<const T*>(&_storage);
373 }
374
375 template <bool B = all_equality_comparable<Ts...>::value, etl::enable_if_t<B, int> = 0>
376 friend bool operator==(const mini_variant& lhs, const mini_variant& rhs)
377 {
378 if (lhs._index != rhs._index)
379 {
380 return false;
381 }
382 if (lhs._index == mini_variant_npos)
383 {
384 return true;
385 }
386 return equal_table()[lhs._index](&lhs._storage, &rhs._storage);
387 }
388
389 template <bool B = all_equality_comparable<Ts...>::value, etl::enable_if_t<B, int> = 0>
390 friend bool operator!=(const mini_variant& lhs, const mini_variant& rhs)
391 {
392 return !(lhs == rhs);
393 }
394 };
395 } // namespace private_ranges
396
397 } // namespace ranges
398
399 template <size_t I, typename... Ts>
400 typename ranges::private_ranges::type_at_index_t<I, Ts...>& get(ranges::private_ranges::mini_variant<Ts...>& v)
401 {
402 return v.template get_ref<I>();
403 }
404
405 template <size_t I, typename... Ts>
406 const typename ranges::private_ranges::type_at_index_t<I, Ts...>& get(const ranges::private_ranges::mini_variant<Ts...>& v)
407 {
408 return v.template get_ref<I>();
409 }
410
411 template <size_t I, typename... Ts>
412 typename ranges::private_ranges::type_at_index_t<I, Ts...>&& get(ranges::private_ranges::mini_variant<Ts...>&& v)
413 {
414 return etl::move(v.template get_ref<I>());
415 }
416
417 template <size_t I, typename... Ts>
418 const typename ranges::private_ranges::type_at_index_t<I, Ts...>&& get(const ranges::private_ranges::mini_variant<Ts...>&& v)
419 {
420 return etl::move(v.template get_ref<I>());
421 }
422
423} // namespace etl
424
425#endif // ETL_USING_CPP17
426#endif
ETL_CONSTEXPR14 bool operator!=(const etl::bitset< Active_Bits, TElement > &lhs, const etl::bitset< Active_Bits, TElement > &rhs) ETL_NOEXCEPT
Definition bitset_new.h:2529
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
bitset_ext
Definition absolute.h:40
ETL_CONSTEXPR14 bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:1081
integral_constant< bool, false > false_type
integral_constant specialisations
Definition type_traits.h:80
T & get(array< T, Size > &a)
Definition array.h:1161