-
Notifications
You must be signed in to change notification settings - Fork 0
/
smart_enum.hpp
242 lines (226 loc) · 8.32 KB
/
smart_enum.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#pragma once
#include "utilities/macros/for_each.hpp"
#include "utilities/static_string.hpp"
#include <set>
namespace utilities {
/** @brief A class to implement smart enumerations, based on strings
*
* I stole the basic design of this class from
* [here](http://www.drdobbs.com/when-enum-just-isnt-enough-enumeration-c
* /184403955). That said the actual implementation is a bit different in that
* I am not concerned with being able to iterate over all the possibilities.
* This means I can dodge the weird static `std::set` instance. It also
* means I can get the entire class to be a compile-time literal.
*/
template<class T>
class SmartEnum {
private:
/// The type of this class, for convenience
using my_type = SmartEnum<T>;
public:
/// Intel won't let this be private
template<std::size_t N>
constexpr explicit SmartEnum(const char (&str)[N]) : value_(str) {}
/**
* @brief Compares two SmartEnums for equality.
*
* All SmartEnum comparison operators defer to the underlying StaticString
* instance and thus this class uses the same definition of equality.
*
* @param rhs The SmartEnum to compare to.
*
* @return True if the two SmartEnum instances are the same and false
* otherwise.
*
* @throw None. No throw guarantee.
*
* @par Complexity:
* Worst case linear in the length of the underlying string
*
* @par Data Races:
* None. All SmartEnums are read-only at run-time.
*/
constexpr bool operator==(const my_type& rhs) const noexcept {
return value_ == rhs.value_;
}
/**
* @brief Compares two SmartEnums for inequality.
*
* All SmartEnum comparison operators defer to the underlying StaticString
* instance and thus this class uses the same definition of inequality.
*
* @param rhs The SmartEnum to compare to.
*
* @return True if the two SmartEnum instances are different and false
* otherwise.
*
* @throw None. No throw guarantee.
*
* @par Complexity:
* Worst case linear in the length of the underlying string
*
* @par Data Races:
* None. All SmartEnums are read-only at run-time.
*/
constexpr bool operator!=(const my_type& rhs) const noexcept {
return value_ != rhs.value_;
}
/**
* @brief Determines if the current SmartEnum is less than another instance.
*
* All SmartEnum comparison operators defer to the underlying StaticString
* instance and thus this class uses the same definition of less than.
*
* @param rhs The SmartEnum to compare to.
*
* @return True if the current SmartEnum instance is less than and
* false otherwise.
*
* @throw None. No throw guarantee.
*
* @par Complexity:
* Worst case linear in the length of the underlying string
*
* @par Data Races:
* None. All SmartEnums are read-only at run-time.
*/
constexpr bool operator<(const my_type& rhs) const noexcept {
return value_ < rhs.value_;
}
/**
* @brief Determines if the current SmartEnum is less than or equal to
* another instance.
*
* All SmartEnum comparison operators defer to the underlying StaticString
* instance and thus this class uses the same definition of less than or
* equal to.
*
* @param rhs The SmartEnum to compare to.
*
* @return True if the current SmartEnum instance is less than or equal to
* @p rhs and false otherwise.
*
* @throw None. No throw guarantee.
*
* @par Complexity:
* Worst case linear in the length of the underlying string
*
* @par Data Races:
* None. All SmartEnums are read-only at run-time.
*/
constexpr bool operator<=(const my_type& rhs) const noexcept {
return value_ <= rhs.value_;
}
/**
* @brief Determines if the current SmartEnum is greater than another
* instance.
*
* All SmartEnum comparison operators defer to the underlying StaticString
* instance and thus this class uses the same definition of greater than.
*
* @param rhs The SmartEnum to compare to.
*
* @return True if the current SmartEnum instance is greater than and
* false otherwise.
*
* @throw None. No throw guarantee.
*
* @par Complexity:
* Worst case linear in the length of the underlying string
*
* @par Data Races:
* None. All SmartEnums are read-only at run-time.
*/
constexpr bool operator>(const my_type& rhs) const noexcept {
return value_ > rhs.value_;
}
/**
* @brief Determines if the current SmartEnum is greater than or equal to
* another instance.
*
* All SmartEnum comparison operators defer to the underlying StaticString
* instance and thus this class uses the same definition of greater than or
* equal to.
*
* @param rhs The SmartEnum to compare to.
*
* @return True if the current SmartEnum instance is greater than or equal
* to @p rhs, and false otherwise.
*
* @throw None. No throw guarantee.
*
* @par Complexity:
* Worst case linear in the length of the underlying string
*
* @par Data Races:
* None. All SmartEnums are read-only at run-time.
*/
constexpr bool operator>=(const my_type& rhs) const noexcept {
return value_ >= rhs.value_;
}
/**
* @brief Allows the enum to be implicitly converted to a C-style string.
*
*
* @return The current enum as a C-style string.
* @throw None. No throw guarantee.
* @par Complexity:
* Constant.
* @par Data Races:
* None. All SmartEnums are read-only at run-time.
*/
constexpr operator const char*() const noexcept { return value_; }
private:
/// The value this particular enum holds
StaticString value_;
protected:
/// Constructor, protected cause you won't ever call it outside derived
/// class
};
} // namespace utilities
/// Implementation detail for declaring the enum instances in DECLARE_SmartEnum
#define _ADD_SMARTENUM(name) static const T name;
/// Implementation detail for defining the enum instances in DECLARE_SmartEnum
#define _DEFINE_SMARTENUM(enum_name, name) \
template<typename T> \
constexpr T enum_name##Impl<T>::name(#name);
/**
* @brief Convenience function for declaring a SmartEnum set.
*
* This macro hides the boilerplate for declaring a new set of SmartEnum
* instances. It relies on the CALL_MACRO_X_FOR_EACH macro which has a hard
* coded limit of the maximum number of variable arguments it can handle (this
* is an artifact of the fact that C macros can't be called recursively).
*
* Usage to make a set of SmartEnum "Fruits" which contains apple, pear, and
* orange:
* @code
* DECLARE_SmartEnum(Fruits, apple, pear, orange);
* @endcode
*
* @param[in] enum_name This will become the name of the class which holds your
* enum (Fruits in the example above)
* @param[in] ... These are the values of your enum. (apple, pear, orange in the
* example above).
*
* Notes on the actual implementation:
* - We actually create a templated trampoline class enum_nameImpl which allows
* us to define the static member variables in a header without fear of
* multiple definition reprisal because templates are immune to the ODR.
*
*
*/
#define DECLARE_SmartEnum(enum_name, ...) \
template<typename T> \
class enum_name##Impl : public utilities::SmartEnum<T> { \
public: \
using utilities::SmartEnum<T>::SmartEnum; \
\
public: \
CALL_MACRO_X_FOR_EACH(_ADD_SMARTENUM, __VA_ARGS__) \
}; \
CALL_MACRO_X_FOR_EACH1(_DEFINE_SMARTENUM, enum_name, __VA_ARGS__) \
class enum_name : public enum_name##Impl<enum_name> { \
public: \
using enum_name##Impl<enum_name>::enum_name##Impl; \
}