Elementa v8.0.0
Minimalistic library for any C++ application (C++11 and up)
Loading...
Searching...
No Matches
enums.h
Go to the documentation of this file.
1
3#include "elementa/license.inc"
4#include "elementa/checks.inc"
5
6#ifndef ELEMENTA_BASE_ENUMS_H
7#define ELEMENTA_BASE_ENUMS_H
8
9#include <stdexcept>
10#include <string>
11#include <vector>
12#include <bitset>
13#include <initializer_list>
14#include <type_traits>
16
17
18namespace elementa
19{
20
21namespace base
22{
23
139/* ***************************************************************************
140
141 Template class: EnumExtPriv
142 Template subclass: EnumExtPriv::Combination
143
144*****************************************************************************/
145
147
155template <typename BaseID, class HelperIDString>
156class EnumExtPriv final
157{
158 public:
159
161 using IDBase = BaseID;
162
165 {
166 public:
167
169 class Iterator
170 {
171 public:
172
177
179 Iterator(const Combination & c, bool end = false) noexcept:
180 comb_{c}
181 { if (end) v_ = EnumExtPriv::kValue(BaseID::kAll_);
182 else
183 {
184 typename std::underlying_type<BaseID>::type f;
185 for (f=0; f<EnumExtPriv::kValue(BaseID::kAll_); f++)
186 if (comb_.has(EnumExtPriv::id(f))) break;
187 v_ = f;
188 }
189 }
190
191 // Destructor (non virtual), copies and moves by default.
192
196 BaseID operator*(void) const // may throw
197 { return(EnumExtPriv::id(v_)); }
198
200 Iterator & operator++(void) noexcept // may throw
201 { while (v_ < EnumExtPriv::kValue(BaseID::kAll_))
202 { ++v_; if (v_ == EnumExtPriv::kValue(BaseID::kAll_)) break;
203 if (comb_.has(EnumExtPriv::id(v_))) break; }
204 return(*this); }
205
207 Iterator operator++(int) noexcept
208 { Iterator old{*this}; this->operator++(); return(old); }
209
211 bool operator!=(const Iterator &o) const noexcept
212 { return((v_ != o.v_) || (comb_ != o.comb_)); }
213
215 bool operator==(const Iterator &o) const noexcept
216 { return((v_ == o.v_) && (comb_ == o.comb_)); }
217
218 private:
219
220 const Combination & comb_;
221 typename std::underlying_type<BaseID>::type v_;
222 };
223
224
225 using Initializer = std::initializer_list<BaseID>;
226
230 Combination(void) = default;
231 ~Combination(void) = default;
232
233 Combination(const Combination & tf) = default;
234 Combination & operator=(const Combination & tf) = default;
235
236 Combination(Combination &&) = default;
237 Combination & operator=(Combination &&) = default;
238
239
240 explicit Combination(BaseID f) // constructor from one or all flags
241 { activate(BaseID::kAll_); }
242
244
247 Combination(const Initializer & init)
248 { for (BaseID f: init) { add(f); if (f==BaseID::kAll_) break;} }
249
252 bool operator!=(const Combination &o) const noexcept
253 { return(bset_ != o.bset_); }
254 bool operator==(const Combination &o) const noexcept
255 { return(bset_ == o.bset_); }
256
257 size_t size(void) const noexcept
258 { return(bset_.count()); }
259
260 bool empty(void) const noexcept
261 { return(bset_.count() == 0); }
262
263 bool any(void) const
264 { return(bset_.any()); }
265
266 bool all(void) const
267 { return(bset_.all()); }
268
269 bool has(BaseID f) const
270 { if (f==BaseID::kAll_) return(all());
271 else return(bset_.test(EnumExtPriv::kValue(f))); }
272 bool has(const Combination & otf) const
273 { return((bset_ & otf.bset_) == otf.bset_); }
274
275 bool hasIntersection(const Combination & otf) const
276 { return((bset_ & otf.bset_).any()); }
277
278 void add(BaseID f)
279 { if (f==BaseID::kAll_) bset_.set();
280 else bset_.set(EnumExtPriv::kValue(f)); }
281 void add(const Combination & tf)
282 { bset_ |= tf.bset_; }
283
284 void remove(BaseID f)
285 { if (f==BaseID::kAll_) bset_.reset();
286 else bset_.reset(EnumExtPriv::kValue(f)); }
287 void remove(const Combination & tf)
288 { bset_ &= tf.bset_; }
289
291 std::string to_string(std::string delim=", ") const noexcept
292 { std::string res;
293 size_t c = size();
294 if (c > 0)
295 for (auto id: *this)
296 { res += EnumExtPriv::IdName(id); c--; if (c>0) res += delim; }
297 return(res); }
298
302 Iterator begin(void) const noexcept
303 { return(Iterator(*this)); }
304
305 Iterator end(void) const noexcept
306 { return(Iterator(*this,true)); }
307
311 private:
312
313 std::bitset< EnumExtPriv::kValue(BaseID::kAll_) > bset_{};
314 // bitset has no iterator in C++11, does it would not be of any benefit
315 // to expose this member
316 };
317
319 class Iterator
320 {
321 public:
322
326 Iterator(BaseID val = static_cast<BaseID>(0)) noexcept:
327 v_(EnumExtPriv::kValue(val))
328 {} // subclasses can access protected and private members of parent
329
330 // Destructor (non virtual), moves and copies by default.
331
335 BaseID operator*(void) const // may throw
336 { return(EnumExtPriv::id(v_)); }
337
339 Iterator & operator++(void) noexcept
340 { if (v_ < EnumExtPriv::kValue(BaseID::kAll_)) v_++; return(*this);}
341
343 Iterator operator++(int) noexcept
344 { Iterator old = *this; this->operator++(); return(old); }
345
347 bool operator!=(const Iterator &o) const noexcept
348 { return(v_ != o.v_); }
349
351 bool operator==(const Iterator &o) const noexcept
352 { return(v_ == o.v_); }
353
354 private:
355
356 typename std::underlying_type<BaseID>::type v_;
357 };
358
360 static constexpr size_t kSize(void) noexcept
361 { return(static_cast<size_t>(EnumExtPriv::kValue(BaseID::kAll_))); }
362
364 static BaseID first(void) { return(id(0)); }
365
367 static BaseID last(void)
368 { return(id(EnumExtPriv::kValue(BaseID::kAll_) - 1)); }
369
371#if (ELE_PRE_CPPVER != 2011) && (ELE_PRE_CPPVER != 2014)
372 static constexpr BaseID Nth(size_t n)
373#else
374 static BaseID Nth(size_t n)
375#endif
376 { return(id(static_cast<typename std::underlying_type<BaseID>::type>(
377 n))); }
378
380 static constexpr size_t pos(BaseID id) { return(kValue(id)); }
381
383
384 static BaseID findByName(const std::string & name)
385 {
386 auto res = BaseID::kAll_;
387 if (!name.empty())
388 for (auto m: theEnum()) if (IdName(m) == name) { res = m; break; }
389 return(res);
390 }
391
393
397 static std::string IdName(BaseID id, bool leavek = false)
398 { static std::vector<std::string> strs;
399 static int status{0};
400 static std::string nullstr;
401
402 if (id == BaseID::kAll_) return("<All>");
403 if (status==0) // only do this work once
404 {
405 strs = std::move(split(std::string{HelperIDString::IdNames()},','));
406 if (static_cast<size_t>(strs.size()) !=
407 static_cast<size_t>(EnumExtPriv::kValue(BaseID::kAll_)))
408 status = -1;
409 status = 1;
410 }
411 size_t ind = EnumExtPriv::kValue(id);
412 if ((status != 1) || (ind >= strs.size())) return("<enum-error>");
413 const auto & res = strs[EnumExtPriv::kValue(id)];
414 if (leavek || (res.size() < 2) ||
415 (res[0] != 'k') || (res[1] < 'A') || (res[1] > 'Z')) return(res);
416 return(res.substr(1));
417 }
418
420
423 static constexpr std::string kAllIdNames(void) noexcept
424 { return(HelperIDString::IdNames()); }
425
427
441 static EnumExtPriv & theEnum(void) noexcept
442 { static EnumExtPriv ie; return(ie); }
443
447 // The following cannot be static since they work on an object
448
449 Iterator begin(void) const noexcept
450 { return(Iterator()); }
451
452 Iterator end(void) const noexcept
453 { return(Iterator(BaseID::kAll_)); }
454
457 private:
458
459 // Not public for avoiding abuse of enum IDs like numbers
460 // (use iterations instead).
461
462 static constexpr typename std::underlying_type<BaseID>::type
463 kValue(BaseID id) noexcept // implicitly inline
464 { return(
465 static_cast<typename std::underlying_type<BaseID>::type>(id)); }
466
467#if (ELE_PRE_CPPVER != 2011) && (ELE_PRE_CPPVER != 2014)
468 static constexpr BaseID id(typename std::underlying_type<BaseID>::type v)
469#else
470 // cannot be constexpr for its structure
471 static BaseID id(typename std::underlying_type<BaseID>::type v)
472#endif
473 { if (v >= EnumExtPriv::kValue(BaseID::kAll_))
474 throw(std::out_of_range(""));
475 return(static_cast<BaseID>(v)); }
476
477 EnumExtPriv(void) = default;
478 // move implicitly declared
479 // destructor implicitly declared (non virtual)
480 // copies implictly declared
481
482};
483
484
485/* ***************************************************************************
486
487 Macro: ELE_CLASS_ENUM
488
489*****************************************************************************/
490
492
502#define ELE_CLASS_ENUM(NameEnumClass,...) \
503 enum class NameEnumClass { __VA_ARGS__ , kAll_ }; \
504 struct NameEnumClass##HelperIDString \
505 { \
506 static const char * IdNames(void) noexcept \
507 { return(#__VA_ARGS__); } \
508 }; \
509 using NameEnumClass##Enum = elementa::base::EnumExtPriv<\
510 NameEnumClass, \
511 NameEnumClass##HelperIDString>
512
513
514 // Enums
516
517
518} // end namespace base
519
520} // end namespace elementa
521
522#endif
523
Iterator over the elements of a combination.
Definition: enums.h:170
Iterator(const Combination &c, bool end=false) noexcept
Create an iterator on the given combination.
Definition: enums.h:179
BaseID operator*(void) const
De-referencing the iterator gives the value.
Definition: enums.h:196
Iterator operator++(int) noexcept
Postfix increment: return, then increment.
Definition: enums.h:207
Iterator & operator++(void) noexcept
Increment iterator (pre-fix: first increment, then return)
Definition: enums.h:200
bool operator==(const Iterator &o) const noexcept
Iterator equality.
Definition: enums.h:215
bool operator!=(const Iterator &o) const noexcept
Iterator unequality.
Definition: enums.h:211
A combination of several IDs. Not thread-safe.
Definition: enums.h:165
Combination(const Initializer &init)
Constructor from a set of flags.
Definition: enums.h:247
std::string to_string(std::string delim=", ") const noexcept
Return a string with the names of all the IDs in the combination.
Definition: enums.h:291
Iterator over the elements of an extended enum.
Definition: enums.h:320
BaseID operator*(void) const
De-referencing the iterator gives the value.
Definition: enums.h:335
bool operator!=(const Iterator &o) const noexcept
Iterator unequality.
Definition: enums.h:347
bool operator==(const Iterator &o) const noexcept
Iterator equality.
Definition: enums.h:351
Iterator operator++(int) noexcept
Postfix increment: return, then increment.
Definition: enums.h:343
Iterator & operator++(void) noexcept
Increment iterator (pre-fix: first increment, then return).
Definition: enums.h:339
static constexpr BaseID Nth(size_t n)
Return the n-th ID, or throw if out of range.
Definition: enums.h:372
static BaseID first(void)
Return the first ID.
Definition: enums.h:364
static constexpr std::string kAllIdNames(void) noexcept
Return a copy of all the ID names of the extended enum.
Definition: enums.h:423
static constexpr size_t kSize(void) noexcept
Return the number of IDs defined in the enum.
Definition: enums.h:360
BaseID IDBase
Just to leave the BaseID available here.
Definition: enums.h:161
static std::string IdName(BaseID id, bool leavek=false)
Return the string corresponding to the ID keyword, or "" if not defined.
Definition: enums.h:397
static BaseID findByName(const std::string &name)
Return the ID of a given enum from its name as a string.
Definition: enums.h:384
static EnumExtPriv & theEnum(void) noexcept
Access to the singleton object of this class.
Definition: enums.h:441
static constexpr size_t pos(BaseID id)
Return the position of the given ID, from 0, in the enum.
Definition: enums.h:380
static BaseID last(void)
Return the last ID.
Definition: enums.h:367
Implementation of all extended enum features. You will use its methods.
Definition: enums.h:157
std::vector< std::string > split(const std::string &s, char delim)
Split a string through a given delimiter.