Skip to content

Commit

Permalink
Support using LUA_FUNCTION macros without relying on __COUNTER__
Browse files Browse the repository at this point in the history
__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.
  • Loading branch information
edo9300 committed Mar 8, 2024
1 parent 0366e00 commit 31f98de
Showing 1 changed file with 117 additions and 26 deletions.
143 changes: 117 additions & 26 deletions function_array_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <array>
#include <lauxlib.h>
#include <type_traits>
Expand All @@ -24,61 +31,145 @@

namespace {
namespace Detail {
static constexpr auto COUNTER_OFFSET = __COUNTER__ + 1;

template<std::size_t N>
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<size_t offset, size_t total, std::size_t... I>
constexpr size_t find_prev_element(std::index_sequence<I...>) {
constexpr auto index_to_check = offset - (total - sizeof...(I)) - 1;
if constexpr(LuaFunction<index_to_check>::initialized)
return index_to_check;
else if constexpr(sizeof...(I) <= 1)
return 0;
else
return find_prev_element<offset, total>(std::make_index_sequence<sizeof...(I) - 1>());
}

template<typename T>
constexpr auto count() {
if constexpr(T::initialized)
return 1 + count<typename T::prev_element>();
else
return 0;
}

template <size_t counter, size_t amount = std::min<size_t>(counter, 200) - 1>
using previous_element_t = LuaFunction<find_prev_element<counter, amount>(std::make_index_sequence<amount>())>;

#define TAG_STRUCT(COUNTER) \
static constexpr bool initialized{ true }; \
using prev_element = previous_element_t<COUNTER>; \

template<typename T, typename Arr>
constexpr auto populate_array([[maybe_unused]] Arr& arr, [[maybe_unused]] size_t idx) {
if constexpr(T::initialized) {
arr[idx] = T::elem;
populate_array<typename T::prev_element>(arr, --idx);
}
}

template<size_t counter>
constexpr auto make_lua_functions_array() {
using last_elem = previous_element_t<counter>;
constexpr auto total = count<last_elem>();
std::array<luaL_Reg, total + 1> arr{};
populate_array<last_elem>(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<COUNTER - Detail::COUNTER_OFFSET - (1 * COUNTER != Detail::COUNTER_OFFSET)>, \
void \
>;

template<std::size_t... I>
constexpr auto make_lua_functions_array(std::index_sequence<I...> seq) {
return std::array<luaL_Reg, seq.size() + 1>{Detail::LuaFunction<I>::elem..., luaL_Reg{ nullptr, nullptr }};
constexpr auto make_lua_functions_array_int(std::index_sequence<I...> seq) {
return std::array<luaL_Reg, seq.size() + 1>{LuaFunction<I>::elem..., luaL_Reg{ nullptr, nullptr }};
}

template<std::size_t counter>
constexpr auto make_lua_functions_array() {
return make_lua_functions_array_int(std::make_index_sequence<counter - COUNTER_OFFSET>());
}

#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<COUNTER_MACRO>()

#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<COUNTER - Detail::COUNTER_OFFSET> { \
TAG_STRUCT(COUNTER) \
static int32_t call(lua_State* L) { \
return MAKE_LUA_NAME(LUA_MODULE,name)(L, lua_get<duel*>(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<COUNTER - Detail::COUNTER_OFFSET> { \
TAG_STRUCT(COUNTER) \
static int32_t call(lua_State* L) { \
return MAKE_LUA_NAME(LUA_MODULE,name)(L, lua_get<LUA_CLASS*, true>(L, 1), lua_get<duel*>(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<COUNTER - Detail::COUNTER_OFFSET> { \
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<COUNTER - Detail::COUNTER_OFFSET> { \
static constexpr luaL_Reg elem{#name,Detail::LuaFunction<COUNTER - Detail::COUNTER_OFFSET-1>::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}}
Expand Down

0 comments on commit 31f98de

Please sign in to comment.