-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenum_pp_detail.hpp
291 lines (246 loc) · 13.7 KB
/
enum_pp_detail.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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#ifndef AXIOM_DETAIL_ENUMPP_HPP
#define AXIOM_DETAIL_ENUMPP_HPP
#include <string>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/expand.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/tuple/size.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include "boost/assert.hpp"
#include "boost/container/flat_set.hpp"
#include <boost/unordered_map.hpp>
namespace Axiom
{
namespace Detail
{
template <typename T>
class NameLink
{
public:
static std::string const & get_name()
{
//assertion fails if T was not defined by our custom macro
BOOST_ASSERT(name_);
return *name_;
}
static void assign(std::string const & name)
{
name_ = &name;
}
private:
static std::string const * name_;
};
template <typename T>
std::string const * NameLink<T>::name_ = nullptr;
template <typename T>
struct NameLinkAssigner
{
static bool invoke_assign()
{
NameLink<typename T::Type>::assign(T::get_name());
return true;
}
static bool const invoke_assign_helper_;
};
template <typename T>
bool const NameLinkAssigner<T>::invoke_assign_helper_ = NameLinkAssigner<T>::invoke_assign();
template <typename T>
class ValueSetLink
{
public:
typedef boost::container::flat_set<T> ValueSet;
static ValueSet const & get_value_set()
{
BOOST_ASSERT(value_set_);
return *value_set_;
}
static void assign(ValueSet const & value_set)
{
value_set_ = &value_set;
}
private:
static ValueSet const * value_set_;
};
template <typename T>
typename ValueSetLink<T>::ValueSet const * ValueSetLink<T>::value_set_ = nullptr;
template <typename T>
struct ValueSetLinkAssigner
{
static bool invoke_assign()
{
ValueSetLink<typename T::Type>::assign(T::get_value_set());
return true;
}
static bool const invoke_assign_helper_;
};
template <typename T>
bool const ValueSetLinkAssigner<T>::invoke_assign_helper_ = ValueSetLinkAssigner<T>::invoke_assign();
template <typename T>
class StringMapLink
{
public:
typedef boost::unordered_map<T, std::string> ToStringMap;
typedef boost::unordered_map<std::string, T> FromStringMap;
static ToStringMap const & get_to_string_map()
{
//assertion fails if T was not defined by our custom macro
BOOST_ASSERT(to_string_map_);
return *to_string_map_;
}
static FromStringMap const & get_from_string_map()
{
//assertion fails if T was not defined by our custom macro
BOOST_ASSERT(from_string_map_);
return *from_string_map_;
}
static void assign(ToStringMap const & to_string_map, FromStringMap const & from_string_map)
{
to_string_map_ = &to_string_map;
from_string_map_ = &from_string_map;
}
private:
static ToStringMap const * to_string_map_;
static FromStringMap const * from_string_map_;
};
template <typename T>
typename StringMapLink<T>::ToStringMap const * StringMapLink<T>::to_string_map_ = nullptr;
template <typename T>
typename StringMapLink<T>::FromStringMap const * StringMapLink<T>::from_string_map_ = nullptr;
template <typename T>
struct StringMapLinkAssigner
{
static bool invoke_assign()
{
StringMapLink<typename T::Type>::assign(T::get_to_string_map(), T::get_from_string_map());
return true;
}
static bool const invoke_assign_helper_;
};
template <typename T>
bool const StringMapLinkAssigner<T>::invoke_assign_helper_ = StringMapLinkAssigner<T>::invoke_assign();
} //end of namespace Detail
} //end of namespace Axiom
#define AXIOM_X_ENUMPP__NAME_VALUE_1(elem) \
BOOST_PP_TUPLE_ELEM(0,elem)
#define AXIOM_X_ENUMPP__NAME_VALUE_2(elem) \
BOOST_PP_TUPLE_ELEM(0,elem) = BOOST_PP_TUPLE_ELEM(1,elem)
#define AXIOM_X_ENUMPP__NAME_VALUE_SEQ(s,data,elem) \
BOOST_PP_EXPAND(BOOST_PP_CAT(AXIOM_X_ENUMPP__NAME_VALUE_,BOOST_PP_TUPLE_SIZE(elem))(elem))
#define AXIOM_X_ENUMPP__NAME_ONLY_SEQ(s,data,elem) \
BOOST_PP_TUPLE_ELEM(0,elem)
#define AXIOM_X_ENUMPP__TO_SEQ(seq_type, ...) \
BOOST_PP_SEQ_TRANSFORM( BOOST_PP_CAT(BOOST_PP_CAT(AXIOM_X_ENUMPP__,seq_type),_SEQ) \
, 0 \
, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__) \
)
#define AXIOM_X_ENUMPP__VALUE_SET(r, enum_name, elem) \
value_set.insert(enum_name::elem);
#define AXIOM_X_ENUMPP__TO_STRING_MAPPING(r, enum_name, elem) \
to_string_map[enum_name::elem] = BOOST_PP_STRINGIZE(elem);
#define AXIOM_X_ENUMPP__FROM_STRING_MAPPING(r, enum_name, elem) \
from_string_map[BOOST_PP_STRINGIZE(elem)] = enum_name::elem;
#ifdef _MSC_VER
#define AXIOM_X_ENUMPP__DO_NOT_OPTIMIZE_AWAY __declspec(dllexport)
#else
#define AXIOM_X_ENUMPP__DO_NOT_OPTIMIZE_AWAY
#endif
#define AXIOM_X_ENUMPP__NAME_TYPE_1(name_type) \
BOOST_PP_TUPLE_ELEM(0,name_type)
#define AXIOM_X_ENUMPP__NAME_TYPE_2(name_type) \
BOOST_PP_TUPLE_ELEM(0,name_type) : BOOST_PP_TUPLE_ELEM(1,name_type)
#define AXIOM_X_ENUMPP__NAME_TYPE_DECLARATION(name_type) \
BOOST_PP_EXPAND(BOOST_PP_CAT(AXIOM_X_ENUMPP__NAME_TYPE_,BOOST_PP_TUPLE_SIZE(name_type))(name_type))
#define AXIOM_X_ENUMPP(name_type, ...) \
enum class AXIOM_X_ENUMPP__NAME_TYPE_DECLARATION(name_type) \
{ \
BOOST_PP_SEQ_ENUM(AXIOM_X_ENUMPP__TO_SEQ(NAME_VALUE, __VA_ARGS__)) \
}; \
\
struct BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(0,name_type),EnumPP) \
{ \
typedef BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(0,name_type),EnumPP) Self; \
typedef BOOST_PP_TUPLE_ELEM(0,name_type) Type; \
\
static std::string const & get_name() \
{ \
static std::string const name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0,name_type)); \
return name; \
} \
\
typedef Axiom::Detail::ValueSetLink<Type>::ValueSet ValueSet; \
static ValueSet const & get_value_set() \
{ \
struct LocalScope \
{ \
static ValueSet init() \
{ \
ValueSet value_set; \
\
BOOST_PP_SEQ_FOR_EACH( AXIOM_X_ENUMPP__VALUE_SET \
, BOOST_PP_TUPLE_ELEM(0,name_type) \
, AXIOM_X_ENUMPP__TO_SEQ(NAME_ONLY, __VA_ARGS__) \
) \
\
return value_set; \
} \
}; \
static ValueSet const value_set = LocalScope::init(); \
return value_set; \
} \
\
typedef Axiom::Detail::StringMapLink<Type>::ToStringMap ToStringMap; \
static ToStringMap const& get_to_string_map() \
{ \
struct LocalScope \
{ \
static ToStringMap init() \
{ \
ToStringMap to_string_map; \
\
BOOST_PP_SEQ_FOR_EACH( AXIOM_X_ENUMPP__TO_STRING_MAPPING \
, BOOST_PP_TUPLE_ELEM(0,name_type) \
, AXIOM_X_ENUMPP__TO_SEQ(NAME_ONLY, __VA_ARGS__) \
) \
\
return to_string_map; \
} \
}; \
static ToStringMap const to_string_map = LocalScope::init(); \
return to_string_map; \
} \
\
typedef Axiom::Detail::StringMapLink<Type>::FromStringMap FromStringMap; \
static FromStringMap const& get_from_string_map() \
{ \
struct LocalScope \
{ \
static FromStringMap init() \
{ \
FromStringMap from_string_map; \
\
BOOST_PP_SEQ_FOR_EACH( AXIOM_X_ENUMPP__FROM_STRING_MAPPING \
, BOOST_PP_TUPLE_ELEM(0,name_type) \
, AXIOM_X_ENUMPP__TO_SEQ(NAME_ONLY, __VA_ARGS__) \
) \
\
return from_string_map; \
} \
}; \
static FromStringMap const from_string_map = LocalScope::init(); \
return from_string_map; \
} \
\
private: \
AXIOM_X_ENUMPP__DO_NOT_OPTIMIZE_AWAY \
bool never_called_but_force_initialization() \
{ \
return Axiom::Detail::NameLinkAssigner<Self>::invoke_assign_helper_ \
&& Axiom::Detail::ValueSetLinkAssigner<Self>::invoke_assign_helper_ \
&& Axiom::Detail::StringMapLinkAssigner<Self>::invoke_assign_helper_; \
} \
}
#endif