FastLED 3.10.6
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.

113 {
114 public:
115 using Tag = u8;
116 static constexpr Tag Empty = 0;
117
118 // –– ctors/dtors/assign as before …
119
120 variant() FL_NO_EXCEPT : _tag(Empty) {}
121
122 template <typename T, typename = typename fl::enable_if<
123 contains_type<T, Types...>::value>::type>
124 variant(const T &value) FL_NO_EXCEPT : _tag(Empty) {
125 construct<T>(value);
126 }
127
128 template <typename T, typename = typename fl::enable_if<
129 contains_type<T, Types...>::value>::type>
130 variant(T &&value) FL_NO_EXCEPT : _tag(Empty) {
131 construct<T>(fl::move(value));
132 }
133
134 variant(const variant &other) FL_NO_EXCEPT : _tag(Empty) {
135 if (!other.empty()) {
136 copy_construct_from(other);
137 }
138 }
139
140 variant(variant &&other) FL_NO_EXCEPT : _tag(Empty) {
141 if (!other.empty()) {
142 move_construct_from(other);
143 // After moving, mark other as empty to prevent destructor calls on moved-from objects
144 other._tag = Empty;
145 }
146 }
147
148 ~variant() FL_DTOR_NOEXCEPT { reset(); }
149
150 variant &operator=(const variant &other) FL_NO_EXCEPT {
151 if (this != &other) {
152 reset();
153 if (!other.empty()) {
154 copy_construct_from(other);
155 }
156 }
157 return *this;
158 }
159
160 variant &operator=(variant &&other) FL_NO_EXCEPT {
161 if (this != &other) {
162 reset();
163 if (!other.empty()) {
164 move_construct_from(other);
165 // After moving, mark other as empty to prevent destructor calls on moved-from objects
166 other._tag = Empty;
167 }
168 }
169 return *this;
170 }
171
172 template <typename T, typename = typename fl::enable_if<
173 contains_type<T, Types...>::value>::type>
174 variant &operator=(const T &value) FL_NO_EXCEPT {
175 // Copy first to handle self-referential values (e.g. assigning
176 // from a reference into this variant's own storage)
177 T value_copy(value);
178 reset();
179 construct<T>(fl::move(value_copy));
180 return *this;
181 }
182
183 template <typename T, typename = typename fl::enable_if<
184 contains_type<T, Types...>::value>::type>
185 variant &operator=(T &&value) FL_NO_EXCEPT {
186 reset();
187 construct<T>(fl::move(value));
188 return *this;
189 }
190
191 // –– modifiers, observers, ptr/get, etc. unchanged …
192
193 template <typename T, typename... Args>
194 typename fl::enable_if<contains_type<T, Types...>::value, T &>::type
195 emplace(Args &&...args) FL_NO_EXCEPT {
196 reset();
197 construct<T>(fl::forward<Args>(args)...);
198 return *ptr<T>();
199 }
200
201 void reset() FL_NO_EXCEPT {
202 if (!empty()) {
203 destroy_current();
204 _tag = Empty;
205 }
206 }
207
208 Tag tag() const FL_NO_EXCEPT { return _tag; }
209 bool empty() const FL_NO_EXCEPT { return _tag == Empty; }
210
211 template <typename T> bool is() const FL_NO_EXCEPT {
212 return _tag == type_to_tag<T>();
213 }
214
215 template <typename T> T *ptr() FL_NO_EXCEPT {
216 if (!is<T>()) return nullptr;
217 // Use bit_cast_ptr for safe type-punning on properly aligned storage
218 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
219 return fl::bit_cast_ptr<T>(&_storage[0]);
220 }
221
222 template <typename T> const T *ptr() const FL_NO_EXCEPT {
223 if (!is<T>()) return nullptr;
224 // Use bit_cast_ptr for safe type-punning on properly aligned storage
225 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
226 return fl::bit_cast_ptr<const T>(&_storage[0]);
227 }
228
234 template <typename T> T &get() FL_NO_EXCEPT {
235 // Dereference ptr() directly - will crash with null pointer access if wrong type
236 // This provides fast failure semantics similar to std::variant
237 return *ptr<T>();
238 }
239
245 template <typename T> const T &get() const FL_NO_EXCEPT {
246 // Dereference ptr() directly - will crash with null pointer access if wrong type
247 // This provides fast failure semantics similar to std::variant
248 return *ptr<T>();
249 }
250
251 template <typename T> bool equals(const T &other) const FL_NO_EXCEPT {
252 if (auto p = ptr<T>()) {
253 return *p == other;
254 }
255 return false;
256 }
257
258 // –– visitor using O(1) function‐pointer table
259 template <typename Visitor> void visit(Visitor &visitor) FL_NO_EXCEPT {
260 if (_tag == Empty)
261 return;
262
263 // Fn is "a pointer to function taking (void* storage, Visitor&)"
264 using Fn = void (*)(void *, Visitor &);
265
266 // Build a constexpr array of one thunk per type in Types...
267 // Each thunk casts the storage back to the right T* and calls
268 // visitor.accept
269 static constexpr Fn table[] = {
270 &variant::template visit_fn<Types, Visitor>...};
271
272 // _tag is 1-based, so dispatch in O(1) via one indirect call:
273 // Check bounds to prevent out-of-bounds access
274 size_t index = _tag - 1;
275 if (index < sizeof...(Types)) {
276 table[index](&_storage, visitor);
277 }
278 }
279
280 template <typename Visitor> void visit(Visitor &visitor) const FL_NO_EXCEPT {
281 if (_tag == Empty)
282 return;
283
284 // Fn is "a pointer to function taking (const void* storage, Visitor&)"
285 using Fn = void (*)(const void *, Visitor &);
286
287 // Build a constexpr array of one thunk per type in Types...
288 static constexpr Fn table[] = {
289 &variant::template visit_fn_const<Types, Visitor>...};
290
291 // _tag is 1-based, so dispatch in O(1) via one indirect call:
292 // Check bounds to prevent out-of-bounds access
293 size_t index = _tag - 1;
294 if (index < sizeof...(Types)) {
295 table[index](&_storage, visitor);
296 }
297 }
298
299 private:
300 // –– helper for the visit table
301 template <typename T, typename Visitor>
302 static void visit_fn(void *storage, Visitor &v) FL_NO_EXCEPT {
303 // Use bit_cast_ptr for safe type-punning on properly aligned storage
304 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
305 T* typed_ptr = fl::bit_cast_ptr<T>(storage);
306 v.accept(*typed_ptr);
307 }
308
309 template <typename T, typename Visitor>
310 static void visit_fn_const(const void *storage, Visitor &v) FL_NO_EXCEPT {
311 // Use bit_cast_ptr for safe type-punning on properly aligned storage
312 // The storage is guaranteed to be properly aligned by alignas(max_align<Types...>::value)
313 const T* typed_ptr = fl::bit_cast_ptr<const T>(storage);
314 v.accept(*typed_ptr);
315 }
316
317 // –– destroy via table -- dispatches through fl::detail::pick_variant_destroy_fn,
318 // which collapses trivially-copyable T's to the shared `variant_noop_destroy`
319 // (one symbol across every variant<...> in the link). See #3249 header.
320 void destroy_current() FL_NO_EXCEPT {
323 static constexpr detail::variant_destroy_fn table[] = {
325 };
326 if (_tag != Empty) {
327 table[_tag - 1](&_storage);
328 }
330 }
331
332 // –– copy‐construct via table -- collapses trivially-copyable T's to the
333 // shared per-size `variant_trivial_copy_n<sizeof(T)>` thunk. See #3249.
334 void copy_construct_from(const variant &other) FL_NO_EXCEPT {
337 static constexpr detail::variant_copy_fn table[] = {
339 };
340 table[other._tag - 1](&_storage, &other._storage[0]);
342 _tag = other._tag;
343 }
344
345 // –– move‐construct via table -- collapses trivially-copyable T's to the
346 // shared per-size `variant_trivial_move_n<sizeof(T)>` thunk. See #3249.
347 void move_construct_from(variant &other) FL_NO_EXCEPT {
350 static constexpr detail::variant_move_fn table[] = {
352 };
353 table[other._tag - 1](&_storage, &other._storage[0]);
355 _tag = other._tag;
356 other.reset();
357 }
358
359 // –– everything below here (type_traits, construct<T>, type_to_tag,
360 // storage)
361 // stays exactly as you wrote it:
362
363 // … max_size, max_align, contains_type, type_to_tag_impl, etc. …
364
365 // Helper to map a type to its tag value
366 template <typename T> static constexpr Tag type_to_tag() FL_NO_EXCEPT {
367 return type_to_tag_impl<T, Types...>::value;
368 }
369
370 // Implementation details for type_to_tag
371 template <typename T, typename... Ts> struct type_to_tag_impl;
372
373 template <typename T> struct type_to_tag_impl<T> {
374 static constexpr Tag value = 0; // Not found
375 };
376
377 template <typename T, typename U, typename... Rest>
378 struct type_to_tag_impl<T, U, Rest...> {
379 static constexpr Tag value =
381 ? 1
382 : (type_to_tag_impl<T, Rest...>::value == 0
383 ? 0
384 : type_to_tag_impl<T, Rest...>::value + 1);
385 };
386
387 template <typename T, typename... Args> void construct(Args &&...args) FL_NO_EXCEPT {
388 new (&_storage) T(fl::forward<Args>(args)...);
389 _tag = type_to_tag<T>();
390 }
391
393
394 Tag _tag;
395};
A fixed-size array implementation similar to std::array.
Definition array.h:27
#define FL_DISABLE_WARNING(warning)
#define FL_DISABLE_WARNING_PUSH
#define FL_DISABLE_WARNING_POP
void(*)(void *) variant_destroy_fn
Definition variant.h:48
constexpr variant_destroy_fn pick_variant_destroy_fn() FL_NO_EXCEPT
Definition variant.h:89
constexpr variant_copy_fn pick_variant_copy_fn() FL_NO_EXCEPT
Definition variant.h:96
void(*)(void *, void *) variant_move_fn
Definition variant.h:50
constexpr variant_move_fn pick_variant_move_fn() FL_NO_EXCEPT
Definition variant.h:103
void(*)(void *, const void *) variant_copy_fn
Definition variant.h:49
unsigned char u8
Definition stdint.h:131
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
Definition move.h:28
constexpr int type_rank< T >::value
constexpr T && forward(typename remove_reference< T >::type &t) FL_NO_EXCEPT
InputGamut g FL_NO_EXCEPT
Definition rgbw.h:121
pair_element< I, T1, T2 >::type & get(pair< T1, T2 > &p) FL_NO_EXCEPT
Definition pair.h:115
To * bit_cast_ptr(void *storage) FL_NO_EXCEPT
Definition bit_cast.h:60
corkscrew_args args
Definition old.h:149
#define FL_ALIGN_AS_T(expr)
#define FL_DTOR_NOEXCEPT
#define FL_NO_EXCEPT

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

+ Here is the caller graph for this function: