Created
December 5, 2012 00:01
-
-
Save ishani/4210469 to your computer and use it in GitHub Desktop.
Fancy C++ Enums
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <assert.h> | |
// --------------------------------------------------------------------------------------------------------------------- | |
// these are the actions used within the enum creation macro to produce output per-entry | |
// we break out the _ID ones to avoid triggering errors when using Clang in -Wall mode | |
#define FANCYENUM_DEF_ENUM(_ty) _ty, | |
#define FANCYENUM_DEF_ENUM_ID(_ty, _id) _ty = _id, | |
#define FANCYENUM_DEF_TOSTR(_ty) case _ty: return #_ty; | |
#define FANCYENUM_DEF_FIDX(_ty) case _ty: return _ty; | |
#define FANCYENUM_DEF_VALID(_ty) case _ty: return true; | |
#define FANCYENUM_DEF_FROMSTR(_ty) if (strcmp(str, #_ty) == 0) return _ty; else | |
#define FANCYENUM_DEF_TOSTR_ID(_ty, ...) FANCYENUM_DEF_TOSTR(_ty) | |
#define FANCYENUM_DEF_FIDX_ID(_ty, ...) FANCYENUM_DEF_FIDX(_ty) | |
#define FANCYENUM_DEF_VALID_ID(_ty, ...) FANCYENUM_DEF_VALID(_ty) | |
#define FANCYENUM_DEF_FROMSTR_ID(_ty, ...) FANCYENUM_DEF_FROMSTR(_ty) | |
#if defined(_MSC_VER) && !defined(__CLANG_VSX__) | |
# define FANCYENUM_ADORN abstract sealed | |
# if _MSC_VER > 1600 | |
# define FANCYENUM_STORAGE_SPEC(_storageType) : _storageType | |
# else | |
# define FANCYENUM_STORAGE_SPEC(_storageType) | |
# endif // _MSC_VER > 1600 | |
#else | |
# define FANCYENUM_ADORN | |
# define FANCYENUM_STORAGE_SPEC(_storageType) : _storageType | |
#endif // _MSC_VER | |
// --------------------------------------------------------------------------------------------------------------------- | |
// main code expander | |
// _enumName is the wrapper name for the enum, eg. VertexFormat or PlayerState | |
// _storageType is used as the C++11 storage class if available, along with setting the index type | |
// _enumAdorn pass-through for any declaration adornments, like 'abstract' or 'sealed' on MSVC | |
// _macroWorker is the macro that takes an action macro to create code. confused yet? | |
// _????Builder are the functions that create code specific to individual functions | |
// _topAccessor chooses what to call the accessor for the 'top' or 'count' depending if it has IDs or not | |
// | |
#define _TL_CREATE_FANCYENUM(_enumName, _storageType, _enumAdorn, _macroWorker, _entryBuilder, _fidxBuilder, _validBuilder, _toStrBuilder, _fromStrBuilder, _topAccessor) \ | |
struct _enumName _enumAdorn \ | |
{ \ | |
typedef _storageType StorageType; \ | |
enum Enum FANCYENUM_STORAGE_SPEC(_storageType) \ | |
{ \ | |
_macroWorker(_entryBuilder) \ | |
e_Top \ | |
}; \ | |
\ | |
inline static const char* enumName() { return #_enumName; } \ | |
inline static _storageType _topAccessor() { return static_cast<_storageType>(e_Top); } \ | |
\ | |
inline static _enumName::Enum getByValue(_storageType idx) \ | |
{ \ | |
switch (idx) \ | |
{ \ | |
_macroWorker(_fidxBuilder) \ | |
default: \ | |
{ \ | |
assert(0); \ | |
return (_enumName::e_Top); \ | |
} \ | |
} \ | |
} \ | |
\ | |
inline static bool isValidValue(_storageType idx) \ | |
{ \ | |
switch ((_enumName::Enum)idx) \ | |
{ \ | |
_macroWorker(_validBuilder) \ | |
default: \ | |
return false; \ | |
} \ | |
} \ | |
\ | |
inline static const char* toString(_enumName::Enum e) \ | |
{ \ | |
switch (e) \ | |
{ \ | |
_macroWorker(_toStrBuilder) \ | |
default: \ | |
{ \ | |
assert(0); \ | |
return "error"; \ | |
} \ | |
} \ | |
} \ | |
\ | |
inline static _enumName::Enum fromString(const char* str) \ | |
{ \ | |
_macroWorker(_fromStrBuilder) \ | |
{ \ | |
assert(0); \ | |
return (_enumName::e_Top); \ | |
} \ | |
} \ | |
private: \ | |
_enumName(); \ | |
} | |
#define CREATE_FANCYENUM(_enumName, _storageType, _macroWorker) \ | |
_TL_CREATE_FANCYENUM(_enumName, _storageType, FANCYENUM_ADORN, _macroWorker, FANCYENUM_DEF_ENUM, FANCYENUM_DEF_FIDX, FANCYENUM_DEF_VALID, FANCYENUM_DEF_TOSTR, FANCYENUM_DEF_FROMSTR, enumCount) | |
#define CREATE_FANCYENUM_IDS(_enumName, _storageType, _macroWorker) \ | |
_TL_CREATE_FANCYENUM(_enumName, _storageType, FANCYENUM_ADORN, _macroWorker, FANCYENUM_DEF_ENUM_ID, FANCYENUM_DEF_FIDX_ID, FANCYENUM_DEF_VALID_ID, FANCYENUM_DEF_TOSTR_ID, FANCYENUM_DEF_FROMSTR_ID, enumLast) | |
// --------------------------------------------------------------------------------------------------------------------- | |
// demonstrate creation of default enum | |
// | |
#define BF_VERTEX_FORMATS(_entry) \ | |
_entry(Vertex_Pos3) \ | |
_entry(Vertex_Pos4) \ | |
_entry(Vertex_Pos3_RGBA) \ | |
_entry(Vertex_Pos4_RGBA) \ | |
_entry(Vertex_Pos3_RGBA_Normal3) \ | |
_entry(Vertex_Pos3_RGBA_Normal3_UV0) \ | |
_entry(Vertex_Pos3_RGBA_UV0) | |
CREATE_FANCYENUM(VertexFormat, uint16_t, BF_VERTEX_FORMATS); | |
// --------------------------------------------------------------------------------------------------------------------- | |
// create enum with manual ID assignment | |
// | |
#define BF_WITH_IDS(_entry) \ | |
_entry(Kepler, 5) \ | |
_entry(Hthran, -10) \ | |
_entry(Eidelon, -11) \ | |
_entry(Montegue, -20) \ | |
_entry(Falagray, 22) \ | |
_entry(Sepfarra, 51) \ | |
_entry(Winteray, 60) \ | |
CREATE_FANCYENUM_IDS(Codenames, int32_t, BF_WITH_IDS); | |
// --------------------------------------------------------------------------------------------------------------------- | |
int main(int, char*[]) | |
{ | |
VertexFormat::Enum k = VertexFormat::Vertex_Pos3_RGBA_Normal3_UV0; | |
const char* str = VertexFormat::toString(k); | |
k = VertexFormat::fromString(str); | |
printf("%s has %i entries, of which %s == %i\n\n", | |
VertexFormat::enumName(), | |
VertexFormat::enumCount(), | |
str, | |
k); | |
for (VertexFormat::StorageType i=0; i<VertexFormat::enumCount(); i++) | |
{ | |
printf("> %s == %i \n", VertexFormat::toString( VertexFormat::getByValue(i) ), VertexFormat::getByValue(i) ); | |
} | |
printf("\n------------\n\n"); | |
Codenames::Enum n = Codenames::Falagray; | |
str = Codenames::toString(n); | |
n = Codenames::fromString(str); | |
printf("%s final entry == %i, of which %s == %i\n\n", | |
Codenames::enumName(), | |
Codenames::enumLast(), | |
str, | |
n); | |
for (Codenames::StorageType i=-30; i<(Codenames::StorageType)Codenames::enumLast(); i++) | |
{ | |
if (Codenames::isValidValue(i)) | |
printf("> %s == %i \n", Codenames::toString( Codenames::getByValue(i) ), Codenames::getByValue(i) ); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment