FastLED 3.9.15
Loading...
Searching...
No Matches

◆ FL_ALIGN_AS_T()

template<typename... Types>
class fl::FL_ALIGN_AS_T ( max_align< Types... >::value )

Get a reference to the stored value of type T

Template Parameters
TThe type to retrieve
Returns
Reference to the stored value
Note
Asserts if the variant doesn't contain type T. Use is<T>() to check first.
Warning
Will crash if called with wrong type - this is intentional for fast failure

Get a const reference to the stored value of type T

Template Parameters
TThe type to retrieve
Returns
Const reference to the stored value
Note
Asserts if the variant doesn't contain type T. Use is<T>() to check first.
Warning
Will crash if called with wrong type - this is intentional for fast failure

Definition at line 1 of file variant.h.

17 {
18 public:
19 using Tag = u8;
20 static constexpr Tag Empty = 0;
21
22 // –– ctors/dtors/assign as before …
23
24 variant() FL_NOEXCEPT : _tag(Empty) {}
25
26 template <typename T, typename = typename fl::enable_if<
27 contains_type<T, Types...>::value>::type>
28 variant(const T &value) FL_NOEXCEPT : _tag(Empty) {
29 construct<T>(value);
30 }
31
32 template <typename T, typename = typename fl::enable_if<
33 contains_type<T, Types...>::value>::type>
34 variant(T &&value) FL_NOEXCEPT : _tag(Empty) {
35 construct<T>(fl::move(value));
36 }
37
38 variant(const variant &other) FL_NOEXCEPT : _tag(Empty) {
39 if (!other.empty()) {
40 copy_construct_from(other);
41 }
42 }
43
44 variant(variant &&other) FL_NOEXCEPT : _tag(Empty) {
45 if (!other.empty()) {
46 move_construct_from(other);
47 // After moving, mark other as empty to prevent destructor calls on moved-from objects
48 other._tag = Empty;
49 }
50 }
51
52 ~variant() FL_NOEXCEPT { reset(); }
53
54 variant &operator=(const variant &other) FL_NOEXCEPT {
55 if (this != &other) {
56 reset();
57 if (!other.empty()) {
58 copy_construct_from(other);
59 }
60 }
61 return *this;
62 }
63
64 variant &operator=(variant &&other) FL_NOEXCEPT {
65 if (this != &other) {
66 reset();
67 if (!other.empty()) {
68 move_construct_from(other);
69 // After moving, mark other as empty to prevent destructor calls on moved-from objects
70 other._tag = Empty;
71 }
72 }
73 return *this;
74 }
75
76 template <typename T, typename = typename fl::enable_if<
77 contains_type<T, Types...>::value>::type>
78 variant &operator=(const T &value) FL_NOEXCEPT {
79 // Copy first to handle self-referential values (e.g. assigning
80 // from a reference into this variant's own storage)
81 T value_copy(value);
82 reset();
83 construct<T>(fl::move(value_copy));
84 return *this;
85 }
86
87 template <typename T, typename = typename fl::enable_if<
88 contains_type<T, Types...>::value>::type>
89 variant &operator=(T &&value) FL_NOEXCEPT {
90 reset();
91 construct<T>(fl::move(value));
92 return *this;
93 }
94
95 // –– modifiers, observers, ptr/get, etc. unchanged …
96
97 template <typename T, typename... Args>
98 typename fl::enable_if<contains_type<T, Types...>::value, T &>::type
99 emplace(Args &&...args) FL_NOEXCEPT {
100 reset();
101 construct<T>(fl::forward<Args>(args)...);
102 return *ptr<T>();
103 }
104
105 void reset() FL_NOEXCEPT {
106 if (!empty()) {
107 destroy_current();
108 _tag = Empty;
109 }
110 }
111
112 Tag tag() const FL_NOEXCEPT { return _tag; }
113 bool empty() const FL_NOEXCEPT { return _tag == Empty; }
114
115 template <typename T> bool is() const FL_NOEXCEPT {
116 return _tag == type_to_tag<T>();
117 }
118
119 template <typename T> T *ptr() FL_NOEXCEPT {
120 if (!is<T>()) return nullptr;
121 // Use bit_cast_ptr for safe type-punning on properly aligned storage
122 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
123 return fl::bit_cast_ptr<T>(&_storage[0]);
124 }
125
126 template <typename T> const T *ptr() const FL_NOEXCEPT {
127 if (!is<T>()) return nullptr;
128 // Use bit_cast_ptr for safe type-punning on properly aligned storage
129 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
130 return fl::bit_cast_ptr<const T>(&_storage[0]);
131 }
132
138 template <typename T> T &get() FL_NOEXCEPT {
139 // Dereference ptr() directly - will crash with null pointer access if wrong type
140 // This provides fast failure semantics similar to std::variant
141 return *ptr<T>();
142 }
143
149 template <typename T> const T &get() const FL_NOEXCEPT {
150 // Dereference ptr() directly - will crash with null pointer access if wrong type
151 // This provides fast failure semantics similar to std::variant
152 return *ptr<T>();
153 }
154
155 template <typename T> bool equals(const T &other) const FL_NOEXCEPT {
156 if (auto p = ptr<T>()) {
157 return *p == other;
158 }
159 return false;
160 }
161
162 // –– visitor using O(1) function‐pointer table
163 template <typename Visitor> void visit(Visitor &visitor) FL_NOEXCEPT {
164 if (_tag == Empty)
165 return;
166
167 // Fn is "a pointer to function taking (void* storage, Visitor&)"
168 using Fn = void (*)(void *, Visitor &);
169
170 // Build a constexpr array of one thunk per type in Types...
171 // Each thunk casts the storage back to the right T* and calls
172 // visitor.accept
173 static constexpr Fn table[] = {
174 &variant::template visit_fn<Types, Visitor>...};
175
176 // _tag is 1-based, so dispatch in O(1) via one indirect call:
177 // Check bounds to prevent out-of-bounds access
178 size_t index = _tag - 1;
179 if (index < sizeof...(Types)) {
180 table[index](&_storage, visitor);
181 }
182 }
183
184 template <typename Visitor> void visit(Visitor &visitor) const FL_NOEXCEPT {
185 if (_tag == Empty)
186 return;
187
188 // Fn is "a pointer to function taking (const void* storage, Visitor&)"
189 using Fn = void (*)(const void *, Visitor &);
190
191 // Build a constexpr array of one thunk per type in Types...
192 static constexpr Fn table[] = {
193 &variant::template visit_fn_const<Types, Visitor>...};
194
195 // _tag is 1-based, so dispatch in O(1) via one indirect call:
196 // Check bounds to prevent out-of-bounds access
197 size_t index = _tag - 1;
198 if (index < sizeof...(Types)) {
199 table[index](&_storage, visitor);
200 }
201 }
202
203 private:
204 // –– helper for the visit table
205 template <typename T, typename Visitor>
206 static void visit_fn(void *storage, Visitor &v) FL_NOEXCEPT {
207 // Use bit_cast_ptr for safe type-punning on properly aligned storage
208 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
209 T* typed_ptr = fl::bit_cast_ptr<T>(storage);
210 v.accept(*typed_ptr);
211 }
212
213 template <typename T, typename Visitor>
214 static void visit_fn_const(const void *storage, Visitor &v) FL_NOEXCEPT {
215 // Use bit_cast_ptr for safe type-punning on properly aligned storage
216 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
217 const T* typed_ptr = fl::bit_cast_ptr<const T>(storage);
218 v.accept(*typed_ptr);
219 }
220
221 // –– destroy via table
222 void destroy_current() FL_NOEXCEPT {
223 using Fn = void (*)(void *);
226 static constexpr Fn table[] = {&variant::template destroy_fn<Types>...};
227 if (_tag != Empty) {
228 table[_tag - 1](&_storage);
229 }
231 }
232
233 template <typename T> static void destroy_fn(void *storage) FL_NOEXCEPT {
234 // Use bit_cast_ptr for safe type-punning on properly aligned storage
235 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
236 T* typed_ptr = fl::bit_cast_ptr<T>(storage);
237 typed_ptr->~T();
238 }
239
240 // –– copy‐construct via table
241 void copy_construct_from(const variant &other) FL_NOEXCEPT {
242 using Fn = void (*)(void *, const variant &);
245 static constexpr Fn table[] = {&variant::template copy_fn<Types>...};
246 table[other._tag - 1](&_storage, other);
248 _tag = other._tag;
249 }
250
251 template <typename T>
252 static void copy_fn(void *storage, const variant &other) FL_NOEXCEPT {
253 // Use bit_cast_ptr for safe type-punning on properly aligned storage
254 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
255 const T* source_ptr = fl::bit_cast_ptr<const T>(&other._storage[0]);
256 new (storage) T(*source_ptr);
257 }
258
259 // –– move‐construct via table
260 void move_construct_from(variant &other) FL_NOEXCEPT {
261 using Fn = void (*)(void *, variant &);
264 static constexpr Fn table[] = {&variant::template move_fn<Types>...};
265 table[other._tag - 1](&_storage, other);
267 _tag = other._tag;
268 other.reset();
269 }
270
271 template <typename T> static void move_fn(void *storage, variant &other) FL_NOEXCEPT {
272 // Use bit_cast_ptr for safe type-punning on properly aligned storage
273 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
274 T* source_ptr = fl::bit_cast_ptr<T>(&other._storage[0]);
275 new (storage) T(fl::move(*source_ptr));
276 }
277
278 // –– everything below here (type_traits, construct<T>, type_to_tag,
279 // storage)
280 // stays exactly as you wrote it:
281
282 // … max_size, max_align, contains_type, type_to_tag_impl, etc. …
283
284 // Helper to map a type to its tag value
285 template <typename T> static constexpr Tag type_to_tag() FL_NOEXCEPT {
286 return type_to_tag_impl<T, Types...>::value;
287 }
288
289 // Implementation details for type_to_tag
290 template <typename T, typename... Ts> struct type_to_tag_impl;
291
292 template <typename T> struct type_to_tag_impl<T> {
293 static constexpr Tag value = 0; // Not found
294 };
295
296 template <typename T, typename U, typename... Rest>
297 struct type_to_tag_impl<T, U, Rest...> {
298 static constexpr Tag value =
300 ? 1
301 : (type_to_tag_impl<T, Rest...>::value == 0
302 ? 0
303 : type_to_tag_impl<T, Rest...>::value + 1);
304 };
305
306 template <typename T, typename... Args> void construct(Args &&...args) FL_NOEXCEPT {
307 new (&_storage) T(fl::forward<Args>(args)...);
308 _tag = type_to_tag<T>();
309 }
310
312
313 Tag _tag;
314};
A fixed-size array implementation similar to std::array.
Definition array.h:27
constexpr T && forward(typename remove_reference< T >::type &t) FL_NOEXCEPT
Definition s16x16x4.h:234
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
unsigned char u8
Definition stdint.h:131
constexpr int type_rank< T >::value
To * bit_cast_ptr(void *storage) FL_NOEXCEPT
Definition bit_cast.h:60
pair_element< I, T1, T2 >::type & get(pair< T1, T2 > &p) FL_NOEXCEPT
Definition pair.h:115
corkscrew_args args
Definition old.h:149
#define FL_ALIGN_AS_T(expr)
#define FL_DISABLE_WARNING(warning)
#define FL_DISABLE_WARNING_PUSH
#define FL_DISABLE_WARNING_POP
#define FL_NOEXCEPT

References args, bit_cast_ptr(), FL_ALIGN_AS_T(), FL_ALIGN_AS_T, FL_DISABLE_WARNING, FL_DISABLE_WARNING_POP, FL_DISABLE_WARNING_PUSH, FL_NOEXCEPT, fl::fl::forward(), get(), fl::fl::move(), type_rank< T >::value, and fl::fl::is_same< T, U >::value.

Referenced by FL_ALIGN_AS_T(), fl::Singleton< AutoResearchRemoteControl >::instance(), fl::SingletonThreadLocal< T, N >::instance(), and fl::SingletonShared< T, N >::instanceInner().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: