blob: cd2f599712001ea14363e9cc1c96892bbe77a66d [file] [log] [blame]
Jeff Thompson86b6d642013-10-17 15:01:56 -07001// scoped_enum_emulation.hpp ---------------------------------------------------------//
2
3// Copyright Beman Dawes, 2009
4// Copyright (C) 2011-2012 Vicente J. Botet Escriba
5// Copyright (C) 2012 Anthony Williams
6
7// Distributed under the Boost Software License, Version 1.0.
8// See http://www.boost.org/LICENSE_1_0.txt
9
10/*
11[section:scoped_enums Scoped Enums]
12
13Generates C++0x scoped enums if the feature is present, otherwise emulates C++0x
14scoped enums with C++03 namespaces and enums. The Boost.Config NDNBOOST_NO_CXX11_SCOPED_ENUMS
15macro is used to detect feature support.
16
17See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf for a
18description of the scoped enum feature. Note that the committee changed the name
19from strongly typed enum to scoped enum.
20
21Some of the enumerations defined in the standard library are scoped enums.
22
23 enum class future_errc
24 {
25 broken_promise,
26 future_already_retrieved,
27 promise_already_satisfied,
28 no_state
29 };
30
31On compilers that don't support them, the library provides two emulations:
32
33[heading Strict]
34
35* Able to specify the underlying type.
36* explicit conversion to/from underlying type.
37* The wrapper is not a C++03 enum type.
38
39The user can declare declare these types as
40
41 NDNBOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc)
42 {
43 broken_promise,
44 future_already_retrieved,
45 promise_already_satisfied,
46 no_state
47 }
48 NDNBOOST_SCOPED_ENUM_DECLARE_END(future_errc)
49
50These macros allows to use 'future_errc' in almost all the cases as an scoped enum.
51
52 future_errc err = future_errc::no_state;
53
54There are however some limitations:
55
56* The type is not a C++ enum, so 'is_enum<future_errc>' will be false_type.
57* The emulated scoped enum can not be used in switch nor in template arguments. For these cases the user needs to use some macros.
58
59Instead of
60
61 switch (ev)
62 {
63 case future_errc::broken_promise:
64 // ...
65
66use
67
68 switch (ndnboost::native_value(ev))
69 {
70 case future_errc::broken_promise:
71
72And instead of
73
74 #ifdef NDNBOOST_NO_CXX11_SCOPED_ENUMS
75 template <>
76 struct NDNBOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type { };
77 #endif
78
79use
80
81 #ifdef NDNBOOST_NO_CXX11_SCOPED_ENUMS
82 template <>
83 struct NDNBOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type > : public true_type { };
84 #endif
85
86
87Sample usage:
88
89 NDNBOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(algae, char) { green, red, cyan }; NDNBOOST_SCOPED_ENUM_DECLARE_END(algae)
90 ...
91 algae sample( algae::red );
92 void foo( algae color );
93 ...
94 sample = algae::green;
95 foo( algae::cyan );
96
97 Light
98 Caution: only the syntax is emulated; the semantics are not emulated and
99 the syntax emulation doesn't include being able to specify the underlying
100 representation type.
101
102 The literal scoped emulation is via struct rather than namespace to allow use within classes.
103 Thanks to Andrey Semashev for pointing that out.
104 However the type is an real C++03 enum and so convertible implicitly to an int.
105
106 Sample usage:
107
108 NDNBOOST_SCOPED_ENUM_START(algae) { green, red, cyan }; NDNBOOST_SCOPED_ENUM_END
109 ...
110 NDNBOOST_SCOPED_ENUM(algae) sample( algae::red );
111 void foo( NDNBOOST_SCOPED_ENUM(algae) color );
112 ...
113 sample = algae::green;
114 foo( algae::cyan );
115
116 Helpful comments and suggestions were also made by Kjell Elster, Phil Endecott,
117 Joel Falcou, Mathias Gaunard, Felipe Magno de Almeida, Matt Calabrese, Vicente
118 Botet, and Daniel James.
119
120[endsect]
121*/
122
123
124#ifndef NDNBOOST_SCOPED_ENUM_EMULATION_HPP
125#define NDNBOOST_SCOPED_ENUM_EMULATION_HPP
126
127#include <ndnboost/config.hpp>
128#include <ndnboost/detail/workaround.hpp>
129
130namespace ndnboost
131{
132
133#ifdef NDNBOOST_NO_CXX11_SCOPED_ENUMS
134 /**
135 * Meta-function to get the underlying type of a scoped enum.
136 *
137 * Requires EnumType must be an enum type or the emulation of a scoped enum
138 */
139 template <typename EnumType>
140 struct underlying_type
141 {
142 /**
143 * The member typedef type names the underlying type of EnumType. It is EnumType::underlying_type when the EnumType is an emulated scoped enum,
144 * std::underlying_type<EnumType>::type when the standard library std::underlying_type is provided.
145 *
146 * The user will need to specialize it when the compiler supports scoped enums but don't provides std::underlying_type.
147 */
148 typedef typename EnumType::underlying_type type;
149 };
150
151 /**
152 * Meta-function to get the native enum type associated to an enum class or its emulation.
153 */
154 template <typename EnumType>
155 struct native_type
156 {
157 /**
158 * The member typedef type names the native enum type associated to the scoped enum,
159 * which is it self if the compiler supports scoped enums or EnumType::enum_type if it is an emulated scoped enum.
160 */
161 typedef typename EnumType::enum_type type;
162 };
163
164 /**
165 * Casts a scoped enum to its underlying type.
166 *
167 * This function is useful when working with scoped enum classes, which doens't implicitly convert to the underlying type.
168 * @param v A scoped enum.
169 * @returns The underlying type.
170 * @throws No-throws.
171 */
172 template <typename UnderlyingType, typename EnumType>
173 UnderlyingType underlying_cast(EnumType v)
174 {
175 return v.get_underlying_value_();
176 }
177
178 /**
179 * Casts a scoped enum to its native enum type.
180 *
181 * This function is useful to make programs portable when the scoped enum emulation can not be use where native enums can.
182 *
183 * EnumType the scoped enum type
184 *
185 * @param v A scoped enum.
186 * @returns The native enum value.
187 * @throws No-throws.
188 */
189 template <typename EnumType>
190 inline
191 typename EnumType::enum_type native_value(EnumType e)
192 {
193 return e.native_value_();
194 }
195
196#else // NDNBOOST_NO_CXX11_SCOPED_ENUMS
197
198 template <typename EnumType>
199 struct underlying_type
200 {
201 //typedef typename std::underlying_type<EnumType>::type type;
202 };
203
204 template <typename EnumType>
205 struct native_type
206 {
207 typedef EnumType type;
208 };
209
210 template <typename UnderlyingType, typename EnumType>
211 UnderlyingType underlying_cast(EnumType v)
212 {
213 return static_cast<UnderlyingType>(v);
214 }
215
216 template <typename EnumType>
217 inline
218 EnumType native_value(EnumType e)
219 {
220 return e;
221 }
222
223#endif
224}
225
226
227#ifdef NDNBOOST_NO_CXX11_SCOPED_ENUMS
228
229#ifndef NDNBOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
230
231#define NDNBOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR \
232 explicit operator underlying_type() const { return get_underlying_value_(); }
233
234#else
235
236#define NDNBOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR
237
238#endif
239
240/**
241 * Start a declaration of a scoped enum.
242 *
243 * @param EnumType The new scoped enum.
244 * @param UnderlyingType The underlying type.
245 */
246#define NDNBOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType, UnderlyingType) \
247 struct EnumType { \
248 typedef UnderlyingType underlying_type; \
249 EnumType() NDNBOOST_NOEXCEPT {} \
250 explicit EnumType(underlying_type v) : v_(v) {} \
251 underlying_type get_underlying_value_() const { return v_; } \
252 NDNBOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR \
253 private: \
254 underlying_type v_; \
255 typedef EnumType self_type; \
256 public: \
257 enum enum_type
258
259#define NDNBOOST_SCOPED_ENUM_DECLARE_END2() \
260 enum_type get_native_value_() const NDNBOOST_NOEXCEPT { return enum_type(v_); } \
261 operator enum_type() const NDNBOOST_NOEXCEPT { return get_native_value_(); } \
262 friend bool operator ==(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)==enum_type(rhs.v_); } \
263 friend bool operator ==(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)==rhs; } \
264 friend bool operator ==(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs==enum_type(rhs.v_); } \
265 friend bool operator !=(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)!=enum_type(rhs.v_); } \
266 friend bool operator !=(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)!=rhs; } \
267 friend bool operator !=(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs!=enum_type(rhs.v_); } \
268 friend bool operator <(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)<enum_type(rhs.v_); } \
269 friend bool operator <(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)<rhs; } \
270 friend bool operator <(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs<enum_type(rhs.v_); } \
271 friend bool operator <=(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)<=enum_type(rhs.v_); } \
272 friend bool operator <=(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)<=rhs; } \
273 friend bool operator <=(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs<=enum_type(rhs.v_); } \
274 friend bool operator >(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)>enum_type(rhs.v_); } \
275 friend bool operator >(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)>rhs; } \
276 friend bool operator >(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs>enum_type(rhs.v_); } \
277 friend bool operator >=(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)>=enum_type(rhs.v_); } \
278 friend bool operator >=(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)>=rhs; } \
279 friend bool operator >=(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs>=enum_type(rhs.v_); } \
280 };
281
282#define NDNBOOST_SCOPED_ENUM_DECLARE_END(EnumType) \
283 ; \
284 EnumType(enum_type v) NDNBOOST_NOEXCEPT : v_(v) {} \
285 NDNBOOST_SCOPED_ENUM_DECLARE_END2()
286
287/**
288 * Starts a declaration of a scoped enum with the default int underlying type.
289 *
290 * @param EnumType The new scoped enum.
291 */
292#define NDNBOOST_SCOPED_ENUM_DECLARE_BEGIN(EnumType) \
293 NDNBOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType,int)
294
295/**
296 * Name of the native enum type.
297 *
298 * @param NT The new scoped enum.
299 */
300#define NDNBOOST_SCOPED_ENUM_NATIVE(EnumType) EnumType::enum_type
301/**
302 * Forward declares an scoped enum.
303 *
304 * @param NT The scoped enum.
305 */
306#define NDNBOOST_SCOPED_ENUM_FORWARD_DECLARE(EnumType) struct EnumType
307
308#else // NDNBOOST_NO_CXX11_SCOPED_ENUMS
309
310#define NDNBOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType,UnderlyingType) enum class EnumType:UnderlyingType
311#define NDNBOOST_SCOPED_ENUM_DECLARE_BEGIN(EnumType) enum class EnumType
312#define NDNBOOST_SCOPED_ENUM_DECLARE_END2()
313#define NDNBOOST_SCOPED_ENUM_DECLARE_END(EnumType) ;
314
315#define NDNBOOST_SCOPED_ENUM_NATIVE(EnumType) EnumType
316#define NDNBOOST_SCOPED_ENUM_FORWARD_DECLARE(EnumType) enum class EnumType
317
318#endif // NDNBOOST_NO_CXX11_SCOPED_ENUMS
319
320#define NDNBOOST_SCOPED_ENUM_START(name) NDNBOOST_SCOPED_ENUM_DECLARE_BEGIN(name)
321#define NDNBOOST_SCOPED_ENUM_END NDNBOOST_SCOPED_ENUM_DECLARE_END2()
322#define NDNBOOST_SCOPED_ENUM(name) NDNBOOST_SCOPED_ENUM_NATIVE(name)
323
324//#ifdef NDNBOOST_NO_CXX11_SCOPED_ENUMS
325//
326//# define NDNBOOST_SCOPED_ENUM_START(name) struct name { enum enum_type
327//# define NDNBOOST_SCOPED_ENUM_END };
328//# define NDNBOOST_SCOPED_ENUM(name) name::enum_type
329//
330//#else
331//
332//# define NDNBOOST_SCOPED_ENUM_START(name) enum class name
333//# define NDNBOOST_SCOPED_ENUM_END
334//# define NDNBOOST_SCOPED_ENUM(name) name
335//
336//#endif
337#endif // NDNBOOST_SCOPED_ENUM_EMULATION_HPP