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
|
#ifndef NAMED_ENUM_H
#define NAMED_ENUM_H
#ifndef NAMED_ENUM_USE_OPTIONAL
# define NAMED_ENUM_USE_OPTIONAL 1
#endif
//TODO: efficiency - supply map type (e.g. std::map or tr1::unordered_map) for string->int (int->string already fast w/ switch) - then implement iterators that don't assume contiguous ids.
//TODO: hidden (can't convert string->id, but can do reverse) sentinel values. XX (hidden) and XY (can convert to)
//TODO: bitfield "A|B" strings - note: slightly complicates int->string, as well.
//TODO: option for case-insensitive compare (ctype tolower?)
/* named enum (string<->int). note: inefficient linear search for string->int
in e.h:
#include "named_enum.h"
#define SOME_ENUM(X,t) \
X(t,FirstValue,) \
X(t,SecondValue,) \
X(t,SomeOtherValue,=50) \
X(t,OneMoreValue,=100) \
#define SOME_ENUM_TYPE MyEnum
DECLARE_NAMED_ENUM(SOME_ENUM)
in e.cc:
DEFINE_NAMED_ENUM(SOME_ENUM)
(or DEFINE_NAMED_ENUM_T(MyEnum,SOME_ENUM) )
#include "e.h"
elsewhere:
#include "e.h"
MyEnum e=GetMyEnum("FirstValue");
string s=GetName(e);
assert(s=="FirstValue");
string usage=MyEnumNames("\n");
*/
#include <stdexcept>
#include <sstream>
#if NAMED_ENUM_USE_OPTIONAL
# include <boost/optional.hpp>
#endif
#include "utoa.h"
inline void throw_enum_error(std::string const& enumtype,std::string const& msg) {
throw std::runtime_error(enumtype+": "+msg);
}
#if NAMED_ENUM_USE_OPTIONAL
#define NAMED_ENUM_OPTIONAL(x) x
#else
#define NAMED_ENUM_OPTIONAL(x)
#endif
// expansion macro for enum value definition
#define NAMED_ENUM_VALUE(t,name,assign) name assign,
// expansion macro for enum to string conversion
#define NAMED_ENUM_CASE(t,name,assign) case name: return #name;
// expansion macro for enum to string conversion
#define NAMED_ENUM_STRCMP(t,name,assign) if (!std::strcmp(str,#name)) return name;
// expansion macro for enum to optional conversion
#define NAMED_ENUM_STRCMP_OPTIONAL(t,name,assign) if (!std::strcmp(str,#name)) return boost::optional<t>(name);
#define NAMED_ENUM_APPEND_USAGE(t,name,assign) o << #name <<sp; sp=sep;
/// declare the access function and define enum values
#define DECLARE_NAMED_ENUM_T(DEF,EnumType) \
enum EnumType { \
DEF(NAMED_ENUM_VALUE,EnumType) \
}; \
const char *GetName(EnumType dummy); \
EnumType Get ## EnumType (const char *string); \
inline EnumType Get ## EnumType (std::string const& s) { return Get ## EnumType (s.c_str()); } \
std::string EnumType ## Names (char const* sep=","); \
NAMED_ENUM_OPTIONAL(boost::optional<EnumType> Get ## EnumType ## Optional (const char *string); inline boost::optional<EnumType> Get ## EnumType ## Optional (std::string const& s) { return Get ## EnumType ## Optional (s.c_str()); })
/// define the access function names
#define DEFINE_NAMED_ENUM_T(DEF,EnumType) \
const char *GetName(EnumType value) \
{ \
switch(value) \
{ \
DEF(NAMED_ENUM_CASE,EnumType) \
default: \
throw_enum_error(#EnumType,"Illegal enum value (no name defined) "+itos((int)value)); \
return ""; /* handle input error */ \
} \
} \
EnumType Get ## EnumType (const char *str) \
{ \
DEF(NAMED_ENUM_STRCMP,EnumType) \
throw_enum_error(#EnumType,"Couldn't convert '"+std::string(str)+"' - legal names: "+EnumType ## Names(" ")); \
return (EnumType)0; /* handle input error */ \
} \
std::string EnumType ## Names(char const* sep) { \
std::ostringstream o; \
char const* sp=""; \
DEF(NAMED_ENUM_APPEND_USAGE,EnumType) \
return o.str(); \
} \
NAMED_ENUM_OPTIONAL(boost::optional<EnumType> Get ## EnumType ## Optional (const char *str) { DEF(NAMED_ENUM_STRCMP_OPTIONAL,EnumType) return boost::optional<EnumType>(); })
#undef _TYPE
#define DECLARE_NAMED_ENUM_T2(x,y) DECLARE_NAMED_ENUM_T(x,y)
#define DEFINE_NAMED_ENUM_T2(x,y) DEFINE_NAMED_ENUM_T(x,y)
#define DECLARE_NAMED_ENUM(ENUM_DEF) DECLARE_NAMED_ENUM_T2(ENUM_DEF,ENUM_DEF ## _TYPE)
#define DEFINE_NAMED_ENUM(ENUM_DEF) DEFINE_NAMED_ENUM_T2(ENUM_DEF,ENUM_DEF ## _TYPE)
#define MAKE_NAMED_ENUM(ENUM_DEF) \
DECLARE_NAMED_ENUM(ENUM_DEF) \
DEFINE_NAMED_ENUM(ENUM_DEF)
#endif
|