From 31f98dea0851098e2d7c1e2d3fbbc1c4362d6149 Mon Sep 17 00:00:00 2001 From: Edoardo Lolletti Date: Fri, 8 Mar 2024 22:39:06 +0100 Subject: [PATCH] Support using LUA_FUNCTION macros without relying on __COUNTER__ __COUNTER__ is a nonstandard extension, and a random compiler might not be implementing it, or could be implementing it in a broken way, to address that, add fallback equivalent code utilizing __LINE__ to generate the luaL_Reg elements, still at compile time. This is not enabled by default because it increases build times as it performs more computations. --- function_array_helper.h | 143 ++++++++++++++++++++++++++++++++-------- 1 file changed, 117 insertions(+), 26 deletions(-) diff --git a/function_array_helper.h b/function_array_helper.h index 21d39fee..650e16df 100644 --- a/function_array_helper.h +++ b/function_array_helper.h @@ -9,7 +9,14 @@ #define MAKE_LUA_NAME_IMPL(module, name) c_lua_##module##_##name #define MAKE_LUA_NAME(module, name) MAKE_LUA_NAME_IMPL(module, name) -#ifndef __INTELLISENSE__ +// if subsequent calls to __COUNTER__ produce the same result, that macro is broken +#if !defined(__COUNTER__) || (__COUNTER__ + 0 == __COUNTER__ + 0) +#define HAS_COUNTER 0 +#else +#define HAS_COUNTER 1 +#endif + +#if !defined(__INTELLISENSE__) || !HAS_COUNTER #include #include #include @@ -24,61 +31,145 @@ namespace { namespace Detail { -static constexpr auto COUNTER_OFFSET = __COUNTER__ + 1; + template -struct LuaFunction; +struct LuaFunction { + static constexpr luaL_Reg elem{ nullptr, nullptr }; + static constexpr bool initialized{ false }; +}; + +#if !HAS_COUNTER +#define COUNTER_MACRO __LINE__ +static constexpr auto COUNTER_OFFSET = 0; + +template +constexpr size_t find_prev_element(std::index_sequence) { + constexpr auto index_to_check = offset - (total - sizeof...(I)) - 1; + if constexpr(LuaFunction::initialized) + return index_to_check; + else if constexpr(sizeof...(I) <= 1) + return 0; + else + return find_prev_element(std::make_index_sequence()); +} + +template +constexpr auto count() { + if constexpr(T::initialized) + return 1 + count(); + else + return 0; +} + +template (counter, 200) - 1> +using previous_element_t = LuaFunction(std::make_index_sequence())>; + +#define TAG_STRUCT(COUNTER) \ + static constexpr bool initialized{ true }; \ + using prev_element = previous_element_t; \ + +template +constexpr auto populate_array([[maybe_unused]] Arr& arr, [[maybe_unused]] size_t idx) { + if constexpr(T::initialized) { + arr[idx] = T::elem; + populate_array(arr, --idx); + } +} + +template +constexpr auto make_lua_functions_array() { + using last_elem = previous_element_t; + constexpr auto total = count(); + std::array arr{}; + populate_array(arr, arr.size() - 2); + arr[total] = { nullptr, nullptr }; + return arr; +} + +#else + +#define COUNTER_MACRO __COUNTER__ +static constexpr auto COUNTER_OFFSET = __COUNTER__ + 1; +#define TAG_STRUCT(COUNTER) \ + using prev_element = std::conditional_t< \ + COUNTER != Detail::COUNTER_OFFSET, \ + /* "COUNTER - Detail::COUNTER_OFFSET - 1" is always evaluated, even if the condition is false, leading \ + to a compilation error when since the value would underflow, work around that */ \ + Detail::LuaFunction, \ + void \ + >; template -constexpr auto make_lua_functions_array(std::index_sequence seq) { - return std::array{Detail::LuaFunction::elem..., luaL_Reg{ nullptr, nullptr }}; +constexpr auto make_lua_functions_array_int(std::index_sequence seq) { + return std::array{LuaFunction::elem..., luaL_Reg{ nullptr, nullptr }}; } +template +constexpr auto make_lua_functions_array() { + return make_lua_functions_array_int(std::make_index_sequence()); +} + +#endif + } // namespace Detail } // namespace -#define LUA_STATIC_FUNCTION(name) \ -static LUA_INLINE int32_t MAKE_LUA_NAME(LUA_MODULE,name)(lua_State* const, duel* const); \ +#define GET_LUA_FUNCTIONS_ARRAY() \ + Detail::make_lua_functions_array() + +#define LUA_STATIC_FUNCTION(name) LUA_STATIC_FUNCTION_INT(name, COUNTER_MACRO) + +#define LUA_STATIC_FUNCTION_INT(name, COUNTER) \ +static LUA_INLINE int32_t MAKE_LUA_NAME(LUA_MODULE,name) \ + (lua_State* const, duel* const); \ template<> \ -struct Detail::LuaFunction<__COUNTER__ - Detail::COUNTER_OFFSET> { \ +struct Detail::LuaFunction { \ + TAG_STRUCT(COUNTER) \ static int32_t call(lua_State* L) { \ return MAKE_LUA_NAME(LUA_MODULE,name)(L, lua_get(L)); \ } \ static constexpr luaL_Reg elem{#name, call}; \ }; \ -static LUA_INLINE int32_t MAKE_LUA_NAME(LUA_MODULE,name)([[maybe_unused]] lua_State* const L, [[maybe_unused]] duel* const pduel) +static LUA_INLINE int32_t MAKE_LUA_NAME(LUA_MODULE,name) \ + ([[maybe_unused]] lua_State* const L, [[maybe_unused]] duel* const pduel) -#define LUA_FUNCTION(name) \ -static LUA_INLINE int32_t MAKE_LUA_NAME(LUA_MODULE,name)(lua_State* const, LUA_CLASS* const, duel* const); \ +#define LUA_FUNCTION(name) LUA_FUNCTION_INT(name, COUNTER_MACRO) +#define LUA_FUNCTION_INT(name, COUNTER) \ +static LUA_INLINE int32_t MAKE_LUA_NAME(LUA_MODULE,name) \ + (lua_State* const, LUA_CLASS* const, duel* const); \ template<> \ -struct Detail::LuaFunction<__COUNTER__ - Detail::COUNTER_OFFSET> { \ +struct Detail::LuaFunction { \ + TAG_STRUCT(COUNTER) \ static int32_t call(lua_State* L) { \ return MAKE_LUA_NAME(LUA_MODULE,name)(L, lua_get(L, 1), lua_get(L)); \ } \ static constexpr luaL_Reg elem{#name, call}; \ }; \ -static LUA_INLINE int32_t MAKE_LUA_NAME(LUA_MODULE,name)([[maybe_unused]] lua_State* const L, \ - [[maybe_unused]] LUA_CLASS* const self, [[maybe_unused]] duel* const pduel) - -#define GET_LUA_FUNCTIONS_ARRAY() \ - Detail::make_lua_functions_array(std::make_index_sequence<__COUNTER__ - Detail::COUNTER_OFFSET>()) +static LUA_INLINE int32_t MAKE_LUA_NAME(LUA_MODULE,name) \ + ([[maybe_unused]] lua_State* const L, \ + [[maybe_unused]] LUA_CLASS* const self, [[maybe_unused]] duel* const pduel) -#define LUA_FUNCTION_EXISTING(name,...) \ +#define LUA_FUNCTION_EXISTING(name,...) LUA_FUNCTION_EXISTING_INT(name, COUNTER_MACRO, __VA_ARGS__) +#define LUA_FUNCTION_EXISTING_INT(name, COUNTER, ...) \ template<> \ -struct Detail::LuaFunction<__COUNTER__ - Detail::COUNTER_OFFSET> { \ - static constexpr luaL_Reg elem{#name,__VA_ARGS__}; \ +struct Detail::LuaFunction { \ + TAG_STRUCT(COUNTER) \ + static constexpr luaL_Reg elem{#name,__VA_ARGS__}; \ } -#define LUA_FUNCTION_ALIAS(name) LUA_DECLARE_ALIAS_INT(name, __COUNTER__) -#define LUA_DECLARE_ALIAS_INT(name, COUNTER) \ +#define LUA_FUNCTION_ALIAS(name) LUA_FUNCTION_ALIAS_INT(name, COUNTER_MACRO) +#define LUA_FUNCTION_ALIAS_INT(name, COUNTER) \ template<> \ struct Detail::LuaFunction { \ - static constexpr luaL_Reg elem{#name,Detail::LuaFunction::elem.func}; \ + TAG_STRUCT(COUNTER) \ + static constexpr luaL_Reg elem{#name,prev_element::elem.func}; \ } #else -#define LUA_FUNCTION(name) static int32_t MAKE_LUA_NAME(LUA_MODULE,name)([[maybe_unused]] lua_State* const L, \ - [[maybe_unused]] LUA_CLASS* const self, [[maybe_unused]] duel* const pduel) -#define LUA_STATIC_FUNCTION(name) static int32_t MAKE_LUA_NAME(LUA_MODULE,name)([[maybe_unused]] lua_State* const L, [[maybe_unused]] duel* const pduel) +#define LUA_FUNCTION(name) static int32_t MAKE_LUA_NAME(LUA_MODULE,name) \ + ([[maybe_unused]] lua_State* const L, [[maybe_unused]] LUA_CLASS* const self, [[maybe_unused]] duel* const pduel) +#define LUA_STATIC_FUNCTION(name) static int32_t MAKE_LUA_NAME(LUA_MODULE,name) \ + ([[maybe_unused]] lua_State* const L, [[maybe_unused]] duel* const pduel) #define LUA_FUNCTION_EXISTING(name,...) struct MAKE_LUA_NAME(LUA_MODULE,name) {} #define LUA_FUNCTION_ALIAS(name) struct MAKE_LUA_NAME(LUA_MODULE,name) {} #define GET_LUA_FUNCTIONS_ARRAY() std::array{luaL_Reg{nullptr,nullptr}}