diff options
| -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 | 
