11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
23PROMEKI_NAMESPACE_BEGIN
116 PROMEKI_DATATYPE(Enum, DataTypeEnum, 1)
119 Error writeToStream(DataStream &s) const;
121 template <uint32_t V> static Result<Enum> readFromStream(DataStream &s);
124 static constexpr
int InvalidValue = -1;
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;
182 mutable StringLiteralData *nameLit =
nullptr;
191 mutable StringLiteralData *entryNameLits =
nullptr;
212 mutable StringLiteralData *entryQualifiedLits =
nullptr;
215 const Entry *findByName(
const String &n)
const;
217 const Entry *findByValue(
int v)
const;
233 bool isValid()
const {
return _def !=
nullptr; }
257 const Definition *definition()
const {
return _def; }
260 bool operator==(
const Type &o)
const {
return _def == o._def; }
261 bool operator!=(
const Type &o)
const {
return _def != o._def; }
264 bool operator<(
const Type &o)
const {
return _def < o._def; }
268 explicit Type(
const Definition *def) : _def(def) {}
269 const Definition *_def =
nullptr;
274 using Value = Pair<String, int>;
277 using ValueList = ::promeki::List<Value>;
280 using TypeList = StringList;
300 static Type registerDefinition(Definition *def);
332 static Type registerType(
const String &typeName,
const ValueList &values,
int defaultValue);
339 static Type findType(
const String &typeName);
342 static TypeList registeredTypes();
352 static ValueList values(Type type);
359 static int defaultValue(Type type);
374 static Result<int> valueOf(Type type,
const String &name);
383 static String nameOf(Type type,
int value, Error *err =
nullptr);
403 static Enum lookup(
const String &text, Error *err =
nullptr);
413 static Result<Enum> fromString(
const String &text) {
415 Enum e = lookup(text, &err);
416 if (err.isError())
return makeError<Enum>(err);
417 return makeResult(e);
431 explicit Enum(Type type);
442 Enum(Type type,
int value) : _def(type._def), _value(value) {}
453 Enum(Type type,
const String &name);
456 Type type()
const {
return Type(_def); }
459 int value()
const {
return _value; }
468 String valueName()
const;
471 String typeName()
const;
488 String toString()
const;
500 bool isValid()
const;
509 bool hasListedValue()
const;
512 bool operator==(
const Enum &o)
const {
return _def == o._def && _value == o._value; }
513 bool operator!=(
const Enum &o)
const {
return !(*
this == o); }
516 const Definition *_def =
nullptr;
517 int _value = InvalidValue;
569template <
typename Derived>
class TypedEnum :
public Enum {
578 TypedEnum() : Enum(Derived::Type) {}
587 explicit TypedEnum(
int value) : Enum(Derived::Type, value) {}
596 explicit TypedEnum(
const String &name) : Enum(Derived::Type, name) {}
602 constexpr bool enumStrEqual(
const char *a,
const char *b) {
603 while (*a !=
'\0' && *b !=
'\0') {
604 if (*a != *b)
return false;
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;
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;
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), \
693 static inline const ::promeki::Enum::Type Type = ::promeki::Enum::registerDefinition(&_promeki_enum_def_)
695PROMEKI_FORMAT_VIA_TOSTRING(promeki::Enum);