├── EnumReflection.cpp ├── EnumReflection.h ├── LICENSE.txt └── Test.cpp /EnumReflection.cpp: -------------------------------------------------------------------------------- 1 | // (c) 2016 Yakov Litvitskiy 2 | // See LICENSE.txt 3 | #include "EnumReflection.h" 4 | #include 5 | #include 6 | 7 | struct EnumReflector::Private 8 | { 9 | struct Enumerator 10 | { 11 | std::string name; 12 | int value; 13 | }; 14 | std::vector values; 15 | std::string enumName; 16 | }; 17 | 18 | static bool IsIdentChar(char c) 19 | { 20 | return (c >= 'A' && c <= 'Z') || 21 | (c >= 'a' && c <= 'z') || 22 | (c >= '0' && c <= '9') || 23 | (c == '_'); 24 | } 25 | 26 | EnumReflector::EnumReflector(const int* vals, int count, const char* name, const char* body) 27 | : _data(new Private) 28 | { 29 | _data->enumName = name; 30 | _data->values.resize(count); 31 | enum states 32 | { 33 | state_start, // Before identifier 34 | state_ident, // In identifier 35 | state_skip, // Looking for separator comma 36 | } state = state_start; 37 | assert(*body == '('); 38 | ++body; 39 | const char* ident_start = nullptr; 40 | int value_index = 0; 41 | int level = 0; 42 | for (;;) 43 | { 44 | assert(*body); 45 | switch (state) 46 | { 47 | case state_start: 48 | if (IsIdentChar(*body)) 49 | { 50 | state = state_ident; 51 | ident_start = body; 52 | } 53 | ++body; 54 | break; 55 | case state_ident: 56 | if (!IsIdentChar(*body)) 57 | { 58 | state = state_skip; 59 | assert(value_index < count); 60 | _data->values[value_index].name = std::string(ident_start, body - ident_start); 61 | _data->values[value_index].value = vals[value_index]; 62 | ++value_index; 63 | } 64 | else 65 | { 66 | ++body; 67 | } 68 | break; 69 | case state_skip: 70 | if (*body == '(') 71 | { 72 | ++level; 73 | } 74 | else if (*body == ')') 75 | { 76 | if (level == 0) 77 | { 78 | assert(value_index == count); 79 | return; 80 | } 81 | --level; 82 | } 83 | else if (level == 0 && *body == ',') 84 | { 85 | state = state_start; 86 | } 87 | ++body; 88 | } 89 | } 90 | } 91 | 92 | EnumReflector::~EnumReflector() 93 | { 94 | if(_data) 95 | delete _data; 96 | } 97 | 98 | int EnumReflector::Count() const 99 | { 100 | return (int)_data->values.size(); 101 | } 102 | 103 | EnumReflector::Enumerator EnumReflector::Find(const std::string& name) const 104 | { 105 | for (int i = 0; i < (int)_data->values.size(); ++i) 106 | { 107 | if (_data->values[i].name == name) 108 | return At(i); 109 | } 110 | return end(); 111 | } 112 | 113 | EnumReflector::Enumerator EnumReflector::Find(int value) const 114 | { 115 | for (int i = 0; i < (int)_data->values.size(); ++i) 116 | { 117 | if (_data->values[i].value == value) 118 | return At(i); 119 | } 120 | return end(); 121 | } 122 | 123 | const std::string& EnumReflector::EnumName() const 124 | { 125 | return _data->enumName; 126 | } 127 | 128 | const std::string& EnumReflector::Enumerator::Name() const 129 | { 130 | return _er._data->values[_index].name; 131 | } 132 | 133 | int EnumReflector::Enumerator::Value() const 134 | { 135 | return _er._data->values[_index].value; 136 | } 137 | -------------------------------------------------------------------------------- /EnumReflection.h: -------------------------------------------------------------------------------- 1 | // (c) 2016 Yakov Litvitskiy 2 | // See LICENSE.txt 3 | #ifndef GUARD_EnumReflection_H_INCLUDED 4 | #define GUARD_EnumReflection_H_INCLUDED 5 | #pragma once 6 | 7 | #include 8 | 9 | //-------------------------------- Public Interface -------------------------------- 10 | 11 | // Declare an enumeration inside a class 12 | #define Z_ENUM( enumName, ... )\ 13 | Z_ENUM_DETAIL_MAKE( class, enumName, __VA_ARGS__ ) 14 | 15 | // Declare an enumeration inside a namespace 16 | #define Z_ENUM_NS( enumName, ... )\ 17 | Z_ENUM_DETAIL_MAKE( namespace, enumName, __VA_ARGS__ ) 18 | 19 | // Provides access to information about an enum declared with Z_ENUM or Z_ENUM_NS 20 | class EnumReflector 21 | { 22 | public: 23 | // Returns a reference to EnumReflector object which can be used 24 | // to retrieve information about the enumeration declared with Z_ENUM or Z_ENUM_NS 25 | template 26 | static const EnumReflector& For(EnumType val = EnumType()); 27 | 28 | // Represents an enumerator (value) of an enumeration 29 | class Enumerator 30 | { 31 | public: 32 | // Returns enumerator name 33 | const std::string& Name() const; 34 | 35 | // Returns enumerator value 36 | int Value() const; 37 | 38 | // Returns enumerator index 39 | int Index() const; 40 | 41 | // Returns parent reflector object 42 | const EnumReflector& Reflector() const; 43 | 44 | // Check if this is an valid Enumerator 45 | bool IsValid() const; 46 | operator bool() const; 47 | 48 | // Check if two objects are the same 49 | bool operator!=(const Enumerator& rhs) const; 50 | 51 | // Moves on to the next Enumerator in enum 52 | Enumerator& operator++(); 53 | 54 | // Provided for compatibility with range-based for construct 55 | const Enumerator& operator*() const; 56 | 57 | private: 58 | friend class EnumReflector; 59 | Enumerator(const EnumReflector&, int); 60 | const EnumReflector& _er; 61 | int _index; 62 | }; 63 | 64 | // Returns Enumerator count 65 | int Count() const; 66 | 67 | // Returns an Enumerator with specified name or invalid Enumerator if not found 68 | Enumerator Find(const std::string& name) const; 69 | 70 | // Returns an Enumerator with specified value or invalid Enumerator if not found 71 | Enumerator Find(int value) const; 72 | 73 | // Returns the enumeration name 74 | const std::string& EnumName() const; 75 | 76 | // Returns Enumerator at specified index 77 | Enumerator At(int index) const; 78 | Enumerator operator[](int index) const; 79 | 80 | // In some cases Enumerators can be used as iterators. The following functions 81 | // are provided e.g. for compatibility with range-based for construct: 82 | 83 | // Returns the first Enumerator 84 | Enumerator begin() const; 85 | 86 | // Returns an invalid Enumerator 87 | Enumerator end() const; 88 | 89 | public: 90 | // Constructor. Used internally by Z_ENUM and Z_ENUM_NS 91 | EnumReflector(const int*, int, const char*, const char*); 92 | EnumReflector(EnumReflector&&); 93 | ~EnumReflector(); 94 | private: 95 | struct Private; 96 | Private* _data; 97 | }; 98 | 99 | //----------------------------- Implementation Details ----------------------------- 100 | 101 | #define Z_ENUM_DETAIL_SPEC_namespace \ 102 | extern "C"{/* Protection from being used inside a class body */} \ 103 | inline 104 | #define Z_ENUM_DETAIL_SPEC_class friend 105 | #define Z_ENUM_DETAIL_STR(x) #x 106 | #define Z_ENUM_DETAIL_MAKE(spec, enumName, ...) \ 107 | enum enumName:int \ 108 | { \ 109 | __VA_ARGS__ \ 110 | }; \ 111 | Z_ENUM_DETAIL_SPEC_##spec const ::EnumReflector& _detail_reflector_(enumName) \ 112 | { \ 113 | static const ::EnumReflector _reflector( []{ \ 114 | static int _detail_sval; \ 115 | _detail_sval = 0; \ 116 | struct _detail_val_t \ 117 | { \ 118 | _detail_val_t(const _detail_val_t& rhs) : _val(rhs) { _detail_sval = _val + 1; }\ 119 | _detail_val_t(int val) : _val(val) { _detail_sval = _val + 1; }\ 120 | _detail_val_t() : _val(_detail_sval){ _detail_sval = _val + 1; }\ 121 | \ 122 | _detail_val_t& operator=(const _detail_val_t&) { return *this; } \ 123 | _detail_val_t& operator=(int) { return *this; } \ 124 | operator int() const { return _val; } \ 125 | int _val; \ 126 | } __VA_ARGS__; \ 127 | const int _detail_vals[] = { __VA_ARGS__ }; \ 128 | return ::EnumReflector( _detail_vals, sizeof(_detail_vals)/sizeof(int), \ 129 | #enumName, Z_ENUM_DETAIL_STR((__VA_ARGS__)) ); \ 130 | }() ); \ 131 | return _reflector; \ 132 | } 133 | 134 | // EnumReflector 135 | 136 | inline EnumReflector::EnumReflector(EnumReflector&& rhs) 137 | : _data(rhs._data) 138 | { 139 | rhs._data = nullptr; 140 | } 141 | 142 | template 143 | inline const EnumReflector & EnumReflector::For(EnumType val) 144 | { 145 | return _detail_reflector_(val); 146 | } 147 | 148 | inline EnumReflector::Enumerator EnumReflector::At(int index) const 149 | { 150 | return Enumerator(*this, index); 151 | } 152 | 153 | inline EnumReflector::Enumerator EnumReflector::operator[](int index) const 154 | { 155 | return At(index); 156 | } 157 | 158 | inline EnumReflector::Enumerator EnumReflector::begin() const 159 | { 160 | return At(0); 161 | } 162 | 163 | inline EnumReflector::Enumerator EnumReflector::end() const 164 | { 165 | return At(Count()); 166 | } 167 | 168 | // EnumReflector::Enumerator 169 | 170 | inline EnumReflector::Enumerator::Enumerator(const EnumReflector& er, int index) 171 | : _er(er) 172 | , _index(index) 173 | { 174 | } 175 | 176 | inline int EnumReflector::Enumerator::Index() const 177 | { 178 | return _index; 179 | } 180 | 181 | inline const EnumReflector& EnumReflector::Enumerator::Reflector() const 182 | { 183 | return _er; 184 | } 185 | 186 | inline EnumReflector::Enumerator::operator bool() const 187 | { 188 | return IsValid(); 189 | } 190 | 191 | inline bool EnumReflector::Enumerator::IsValid() const 192 | { 193 | return _index < _er.Count(); 194 | } 195 | 196 | inline bool EnumReflector::Enumerator::operator!=(const Enumerator& rhs) const 197 | { 198 | return _index != rhs._index; 199 | } 200 | 201 | inline EnumReflector::Enumerator& EnumReflector::Enumerator::operator++() 202 | { 203 | ++_index; 204 | return *this; 205 | } 206 | 207 | inline const EnumReflector::Enumerator& EnumReflector::Enumerator::operator*() const 208 | { 209 | return *this; 210 | } 211 | 212 | #endif//GUARD -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Yakov Litvitskiy 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Test.cpp: -------------------------------------------------------------------------------- 1 | #include "EnumReflection.h" 2 | 3 | #include 4 | using std::cout; 5 | using std::endl; 6 | 7 | 8 | 9 | Z_ENUM_NS( CardSuit, 10 | Spades, 11 | Hearts, 12 | Diamonds, 13 | Clubs 14 | ) 15 | 16 | class SomeClass 17 | { 18 | public: 19 | static const int Constant = 100; 20 | Z_ENUM( TasteFlags, 21 | None = 0, 22 | Salted = 1 << 0, 23 | Sour = 1 << 1, 24 | Sweet = 1 << 2, 25 | SourSweet = (Sour | Sweet), 26 | Other = Constant, 27 | Last 28 | ) 29 | }; 30 | 31 | namespace SomeNamespace 32 | { 33 | Z_ENUM_NS( Ports, 34 | HTTP = 80, 35 | HTTPS = 443, 36 | SSH = 22 37 | ) 38 | 39 | } 40 | 41 | namespace AnotherNamespace 42 | { 43 | static int GetPort(const std::string& name) 44 | { 45 | const auto& port = EnumReflector::For<::SomeNamespace::Ports>().Find(name); 46 | return port.IsValid() ? port.Value() : 0; 47 | } 48 | } 49 | 50 | int main() 51 | { 52 | auto& reflector = EnumReflector::For(); 53 | 54 | cout << "Enum " << reflector.EnumName() << endl; 55 | for (auto& val : reflector) 56 | { 57 | cout << "Value " << val.Name() << " = " << val.Value() << endl; 58 | } 59 | cout << endl; 60 | /////////////////////// 61 | 62 | using AnotherNamespace::GetPort; 63 | 64 | cout << "HTTPS port: " << GetPort("HTTPS") << endl; 65 | 66 | constexpr bool b = std::is_enum::value; 67 | } --------------------------------------------------------------------------------