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)
47template <
typename E, underlying_type_t<E> Value>
49 static constexpr E value = flecs_enum_cast(E, Value);
52template <
typename E, underlying_type_t<E> Value>
65 static constexpr E value = FLECS_ENUM_MAX(E);
69#define FLECS_ENUM_LAST(T, Last)\
72 struct enum_last<T> {\
73 static constexpr T value = Last;\
79#if INTPTR_MAX == INT64_MAX
80 #ifdef ECS_TARGET_MSVC
82 #define ECS_SIZE_T_STR "unsigned __int64"
84 #define ECS_SIZE_T_STR "unsigned int"
86 #elif defined(__clang__)
87 #define ECS_SIZE_T_STR "size_t"
89 #ifdef ECS_TARGET_WINDOWS
90 #define ECS_SIZE_T_STR "constexpr size_t; size_t = long long unsigned int"
92 #define ECS_SIZE_T_STR "constexpr size_t; size_t = long unsigned int"
96 #ifdef ECS_TARGET_MSVC
98 #define ECS_SIZE_T_STR "unsigned __int32"
100 #define ECS_SIZE_T_STR "unsigned int"
102 #elif defined(__clang__)
103 #define ECS_SIZE_T_STR "size_t"
105 #ifdef ECS_TARGET_WINDOWS
106 #define ECS_SIZE_T_STR "constexpr size_t; size_t = unsigned int"
108 #define ECS_SIZE_T_STR "constexpr size_t; size_t = unsigned int"
114constexpr size_t enum_type_len() {
115 return ECS_FUNC_TYPE_LEN(, enum_type_len, ECS_FUNC_NAME)
116 - (
sizeof(ECS_SIZE_T_STR) - 1u);
123#if defined(ECS_TARGET_CLANG)
124#if ECS_CLANG_VERSION < 13
125template <
typename E, E C>
129 enum_type_len<E>() + 6 ] >=
'0') &&
131 enum_type_len<E>() + 6 ] <=
'9')) ||
133 enum_type_len<E>() + 6 ] ==
'-'));
136template <
typename E, E C>
139 enum_type_len<E>() + 6 ] !=
'(');
142#elif defined(ECS_TARGET_GNU)
143template <
typename E, E C>
146 enum_type_len<E>() + 8 ] !=
'(');
152template <
typename E, E C>
155 enum_type_len<E>() + 1] !=
'(';
160template <
typename E, underlying_type_t<E> C>
161constexpr bool enum_constant_is_valid_wrap() {
162 return enum_constant_is_valid<E, flecs_enum_cast(E, C)>();
165template <
typename E, E C>
167 static constexpr bool value = enum_constant_is_valid<E, C>();
171template <
typename E, E C>
172static const char* enum_constant_to_name() {
173 static const size_t len = ECS_FUNC_TYPE_LEN(
174 const char*, enum_constant_to_name, ECS_FUNC_NAME);
175 static char result[len + 1] = {};
176 return ecs_cpp_get_constant_name(
177 result, ECS_FUNC_NAME, string::length(ECS_FUNC_NAME),
191template <
typename E,
typename Handler>
193 using U = underlying_type_t<E>;
211 template <U Low, U High,
typename... Args>
213 return High - Low <= 1
215 ? Handler::template handle_constant<Low>(last_value, args...)
216 : Handler::template handle_constant<High>(
217 Handler::template handle_constant<Low>(last_value, args...),
241 template <U Low, U High,
typename... Args>
245 return (Low & High) || (High <= Low && High != high_bit)
247 : Handler::template handle_constant<High>(
265 template <U Value = static_cast<U>(FLECS_ENUM_MAX(E)),
typename... Args>
267 return each_mask_range<Value, high_bit>(
268 each_enum_range<0, Value>(0, args...), args...);
272 using UU =
typename std::make_unsigned<U>::type;
273 static const U high_bit =
274 static_cast<U
>(
static_cast<UU
>(1) << (
sizeof(UU) * 8 - 1));
291 using U = underlying_type_t<E>;
296 struct reflection_count {
298 flecs::if_not_t< enum_constant_is_valid_wrap<E, Value>() > = 0>
299 static constexpr U handle_constant(U last_value) {
304 flecs::if_t< enum_constant_is_valid_wrap<E, Value>() > = 0>
305 static constexpr U handle_constant(U last_value) {
306 return 1 + last_value;
317 struct reflection_init {
319 flecs::if_not_t< enum_constant_is_valid_wrap<E, Value>() > = 0>
320 static U handle_constant(U last_value,
This&) {
326 flecs::if_t< enum_constant_is_valid_wrap<E, Value>() > = 0>
327 static U handle_constant(U last_value,
This& me) {
330 const char *name = enum_constant_to_name<E, flecs_enum_cast(E, Value)>();
336 if (me.has_contiguous &&
static_cast<U
>(me.max) == v && me.contiguous_until == v) {
337 ++me.contiguous_until;
342 else if (!me.contiguous_until && me.has_contiguous) {
343 me.has_contiguous =
false;
347 v < std::numeric_limits<U>::min() + last_value),
349 "Signed integer enums causes integer overflow when recording "
350 "offset from high positive to low negative. Consider using "
351 "unsigned integers as underlying type.");
353 me.constants[me.max].value = v;
354 me.constants[me.max].offset = v - last_value;
355 me.constants[me.max].name = name;
356 if (!me.constants[me.max].index) {
357 me.constants[me.max].index =
358 flecs_component_ids_index_get();
370 has_contiguous =
true;
371 contiguous_until = 0;
382 flecs::entity_t
entity(E value)
const {
383 int index = index_by_value(value);
385 return constants[index].id;
390 void register_for_world(flecs::world_t *
world, flecs::entity_t
id) {
391#if !FLECS_CPP_ENUM_REFLECTION_SUPPORT
392 ecs_abort(ECS_UNSUPPORTED,
"enum reflection requires gcc 7.5 or higher")
398 for (U v = 0; v < static_cast<U>(max + 1); v ++) {
399 if (constants[v].index) {
400 flecs::entity_t
constant = ecs_cpp_enum_constant_register(
world,
404 flecs_component_ids_set(
world, constants[v].index,
constant);
420 static constexpr unsigned int constants_size =
429template <typename E, if_t< is_enum<E>::value > = 0>
430inline static void init_enum(flecs::world_t *
world, flecs::entity_t
id) {
434template <typename E, if_not_t< is_enum<E>::value > = 0>
435inline static void init_enum(flecs::world_t*, flecs::entity_t) { }
442 using U = underlying_type_t<E>;
460 return impl_.constants[index].index != 0;
471 return is_valid(
static_cast<U
>(value));
485 if (impl_.has_contiguous && value < impl_.contiguous_until && value >= 0) {
486 return static_cast<int>(value);
488 U accumulator = impl_.contiguous_until? impl_.contiguous_until - 1: 0;
489 for (
int i =
static_cast<int>(impl_.contiguous_until); i <= impl_.max; ++i) {
490 accumulator += impl_.constants[i].offset;
491 if (accumulator == value) {
516 int next(
int cur)
const {
524 flecs::world_t *world_;
525 _::enum_type<E>& impl_;
component< T > & constant(const char *name, T value)
Add constant.
#define ecs_assert(condition, error_code,...)
Assert.
#define ecs_abort(error_code,...)
Abort.
constexpr bool enum_constant_is_valid()
Test if value is valid for enumeration.
Enumeration constant data.
Provides utilities for enum reflection.
static constexpr U each_enum_range(U last_value, Args &... args)
Iterates over the range [Low, High] of enum values between Low and High.
static constexpr U each_enum(Args &... args)
Handles enum iteration for gathering reflection data.
static constexpr U each_mask_range(U last_value, Args &... args)
Iterates over the mask range (Low, High] of enum values between Low and High.
Class that scans an enum for constants, extracts names & creates entities.
Convenience type with enum reflection data.
int index_by_value(E value) const
Finds the index into the constants array for an enum value, if one exists.
bool is_valid(U value)
Checks if a given integral value is a valid enum value.
int index_by_value(U value) const
Finds the index into the constants array for a value, if one exists.
bool is_valid(E value)
Checks if a given enum value is valid.