diff options
Diffstat (limited to 'utils/named_enum.h')
-rwxr-xr-x | utils/named_enum.h | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/utils/named_enum.h b/utils/named_enum.h new file mode 100755 index 00000000..b459b4a9 --- /dev/null +++ b/utils/named_enum.h @@ -0,0 +1,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) \ + typedef enum { \ + DEF(NAMED_ENUM_VALUE,EnumType) \ + } 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 |