libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
enum.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
13#include <cstdint>
14#include <promeki/namespace.h>
15#include <promeki/string.h>
16#include <promeki/stringlist.h>
17#include <promeki/list.h>
18#include <promeki/pair.h>
19#include <promeki/error.h>
20#include <promeki/result.h>
21#include <promeki/datatype.h>
22
23PROMEKI_NAMESPACE_BEGIN
24
25class DataStream;
26
114class Enum {
115 public:
116 PROMEKI_DATATYPE(Enum, DataTypeEnum, 1)
117
118
119 Error writeToStream(DataStream &s) const;
121 template <uint32_t V> static Result<Enum> readFromStream(DataStream &s);
122
124 static constexpr int InvalidValue = -1;
125
134 struct Entry {
135 const char *name;
136 int value;
137 };
138
165 struct Definition {
166 const char *name = nullptr;
167 const Entry *entries = nullptr;
168 size_t entryCount = 0;
169 int defaultValue = InvalidValue;
170 mutable uint32_t typeIndex = 0;
171
182 mutable StringLiteralData *nameLit = nullptr;
183
191 mutable StringLiteralData *entryNameLits = nullptr;
192
212 mutable StringLiteralData *entryQualifiedLits = nullptr;
213
215 const Entry *findByName(const String &n) const;
217 const Entry *findByValue(int v) const;
218 };
219
227 class Type {
228 public:
230 Type() = default;
231
233 bool isValid() const { return _def != nullptr; }
234
236 String name() const;
237
247 uint32_t id() const;
248
257 const Definition *definition() const { return _def; }
258
260 bool operator==(const Type &o) const { return _def == o._def; }
261 bool operator!=(const Type &o) const { return _def != o._def; }
262
264 bool operator<(const Type &o) const { return _def < o._def; }
265
266 private:
267 friend class Enum;
268 explicit Type(const Definition *def) : _def(def) {}
269 const Definition *_def = nullptr;
270 };
271
274 using Value = Pair<String, int>;
275
277 using ValueList = ::promeki::List<Value>;
278
280 using TypeList = StringList;
281
300 static Type registerDefinition(Definition *def);
301
332 static Type registerType(const String &typeName, const ValueList &values, int defaultValue);
333
339 static Type findType(const String &typeName);
340
342 static TypeList registeredTypes();
343
352 static ValueList values(Type type);
353
359 static int defaultValue(Type type);
360
374 static Result<int> valueOf(Type type, const String &name);
375
383 static String nameOf(Type type, int value, Error *err = nullptr);
384
403 static Enum lookup(const String &text, Error *err = nullptr);
404
413 static Result<Enum> fromString(const String &text) {
414 Error err;
415 Enum e = lookup(text, &err);
416 if (err.isError()) return makeError<Enum>(err);
417 return makeResult(e);
418 }
419
421 Enum() = default;
422
431 explicit Enum(Type type);
432
442 Enum(Type type, int value) : _def(type._def), _value(value) {}
443
453 Enum(Type type, const String &name);
454
456 Type type() const { return Type(_def); }
457
459 int value() const { return _value; }
460
468 String valueName() const;
469
471 String typeName() const;
472
488 String toString() const;
489
500 bool isValid() const;
501
509 bool hasListedValue() const;
510
512 bool operator==(const Enum &o) const { return _def == o._def && _value == o._value; }
513 bool operator!=(const Enum &o) const { return !(*this == o); }
514
515 private:
516 const Definition *_def = nullptr;
517 int _value = InvalidValue;
518};
519
569template <typename Derived> class TypedEnum : public Enum {
570 public:
578 TypedEnum() : Enum(Derived::Type) {}
579
587 explicit TypedEnum(int value) : Enum(Derived::Type, value) {}
588
596 explicit TypedEnum(const String &name) : Enum(Derived::Type, name) {}
597};
598
599namespace detail {
600
602 constexpr bool enumStrEqual(const char *a, const char *b) {
603 while (*a != '\0' && *b != '\0') {
604 if (*a != *b) return false;
605 ++a;
606 ++b;
607 }
608 return *a == *b;
609 }
610
612 consteval bool enumEntriesUnique(const Enum::Entry *entries, size_t count) {
613 for (size_t i = 0; i < count; ++i) {
614 for (size_t j = i + 1; j < count; ++j) {
615 if (enumStrEqual(entries[i].name, entries[j].name)) return false;
616 if (entries[i].value == entries[j].value) return false;
617 }
618 }
619 return true;
620 }
621
623 consteval bool enumHasDefault(const Enum::Entry *entries, size_t count, int def) {
624 for (size_t i = 0; i < count; ++i) {
625 if (entries[i].value == def) return true;
626 }
627 return false;
628 }
629
630} // namespace detail
631
632PROMEKI_NAMESPACE_END
633
675#define PROMEKI_REGISTER_ENUM_TYPE(TypeName, Default, ...) \
676 static constexpr ::promeki::Enum::Entry _promeki_enum_entries_[] = {__VA_ARGS__}; \
677 static_assert(sizeof(_promeki_enum_entries_) / sizeof(_promeki_enum_entries_[0]) > 0, \
678 "Enum type '" TypeName "' has no entries"); \
679 static_assert(::promeki::detail::enumEntriesUnique(_promeki_enum_entries_, \
680 sizeof(_promeki_enum_entries_) / \
681 sizeof(_promeki_enum_entries_[0])), \
682 "Enum type '" TypeName "' has duplicate name or value"); \
683 static_assert(::promeki::detail::enumHasDefault( \
684 _promeki_enum_entries_, \
685 sizeof(_promeki_enum_entries_) / sizeof(_promeki_enum_entries_[0]), (Default)), \
686 "Enum type '" TypeName "' default value not in entry table"); \
687 static inline ::promeki::Enum::Definition _promeki_enum_def_{.name = TypeName, \
688 .entries = _promeki_enum_entries_, \
689 .entryCount = sizeof(_promeki_enum_entries_) / \
690 sizeof(_promeki_enum_entries_[0]), \
691 .defaultValue = (Default), \
692 .typeIndex = 0}; \
693 static inline const ::promeki::Enum::Type Type = ::promeki::Enum::registerDefinition(&_promeki_enum_def_)
694
695PROMEKI_FORMAT_VIA_TOSTRING(promeki::Enum);
696
697#endif // PROMEKI_ENABLE_CORE