Gorgon Game Engine
Enum.h
Go to the documentation of this file.
1 
3 #pragma once
4 
5 #include <string>
6 #include <iostream>
7 #include <map>
8 #include <vector>
9 #include "String/Exceptions.h"
10 
12 class gorgon__no_enum_trait {
13 public:
14  static const bool isupgradedenum=false;
15 };
17 
18 template<class T_>
19 gorgon__no_enum_trait gorgon__enum_tr_loc(T_);
20 
21 namespace Gorgon {
22 
94 
97  template<class T_>
98  class expandedenumtraits {
99  public:
100  static_assert(decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, "Should be an enum");
101 
102  expandedenumtraits() {
103  T_ prev=traits.mapping.begin()->first;
104  listing.push_back(prev);
105  for(auto p : traits.mapping) {
106  for(auto &c : p.second) c=tolower(c);
107 
108  reversemapping.insert(std::make_pair(p.second, p.first));
109  if(p.first!=prev) {
110  listing.push_back(p.first);
111  prev=p.first;
112  }
113  }
114  }
115 
116  bool lookupstring(T_ e, std::string &s) const {
117  auto item=traits.mapping.find(e);
118  if(item==traits.mapping.end()) return false;
119  s=item->second;
120  return true;
121  }
122 
123  bool lookupvalue(std::string s, T_ &e) const {
124  for(auto &c : s) c=tolower(c);
125 
126  auto item=reversemapping.find(s);
127  if(item==reversemapping.end()) return false;
128  e=item->second;
129  return true;
130  }
131 
132  typename std::vector<T_>::const_iterator
133  begin() const {
134  return listing.begin();
135  }
136 
137  typename std::vector<T_>::const_iterator
138  end() const {
139  return listing.end();
140  }
141 
142  private:
143  const decltype(gorgon__enum_tr_loc(T_())) traits;
144  std::map<std::string, T_> reversemapping;
145  std::vector<T_> listing;
146  };
147 
149  template<class T_>
150  class staticenumtraits {
151  public:
152  static_assert(decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, "Should be an enum");
153 
154  static bool lookupstring(T_ e, std::string &s) {
155  return traits.lookupstring(e, s);
156  }
157 
158  static bool lookupvalue(const std::string &s, T_ &e) {
159  return traits.lookupvalue(s, e);
160  }
161 
162  static typename std::vector<T_>::const_iterator begin() {
163  return traits.begin();
164  }
165 
166  static typename std::vector<T_>::const_iterator end() {
167  return traits.end();
168  }
169 
170  static const expandedenumtraits<T_> traits;
171  };
172 
173  template<class T_>
174  const expandedenumtraits<T_> staticenumtraits<T_>::traits;
175 
176  template<class T_>
177  class enum_type_id {};
178 
180 
190  #define DefineEnumStrings(type, ...) \
191  class gorgon_enumtraits_##type {\
192  public:\
193  gorgon_enumtraits_##type() : mapping({__VA_ARGS__}) { }\
194  \
195  static const bool isupgradedenum=true;\
196  \
197  static const char *name() { return #type; }\
198  \
199  const std::multimap<type, std::string> mapping;\
200  };\
201  gorgon_enumtraits_##type gorgon__enum_tr_loc(type);
202 
213  #define DefineEnumStringsTN(type, typname, ...) \
214  class gorgon_enumtraits_##type {\
215  public:\
216  gorgon_enumtraits_##type() : mapping({__VA_ARGS__}) { }\
217  \
218  static const bool isupgradedenum=true;\
219  \
220  static const char *name() { return typname; }\
221  \
222  const std::multimap<type, std::string> mapping;\
223  };\
224  gorgon_enumtraits_##type gorgon__enum_tr_loc(type);
225 
235  #define DefineEnumStringsCM(clsname, type, ...) \
236  class gorgon_enumtraits_##type {\
237  public:\
238  gorgon_enumtraits_##type() : mapping({__VA_ARGS__}) { }\
239  \
240  static const bool isupgradedenum=true;\
241  \
242  static const char *name() { return #type; }\
243  \
244  const std::multimap<clsname::type, std::string> mapping;\
245  };\
246  gorgon_enumtraits_##type gorgon__enum_tr_loc(clsname::type);
247 
256  #define DefineEnumStringsCMTN(clsname, type, typname, ...) \
257  class gorgon_enumtraits_##type {\
258  public:\
259  gorgon_enumtraits_##type() : mapping({__VA_ARGS__}) { }\
260  \
261  static const bool isupgradedenum=true;\
262  \
263  static const char *name() { return typname; }\
264  \
265  const std::multimap<clsname::type, std::string> mapping;\
266  };\
267  gorgon_enumtraits_##type gorgon__enum_tr_loc(clsname::type);
268 
275  template<class T_>
276  typename std::enable_if<decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, enum_type_id<T_>>::type
278  return enum_type_id<T_>();
279  }
280 
281  template <class T_>
282  typename std::vector<T_>::const_iterator
283  begin(enum_type_id<T_>) {
285  }
286 
287  template <class T_>
288  typename std::vector<T_>::const_iterator end(enum_type_id<T_>) {
289  return staticenumtraits<T_>::end();
290  }
291 
292  namespace String {
293  template<class T_>
294  typename std::enable_if<decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, T_>::type
295  To(const std::string &text) {
296  T_ e;
297  if(!staticenumtraits<T_>::lookupvalue(text, e)) return T_();
298  return e;
299  }
300 
301  template<class T_>
302  typename std::enable_if<decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, std::string>::type
303  From(const T_ &e) {
304  std::string s;
305  if(!staticenumtraits<T_>::lookupstring(e, s)) return "";
306  return s;
307  }
308 
309  template<class T_>
310  typename std::enable_if<decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, T_>::type
311  Parse(const std::string &text) {
312  T_ e;
313  if(!staticenumtraits<T_>::lookupvalue(text, e)) {
314  std::string s ="\""+text+"\" is not a valid ";
315  s+=decltype(gorgon__enum_tr_loc(T_()))::name();
316  throw ParseError(20001, s);
317  }
318  return e;
319  }
320  }
321 }
322 
324 template<class T_>
325 typename std::enable_if<decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, std::ostream&>::type
326 operator <<(std::ostream &out, const T_ &e) {
327  std::string s;
328  if(!Gorgon::staticenumtraits<T_>::lookupstring(e, s)) return out;
329  out<<s;
330 
331  return out;
332 }
333 
335 template<class T_>
336 typename std::enable_if<decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, std::istream&>::type
337 operator >>(std::istream &in, T_ &e) {
338  std::string s;
339  e=T_();
340  in>>s;
341  if(!Gorgon::staticenumtraits<T_>::lookupvalue(s, e)) in.setstate(in.badbit);
342 
343  return in;
344 }
345 
346 namespace std {
348  template<class T_>
349  typename std::enable_if<decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, std::istream&>::type
350  getline(std::istream &in, T_ &e) {
351  std::string s;
352  e=T_();
353  std::getline(in, s);
354  unsigned i=0;
355  while(s.length()>i && isspace(s[i])) i++;
356  s=s.substr(i);
357 
358  if(!Gorgon::staticenumtraits<T_>::lookupvalue(s, e)) in.setstate(in.badbit);
359 
360  return in;
361  }
362 }
Gorgon::String::From
std::enable_if< decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, std::string >::type From(const T_ &e)
Definition: Enum.h:303
Gorgon::Enumerate
std::enable_if< decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, enum_type_id< T_ > >::type Enumerate()
Allows enumeration of upgraded enums using range based for.
Definition: Enum.h:277
Gorgon::begin
std::vector< T_ >::const_iterator begin(enum_type_id< T_ >)
Definition: Enum.h:283
gorgon__enum_tr_loc
gorgon__no_enum_trait gorgon__enum_tr_loc(T_)
Gorgon::Graphics::internal::isspace
bool isspace(Glyph g)
Definition: Font.cpp:96
Gorgon
Root namespace for Gorgon Game Engine.
Definition: Any.h:19
Gorgon::String::ParseError
This error will be thrown if a parsing function encounters with a general error.
Definition: Exceptions.h:10
std::getline
std::enable_if< decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, std::istream & >::type getline(std::istream &in, T_ &e)
Stream reader for upgraded enums.
Definition: Enum.h:350
Gorgon::String::To
std::enable_if< decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, T_ >::type To(const std::string &text)
Definition: Enum.h:295
Gorgon::end
std::vector< T_ >::const_iterator end(enum_type_id< T_ >)
Definition: Enum.h:288
Exceptions.h
Exceptions This file contains string related exceptions.
Gorgon::String::Parse
std::enable_if< decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, T_ >::type Parse(const std::string &text)
Definition: Enum.h:311