12#define FLECS_ENUM_MAX(T) _::to_constant<T, 128>::value
13#define FLECS_ENUM_MAX_COUNT (FLECS_ENUM_MAX(int) + 1)
15#ifndef FLECS_CPP_ENUM_REFLECTION_SUPPORT
16#if !defined(__clang__) && defined(__GNUC__)
17#if __GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 5)
18#define FLECS_CPP_ENUM_REFLECTION_SUPPORT 1
20#define FLECS_CPP_ENUM_REFLECTION_SUPPORT 0
23#define FLECS_CPP_ENUM_REFLECTION_SUPPORT 1
31template <
typename E, underlying_type_t<E> Value>
33#if defined(__clang__) && __clang_major__ >= 16
35 static constexpr E value = __builtin_bit_cast(E, Value);
37 static constexpr E value =
static_cast<E
>(Value);
41template <
typename E, underlying_type_t<E> Value>
54 static constexpr E value = FLECS_ENUM_MAX(E);
58#define FLECS_ENUM_LAST(T, Last)\
61 struct enum_last<T> {\
62 static constexpr T value = Last;\
68#if INTPTR_MAX == INT64_MAX
69 #ifdef ECS_TARGET_MSVC
71 #define ECS_SIZE_T_STR "unsigned __int64"
73 #define ECS_SIZE_T_STR "unsigned int"
75 #elif defined(__clang__)
76 #define ECS_SIZE_T_STR "size_t"
78 #ifdef ECS_TARGET_WINDOWS
79 #define ECS_SIZE_T_STR "constexpr size_t; size_t = long long unsigned int"
81 #define ECS_SIZE_T_STR "constexpr size_t; size_t = long unsigned int"
85 #ifdef ECS_TARGET_MSVC
87 #define ECS_SIZE_T_STR "unsigned __int32"
89 #define ECS_SIZE_T_STR "unsigned int"
91 #elif defined(__clang__)
92 #define ECS_SIZE_T_STR "size_t"
94 #ifdef ECS_TARGET_WINDOWS
95 #define ECS_SIZE_T_STR "constexpr size_t; size_t = unsigned int"
97 #define ECS_SIZE_T_STR "constexpr size_t; size_t = unsigned int"
103constexpr size_t enum_type_len() {
104 return ECS_FUNC_TYPE_LEN(, enum_type_len, ECS_FUNC_NAME)
105 - (
sizeof(ECS_SIZE_T_STR) - 1u);
112#if defined(ECS_TARGET_CLANG)
113#if ECS_CLANG_VERSION < 13
114template <
typename E, E C>
118 enum_type_len<E>() + 6 ] >=
'0') &&
120 enum_type_len<E>() + 6 ] <=
'9')) ||
122 enum_type_len<E>() + 6 ] ==
'-'));
125template <
typename E, E C>
128 enum_type_len<E>() + 6 ] !=
'(');
131#elif defined(ECS_TARGET_GNU)
132template <
typename E, E C>
135 enum_type_len<E>() + 8 ] !=
'(');
141template <
typename E, E C>
144 enum_type_len<E>() + 1] !=
'(';
148template <
typename E, E C>
150 static constexpr bool value = enum_constant_is_valid<E, C>();
154template <
typename E, E C>
155static const char* enum_constant_to_name() {
156 static const size_t len = ECS_FUNC_TYPE_LEN(
const char*, enum_constant_to_name, ECS_FUNC_NAME);
157 static char result[len + 1] = {};
158 return ecs_cpp_get_constant_name(
159 result, ECS_FUNC_NAME, string::length(ECS_FUNC_NAME),
180template <
typename E,
template<
typename>
class Handler>
183 static constexpr underlying_type_t<E> to_int() {
184 return static_cast<underlying_type_t<E>
>(Value);
187 template <underlying_type_t<E> Value>
188 static constexpr E from_int() {
193 static constexpr underlying_type_t<E> is_not_0() {
194 return static_cast<underlying_type_t<E>
>(Value != from_int<0>());
211 template <E Low, E High,
typename... Args>
212 static constexpr underlying_type_t<E>
each_enum_range(underlying_type_t<E> last_value, Args... args) {
213 return to_int<High>() - to_int<Low>() <= 1
214 ? to_int<High>() == to_int<Low>()
215 ? Handler<E>::template handle_constant<Low>(last_value, args...)
216 : Handler<E>::template handle_constant<High>(Handler<E>::template handle_constant<Low>(last_value, args...), args...)
217 : each_enum_range<from_int<(to_int<Low>()+to_int<High>()) / 2 + 1>(), High>(
218 each_enum_range<Low, from_int<(to_int<Low>()+to_int<High>()) / 2>()>(last_value, args...),
237 template <E Low, E High,
typename... Args>
238 static constexpr underlying_type_t<E>
each_mask_range(underlying_type_t<E> last_value, Args... args) {
240 return (to_int<Low>() & to_int<High>()) || (to_int<High>() <= to_int<Low>() && to_int<High>() != high_bit)
242 : Handler<E>::template handle_constant<High>(
243 each_mask_range<Low, from_int<((to_int<High>() >> 1) & ~high_bit)>()>(last_value, args...),
260 template <E Value = FLECS_ENUM_MAX(E),
typename... Args>
261 static constexpr underlying_type_t<E>
each_enum(Args... args) {
262 return each_mask_range<Value, from_int<high_bit>()>(each_enum_range<from_int<0>(), Value>(0, args...), args...);
265 static const underlying_type_t<E> high_bit =
static_cast<underlying_type_t<E>
>(1) << (
sizeof(underlying_type_t<E>) * 8 - 1);
275 template<
typename Enum>
276 struct reflection_count {
277 template <Enum Value, flecs::if_not_t< enum_constant_is_valid<Enum, Value>() > = 0>
278 static constexpr underlying_type_t<Enum> handle_constant(underlying_type_t<E> last_value) {
282 template <Enum Value, flecs::if_t< enum_constant_is_valid<Enum, Value>() > = 0>
283 static constexpr underlying_type_t<Enum> handle_constant(underlying_type_t<E> last_value) {
284 return 1 + last_value;
293 underlying_type_t<E> contiguous_until;
312 template <
typename Enum>
313 struct reflection_init {
314 template <Enum Value, flecs::if_not_t< enum_constant_is_valid<Enum, Value>() > = 0>
315 static underlying_type_t<Enum> handle_constant(underlying_type_t<Enum> last_value, flecs::world_t*) {
320 template <Enum Value, flecs::if_t< enum_constant_is_valid<Enum, Value>() > = 0>
321 static underlying_type_t<Enum> handle_constant(underlying_type_t<Enum> last_value, flecs::world_t *
world) {
324 const char *name = enum_constant_to_name<Enum, Value>();
337 ecs_assert(!(last_value > 0 && v < std::numeric_limits<underlying_type_t<Enum>>::min() + last_value), ECS_UNSUPPORTED,
338 "Signed integer enums causes integer overflow when recording offset from high positive to"
339 " low negative. Consider using unsigned integers as underlying type.");
355 flecs::entity_t
entity(E value)
const {
356 int index = index_by_value(value);
358 return data.constants[index].id;
363 void init(flecs::world_t *
world, flecs::entity_t
id) {
364#if !FLECS_CPP_ENUM_REFLECTION_SUPPORT
365 ecs_abort(ECS_UNSUPPORTED,
"enum reflection requires gcc 7.5 or higher")
370 data.has_contiguous =
true;
371 data.contiguous_until = 0;
374 ecs_cpp_enum_init(
world,
id);
387template <typename E, if_t< is_enum<E>::value > = 0>
388inline static void init_enum(flecs::world_t *
world, flecs::entity_t
id) {
392template <typename E, if_not_t< is_enum<E>::value > = 0>
393inline static void init_enum(flecs::world_t*, flecs::entity_t) { }
416 return impl_.constants[index].id != 0;
427 return is_valid(
static_cast<underlying_type_t<E>
>(value));
441 if (impl_.has_contiguous && value < impl_.contiguous_until && value >= 0) {
442 return static_cast<int>(value);
444 underlying_type_t<E> accumulator = impl_.contiguous_until? impl_.contiguous_until - 1: 0;
445 for (
int i =
static_cast<int>(impl_.contiguous_until); i <= impl_.max; ++i) {
446 accumulator += impl_.constants[i].offset;
447 if (accumulator == value) {
472 int next(
int cur)
const {
480 flecs::world_t *world_;
481 _::enum_data_impl<E>& impl_;
#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 underlying_type_t< E > each_enum(Args... args)
Handles enum iteration for gathering reflection data.
static constexpr underlying_type_t< E > each_mask_range(underlying_type_t< E > last_value, Args... args)
Iterates over the mask range (Low, High] of enum values between Low and High.
static constexpr underlying_type_t< E > each_enum_range(underlying_type_t< E > last_value, Args... args)
Iterates over the 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.
bool is_valid(underlying_type_t< E > value)
Checks if a given integral value is a valid enum value.
int index_by_value(underlying_type_t< E > value) const
Finds the index into the constants array for a value, if one exists.
int index_by_value(E value) const
Finds the index into the constants array for an enum value, if one exists.
bool is_valid(E value)
Checks if a given enum value is valid.
Class that wraps around a flecs::id_t.