13#define FLECS_ENUM_MAX(T) _::to_constant<T, 126>::value
14#define FLECS_ENUM_MAX_COUNT (FLECS_ENUM_MAX(int) + 1)
17#ifdef FLECS_CPP_NO_ENUM_REFLECTION
18#define FLECS_CPP_ENUM_REFLECTION_SUPPORT 0
22#ifndef FLECS_CPP_ENUM_REFLECTION_SUPPORT
23#if !defined(__clang__) && defined(__GNUC__)
24#if __GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 5)
25#define FLECS_CPP_ENUM_REFLECTION_SUPPORT 1
27#define FLECS_CPP_ENUM_REFLECTION_SUPPORT 0
30#define FLECS_CPP_ENUM_REFLECTION_SUPPORT 1
34#if defined(__clang__) && __clang_major__ >= 16
36#define flecs_enum_cast(T, v) __builtin_bit_cast(T, v)
37#elif defined(__GNUC__) && __GNUC__ > 10
38#define flecs_enum_cast(T, v) __builtin_bit_cast(T, v)
40#define flecs_enum_cast(T, v) static_cast<T>(v)
48template <
typename E, underlying_type_t<E> Value>
50 static constexpr E value = flecs_enum_cast(E, Value);
53template <
typename E, underlying_type_t<E> Value>
54constexpr E to_constant<E, Value>::value;
74 static constexpr E value = FLECS_ENUM_MAX(E);
78#define FLECS_ENUM_LAST(T, Last)\
81 struct enum_last<T> {\
82 static constexpr T value = Last;\
88#if INTPTR_MAX == INT64_MAX
89 #ifdef ECS_TARGET_MSVC
91 #define ECS_SIZE_T_STR "unsigned __int64"
93 #define ECS_SIZE_T_STR "unsigned int"
95 #elif defined(__clang__)
96 #define ECS_SIZE_T_STR "size_t"
98 #ifdef ECS_TARGET_WINDOWS
99 #define ECS_SIZE_T_STR "constexpr size_t; size_t = long long unsigned int"
101 #define ECS_SIZE_T_STR "constexpr size_t; size_t = long unsigned int"
105 #ifdef ECS_TARGET_MSVC
107 #define ECS_SIZE_T_STR "unsigned __int32"
109 #define ECS_SIZE_T_STR "unsigned int"
111 #elif defined(__clang__)
112 #define ECS_SIZE_T_STR "size_t"
114 #ifdef ECS_TARGET_WINDOWS
115 #define ECS_SIZE_T_STR "constexpr size_t; size_t = unsigned int"
117 #define ECS_SIZE_T_STR "constexpr size_t; size_t = unsigned int"
124constexpr size_t enum_type_len() {
125 return ECS_FUNC_TYPE_LEN(, enum_type_len, ECS_FUNC_NAME)
126 - (
sizeof(ECS_SIZE_T_STR) - 1u);
134#if defined(ECS_TARGET_CLANG)
135#if ECS_CLANG_VERSION < 13
136template <
typename E, E C>
137constexpr bool enum_constant_is_valid() {
139 (ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(
bool, enum_constant_is_valid) +
140 enum_type_len<E>() + 6 ] >=
'0') &&
141 (ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(
bool, enum_constant_is_valid) +
142 enum_type_len<E>() + 6 ] <=
'9')) ||
143 (ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(
bool, enum_constant_is_valid) +
144 enum_type_len<E>() + 6 ] ==
'-'));
147template <
typename E, E C>
148constexpr bool enum_constant_is_valid() {
149 return (ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(
bool, enum_constant_is_valid) +
150 enum_type_len<E>() + 6 ] !=
'(');
153#elif defined(ECS_TARGET_GNU)
154template <
typename E, E C>
155constexpr bool enum_constant_is_valid() {
156 return (ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(
constexpr bool, enum_constant_is_valid) +
157 enum_type_len<E>() + 8 ] !=
'(');
162 const char (&func_name)[N],
169 : func_name[pos] ==
'<'
171 : func_name[pos] ==
'>'
173 func_name, pos + 1, end, depth ? depth - 1 : 0)
174 : (func_name[pos] ==
',' && !depth)
177 func_name, pos + 1, end, depth);
184template <
typename E, E C>
185constexpr bool enum_constant_is_valid() {
188 ECS_FUNC_NAME_FRONT(
bool, enum_constant_is_valid),
189 sizeof(ECS_FUNC_NAME) - ECS_FUNC_NAME_BACK - 1u) <
190 (
sizeof(ECS_FUNC_NAME) - ECS_FUNC_NAME_BACK - 1u) &&
193 ECS_FUNC_NAME_FRONT(
bool, enum_constant_is_valid),
194 sizeof(ECS_FUNC_NAME) - ECS_FUNC_NAME_BACK - 1u) + 1u] !=
'(';
199template <
typename E, underlying_type_t<E> C>
200constexpr bool enum_constant_is_valid_wrap() {
201 return enum_constant_is_valid<E, flecs_enum_cast(E, C)>();
205template <
typename E, E C>
206struct enum_is_valid {
207 static constexpr bool value = enum_constant_is_valid<E, C>();
211template <
typename E, E C>
212static const char* enum_constant_to_name() {
213 static const size_t len = ECS_FUNC_TYPE_LEN(
214 const char*, enum_constant_to_name, ECS_FUNC_NAME);
215 static char result[len + 1] = {};
231template <
typename E,
typename Handler>
233 using U = underlying_type_t<E>;
251 template <U Low, U High,
typename... Args>
253 return High - Low <= 1
255 ? Handler::template handle_constant<Low>(last_value, args...)
256 : Handler::template handle_constant<High>(
257 Handler::template handle_constant<Low>(last_value, args...),
281 template <U Low, U High,
typename... Args>
285 return (Low & High) || (High <= Low && High != high_bit)
287 : Handler::template handle_constant<High>(
305 template <U Value = static_cast<U>(FLECS_ENUM_MAX(E)),
typename... Args>
307 return each_mask_range<Value, high_bit>(
308 each_enum_range<0, Value>(0, args...), args...);
312 using UU =
typename std::make_unsigned<U>::type;
313 static const U high_bit =
314 static_cast<U
>(
static_cast<UU
>(1) << (
sizeof(UU) * 8 - 1));
322#ifdef FLECS_MULTI_WORLD
336 bool discovered()
const {
337#ifdef FLECS_MULTI_WORLD
340 return name !=
nullptr ||
id != 0;
349 using This = enum_type<E>;
350 using U = underlying_type_t<E>;
355 struct reflection_count {
357 static constexpr U handle_constant(U last_value) {
358 if constexpr (enum_constant_is_valid_wrap<E, Value>()) {
359 return 1 + last_value;
373 struct reflection_init {
375 static U handle_constant(U last_value, This& me) {
376 if constexpr (enum_constant_is_valid_wrap<E, Value>()) {
379 const char *name = enum_constant_to_name<E, flecs_enum_cast(E, Value)>();
385 if (me.has_contiguous &&
static_cast<U
>(me.max) == v && me.contiguous_until == v) {
386 ++me.contiguous_until;
391 else if (!me.contiguous_until && me.has_contiguous) {
392 me.has_contiguous =
false;
396 v < std::numeric_limits<U>::min() + last_value),
398 "Signed integer enums cause integer overflow when recording "
399 "offset from high positive to low negative. Consider using "
400 "unsigned integers as the underlying type.");
402 me.constants[me.max].value = v;
403 me.constants[me.max].offset = v - last_value;
404 me.constants[me.max].name = name;
405#ifdef FLECS_MULTI_WORLD
406 if (!me.constants[me.max].index) {
407 me.constants[me.max].index =
408 flecs_component_ids_index_get();
426 has_contiguous =
true;
427 contiguous_until = 0;
429#if FLECS_CPP_ENUM_REFLECTION_SUPPORT
430 enum_reflection<E, reflection_init>::
431 template each_enum< static_cast<U>(enum_last<E>::value) >(*this);
436 static enum_type<E>& get() {
437 static _::enum_type<E> instance;
441#ifndef FLECS_MULTI_WORLD
444 int index = index_by_value(value);
446 return constants[index].id;
454#if !FLECS_CPP_ENUM_REFLECTION_SUPPORT
461 for (U v = 0; v < static_cast<U>(max + 1); v ++) {
462 if (constants[v].discovered()) {
464 type<E>::id(world), 0, constants[v].name, &constants[v].value,
465 type<U>::id(world),
sizeof(U));
467#ifdef FLECS_MULTI_WORLD
468 flecs_component_ids_set(world, constants[v].index,
constant);
486 static constexpr unsigned int constants_size =
487 enum_reflection<E, reflection_count>::
488 template each_enum< static_cast<U>(enum_last<E>::value) >();
492 #ifdef FLECS_CPP_ENUM_REFLECTION
493 enum_constant<U> constants[constants_size? constants_size: 1] = {};
498 enum_constant<U> constants[128] = {};
499 bool has_contiguous =
true;
506 (void)world; (void)
id;
507 if constexpr (is_enum_v<E>) {
508 _::enum_type<E>::get().register_for_world(world,
id);
517 using U = underlying_type_t<E>;
536 return impl_.constants[index].discovered();
547 return is_valid(
static_cast<U
>(value));
562 if (impl_.has_contiguous && value < impl_.contiguous_until && value >= 0) {
563 return static_cast<int>(value);
565 U accumulator = impl_.contiguous_until? impl_.contiguous_until - 1: 0;
566 for (
int i =
static_cast<int>(impl_.contiguous_until); i <= impl_.max; ++i) {
567 accumulator += impl_.constants[i].offset;
568 if (accumulator == value) {
613 #ifdef FLECS_CPP_NO_ENUM_REFLECTION
616#ifdef FLECS_MULTI_WORLD
617 if (!impl_.constants[v].index) {
618 impl_.constants[v].index = flecs_component_ids_index_get();
622#ifdef FLECS_MULTI_WORLD
623 flecs_component_ids_set(world, impl_.constants[v].index, e);
626 impl_.constants[v].id = e;
631 if (impl_.contiguous_until <= v) {
632 impl_.contiguous_until = v + 1;
639 _::enum_type<E>& impl_;
646 auto&
ref = _::enum_type<E>::get();
component< T > & constant(const char *name, T value)
Add a constant.
FLECS_API void ecs_cpp_enum_init(ecs_world_t *world, ecs_entity_t id, ecs_entity_t underlying_type)
Initialize a C++ enum type.
FLECS_API ecs_entity_t ecs_cpp_enum_constant_register(ecs_world_t *world, ecs_entity_t parent, ecs_entity_t id, const char *name, void *value, ecs_entity_t value_type, size_t value_size)
Register a C++ enum constant.
FLECS_API char * ecs_cpp_get_constant_name(char *constant_name, const char *func_name, size_t len, size_t back_len)
Get constant name from compiler-generated function name.
#define ecs_assert(condition, error_code,...)
Assert.
#define ECS_UNSUPPORTED
Unsupported error code.
#define ecs_log_push()
Push log indentation at the default level.
#define ecs_abort(error_code,...)
Abort.
#define ecs_log_pop()
Pop log indentation at the default level.
ecs_entity_t entity_t
Entity type.
ecs_world_t world_t
World type.
constexpr size_t enum_template_arg_separator(const char(&func_name)[N], size_t pos, size_t end, size_t depth=0)
Test if a value is valid for an enumeration.
Enumeration constant data.
T offset
Offset from the previous constant value.
const char * name
The constant name.
int32_t index
Global index used to obtain a world-local entity ID.
T value
The constant value.
Provide utilities for enum reflection.
static constexpr U each_enum_range(U last_value, Args &... args)
Iterate over the range [Low, High] of enum values between Low and High.
static constexpr U each_enum(Args &... args)
Handle enum iteration for gathering reflection data.
static constexpr U each_mask_range(U last_value, Args &... args)
Iterate over the mask range (Low, High] of enum values between Low and High.
Convenience type with enum reflection data.
int last() const
Return the index of the last constant.
flecs::entity entity() const
Get entity for the enum type.
int next(int cur) const
Return the next constant index after the given one.
int index_by_value(E value) const
Find the index into the constants array for an enum value, if one exists.
bool is_valid(U value)
Check if a given integral value is a valid enum value.
enum_data(flecs::world_t *world, _::enum_type< E > &impl)
Construct enum_data from a world and an enum_type implementation.
flecs::world_t * world_
Manually register a constant for an enum.
int index_by_value(U value) const
Find the index into the constants array for a value, if one exists.
bool is_valid(E value)
Check if a given enum value is valid.
int first() const
Return the index of the first constant.
Trait to define the last valid enum value for reflection.
Class that wraps around a flecs::id_t.
std::size_t length() const
Return the string length.