11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
24PROMEKI_NAMESPACE_BEGIN
118 PROMEKI_DATATYPE(Enum, DataTypeEnum, 1)
121 Error writeToStream(DataStream &s) const;
123 template <uint32_t V> static Result<Enum> readFromStream(DataStream &s);
126 static constexpr
int InvalidValue = -1;
149 const char *displayName =
nullptr;
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;
199 const char *displayName =
nullptr;
211 mutable StringLiteralData *nameLit =
nullptr;
220 mutable StringLiteralData *entryNameLits =
nullptr;
241 mutable StringLiteralData *entryQualifiedLits =
nullptr;
250 mutable StringLiteralData *displayNameLit =
nullptr;
266 mutable StringLiteralData *entryDisplayLits =
nullptr;
269 const Entry *findByName(
const String &n)
const;
271 const Entry *findByValue(
int v)
const;
287 bool isValid()
const {
return _def !=
nullptr; }
304 String displayName()
const;
325 const Definition *definition()
const {
return _def; }
328 bool operator==(
const Type &o)
const {
return _def == o._def; }
329 bool operator!=(
const Type &o)
const {
return _def != o._def; }
332 bool operator<(
const Type &o)
const {
return _def < o._def; }
336 explicit Type(
const Definition *def) : _def(def) {}
337 const Definition *_def =
nullptr;
342 using Value = Pair<String, int>;
345 using ValueList = ::promeki::List<Value>;
348 using TypeList = StringList;
368 static Type registerDefinition(Definition *def);
400 static Type registerType(
const String &typeName,
const ValueList &values,
int defaultValue);
407 static Type findType(
const String &typeName);
410 static TypeList registeredTypes();
420 static ValueList values(Type type);
427 static int defaultValue(Type type);
442 static Result<int> valueOf(Type type,
const String &name);
451 static String nameOf(Type type,
int value, Error *err =
nullptr);
467 static String displayNameOf(Type type,
int value, Error *err =
nullptr);
487 static Enum lookup(
const String &text, Error *err =
nullptr);
497 static Result<Enum> fromString(
const String &text) {
499 Enum e = lookup(text, &err);
500 if (err.isError())
return makeError<Enum>(err);
501 return makeResult(e);
515 explicit Enum(Type type);
526 Enum(Type type,
int value) : _def(type._def), _value(value) {}
537 Enum(Type type,
const String &name);
540 Type type()
const {
return Type(_def); }
543 int value()
const {
return _value; }
552 String valueName()
const;
564 String valueDisplayName()
const;
567 String typeName()
const;
578 String typeDisplayName()
const;
595 String toString()
const;
607 bool isValid()
const;
616 bool hasListedValue()
const;
619 bool operator==(
const Enum &o)
const {
return _def == o._def && _value == o._value; }
620 bool operator!=(
const Enum &o)
const {
return !(*
this == o); }
623 const Definition *_def =
nullptr;
624 int _value = InvalidValue;
676template <
typename Derived>
class TypedEnum :
public Enum {
685 TypedEnum() : Enum(Derived::Type) {}
694 explicit TypedEnum(
int value) : Enum(Derived::Type, value) {}
703 explicit TypedEnum(
const String &name) : Enum(Derived::Type, name) {}
714 friend bool operator==(
const Derived &a,
const Derived &b) {
715 return static_cast<const Enum &
>(a) ==
static_cast<const Enum &
>(b);
719 friend bool operator!=(
const Derived &a,
const Derived &b) {
return !(a == b); }
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;
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;
744 constexpr bool enumStrEqual(
const char *a,
const char *b) {
745 while (*a !=
'\0' && *b !=
'\0') {
746 if (*a != *b)
return false;
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;
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;
825#define PROMEKI_REGISTER_ENUM_TYPE(TypeName, Default, ...) \
826 PROMEKI_REGISTER_ENUM_TYPE_DISPLAY(TypeName, nullptr, Default, __VA_ARGS__)
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), \
870 .displayName = (DisplayName)}; \
871 static inline const ::promeki::Enum::Type Type = ::promeki::Enum::registerDefinition(&_promeki_enum_def_)
873PROMEKI_FORMAT_VIA_TOSTRING(promeki::Enum);