BeeeOn Gateway  v2020.3.1-2-g6f737dc
Platform to interconnect the IoT world
Enum.h
1 #pragma once
2 
3 #include <Poco/Exception.h>
4 #include <Poco/Logger.h>
5 #include <Poco/Random.h>
6 
7 #include <map>
8 #include <string>
9 
10 namespace BeeeOn {
11 
15 template <typename Raw>
16 struct EnumHelper {
20  typedef std::map<Raw, std::string> ValueMap;
25  typedef typename ValueMap::const_iterator Value;
29  typedef std::map<Raw, Value> RawMap;
33  typedef std::map<std::string, Value> NamesMap;
34 
35  static RawMap initRawMap(const ValueMap &valueMap)
36  {
37  RawMap rawMap;
38 
39  for (Value it = valueMap.begin(); it != valueMap.end(); ++it) {
40  auto result = rawMap.insert(std::make_pair(it->first, it));
41  if (!result.second)
42  throw Poco::ExistsException(
43  "duplicate raw value " + std::to_string(it->first));
44  }
45 
46  return rawMap;
47  }
48 };
49 
50 template <typename Raw>
52  typedef typename EnumHelper<Raw>::Value Value;
53  typedef typename EnumHelper<Raw>::ValueMap ValueMap;
54  typedef typename EnumHelper<Raw>::NamesMap NamesMap;
55 
56  EnumNamesInitializer(const NamesMap &map):
57  namesMap(map)
58  {
59  }
60 
61  EnumNamesInitializer(const ValueMap &valueMap):
62  namesMap(initNamesMap(valueMap))
63  {
64  }
65 
66  static NamesMap initNamesMap(const ValueMap &valueMap)
67  {
68  NamesMap namesMap;
69 
70  for (Value it = valueMap.begin(); it != valueMap.end(); ++it) {
71  auto result = namesMap.insert(std::make_pair(it->second, it));
72  if (!result.second)
73  throw Poco::ExistsException(
74  "duplicate string value " + it->second);
75  }
76 
77  return namesMap;
78  }
79 
80  const NamesMap namesMap;
81 };
82 
104 template <typename Base, typename RawType = typename Base::Raw,
105  typename NamesMapInitializer = EnumNamesInitializer<RawType>>
106 class Enum : public Base {
107 public:
108  typedef RawType Raw;
110 
111  typedef typename EnumHelper<Raw>::ValueMap ValueMap;
112  typedef typename EnumHelper<Raw>::Value Value;
113 
114  Enum(const Raw &raw):
115  Enum(fromRaw(raw).m_value)
116  {
117  }
118 
119 private:
120  Enum(const Value &value):
121  m_value(value)
122  {
123  if (value == Base::valueMap().end()) {
124  if (Base::valueMap().empty()) {
125  throw Poco::IllegalStateException(
126  "attempt to create enum that is empty");
127  }
128 
129  // this is certainly a bug in the Enum class
130  throw Poco::IllegalStateException(
131  "invalid enum value determined");
132  }
133  }
134 
138  class Iterator {
139  public:
140  Iterator(typename EnumHelper<Raw>::RawMap::const_iterator current):
141  m_current(current)
142  {
143  }
144 
145  Iterator &operator ++()
146  {
147  ++m_current;
148  return *this;
149  }
150 
151  Iterator operator ++(int)
152  {
153  return Iterator(m_current++);
154  }
155 
156  bool operator ==(const Iterator &it) const
157  {
158  return m_current == it.m_current;
159  }
160 
161  bool operator !=(const Iterator &it) const
162  {
163  return m_current != it.m_current;
164  }
165 
166  ThisEnum operator *()
167  {
168  return ThisEnum(m_current->second);
169  }
170 
171  private:
172  typename EnumHelper<Raw>::RawMap::const_iterator m_current;
173  };
174 
180  class Iterable {
181  public:
182  Iterator begin() const
183  {
184  return Iterator(rawMap().begin());
185  }
186 
187  Iterator end() const
188  {
189  return Iterator(rawMap().end());
190  }
191  };
192 
193 protected:
194  static typename EnumHelper<Raw>::RawMap &rawMap()
195  {
196  static typename EnumHelper<Raw>::RawMap rawMap(
197  EnumHelper<Raw>::initRawMap(Base::valueMap())
198  );
199 
200  return rawMap;
201  }
202 
203  static const typename EnumHelper<Raw>::NamesMap &namesMap()
204  {
205  static NamesMapInitializer initializer(Base::valueMap());
206  return initializer.namesMap;
207  }
208 
209 public:
210  Raw raw() const
211  {
212  return m_value->first;
213  }
214 
215  const std::string &toString() const
216  {
217  return m_value->second;
218  }
219 
220  static const Iterable &all()
221  {
222  static const Iterable it;
223  return it;
224  }
225 
226  static ThisEnum parse(const std::string &input)
227  {
228  auto it = namesMap().find(input);
229  if (it == namesMap().end()) {
230  throw Poco::InvalidArgumentException(
231  "failed to parse '" + input + "'");
232  }
233 
234  return ThisEnum(it->second);
235  }
236 
237  static ThisEnum fromRaw(const Raw &raw)
238  {
239  auto it = rawMap().find(raw);
240  if (it == rawMap().end()) {
241  throw Poco::InvalidArgumentException(
242  "unrecognized raw value " + std::to_string(raw));
243  }
244 
245  return ThisEnum(it->second);
246  }
247 
248  static ThisEnum random()
249  {
250  Poco::Random rnd;
251  rnd.seed();
252 
253  const std::size_t index = rnd.next(Base::valueMap().size());
254  Value it = Base::valueMap().begin();
255 
256  for (std::size_t k = 0; it != Base::valueMap().end(); ++it, ++k) {
257  if (k == index)
258  break;
259  }
260 
261  return ThisEnum(it);
262  }
263 
264  static ThisEnum fromRaw(const unsigned int raw)
265  {
266  return fromRaw(Raw(raw));
267  }
268 
269  operator Raw() const
270  {
271  return raw();
272  }
273 
274  bool operator ==(const Enum &other) const
275  {
276  return m_value == other.m_value;
277  }
278 
279  bool operator ==(const Enum::Raw &other) const
280  {
281  return m_value->first == other;
282  }
283 
284  bool operator !=(const Enum &other) const
285  {
286  return m_value != other.m_value;
287  }
288 
289  bool operator !=(const Enum::Raw &other) const
290  {
291  return m_value->first != other;
292  }
293 
294  bool operator <(const Enum &other) const
295  {
296  return m_value->first < other.m_value->first;
297  }
298 
299  bool operator <(const Enum::Raw &other) const
300  {
301  return m_value->first < other;
302  }
303 
304  bool operator >(const Enum &other) const
305  {
306  return m_value->first > other.m_value->first;
307  }
308 
309  bool operator >(const Enum::Raw &other) const
310  {
311  return m_value->first > other;
312  }
313 
314  bool operator <=(const Enum &other) const
315  {
316  return m_value->first <= other.m_value->first;
317  }
318 
319  bool operator <=(const Enum::Raw &other) const
320  {
321  return m_value->first <= other;
322  }
323 
324  bool operator >=(const Enum &other) const
325  {
326  return m_value->first >= other.m_value->first;
327  }
328 
329  bool operator >=(const Enum::Raw &other) const
330  {
331  return m_value->first >= other;
332  }
333 
334 private:
335  Value m_value;
336 };
337 
338 template <typename Base, typename Raw = typename Base::Raw,
339  typename NamesMapInitializer = EnumNamesInitializer<Raw>>
340 inline std::string operator +(const std::string &s, const Enum<Base, Raw, NamesMapInitializer> &e)
341 {
342  return s + e.toString();
343 }
344 
345 template <typename Base, typename Raw = typename Base::Raw,
346  typename NamesMapInitializer = EnumNamesInitializer<Raw>>
347 inline std::string operator +(const char *s, const Enum<Base, Raw, NamesMapInitializer> &e)
348 {
349  return s + e.toString();
350 }
351 
352 }
std::map< std::string, Value > NamesMap
Definition: Enum.h:33
std::map< Raw, Value > RawMap
Definition: Enum.h:29
Definition: Enum.h:16
Definition: Enum.h:106
ValueMap::const_iterator Value
Definition: Enum.h:25
std::map< Raw, std::string > ValueMap
Definition: Enum.h:20
Definition: Enum.h:51