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 <type_traits>
15#include <promeki/namespace.h>
16#include <promeki/string.h>
17#include <promeki/stringlist.h>
18#include <promeki/list.h>
19#include <promeki/pair.h>
20#include <promeki/error.h>
21#include <promeki/result.h>
22#include <promeki/datatype.h>
23
24PROMEKI_NAMESPACE_BEGIN
25
26class DataStream;
27
116class Enum {
117 public:
118 PROMEKI_DATATYPE(Enum, DataTypeEnum, 1)
119
120
121 Error writeToStream(DataStream &s) const;
123 template <uint32_t V> static Result<Enum> readFromStream(DataStream &s);
124
126 static constexpr int InvalidValue = -1;
127
146 struct Entry {
147 const char *name;
148 int value;
149 const char *displayName = nullptr;
150 };
151
178 struct Definition {
179 const char *name = nullptr;
180 const Entry *entries = nullptr;
181 size_t entryCount = 0;
182 int defaultValue = InvalidValue;
183 mutable uint32_t typeIndex = 0;
184
199 const char *displayName = nullptr;
200
211 mutable StringLiteralData *nameLit = nullptr;
212
220 mutable StringLiteralData *entryNameLits = nullptr;
221
241 mutable StringLiteralData *entryQualifiedLits = nullptr;
242
250 mutable StringLiteralData *displayNameLit = nullptr;
251
266 mutable StringLiteralData *entryDisplayLits = nullptr;
267
269 const Entry *findByName(const String &n) const;
271 const Entry *findByValue(int v) const;
272 };
273
281 class Type {
282 public:
284 Type() = default;
285
287 bool isValid() const { return _def != nullptr; }
288
290 String name() const;
291
304 String displayName() const;
305
315 uint32_t id() const;
316
325 const Definition *definition() const { return _def; }
326
328 bool operator==(const Type &o) const { return _def == o._def; }
329 bool operator!=(const Type &o) const { return _def != o._def; }
330
332 bool operator<(const Type &o) const { return _def < o._def; }
333
334 private:
335 friend class Enum;
336 explicit Type(const Definition *def) : _def(def) {}
337 const Definition *_def = nullptr;
338 };
339
342 using Value = Pair<String, int>;
343
345 using ValueList = ::promeki::List<Value>;
346
348 using TypeList = StringList;
349
368 static Type registerDefinition(Definition *def);
369
400 static Type registerType(const String &typeName, const ValueList &values, int defaultValue);
401
407 static Type findType(const String &typeName);
408
410 static TypeList registeredTypes();
411
420 static ValueList values(Type type);
421
427 static int defaultValue(Type type);
428
442 static Result<int> valueOf(Type type, const String &name);
443
451 static String nameOf(Type type, int value, Error *err = nullptr);
452
467 static String displayNameOf(Type type, int value, Error *err = nullptr);
468
487 static Enum lookup(const String &text, Error *err = nullptr);
488
497 static Result<Enum> fromString(const String &text) {
498 Error err;
499 Enum e = lookup(text, &err);
500 if (err.isError()) return makeError<Enum>(err);
501 return makeResult(e);
502 }
503
505 Enum() = default;
506
515 explicit Enum(Type type);
516
526 Enum(Type type, int value) : _def(type._def), _value(value) {}
527
537 Enum(Type type, const String &name);
538
540 Type type() const { return Type(_def); }
541
543 int value() const { return _value; }
544
552 String valueName() const;
553
564 String valueDisplayName() const;
565
567 String typeName() const;
568
578 String typeDisplayName() const;
579
595 String toString() const;
596
607 bool isValid() const;
608
616 bool hasListedValue() const;
617
619 bool operator==(const Enum &o) const { return _def == o._def && _value == o._value; }
620 bool operator!=(const Enum &o) const { return !(*this == o); }
621
622 private:
623 const Definition *_def = nullptr;
624 int _value = InvalidValue;
625};
626
676template <typename Derived> class TypedEnum : public Enum {
677 public:
685 TypedEnum() : Enum(Derived::Type) {}
686
694 explicit TypedEnum(int value) : Enum(Derived::Type, value) {}
695
703 explicit TypedEnum(const String &name) : Enum(Derived::Type, name) {}
704
714 friend bool operator==(const Derived &a, const Derived &b) {
715 return static_cast<const Enum &>(a) == static_cast<const Enum &>(b);
716 }
717
719 friend bool operator!=(const Derived &a, const Derived &b) { return !(a == b); }
720
731 template <typename Other>
732 requires(::std::is_base_of_v<TypedEnum<Other>, Other> && !::std::is_same_v<Other, Derived>)
733 friend bool operator==(const Derived &, const Other &) = delete;
734
736 template <typename Other>
737 requires(::std::is_base_of_v<TypedEnum<Other>, Other> && !::std::is_same_v<Other, Derived>)
738 friend bool operator!=(const Derived &, const Other &) = delete;
739};
740
741namespace detail {
742
744 constexpr bool enumStrEqual(const char *a, const char *b) {
745 while (*a != '\0' && *b != '\0') {
746 if (*a != *b) return false;
747 ++a;
748 ++b;
749 }
750 return *a == *b;
751 }
752
754 consteval bool enumEntriesUnique(const Enum::Entry *entries, size_t count) {
755 for (size_t i = 0; i < count; ++i) {
756 for (size_t j = i + 1; j < count; ++j) {
757 if (enumStrEqual(entries[i].name, entries[j].name)) return false;
758 if (entries[i].value == entries[j].value) return false;
759 }
760 }
761 return true;
762 }
763
765 consteval bool enumHasDefault(const Enum::Entry *entries, size_t count, int def) {
766 for (size_t i = 0; i < count; ++i) {
767 if (entries[i].value == def) return true;
768 }
769 return false;
770 }
771
772} // namespace detail
773
774PROMEKI_NAMESPACE_END
775
825#define PROMEKI_REGISTER_ENUM_TYPE(TypeName, Default, ...) \
826 PROMEKI_REGISTER_ENUM_TYPE_DISPLAY(TypeName, nullptr, Default, __VA_ARGS__)
827
852#define PROMEKI_REGISTER_ENUM_TYPE_DISPLAY(TypeName, DisplayName, Default, ...) \
853 static constexpr ::promeki::Enum::Entry _promeki_enum_entries_[] = {__VA_ARGS__}; \
854 static_assert(sizeof(_promeki_enum_entries_) / sizeof(_promeki_enum_entries_[0]) > 0, \
855 "Enum type '" TypeName "' has no entries"); \
856 static_assert(::promeki::detail::enumEntriesUnique(_promeki_enum_entries_, \
857 sizeof(_promeki_enum_entries_) / \
858 sizeof(_promeki_enum_entries_[0])), \
859 "Enum type '" TypeName "' has duplicate name or value"); \
860 static_assert(::promeki::detail::enumHasDefault( \
861 _promeki_enum_entries_, \
862 sizeof(_promeki_enum_entries_) / sizeof(_promeki_enum_entries_[0]), (Default)), \
863 "Enum type '" TypeName "' default value not in entry table"); \
864 static inline ::promeki::Enum::Definition _promeki_enum_def_{.name = TypeName, \
865 .entries = _promeki_enum_entries_, \
866 .entryCount = sizeof(_promeki_enum_entries_) / \
867 sizeof(_promeki_enum_entries_[0]), \
868 .defaultValue = (Default), \
869 .typeIndex = 0, \
870 .displayName = (DisplayName)}; \
871 static inline const ::promeki::Enum::Type Type = ::promeki::Enum::registerDefinition(&_promeki_enum_def_)
872
873PROMEKI_FORMAT_VIA_TOSTRING(promeki::Enum);
874
875#endif // PROMEKI_ENABLE_CORE