Honeycomb  0.1
Component-Model Framework
Enum.h
Go to the documentation of this file.
1 // Honeycomb, Copyright (C) 2015 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
2 #pragma once
3 
4 #include "Honey/String/Id.h"
5 #include "Honey/Math/Numeral.h"
6 #include "Honey/Misc/Exception.h"
7 
8 namespace honey
9 {
10 
12 
70 
73 #define ENUM(Base, Class) \
74  class Class : public EnumElem \
75  { \
76  public: \
77  enum Enum \
78  { \
79  ENUM_ELEM_CALL(ENUM_E_ENUM, Base, Class) \
80  __VALMAX \
81  }; \
82  static const int valMax = __VALMAX; \
83  \
84  Class() {} \
85  \
86  Class(const Enum val) { operator=(val); } \
87  \
88  explicit Class(const int val) { operator=(static_cast<Enum>(enumInfo().elem(val).val)); } \
89  \
90  explicit Class(const Id& val) { operator=(static_cast<Enum>(enumInfo().elem(val).val)); } \
91  \
92  \
93  Class& operator=(const Enum rhs) { _val = rhs; return *this; } \
94  \
95  \
96  bool operator==(const Class& rhs) const { return val() == rhs.val(); } \
97  bool operator!=(const Class& rhs) const { return val() != rhs.val(); } \
98  bool operator< (const Class& rhs) const { return val() < rhs.val(); } \
99  bool operator> (const Class& rhs) const { return val() > rhs.val(); } \
100  bool operator<=(const Class& rhs) const { return val() <= rhs.val(); } \
101  bool operator>=(const Class& rhs) const { return val() >= rhs.val(); } \
102  \
103  bool operator==(const Enum rhs) const { return val() == rhs; } \
104  bool operator!=(const Enum rhs) const { return val() != rhs; } \
105  bool operator< (const Enum rhs) const { return val() < rhs; } \
106  bool operator> (const Enum rhs) const { return val() > rhs; } \
107  bool operator<=(const Enum rhs) const { return val() <= rhs; } \
108  bool operator>=(const Enum rhs) const { return val() >= rhs; } \
109  \
110  private: \
111  \
112  bool operator==(int) const { return false; } \
113  bool operator!=(int) const { return false; } \
114  bool operator< (int) const { return false; } \
115  bool operator> (int) const { return false; } \
116  bool operator<=(int) const { return false; } \
117  bool operator>=(int) const { return false; } \
118  template<class T> struct DisableCmp : mt::Value<bool, std::is_convertible<T,int>::value && !std::is_same<T,Enum>::value> {}; \
119  template<class T> friend typename std::enable_if<DisableCmp<T>::value, bool>::type operator==(const T&, const Class&) { static_assert(!mt::True<T>::value, "Enum compare type mismatch"); } \
120  template<class T> friend typename std::enable_if<DisableCmp<T>::value, bool>::type operator!=(const T&, const Class&) { static_assert(!mt::True<T>::value, "Enum compare type mismatch"); } \
121  template<class T> friend typename std::enable_if<DisableCmp<T>::value, bool>::type operator<=(const T&, const Class&) { static_assert(!mt::True<T>::value, "Enum compare type mismatch"); } \
122  template<class T> friend typename std::enable_if<DisableCmp<T>::value, bool>::type operator>=(const T&, const Class&) { static_assert(!mt::True<T>::value, "Enum compare type mismatch"); } \
123  template<class T> friend typename std::enable_if<DisableCmp<T>::value, bool>::type operator< (const T&, const Class&) { static_assert(!mt::True<T>::value, "Enum compare type mismatch"); } \
124  template<class T> friend typename std::enable_if<DisableCmp<T>::value, bool>::type operator> (const T&, const Class&) { static_assert(!mt::True<T>::value, "Enum compare type mismatch"); } \
125  \
126  public: \
127  \
128  const NameId& classId() const { return enumInfo().elem(val()).classId; } \
129  \
130  const NameId& id() const { return enumInfo().elem(val()).id; } \
131  \
132  friend ostream& operator<<(ostream& os, const Class& val) { return os << val.classId() << "::" << val.id(); } \
133  \
134  \
135  class EnumInfo : public EnumInfo_<Class> \
136  { \
137  friend class Class; \
138  \
139  EnumInfo() { ENUM_ELEM_CALL(ENUM_E_CTOR, Base, Class) this->setup(); } \
140  }; \
141  \
142  static const EnumInfo& enumInfo() { static const EnumInfo info; return info; } \
143  }; \
144 
145 
147 #define ENUM_ELEM_CALL(EFunc, Base, Class) ENUM_LIST(EFunc, STRINGIFY(IFEMPTY(, UNBRACKET(Base)::, Base)Class))
148 
149 #define ENUM_E_ENUM(...) EVAL(TOKCAT(ENUM_E_ENUM_, NUMARGS(__VA_ARGS__))(__VA_ARGS__))
150 #define ENUM_E_ENUM_2(ClassName, name) name,
151 #define ENUM_E_ENUM_4(ClassName, name, str, val) name IFEMPTY(,= UNBRACKET(val),val),
152 
153 #define ENUM_E_CTOR(...) EVAL(TOKCAT(ENUM_E_CTOR_, NUMARGS(__VA_ARGS__))(__VA_ARGS__))
154 #define ENUM_E_CTOR_2(ClassName, name) ENUM_E_CTOR_4(ClassName, name, EMPTY, EMPTY)
155 #define ENUM_E_CTOR_4(ClassName, name, str, val) this->addElem(ClassName, IFEMPTY(#name, str, str), name);
156 
158 //====================================================
159 // EnumElem
160 //====================================================
161 
163 
165 class EnumElem
166 {
167 public:
168  EnumElem() {}
169  EnumElem(int val) : _val(val) {}
170 
172  int val() const { return _val; }
174  operator int() const { return _val; }
175 
176 protected:
177  int _val;
178 };
179 
180 //====================================================
181 // EnumInfo
182 //====================================================
183 
185 template<class EnumType>
187 {
188  friend EnumType;
189 
190  typedef unordered_map<Id, int> IdElemMap;
191  typedef unordered_map<int, int> ValElemMap;
192  typedef vector<int> ValElemTable;
193 
194 public:
195  struct Elem
196  {
197  Elem(const String& className, const String& name, int val) :
198  classId(className), id(name), val(val) {}
199 
202  int val;
203  };
204 
205  typedef vector<Elem> ElemList;
206 
208  const ElemList& elemList() const { return _elemList; }
209 
211  const Elem& elem(const Id& id) const
212  {
213  IdElemMap::const_iterator it = _idElemMap.find(id);
214  if (it != _idElemMap.end()) return _elemList[it->second];
215  throw_ EnumError(); throw;
216  }
217 
219  const Elem& elem(int val) const
220  {
221  //Use lookup table if available
222  if (_valElemTable.size() > 0)
223  {
224  int index = val - _valMin;
225  if (index >= 0 && index < (int)_valElemTable.size() && _valElemTable[index] != -1) return _elemList[_valElemTable[index]];
226  throw_ EnumError();
227  }
228 
229  //Fall back to map
230  ValElemMap::const_iterator it = _valElemMap.find(val);
231  if (it != _valElemMap.end()) return _elemList[it->second];
232  throw_ EnumError(); throw;
233  }
234 
235 protected:
236 
237  EnumInfo_() : _valMin(0), _valMax(0) {}
238 
239  void addElem(const String& className, const String& name, int val)
240  {
241  _elemList.push_back(Elem(className, name, val));
242  _idElemMap[_elemList.back().id] = (int)_elemList.size()-1;
243 
244  //Track min/max values
245  if (_elemList.size() == 1)
246  {
247  _valMin = val;
248  _valMax = val;
249  }
250  else
251  {
252  if (val < _valMin) _valMin = val;
253  if (val > _valMax) _valMax = val;
254  }
255  }
256 
257  void setup()
258  {
259  //If range is small enough, use value lookup table instead of a map
260  int range = _valMax - _valMin;
261  if (range <= _tableRangeMax)
262  {
263  _valElemTable.resize(range + 1, -1);
264  for (int i = 0; i < (int)_elemList.size(); ++i)
265  _valElemTable[_elemList[i].val - _valMin] = i;
266  }
267  else
268  {
269  //Otherwise use a map
270  for (int i = 0; i < (int)_elemList.size(); ++i)
271  _valElemMap[_elemList[i].val] = i;
272  }
273  }
274 
275 private:
276  ElemList _elemList;
277  IdElemMap _idElemMap;
278  ValElemMap _valElemMap;
279 
280  static const int _tableRangeMax = 100;
281  ValElemTable _valElemTable;
282  int _valMin;
283  int _valMax;
284 };
285 
287 
288 }
const ElemList & elemList() const
Get all elements.
Definition: Enum.h:208
Definition: Enum.h:195
int val() const
Get integral value.
Definition: Enum.h:172
NameId classId
Definition: Enum.h:200
int val
Definition: Enum.h:202
Holds both a name string and its hashed value, and unlike Id the name is never compiled out...
Definition: Id.h:144
EnumInfo_()
Definition: Enum.h:237
void setup()
Definition: Enum.h:257
std::enable_if< mt::isIterator< Iter1 >::value, Range_< Iter1, Iter2 > >::type range(Iter1 &&first, Iter2 &&last)
Range from iterators [first, last)
Definition: Range.h:116
int _val
Definition: Enum.h:177
Elem(const String &className, const String &name, int val)
Definition: Enum.h:197
#define EXCEPTION(Class)
Declares methods required for every subclass of honey::Exception.
Definition: Exception.h:17
Definition: Enum.h:162
Run-time info about an enum class. Contains a list of elements and maps for element lookups...
Definition: Enum.h:186
void addElem(const String &className, const String &name, int val)
Definition: Enum.h:239
Unicode UTF-16 string class, wrapper around std::u16string.
Definition: String.h:23
vector< Elem > ElemList
Definition: Enum.h:205
const Elem & elem(int val) const
Get element by value, throws EnumError if not found.
Definition: Enum.h:219
Base exception class. Exceptions inherited from this class provide debug info and can be thrown polym...
Definition: Exception.h:45
#define throw_
Use in place of throw keyword to throw a honey::Exception object polymorphically and provide debug in...
Definition: Exception.h:11
EnumElem()
Definition: Enum.h:168
NameId id
Definition: Enum.h:201
Base class of all generated enum classes. A single element in the enumeration. See Enumeration Classe...
Definition: Enum.h:165
const Elem & elem(const Id &id) const
Get element by id, throws EnumError if not found.
Definition: Enum.h:211
Holds a name string and its hashed value for fast comparison ops. See String Identifier.
Definition: Id.h:25
Global Honeycomb namespace.
EnumElem(int val)
Definition: Enum.h:169