1 | // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors |
2 | // Licensed under the MIT License: |
3 | // |
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | // of this software and associated documentation files (the "Software"), to deal |
6 | // in the Software without restriction, including without limitation the rights |
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
8 | // copies of the Software, and to permit persons to whom the Software is |
9 | // furnished to do so, subject to the following conditions: |
10 | // |
11 | // The above copyright notice and this permission notice shall be included in |
12 | // all copies or substantial portions of the Software. |
13 | // |
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
20 | // THE SOFTWARE. |
21 | |
22 | #pragma once |
23 | |
24 | #if defined(__GNUC__) && !KJ_HEADER_WARNINGS |
25 | #pragma GCC system_header |
26 | #endif |
27 | |
28 | #include "common.h" |
29 | |
30 | namespace kj { |
31 | |
32 | namespace _ { // private |
33 | |
34 | template <uint i, typename Key, typename First, typename... Rest> |
35 | struct TypeIndex_ { static constexpr uint value = TypeIndex_<i + 1, Key, Rest...>::value; }; |
36 | template <uint i, typename Key, typename... Rest> |
37 | struct TypeIndex_<i, Key, Key, Rest...> { static constexpr uint value = i; }; |
38 | |
39 | enum class Variants0 {}; |
40 | enum class Variants1 { _variant0 }; |
41 | enum class Variants2 { _variant0, _variant1 }; |
42 | enum class Variants3 { _variant0, _variant1, _variant2 }; |
43 | enum class Variants4 { _variant0, _variant1, _variant2, _variant3 }; |
44 | enum class Variants5 { _variant0, _variant1, _variant2, _variant3, _variant4 }; |
45 | enum class Variants6 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5 }; |
46 | enum class Variants7 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6 }; |
47 | enum class Variants8 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6, |
48 | _variant7 }; |
49 | |
50 | template <uint i> struct Variants_; |
51 | template <> struct Variants_<0> { typedef Variants0 Type; }; |
52 | template <> struct Variants_<1> { typedef Variants1 Type; }; |
53 | template <> struct Variants_<2> { typedef Variants2 Type; }; |
54 | template <> struct Variants_<3> { typedef Variants3 Type; }; |
55 | template <> struct Variants_<4> { typedef Variants4 Type; }; |
56 | template <> struct Variants_<5> { typedef Variants5 Type; }; |
57 | template <> struct Variants_<6> { typedef Variants6 Type; }; |
58 | template <> struct Variants_<7> { typedef Variants7 Type; }; |
59 | template <> struct Variants_<8> { typedef Variants8 Type; }; |
60 | |
61 | template <uint i> |
62 | using Variants = typename Variants_<i>::Type; |
63 | |
64 | } // namespace _ (private) |
65 | |
66 | template <typename... Variants> |
67 | class OneOf { |
68 | template <typename Key> |
69 | static inline constexpr uint typeIndex() { return _::TypeIndex_<1, Key, Variants...>::value; } |
70 | // Get the 1-based index of Key within the type list Types. |
71 | |
72 | public: |
73 | inline OneOf(): tag(0) {} |
74 | OneOf(const OneOf& other) { copyFrom(other); } |
75 | OneOf(OneOf& other) { copyFrom(other); } |
76 | OneOf(OneOf&& other) { moveFrom(other); } |
77 | template <typename T> |
78 | OneOf(T&& other): tag(typeIndex<Decay<T>>()) { |
79 | ctor(*reinterpret_cast<Decay<T>*>(space), kj::fwd<T>(other)); |
80 | } |
81 | ~OneOf() { destroy(); } |
82 | |
83 | OneOf& operator=(const OneOf& other) { if (tag != 0) destroy(); copyFrom(other); return *this; } |
84 | OneOf& operator=(OneOf&& other) { if (tag != 0) destroy(); moveFrom(other); return *this; } |
85 | |
86 | inline bool operator==(decltype(nullptr)) const { return tag == 0; } |
87 | inline bool operator!=(decltype(nullptr)) const { return tag != 0; } |
88 | |
89 | template <typename T> |
90 | bool is() const { |
91 | return tag == typeIndex<T>(); |
92 | } |
93 | |
94 | template <typename T> |
95 | T& get() { |
96 | KJ_IREQUIRE(is<T>(), "Must check OneOf::is<T>() before calling get<T>()." ); |
97 | return *reinterpret_cast<T*>(space); |
98 | } |
99 | template <typename T> |
100 | const T& get() const { |
101 | KJ_IREQUIRE(is<T>(), "Must check OneOf::is<T>() before calling get<T>()." ); |
102 | return *reinterpret_cast<const T*>(space); |
103 | } |
104 | |
105 | template <typename T, typename... Params> |
106 | T& init(Params&&... params) { |
107 | if (tag != 0) destroy(); |
108 | ctor(*reinterpret_cast<T*>(space), kj::fwd<Params>(params)...); |
109 | tag = typeIndex<T>(); |
110 | return *reinterpret_cast<T*>(space); |
111 | } |
112 | |
113 | template <typename T> |
114 | Maybe<T&> tryGet() { |
115 | if (is<T>()) { |
116 | return *reinterpret_cast<T*>(space); |
117 | } else { |
118 | return nullptr; |
119 | } |
120 | } |
121 | |
122 | template <uint i> |
123 | KJ_NORETURN(void allHandled()); |
124 | // After a series of if/else blocks handling each variant of the OneOf, have the final else |
125 | // block call allHandled<n>() where n is the number of variants. This will fail to compile |
126 | // if new variants are added in the future. |
127 | |
128 | typedef _::Variants<sizeof...(Variants)> Tag; |
129 | |
130 | Tag which() const { |
131 | KJ_IREQUIRE(tag != 0, "Can't KJ_SWITCH_ONEOF() on uninitialized value." ); |
132 | return static_cast<Tag>(tag - 1); |
133 | } |
134 | |
135 | template <typename T> |
136 | static constexpr Tag tagFor() { |
137 | return static_cast<Tag>(typeIndex<T>() - 1); |
138 | } |
139 | |
140 | OneOf* _switchSubject() & { return this; } |
141 | const OneOf* _switchSubject() const& { return this; } |
142 | _::NullableValue<OneOf> _switchSubject() && { return kj::mv(*this); } |
143 | |
144 | private: |
145 | uint tag; |
146 | |
147 | static inline constexpr size_t maxSize(size_t a) { |
148 | return a; |
149 | } |
150 | template <typename... Rest> |
151 | static inline constexpr size_t maxSize(size_t a, size_t b, Rest... rest) { |
152 | return maxSize(kj::max(a, b), rest...); |
153 | } |
154 | // Returns the maximum of all the parameters. |
155 | // TODO(someday): Generalize the above template and make it common. I tried, but C++ decided to |
156 | // be difficult so I cut my losses. |
157 | |
158 | static constexpr auto spaceSize = maxSize(sizeof(Variants)...); |
159 | // TODO(msvc): This constant could just as well go directly inside space's bracket's, where it's |
160 | // used, but MSVC suffers a parse error on `...`. |
161 | |
162 | union { |
163 | byte space[spaceSize]; |
164 | |
165 | void* forceAligned; |
166 | // TODO(someday): Use C++11 alignas() once we require GCC 4.8 / Clang 3.3. |
167 | }; |
168 | |
169 | template <typename... T> |
170 | inline void doAll(T... t) {} |
171 | |
172 | template <typename T> |
173 | inline bool destroyVariant() { |
174 | if (tag == typeIndex<T>()) { |
175 | tag = 0; |
176 | dtor(*reinterpret_cast<T*>(space)); |
177 | } |
178 | return false; |
179 | } |
180 | void destroy() { |
181 | doAll(destroyVariant<Variants>()...); |
182 | } |
183 | |
184 | template <typename T> |
185 | inline bool copyVariantFrom(const OneOf& other) { |
186 | if (other.is<T>()) { |
187 | ctor(*reinterpret_cast<T*>(space), other.get<T>()); |
188 | } |
189 | return false; |
190 | } |
191 | void copyFrom(const OneOf& other) { |
192 | // Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag |
193 | // is invalid. |
194 | tag = other.tag; |
195 | doAll(copyVariantFrom<Variants>(other)...); |
196 | } |
197 | |
198 | template <typename T> |
199 | inline bool copyVariantFrom(OneOf& other) { |
200 | if (other.is<T>()) { |
201 | ctor(*reinterpret_cast<T*>(space), other.get<T>()); |
202 | } |
203 | return false; |
204 | } |
205 | void copyFrom(OneOf& other) { |
206 | // Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag |
207 | // is invalid. |
208 | tag = other.tag; |
209 | doAll(copyVariantFrom<Variants>(other)...); |
210 | } |
211 | |
212 | template <typename T> |
213 | inline bool moveVariantFrom(OneOf& other) { |
214 | if (other.is<T>()) { |
215 | ctor(*reinterpret_cast<T*>(space), kj::mv(other.get<T>())); |
216 | } |
217 | return false; |
218 | } |
219 | void moveFrom(OneOf& other) { |
220 | // Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag |
221 | // is invalid. |
222 | tag = other.tag; |
223 | doAll(moveVariantFrom<Variants>(other)...); |
224 | } |
225 | }; |
226 | |
227 | template <typename... Variants> |
228 | template <uint i> |
229 | void OneOf<Variants...>::allHandled() { |
230 | // After a series of if/else blocks handling each variant of the OneOf, have the final else |
231 | // block call allHandled<n>() where n is the number of variants. This will fail to compile |
232 | // if new variants are added in the future. |
233 | |
234 | static_assert(i == sizeof...(Variants), "new OneOf variants need to be handled here" ); |
235 | KJ_UNREACHABLE; |
236 | } |
237 | |
238 | #if __cplusplus > 201402L |
239 | #define KJ_SWITCH_ONEOF(value) \ |
240 | switch (auto _kj_switch_subject = (value)._switchSubject(); _kj_switch_subject->which()) |
241 | #else |
242 | #define KJ_SWITCH_ONEOF(value) \ |
243 | /* Without C++17, we can only support one switch per containing block. Deal with it. */ \ |
244 | auto _kj_switch_subject = (value)._switchSubject(); \ |
245 | switch (_kj_switch_subject->which()) |
246 | #endif |
247 | #define KJ_CASE_ONEOF(name, ...) \ |
248 | break; \ |
249 | case ::kj::Decay<decltype(*_kj_switch_subject)>::tagFor<__VA_ARGS__>(): \ |
250 | for (auto& name = _kj_switch_subject->get<__VA_ARGS__>(), *_kj_switch_done = &name; \ |
251 | _kj_switch_done; _kj_switch_done = nullptr) |
252 | #define KJ_CASE_ONEOF_DEFAULT break; default: |
253 | // Allows switching over a OneOf. |
254 | // |
255 | // Example: |
256 | // |
257 | // kj::OneOf<int, float, const char*> variant; |
258 | // KJ_SWITCH_ONEOF(variant) { |
259 | // KJ_CASE_ONEOF(i, int) { |
260 | // doSomethingWithInt(i); |
261 | // } |
262 | // KJ_CASE_ONEOF(s, const char*) { |
263 | // doSomethingWithString(s); |
264 | // } |
265 | // KJ_CASE_ONEOF_DEFAULT { |
266 | // doSomethingElse(); |
267 | // } |
268 | // } |
269 | // |
270 | // Notes: |
271 | // - If you don't handle all possible types and don't include a default branch, you'll get a |
272 | // compiler warning, just like a regular switch() over an enum where one of the enum values is |
273 | // missing. |
274 | // - There's no need for a `break` statement in a KJ_CASE_ONEOF; it is implied. |
275 | // - Under C++11 and C++14, only one KJ_SWITCH_ONEOF() can appear in a block. Wrap the switch in |
276 | // a pair of braces if you need a second switch in the same block. If C++17 is enabled, this is |
277 | // not an issue. |
278 | // |
279 | // Implementation notes: |
280 | // - The use of __VA_ARGS__ is to account for template types that have commas separating type |
281 | // parameters, since macros don't recognize <> as grouping. |
282 | // - _kj_switch_done is really used as a boolean flag to prevent the for() loop from actually |
283 | // looping, but it's defined as a pointer since that's all we can define in this context. |
284 | |
285 | } // namespace kj |
286 | |