diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-10-28 17:43:20 +0100 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-10-28 17:43:20 +0100 |
commit | 96a63454957ef3bc6d70a413c0793771c5568ed0 (patch) | |
tree | ede5da2201a5f0484a3bef9d6d3e8b391d67b7f3 /src/compat.h | |
parent | 524a62f2a2aa4b8b4515ff1f6b1addb8abdd4267 (diff) | |
download | lanes-96a63454957ef3bc6d70a413c0793771c5568ed0.tar.gz lanes-96a63454957ef3bc6d70a413c0793771c5568ed0.tar.bz2 lanes-96a63454957ef3bc6d70a413c0793771c5568ed0.zip |
Renamed compat.h → compat.hpp
Diffstat (limited to 'src/compat.h')
-rw-r--r-- | src/compat.h | 428 |
1 files changed, 0 insertions, 428 deletions
diff --git a/src/compat.h b/src/compat.h deleted file mode 100644 index 59c8001..0000000 --- a/src/compat.h +++ /dev/null | |||
@@ -1,428 +0,0 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "debug.hpp" | ||
4 | #include "stackindex.hpp" | ||
5 | |||
6 | // try to detect if we are building against LuaJIT or MoonJIT | ||
7 | #if defined(LUA_JITLIBNAME) | ||
8 | #include "luajit.h" | ||
9 | #if (defined(__x86_64__) || defined(_M_X64) || defined(__LP64__)) | ||
10 | #define LUAJIT_FLAVOR() 64 | ||
11 | #else // 64 bits | ||
12 | #define LUAJIT_FLAVOR() 32 | ||
13 | #endif // 64 bits | ||
14 | #else // LUA_JITLIBNAME | ||
15 | #define LUAJIT_FLAVOR() 0 | ||
16 | #define LUA_JITLIBNAME "jit" | ||
17 | #endif // LUA_JITLIBNAME | ||
18 | |||
19 | #ifndef LUA_OK | ||
20 | #define LUA_OK 0 // doesn't exist in Lua 5.1 | ||
21 | #endif // LUA_OK | ||
22 | |||
23 | #ifndef LUA_ERRGCMM | ||
24 | #define LUA_ERRGCMM 666 // doesn't exist in Lua 5.1 and Lua 5.4, we don't care about the actual value | ||
25 | #endif // LUA_ERRGCMM | ||
26 | |||
27 | |||
28 | #ifndef LUA_LOADED_TABLE | ||
29 | #define LUA_LOADED_TABLE "_LOADED" // doesn't exist before Lua 5.3 | ||
30 | #endif // LUA_LOADED_TABLE | ||
31 | |||
32 | // code is now preferring Lua 5.4 API | ||
33 | |||
34 | // ################################################################################################# | ||
35 | |||
36 | // a strong-typed wrapper over lua types to see them easier in a debugger | ||
37 | enum class LuaType | ||
38 | { | ||
39 | NONE = LUA_TNONE, | ||
40 | NIL = LUA_TNIL, | ||
41 | BOOLEAN = LUA_TBOOLEAN, | ||
42 | LIGHTUSERDATA = LUA_TLIGHTUSERDATA, | ||
43 | NUMBER = LUA_TNUMBER, | ||
44 | STRING = LUA_TSTRING, | ||
45 | TABLE = LUA_TTABLE, | ||
46 | FUNCTION = LUA_TFUNCTION, | ||
47 | USERDATA = LUA_TUSERDATA, | ||
48 | THREAD = LUA_TTHREAD, | ||
49 | CDATA = 10 // LuaJIT CDATA | ||
50 | }; | ||
51 | |||
52 | // ################################################################################################# | ||
53 | |||
54 | // add some Lua 5.3-style API when building for Lua 5.1 | ||
55 | #if LUA_VERSION_NUM == 501 | ||
56 | |||
57 | inline size_t lua_rawlen(lua_State* L_, StackIndex idx_) | ||
58 | { | ||
59 | return lua_objlen(L_, idx_); | ||
60 | } | ||
61 | void luaL_requiref(lua_State* L_, const char* modname_, lua_CFunction openf_, int glb_); // implementation copied from Lua 5.2 sources | ||
62 | |||
63 | int luaL_getsubtable(lua_State* L_, StackIndex idx_, const char* fname_); | ||
64 | |||
65 | #endif // LUA_VERSION_NUM == 501 | ||
66 | |||
67 | // ################################################################################################# | ||
68 | |||
69 | // wrap Lua 5.3 calls under Lua 5.1 API when it is simpler that way | ||
70 | #if LUA_VERSION_NUM == 503 | ||
71 | |||
72 | inline int luaL_optint(lua_State* L_, int n_, lua_Integer d_) | ||
73 | { | ||
74 | return static_cast<int>(luaL_optinteger(L_, n_, d_)); | ||
75 | } | ||
76 | |||
77 | #endif // LUA_VERSION_NUM == 503 | ||
78 | |||
79 | // ################################################################################################# | ||
80 | |||
81 | #if LUA_VERSION_NUM < 504 | ||
82 | |||
83 | void* lua_newuserdatauv(lua_State* L_, size_t sz_, UserValueCount nuvalue_); | ||
84 | int lua_getiuservalue(lua_State* L_, StackIndex idx_, UserValueIndex n_); | ||
85 | int lua_setiuservalue(lua_State* L_, StackIndex idx_, UserValueIndex n_); | ||
86 | |||
87 | #define LUA_GNAME "_G" | ||
88 | |||
89 | #endif // LUA_VERSION_NUM < 504 | ||
90 | |||
91 | // ################################################################################################# | ||
92 | |||
93 | // wrap Lua 5.4 calls under Lua 5.1 API when it is simpler that way | ||
94 | #if LUA_VERSION_NUM == 504 | ||
95 | |||
96 | inline int luaL_optint(lua_State* L_, StackIndex n_, lua_Integer d_) | ||
97 | { | ||
98 | return static_cast<int>(luaL_optinteger(L_, n_, d_)); | ||
99 | } | ||
100 | |||
101 | #endif // LUA_VERSION_NUM == 504 | ||
102 | |||
103 | // ################################################################################################# | ||
104 | |||
105 | // a strong-typed wrapper over lua error codes to see them easier in a debugger | ||
106 | enum class LuaError | ||
107 | { | ||
108 | OK = LUA_OK, | ||
109 | YIELD = LUA_YIELD, | ||
110 | ERRRUN = LUA_ERRRUN, | ||
111 | ERRSYNTAX = LUA_ERRSYNTAX, | ||
112 | ERRMEM = LUA_ERRMEM, | ||
113 | ERRGCMM = LUA_ERRGCMM, | ||
114 | ERRERR = LUA_ERRERR, | ||
115 | ERRFILE = LUA_ERRFILE | ||
116 | }; | ||
117 | |||
118 | inline constexpr LuaError ToLuaError(int const rc_) | ||
119 | { | ||
120 | assert(rc_ == LUA_OK || rc_ == LUA_YIELD || rc_ == LUA_ERRRUN || rc_ == LUA_ERRSYNTAX || rc_ == LUA_ERRMEM || rc_ == LUA_ERRGCMM || rc_ == LUA_ERRERR || rc_ == LUA_ERRFILE); | ||
121 | return static_cast<LuaError>(rc_); | ||
122 | } | ||
123 | |||
124 | // ################################################################################################# | ||
125 | |||
126 | // break lexical order for that one because it's needed below | ||
127 | inline LuaType luaG_type(lua_State* const L_, StackIndex const idx_) | ||
128 | { | ||
129 | return static_cast<LuaType>(lua_type(L_, idx_)); | ||
130 | } | ||
131 | |||
132 | // ################################################################################################# | ||
133 | // ################################################################################################# | ||
134 | // All the compatibility wrappers we expose start with luaG_ | ||
135 | // ################################################################################################# | ||
136 | // ################################################################################################# | ||
137 | |||
138 | // must keep as a macro as long as we do constant string concatenations | ||
139 | #define STRINGVIEW_FMT "%.*s" | ||
140 | |||
141 | // a replacement of lua_tolstring | ||
142 | [[nodiscard]] inline std::string_view luaG_tostring(lua_State* const L_, StackIndex const idx_) | ||
143 | { | ||
144 | size_t _len{ 0 }; | ||
145 | char const* _str{ lua_tolstring(L_, idx_, &_len) }; | ||
146 | return _str ? std::string_view{ _str, _len } : ""; | ||
147 | } | ||
148 | |||
149 | [[nodiscard]] inline std::string_view luaG_checkstring(lua_State* const L_, StackIndex const idx_) | ||
150 | { | ||
151 | size_t _len{ 0 }; | ||
152 | char const* _str{ luaL_checklstring(L_, idx_, &_len) }; | ||
153 | return std::string_view{ _str, _len }; | ||
154 | } | ||
155 | |||
156 | [[nodiscard]] inline std::string_view luaG_optstring(lua_State* const L_, StackIndex const idx_, std::string_view const& default_) | ||
157 | { | ||
158 | if (lua_isnoneornil(L_, idx_)) { | ||
159 | return default_; | ||
160 | } | ||
161 | size_t _len{ 0 }; | ||
162 | char const* _str{ luaL_optlstring(L_, idx_, default_.data(), &_len) }; | ||
163 | return std::string_view{ _str, _len }; | ||
164 | } | ||
165 | |||
166 | template <typename... EXTRA> | ||
167 | inline std::string_view luaG_pushstring(lua_State* const L_, std::string_view const& str_, EXTRA&&... extra_) | ||
168 | { | ||
169 | if constexpr (sizeof...(EXTRA) == 0) { | ||
170 | if constexpr (LUA_VERSION_NUM == 501) { | ||
171 | // lua_pushlstring doesn't return a value in Lua 5.1 | ||
172 | lua_pushlstring(L_, str_.data(), str_.size()); | ||
173 | return luaG_tostring(L_, kIdxTop); | ||
174 | } else { | ||
175 | return std::string_view{ lua_pushlstring(L_, str_.data(), str_.size()), str_.size() }; | ||
176 | } | ||
177 | } else { | ||
178 | static_assert((... && std::is_trivial_v<std::decay_t<EXTRA>>)); | ||
179 | return std::string_view{ lua_pushfstring(L_, str_.data(), std::forward<EXTRA>(extra_)...) }; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | // ################################################################################################# | ||
184 | |||
185 | // use this in place of lua_absindex to save a function call | ||
186 | inline StackIndex luaG_absindex(lua_State* const L_, StackIndex const idx_) | ||
187 | { | ||
188 | return StackIndex{ (idx_ >= 0 || idx_ <= kIdxRegistry) ? idx_ : StackIndex{ lua_gettop(L_) + idx_ + 1 } }; | ||
189 | } | ||
190 | |||
191 | // ################################################################################################# | ||
192 | |||
193 | template <typename LUA_DUMP> | ||
194 | concept RequiresOldLuaDump = requires(LUA_DUMP f_) { { f_(nullptr, nullptr, nullptr) } -> std::same_as<int>; }; | ||
195 | |||
196 | template <RequiresOldLuaDump LUA_DUMP> | ||
197 | static inline int WrapLuaDump(LUA_DUMP f_, lua_State* const L_, lua_Writer const writer_, void* const data_, [[maybe_unused]] int const strip_) | ||
198 | { | ||
199 | return f_(L_, writer_, data_); | ||
200 | } | ||
201 | |||
202 | // ------------------------------------------------------------------------------------------------- | ||
203 | |||
204 | template <typename LUA_DUMP> | ||
205 | concept RequiresNewLuaDump = requires(LUA_DUMP f_) { { f_(nullptr, nullptr, nullptr, 0) } -> std::same_as<int>; }; | ||
206 | |||
207 | template <RequiresNewLuaDump LUA_DUMP> | ||
208 | static inline int WrapLuaDump(LUA_DUMP f_, lua_State* const L_, lua_Writer const writer_, void* const data_, int const strip_) | ||
209 | { | ||
210 | return f_(L_, writer_, data_, strip_); | ||
211 | } | ||
212 | |||
213 | // ------------------------------------------------------------------------------------------------- | ||
214 | |||
215 | static inline int luaG_dump(lua_State* const L_, lua_Writer const writer_, void* const data_, int const strip_) | ||
216 | { | ||
217 | return WrapLuaDump(lua_dump, L_, writer_, data_, strip_); | ||
218 | } | ||
219 | |||
220 | // ################################################################################################# | ||
221 | |||
222 | UserValueCount luaG_getalluservalues(lua_State* L_, StackIndex idx_); | ||
223 | |||
224 | // ################################################################################################# | ||
225 | |||
226 | template <typename LUA_GETFIELD> | ||
227 | concept RequiresOldLuaGetfield = requires(LUA_GETFIELD f_) | ||
228 | { | ||
229 | { | ||
230 | f_(nullptr, 0, nullptr) | ||
231 | } -> std::same_as<void>; | ||
232 | }; | ||
233 | |||
234 | template <RequiresOldLuaGetfield LUA_GETFIELD> | ||
235 | static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, StackIndex const idx_, std::string_view const& name_) | ||
236 | { | ||
237 | f_(L_, idx_, name_.data()); | ||
238 | return lua_type(L_, -1); | ||
239 | } | ||
240 | |||
241 | // ------------------------------------------------------------------------------------------------- | ||
242 | |||
243 | template <typename LUA_GETFIELD> | ||
244 | concept RequiresNewLuaGetfield = requires(LUA_GETFIELD f_) | ||
245 | { | ||
246 | { | ||
247 | f_(nullptr, 0, nullptr) | ||
248 | } -> std::same_as<int>; | ||
249 | }; | ||
250 | |||
251 | template <RequiresNewLuaGetfield LUA_GETFIELD> | ||
252 | static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, StackIndex const idx_, std::string_view const& name_) | ||
253 | { | ||
254 | return f_(L_, idx_, name_.data()); | ||
255 | } | ||
256 | |||
257 | // ------------------------------------------------------------------------------------------------- | ||
258 | |||
259 | static inline LuaType luaG_getfield(lua_State* const L_, StackIndex const idx_, std::string_view const& name_) | ||
260 | { | ||
261 | return static_cast<LuaType>(WrapLuaGetField(lua_getfield, L_, idx_, name_)); | ||
262 | } | ||
263 | |||
264 | // ################################################################################################# | ||
265 | |||
266 | LuaType luaG_getmodule(lua_State* L_, std::string_view const& name_); | ||
267 | |||
268 | // ################################################################################################# | ||
269 | |||
270 | inline void luaG_registerlibfuncs(lua_State* L_, luaL_Reg const* funcs_) | ||
271 | { | ||
272 | // fake externs to make clang happy... | ||
273 | extern void luaL_register(lua_State*, char const*, luaL_Reg const*); // Lua 5.1 | ||
274 | extern void luaL_setfuncs(lua_State* const L_, luaL_Reg const funcs_[], int nup_); // Lua 5.2+ | ||
275 | if constexpr (LUA_VERSION_NUM == 501) { | ||
276 | luaL_register(L_, nullptr, funcs_); | ||
277 | } else { | ||
278 | luaL_setfuncs(L_, funcs_, 0); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | // ################################################################################################# | ||
283 | |||
284 | template <typename LUA_RESUME> | ||
285 | concept RequiresLuaResume51 = requires(LUA_RESUME f_) { { f_(nullptr, 0) } -> std::same_as<int>; }; | ||
286 | |||
287 | template <RequiresLuaResume51 LUA_RESUME> | ||
288 | static inline int WrapLuaResume(LUA_RESUME const lua_resume_, lua_State* const L_, [[maybe_unused]] lua_State* const from_, int const nargs_, int* const nresults_) | ||
289 | { | ||
290 | // lua_resume is supposed to be called from a "clean" stack: | ||
291 | // it should only contain the function and its initial arguments on first call, or the resume arguments on subsequent invocations | ||
292 | int const _rc{ lua_resume_(L_, nargs_) }; | ||
293 | // after resuming, the stack should only contain the yielded values | ||
294 | *nresults_ = lua_gettop(L_); | ||
295 | return _rc; | ||
296 | } | ||
297 | |||
298 | // ------------------------------------------------------------------------------------------------- | ||
299 | |||
300 | template <typename LUA_RESUME> | ||
301 | concept RequiresLuaResume52 = requires(LUA_RESUME f_) { { f_(nullptr, nullptr, 0) } -> std::same_as<int>; }; | ||
302 | |||
303 | template <RequiresLuaResume52 LUA_RESUME> | ||
304 | static inline int WrapLuaResume(LUA_RESUME const lua_resume_, lua_State* const L_, lua_State* const from_, int const nargs_, [[maybe_unused]] int* const nresults_) | ||
305 | { | ||
306 | // lua_resume is supposed to be called from a "clean" stack: | ||
307 | // it should only contain the function and its initial arguments on first call, or the resume arguments on subsequent invocations | ||
308 | int const _rc{ lua_resume_(L_, from_, nargs_) }; | ||
309 | // after resuming, the stack should only contain the yielded values | ||
310 | *nresults_ = lua_gettop(L_); | ||
311 | return _rc; | ||
312 | } | ||
313 | |||
314 | // ------------------------------------------------------------------------------------------------- | ||
315 | |||
316 | template <typename LUA_RESUME> | ||
317 | concept RequiresLuaResume54 = requires(LUA_RESUME f_) { { f_(nullptr, nullptr, 0, nullptr) } -> std::same_as<int>; }; | ||
318 | |||
319 | template <RequiresLuaResume54 LUA_RESUME> | ||
320 | static inline int WrapLuaResume(LUA_RESUME const lua_resume_, lua_State* const L_, lua_State* const from_, int const nargs_, int* const nresults_) | ||
321 | { | ||
322 | // starting with Lua 5.4, the stack can contain stuff below the actual yielded values, but lua_resume tells us the correct nresult | ||
323 | return lua_resume_(L_, from_, nargs_, nresults_); | ||
324 | } | ||
325 | |||
326 | // ------------------------------------------------------------------------------------------------- | ||
327 | |||
328 | static inline LuaError luaG_resume(lua_State* const L_, lua_State* const from_, int const nargs_, int* const nresults_) | ||
329 | { | ||
330 | return ToLuaError(WrapLuaResume(lua_resume, L_, from_, nargs_, nresults_)); | ||
331 | } | ||
332 | |||
333 | // ################################################################################################# | ||
334 | |||
335 | static inline LuaType luaG_rawgetfield(lua_State* const L_, StackIndex const idx_, std::string_view const& name_) | ||
336 | { | ||
337 | auto const _absIdx{ luaG_absindex(L_, idx_) }; | ||
338 | luaG_pushstring(L_, name_); // L_: ... t ... name_ | ||
339 | lua_rawget(L_, _absIdx); // L_: ... t ... <field> | ||
340 | return luaG_type(L_, kIdxTop); | ||
341 | } | ||
342 | |||
343 | // ################################################################################################# | ||
344 | |||
345 | template <size_t N> | ||
346 | static inline void luaG_newlib(lua_State* const L_, luaL_Reg const (&funcs_)[N]) | ||
347 | { | ||
348 | lua_createtable(L_, 0, N - 1); | ||
349 | luaG_registerlibfuncs(L_, funcs_); | ||
350 | } | ||
351 | |||
352 | // ################################################################################################# | ||
353 | |||
354 | template <typename T> | ||
355 | [[nodiscard]] T* luaG_newuserdatauv(lua_State* L_, UserValueCount nuvalue_) | ||
356 | { | ||
357 | return static_cast<T*>(lua_newuserdatauv(L_, sizeof(T), nuvalue_)); | ||
358 | } | ||
359 | |||
360 | // ################################################################################################# | ||
361 | |||
362 | inline void luaG_pushglobaltable(lua_State* const L_) | ||
363 | { | ||
364 | #ifdef LUA_GLOBALSINDEX // All flavors of Lua 5.1 | ||
365 | ::lua_pushvalue(L_, LUA_GLOBALSINDEX); | ||
366 | #else // LUA_GLOBALSINDEX | ||
367 | ::lua_rawgeti(L_, kIdxRegistry, LUA_RIDX_GLOBALS); | ||
368 | #endif // LUA_GLOBALSINDEX | ||
369 | } | ||
370 | |||
371 | // ################################################################################################# | ||
372 | |||
373 | inline void luaG_setfield(lua_State* const L_, StackIndex const idx_, char const* k_) = delete; | ||
374 | inline void luaG_setfield(lua_State* const L_, StackIndex const idx_, std::string_view const& k_) | ||
375 | { | ||
376 | lua_setfield(L_, idx_, k_.data()); | ||
377 | } | ||
378 | |||
379 | // ################################################################################################# | ||
380 | |||
381 | inline void luaG_setmetatable(lua_State* const L_, std::string_view const& tname_) | ||
382 | { | ||
383 | // fake externs to make clang happy... | ||
384 | if constexpr (LUA_VERSION_NUM > 501) { | ||
385 | extern void luaL_setmetatable(lua_State* const L_, char const* const tname_); // Lua 5.2+ | ||
386 | luaL_setmetatable(L_, tname_.data()); | ||
387 | } else { | ||
388 | luaL_getmetatable(L_, tname_.data()); | ||
389 | lua_setmetatable(L_, -2); | ||
390 | } | ||
391 | } | ||
392 | |||
393 | // ################################################################################################# | ||
394 | |||
395 | // a small helper to extract a full userdata pointer from the stack in a safe way | ||
396 | template <typename T> | ||
397 | [[nodiscard]] T* luaG_tofulluserdata(lua_State* const L_, StackIndex const index_) | ||
398 | { | ||
399 | LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_type(L_, index_) == LUA_TUSERDATA); | ||
400 | return static_cast<T*>(lua_touserdata(L_, index_)); | ||
401 | } | ||
402 | |||
403 | // ------------------------------------------------------------------------------------------------- | ||
404 | |||
405 | template <typename T> | ||
406 | [[nodiscard]] auto luaG_tolightuserdata(lua_State* const L_, StackIndex const index_) | ||
407 | { | ||
408 | LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_islightuserdata(L_, index_)); | ||
409 | if constexpr (std::is_pointer_v<T>) { | ||
410 | return static_cast<T>(lua_touserdata(L_, index_)); | ||
411 | } else { | ||
412 | return static_cast<T*>(lua_touserdata(L_, index_)); | ||
413 | } | ||
414 | } | ||
415 | |||
416 | // ------------------------------------------------------------------------------------------------- | ||
417 | |||
418 | [[nodiscard]] inline std::string_view luaG_typename(lua_State* const L_, LuaType const t_) | ||
419 | { | ||
420 | return lua_typename(L_, static_cast<int>(t_)); | ||
421 | } | ||
422 | |||
423 | // ------------------------------------------------------------------------------------------------- | ||
424 | |||
425 | [[nodiscard]] inline std::string_view luaG_typename(lua_State* const L_, StackIndex const idx_) | ||
426 | { | ||
427 | return luaG_typename(L_, luaG_type(L_, idx_)); | ||
428 | } | ||