Bumping manifests a=b2g-bump
[gecko.git] / mfbt / TypedEnum.h
blobd84cd902572653d2fcf1cdfd9e3a14134a6766fa
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Macros to emulate C++11 typed enums and enum classes. */
9 #ifndef mozilla_TypedEnum_h
10 #define mozilla_TypedEnum_h
12 #include "mozilla/TypedEnumInternal.h"
13 #include "mozilla/MacroArgs.h"
15 #if defined(__cplusplus)
17 /**
18 * MOZ_ENUM_TYPE specifies the underlying numeric type for an enum. It's
19 * specified by placing MOZ_ENUM_TYPE(type) immediately after the enum name in
20 * its declaration, and before the opening curly brace, like
22 * enum MyEnum MOZ_ENUM_TYPE(uint16_t)
23 * {
24 * A,
25 * B = 7,
26 * C
27 * };
29 * In supporting compilers, the macro will expand to ": uint16_t". The
30 * compiler will allocate exactly two bytes for MyEnum and will require all
31 * enumerators to have values between 0 and 65535. (Thus specifying "B =
32 * 100000" instead of "B = 7" would fail to compile.) In old compilers the
33 * macro expands to the empty string, and the underlying type is generally
34 * undefined.
36 #ifdef MOZ_HAVE_CXX11_ENUM_TYPE
37 # define MOZ_ENUM_TYPE(type) : type
38 #else
39 # define MOZ_ENUM_TYPE(type) /* no support */
40 #endif
42 /**
43 * MOZ_BEGIN_ENUM_CLASS and MOZ_END_ENUM_CLASS provide access to the
44 * strongly-typed enumeration feature of C++11 ("enum class"). If supported
45 * by the compiler, an enum defined using these macros will not be implicitly
46 * converted to any other type, and its enumerators will be scoped using the
47 * enumeration name. Place MOZ_BEGIN_ENUM_CLASS(EnumName [, type]) in place of
48 * "enum EnumName {", and MOZ_END_ENUM_CLASS(EnumName) in place of the closing
49 * "};". For example,
51 * MOZ_BEGIN_ENUM_CLASS(Enum, int32_t)
52 * A,
53 * B = 6
54 * MOZ_END_ENUM_CLASS(Enum)
56 * This will make "Enum::A" and "Enum::B" appear in the global scope, but "A"
57 * and "B" will not. In compilers that support C++11 strongly-typed
58 * enumerations, implicit conversions of Enum values to numeric types will
59 * fail. In other compilers, Enum itself will actually be defined as a class,
60 * and some implicit conversions will fail while others will succeed.
62 * The optional type argument specifies the underlying type for the enum where
63 * supported, as with MOZ_ENUM_TYPE(). As with MOZ_ENUM_TYPE(), it will do
64 * nothing on compilers that do not support it.
66 * MOZ_{BEGIN,END}_ENUM_CLASS doesn't work for defining enum classes nested
67 * inside classes. To define an enum class nested inside another class, use
68 * MOZ_{BEGIN,END}_NESTED_ENUM_CLASS, and place a MOZ_FINISH_NESTED_ENUM_CLASS
69 * in namespace scope to handle bits that can only be implemented with
70 * namespace-scoped code. For example:
72 * class FooBar
73 * {
74 * MOZ_BEGIN_NESTED_ENUM_CLASS(Enum, int32_t)
75 * A,
76 * B = 6
77 * MOZ_END_NESTED_ENUM_CLASS(Enum)
78 * };
80 * MOZ_FINISH_NESTED_ENUM_CLASS(FooBar::Enum)
82 #if defined(MOZ_HAVE_CXX11_STRONG_ENUMS)
84 * All compilers that support strong enums also support an explicit
85 * underlying type, so no extra check is needed.
88 /* Single-argument form. */
89 # define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER1(Name) \
90 enum class Name {
91 /* Two-argument form. */
92 # define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \
93 enum class Name : type {
94 # define MOZ_END_NESTED_ENUM_CLASS(Name) \
96 # define MOZ_FINISH_NESTED_ENUM_CLASS(Name) /* nothing */
99 * MOZ_ENUM_CLASS_ENUM_TYPE allows using enum classes
100 * as template parameter types. For that, we need integer types.
101 * In the present case where the compiler supports strong enums,
102 * these are already integer types so there is nothing more to do.
104 # define MOZ_ENUM_CLASS_ENUM_TYPE(Name) Name
106 * See the comment below about MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE.
108 # define MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE(Name) Name
109 #else
111 * We need Name to both name a type, and scope the provided enumerator
112 * names. Namespaces and classes both provide scoping, but namespaces
113 * aren't types, so we need to use a class that wraps the enum values. We
114 * have an implicit conversion from the inner enum type to the class, so
115 * statements like
117 * Enum x = Enum::A;
119 * will still work. We need to define an implicit conversion from the class
120 * to the inner enum as well, so that (for instance) switch statements will
121 * work. This means that the class can be implicitly converted to a numeric
122 * value as well via the enum type, since C++ allows an implicit
123 * user-defined conversion followed by a standard conversion to still be
124 * implicit.
126 * We have an explicit constructor from int defined, so that casts like
127 * (Enum)7 will still work. We also have a zero-argument constructor with
128 * no arguments, so declaration without initialization (like "Enum foo;")
129 * will work.
131 * Additionally, we'll delete as many operators as possible for the inner
132 * enum type, so statements like this will still fail:
134 * f(5 + Enum::B); // deleted operator+
136 * But we can't prevent things like this, because C++ doesn't allow
137 * overriding conversions or assignment operators for enums:
139 * int x = Enum::A;
140 * int f()
142 * return Enum::A;
146 /* Single-argument form. */
147 # define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER1(Name) \
148 class Name \
150 public: \
151 enum Enum \
153 /* Two-argument form. */
154 # define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \
155 class Name \
157 public: \
158 enum Enum MOZ_ENUM_TYPE(type) \
160 # define MOZ_END_NESTED_ENUM_CLASS(Name) \
161 }; \
162 Name() {} \
163 MOZ_CONSTEXPR Name(Enum aEnum) : mEnum(aEnum) {} \
164 template<typename Other> \
165 explicit MOZ_CONSTEXPR Name(Other num) : mEnum((Enum)num) {} \
166 MOZ_CONSTEXPR operator Enum() const { return mEnum; } \
167 explicit MOZ_CONSTEXPR Name(const mozilla::CastableTypedEnumResult<Name>& aOther) \
168 : mEnum(aOther.get()) \
169 {} \
170 private: \
171 Enum mEnum; \
173 # define MOZ_FINISH_NESTED_ENUM_CLASS(Name) \
174 inline int operator+(const int&, const Name::Enum&) MOZ_DELETE; \
175 inline int operator+(const Name::Enum&, const int&) MOZ_DELETE; \
176 inline int operator-(const int&, const Name::Enum&) MOZ_DELETE; \
177 inline int operator-(const Name::Enum&, const int&) MOZ_DELETE; \
178 inline int operator*(const int&, const Name::Enum&) MOZ_DELETE; \
179 inline int operator*(const Name::Enum&, const int&) MOZ_DELETE; \
180 inline int operator/(const int&, const Name::Enum&) MOZ_DELETE; \
181 inline int operator/(const Name::Enum&, const int&) MOZ_DELETE; \
182 inline int operator%(const int&, const Name::Enum&) MOZ_DELETE; \
183 inline int operator%(const Name::Enum&, const int&) MOZ_DELETE; \
184 inline int operator+(const Name::Enum&) MOZ_DELETE; \
185 inline int operator-(const Name::Enum&) MOZ_DELETE; \
186 inline int& operator++(Name::Enum&) MOZ_DELETE; \
187 inline int operator++(Name::Enum&, int) MOZ_DELETE; \
188 inline int& operator--(Name::Enum&) MOZ_DELETE; \
189 inline int operator--(Name::Enum&, int) MOZ_DELETE; \
190 inline bool operator==(const int&, const Name::Enum&) MOZ_DELETE; \
191 inline bool operator==(const Name::Enum&, const int&) MOZ_DELETE; \
192 inline bool operator!=(const int&, const Name::Enum&) MOZ_DELETE; \
193 inline bool operator!=(const Name::Enum&, const int&) MOZ_DELETE; \
194 inline bool operator>(const int&, const Name::Enum&) MOZ_DELETE; \
195 inline bool operator>(const Name::Enum&, const int&) MOZ_DELETE; \
196 inline bool operator<(const int&, const Name::Enum&) MOZ_DELETE; \
197 inline bool operator<(const Name::Enum&, const int&) MOZ_DELETE; \
198 inline bool operator>=(const int&, const Name::Enum&) MOZ_DELETE; \
199 inline bool operator>=(const Name::Enum&, const int&) MOZ_DELETE; \
200 inline bool operator<=(const int&, const Name::Enum&) MOZ_DELETE; \
201 inline bool operator<=(const Name::Enum&, const int&) MOZ_DELETE; \
202 inline bool operator!(const Name::Enum&) MOZ_DELETE; \
203 inline bool operator&&(const bool&, const Name::Enum&) MOZ_DELETE; \
204 inline bool operator&&(const Name::Enum&, const bool&) MOZ_DELETE; \
205 inline bool operator||(const bool&, const Name::Enum&) MOZ_DELETE; \
206 inline bool operator||(const Name::Enum&, const bool&) MOZ_DELETE; \
207 inline int operator&(const int&, const Name::Enum&) MOZ_DELETE; \
208 inline int operator&(const Name::Enum&, const int&) MOZ_DELETE; \
209 inline int operator|(const int&, const Name::Enum&) MOZ_DELETE; \
210 inline int operator|(const Name::Enum&, const int&) MOZ_DELETE; \
211 inline int operator^(const int&, const Name::Enum&) MOZ_DELETE; \
212 inline int operator^(const Name::Enum&, const int&) MOZ_DELETE; \
213 inline int operator<<(const int&, const Name::Enum&) MOZ_DELETE; \
214 inline int operator<<(const Name::Enum&, const int&) MOZ_DELETE; \
215 inline int operator>>(const int&, const Name::Enum&) MOZ_DELETE; \
216 inline int operator>>(const Name::Enum&, const int&) MOZ_DELETE; \
217 inline int& operator+=(int&, const Name::Enum&) MOZ_DELETE; \
218 inline int& operator-=(int&, const Name::Enum&) MOZ_DELETE; \
219 inline int& operator*=(int&, const Name::Enum&) MOZ_DELETE; \
220 inline int& operator/=(int&, const Name::Enum&) MOZ_DELETE; \
221 inline int& operator%=(int&, const Name::Enum&) MOZ_DELETE; \
222 inline int& operator&=(int&, const Name::Enum&) MOZ_DELETE; \
223 inline int& operator|=(int&, const Name::Enum&) MOZ_DELETE; \
224 inline int& operator^=(int&, const Name::Enum&) MOZ_DELETE; \
225 inline int& operator<<=(int&, const Name::Enum&) MOZ_DELETE; \
226 inline int& operator>>=(int&, const Name::Enum&) MOZ_DELETE;
229 * MOZ_ENUM_CLASS_ENUM_TYPE allows using enum classes
230 * as template parameter types. For that, we need integer types.
231 * In the present case, the integer type is the Enum nested type.
233 # define MOZ_ENUM_CLASS_ENUM_TYPE(Name) Name::Enum
235 * MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE is a variant of MOZ_ENUM_CLASS_ENUM_TYPE
236 * to be used when the enum class at hand depends on template parameters.
238 * Indeed, if T depends on template parameters, in order to name a nested type
239 * in T, C++ does not allow to just write "T::NestedType". Instead, we have
240 * to write "typename T::NestedType". The role of this macro is to add
241 * this "typename" keywords where needed.
243 * Example:
245 * template<typename T, MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE(T) Value>
246 * struct S {};
248 * MOZ_BEGIN_ENUM_CLASS(E)
249 * Foo,
250 * Bar
251 * MOZ_END_ENUM_CLASS(E)
253 * S<E, E::Bar> s;
255 * In this example, the second template parameter to S is meant to be of type
256 * T, but on non-C++11 compilers, type T is a class type, not an integer
257 * type, so it is not accepted as the type of a constant template parameter.
258 * One would then want to use MOZ_ENUM_CLASS_ENUM_TYPE(T), but that doesn't
259 * work either as T depends on template parameters (more specifically here, T
260 * _is_ a template parameter) so as MOZ_ENUM_CLASS_ENUM_TYPE(T) expands to
261 * T::Enum, we are missing the required "typename" keyword. So here,
262 * MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE is needed.
264 # define MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE(Name) typename Name::Enum
265 #endif
267 # define MOZ_BEGIN_NESTED_ENUM_CLASS_GLUE(a, b) a b
268 # define MOZ_BEGIN_NESTED_ENUM_CLASS(...) \
269 MOZ_BEGIN_NESTED_ENUM_CLASS_GLUE( \
270 MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER, \
271 __VA_ARGS__), \
272 (__VA_ARGS__))
274 # define MOZ_BEGIN_ENUM_CLASS(...) MOZ_BEGIN_NESTED_ENUM_CLASS(__VA_ARGS__)
275 # define MOZ_END_ENUM_CLASS(Name) \
276 MOZ_END_NESTED_ENUM_CLASS(Name) \
277 MOZ_FINISH_NESTED_ENUM_CLASS(Name)
279 #endif /* __cplusplus */
281 #endif /* mozilla_TypedEnum_h */