-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathfunction_array_helper.h
180 lines (154 loc) · 6.13 KB
/
function_array_helper.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
* Copyright (c) 2022-2024, Edoardo Lolletti (edo9300) <[email protected]>
*
* 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)
// 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 <array>
#include <lauxlib.h>
#if HAS_COUNTER
#include <type_traits> //std::conditional_t
#endif
#include <utility> //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
namespace {
namespace Detail {
template<std::size_t N>
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_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 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> { \
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)
#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> { \
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 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> { \
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<COUNTER - Detail::COUNTER_OFFSET> { \
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