FastLED 3.9.15
Loading...
Searching...
No Matches
variant.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/inplacenew.h" // for fl::move, fl::forward, in‐place new
4#include "fl/type_traits.h" // for fl::enable_if, fl::is_same, etc.
5
6namespace fl {
7
8// A variant that can hold any of N different types
9template <typename... Types> class Variant {
10 public:
11 using Tag = uint8_t;
12 static constexpr Tag Empty = 0;
13
14 // –– ctors/dtors/assign as before …
15
16 Variant() noexcept : _tag(Empty) {}
17
18 template <typename T, typename = typename fl::enable_if<
19 contains_type<T, Types...>::value>::type>
20 Variant(const T &value) : _tag(Empty) {
21 construct<T>(value);
22 }
23
24 template <typename T, typename = typename fl::enable_if<
25 contains_type<T, Types...>::value>::type>
26 Variant(T &&value) : _tag(Empty) {
27 construct<T>(fl::move(value));
28 }
29
30 Variant(const Variant &other) : _tag(Empty) {
31 if (!other.empty()) {
32 copy_construct_from(other);
33 }
34 }
35
36 Variant(Variant &&other) noexcept : _tag(Empty) {
37 if (!other.empty()) {
39 other.reset();
40 }
41 }
42
43 ~Variant() { reset(); }
44
45 Variant &operator=(const Variant &other) {
46 if (this != &other) {
47 reset();
48 if (!other.empty()) {
50 }
51 }
52 return *this;
53 }
54
55 Variant &operator=(Variant &&other) noexcept {
56 if (this != &other) {
57 reset();
58 if (!other.empty()) {
60 other.reset();
61 }
62 }
63 return *this;
64 }
65
66 template <typename T, typename = typename fl::enable_if<
67 contains_type<T, Types...>::value>::type>
68 Variant &operator=(const T &value) {
69 reset();
70 construct<T>(value);
71 return *this;
72 }
73
74 template <typename T, typename = typename fl::enable_if<
75 contains_type<T, Types...>::value>::type>
76 Variant &operator=(T &&value) {
77 reset();
78 construct<T>(fl::move(value));
79 return *this;
80 }
81
82 // –– modifiers, observers, ptr/get, etc. unchanged …
83
84 template <typename T, typename... Args>
85 typename fl::enable_if<contains_type<T, Types...>::value, T &>::type
86 emplace(Args &&...args) {
87 reset();
89 return ptr<T>();
90 }
91
92 void reset() noexcept {
93 if (!empty()) {
95 _tag = Empty;
96 }
97 }
98
99 Tag tag() const noexcept { return _tag; }
100 bool empty() const noexcept { return _tag == Empty; }
101
102 template <typename T> bool is() const noexcept {
103 return _tag == type_to_tag<T>();
104 }
105
106 template <typename T> T *ptr() {
107 return is<T>() ? reinterpret_cast<T *>(&_storage) : nullptr;
108 }
109
110 template <typename T> const T *ptr() const {
111 return is<T>() ? reinterpret_cast<const T *>(&_storage) : nullptr;
112 }
113
114 // template <typename T> T &get() {
115 // if (auto p = ptr<T>())
116 // return *p;
117 // static T dummy;
118 // return dummy;
119 // }
120
121 // template <typename T> const T &get() const {
122 // if (auto p = ptr<T>())
123 // return *p;
124 // static const T dummy{};
125 // return dummy;
126 // }
127
128 template <typename T> bool equals(const T &other) const {
129 if (auto p = ptr<T>()) {
130 return *p == other;
131 }
132 return false;
133 }
134
135 // –– visitor using O(1) function‐pointer table
136 template <typename Visitor> void visit(Visitor &visitor) {
137 if (_tag == Empty)
138 return;
139
140 // Fn is "a pointer to function taking (void* storage, Visitor&)"
141 using Fn = void (*)(void *, Visitor &);
142
143 // Build a constexpr array of one thunk per type in Types...
144 // Each thunk casts the storage back to the right T* and calls
145 // visitor.accept
146 static constexpr Fn table[] = {
147 &Variant::template visit_fn<Types, Visitor>...};
148
149 // _tag is 1-based, so dispatch in O(1) via one indirect call:
150 table[_tag - 1](&_storage, visitor);
151 }
152
153 template <typename Visitor> void visit(Visitor &visitor) const {
154 if (_tag == Empty)
155 return;
156
157 // Fn is "a pointer to function taking (const void* storage, Visitor&)"
158 using Fn = void (*)(const void *, Visitor &);
159
160 // Build a constexpr array of one thunk per type in Types...
161 static constexpr Fn table[] = {
162 &Variant::template visit_fn_const<Types, Visitor>...};
163
164 // _tag is 1-based, so dispatch in O(1) via one indirect call:
165 table[_tag - 1](&_storage, visitor);
166 }
167
168 private:
169 // –– helper for the visit table
170 template <typename T, typename Visitor>
171 static void visit_fn(void *storage, Visitor &v) {
172 // unsafe_cast is OK here because we know _tag matched T
173 v.accept(*reinterpret_cast<T *>(storage));
174 }
175
176 template <typename T, typename Visitor>
177 static void visit_fn_const(const void *storage, Visitor &v) {
178 // unsafe_cast is OK here because we know _tag matched T
179 v.accept(*reinterpret_cast<const T *>(storage));
180 }
181
182 // –– destroy via table
183 void destroy_current() noexcept {
184 using Fn = void (*)(void *);
185 static constexpr Fn table[] = {&Variant::template destroy_fn<Types>...};
186 if (_tag != Empty) {
187 table[_tag - 1](&_storage);
188 }
189 }
190
191 template <typename T> static void destroy_fn(void *storage) {
192 reinterpret_cast<T *>(storage)->~T();
193 }
194
195 // –– copy‐construct via table
196 void copy_construct_from(const Variant &other) {
197 using Fn = void (*)(void *, const Variant &);
198 static constexpr Fn table[] = {&Variant::template copy_fn<Types>...};
199 table[other._tag - 1](&_storage, other);
200 _tag = other._tag;
201 }
202
203 template <typename T>
204 static void copy_fn(void *storage, const Variant &other) {
205 new (storage) T(*reinterpret_cast<const T *>(&other._storage));
206 }
207
208 // –– move‐construct via table
209 void move_construct_from(Variant &other) noexcept {
210 using Fn = void (*)(void *, Variant &);
211 static constexpr Fn table[] = {&Variant::template move_fn<Types>...};
212 table[other._tag - 1](&_storage, other);
213 _tag = other._tag;
214 other.reset();
215 }
216
217 template <typename T> static void move_fn(void *storage, Variant &other) {
218 new (storage) T(fl::move(*reinterpret_cast<T *>(&other._storage)));
219 }
220
221 // –– everything below here (type_traits, construct<T>, type_to_tag,
222 // storage)
223 // stays exactly as you wrote it:
224
225 // … max_size, max_align, contains_type, type_to_tag_impl, etc. …
226
227 // Helper to map a type to its tag value
228 template <typename T> static constexpr Tag type_to_tag() {
229 return type_to_tag_impl<T, Types...>::value;
230 }
231
232 // Implementation details for type_to_tag
233 template <typename T, typename... Ts> struct type_to_tag_impl;
234
235 template <typename T> struct type_to_tag_impl<T> {
236 static constexpr Tag value = 0; // Not found
237 };
238
239 template <typename T, typename U, typename... Rest>
240 struct type_to_tag_impl<T, U, Rest...> {
241 static constexpr Tag value =
243 ? 1
244 : (type_to_tag_impl<T, Rest...>::value == 0
245 ? 0
246 : type_to_tag_impl<T, Rest...>::value + 1);
247 };
248
249 template <typename T, typename... Args> void construct(Args &&...args) {
250 new (&_storage) T(fl::forward<Args>(args)...);
252 }
253
254 alignas(
256
258};
259
260} // namespace fl
Variant & operator=(Variant &&other) noexcept
Definition variant.h:55
Variant(const T &value)
Definition variant.h:20
Variant & operator=(const T &value)
Definition variant.h:68
const T * ptr() const
Definition variant.h:110
Variant & operator=(const Variant &other)
Definition variant.h:45
Tag tag() const noexcept
Definition variant.h:99
void construct(Args &&...args)
Definition variant.h:249
bool is() const noexcept
Definition variant.h:102
Variant() noexcept
Definition variant.h:16
Variant(const Variant &other)
Definition variant.h:30
T * ptr()
Definition variant.h:106
void reset() noexcept
Definition variant.h:92
static constexpr Tag type_to_tag()
Definition variant.h:228
fl::enable_if< contains_type< T, Types... >::value, T & >::type emplace(Args &&...args)
Definition variant.h:86
Variant(T &&value)
Definition variant.h:26
void destroy_current() noexcept
Definition variant.h:183
void visit(Visitor &visitor) const
Definition variant.h:153
Variant & operator=(T &&value)
Definition variant.h:76
void visit(Visitor &visitor)
Definition variant.h:136
bool empty() const noexcept
Definition variant.h:100
void copy_construct_from(const Variant &other)
Definition variant.h:196
bool equals(const T &other) const
Definition variant.h:128
Variant(Variant &&other) noexcept
Definition variant.h:36
void move_construct_from(Variant &other) noexcept
Definition variant.h:209
constexpr remove_reference< T >::type && move(T &&t) noexcept
constexpr T && forward(typename remove_reference< T >::type &t) noexcept
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16
static FASTLED_NAMESPACE_BEGIN uint8_t const p[]
Definition noise.cpp:30
static constexpr Tag value
Definition variant.h:236
static constexpr bool value
Definition type_traits.h:54