/* * Copyright (c) 2022-2026, Edoardo Lolletti (edo9300) * * SPDX-License-Identifier: AGPL-3.0-or-later */ #ifndef FUNCTION_ARRAY_HELPER_H #define FUNCTION_ARRAY_HELPER_H #define MAKE_LUA_NAME_IMPL(module, name) c_lua_##module##_##name #define MAKE_LUA_NAME(module, name) MAKE_LUA_NAME_IMPL(module, name) // in clang 22, the usage of the __COUNTER__ macro is now diagnosed as c2y extension and a warning is raised #if (defined(__clang__) && __clang_major__ >= 22) #pragma GCC diagnostic ignored "-Wc2y-extensions" #endif // if subsequent calls to __COUNTER__ don't produce consecutive integers, that macro is broken #if !defined(__COUNTER__) || (__COUNTER__ + 0 != __COUNTER__ - 1) #define HAS_COUNTER 0 #else #define HAS_COUNTER 1 #endif #if !defined(__INTELLISENSE__) || !HAS_COUNTER #include #include #if HAS_COUNTER #include //std::conditional_t #endif #include //std::index_sequence, std::make_index_sequence #include "common.h" // use forceinline only in release builds #if defined(_DEBUG) || (!defined(_MSC_VER) && !defined(__OPTIMIZE__)) #define LUA_INLINE NoInline #else #define LUA_INLINE ForceInline #endif #define LUA_NAMESPACE namespace { namespace LUA_NAMESPACE { namespace Detail { template 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_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 LUA_NAMESPACE } // namespace #define GET_LUA_FUNCTIONS_ARRAY() \ LUA_NAMESPACE::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 { \ 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) #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 { \ 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 LUA_FUNCTION_EXISTING(name,...) LUA_FUNCTION_EXISTING_INT(name, COUNTER_MACRO, __VA_ARGS__) #define LUA_FUNCTION_EXISTING_INT(name, COUNTER, ...) \ template<> \ struct Detail::LuaFunction { \ TAG_STRUCT(COUNTER) \ static constexpr luaL_Reg elem{#name,__VA_ARGS__}; \ } #define LUA_FUNCTION_ALIAS(name) LUA_FUNCTION_ALIAS_INT(name, COUNTER_MACRO) #define LUA_FUNCTION_ALIAS_INT(name, COUNTER) \ template<> \ struct Detail::LuaFunction { \ 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_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}} #endif // __INTELLISENSE__ #endif // FUNCTION_ARRAY_HELPER_H