aboutsummaryrefslogtreecommitdiff
path: root/src/compat.h
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-10-28 17:43:20 +0100
committerBenoit Germain <benoit.germain@ubisoft.com>2024-10-28 17:43:20 +0100
commit96a63454957ef3bc6d70a413c0793771c5568ed0 (patch)
treeede5da2201a5f0484a3bef9d6d3e8b391d67b7f3 /src/compat.h
parent524a62f2a2aa4b8b4515ff1f6b1addb8abdd4267 (diff)
downloadlanes-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.h428
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
37enum 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
57inline size_t lua_rawlen(lua_State* L_, StackIndex idx_)
58{
59 return lua_objlen(L_, idx_);
60}
61void luaL_requiref(lua_State* L_, const char* modname_, lua_CFunction openf_, int glb_); // implementation copied from Lua 5.2 sources
62
63int 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
72inline 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
83void* lua_newuserdatauv(lua_State* L_, size_t sz_, UserValueCount nuvalue_);
84int lua_getiuservalue(lua_State* L_, StackIndex idx_, UserValueIndex n_);
85int 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
96inline 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
106enum 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
118inline 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
127inline 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
166template <typename... EXTRA>
167inline 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
186inline 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
193template <typename LUA_DUMP>
194concept RequiresOldLuaDump = requires(LUA_DUMP f_) { { f_(nullptr, nullptr, nullptr) } -> std::same_as<int>; };
195
196template <RequiresOldLuaDump LUA_DUMP>
197static 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
204template <typename LUA_DUMP>
205concept RequiresNewLuaDump = requires(LUA_DUMP f_) { { f_(nullptr, nullptr, nullptr, 0) } -> std::same_as<int>; };
206
207template <RequiresNewLuaDump LUA_DUMP>
208static 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
215static 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
222UserValueCount luaG_getalluservalues(lua_State* L_, StackIndex idx_);
223
224// #################################################################################################
225
226template <typename LUA_GETFIELD>
227concept RequiresOldLuaGetfield = requires(LUA_GETFIELD f_)
228{
229 {
230 f_(nullptr, 0, nullptr)
231 } -> std::same_as<void>;
232};
233
234template <RequiresOldLuaGetfield LUA_GETFIELD>
235static 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
243template <typename LUA_GETFIELD>
244concept RequiresNewLuaGetfield = requires(LUA_GETFIELD f_)
245{
246 {
247 f_(nullptr, 0, nullptr)
248 } -> std::same_as<int>;
249};
250
251template <RequiresNewLuaGetfield LUA_GETFIELD>
252static 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
259static 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
266LuaType luaG_getmodule(lua_State* L_, std::string_view const& name_);
267
268// #################################################################################################
269
270inline 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
284template <typename LUA_RESUME>
285concept RequiresLuaResume51 = requires(LUA_RESUME f_) { { f_(nullptr, 0) } -> std::same_as<int>; };
286
287template <RequiresLuaResume51 LUA_RESUME>
288static 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
300template <typename LUA_RESUME>
301concept RequiresLuaResume52 = requires(LUA_RESUME f_) { { f_(nullptr, nullptr, 0) } -> std::same_as<int>; };
302
303template <RequiresLuaResume52 LUA_RESUME>
304static 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
316template <typename LUA_RESUME>
317concept RequiresLuaResume54 = requires(LUA_RESUME f_) { { f_(nullptr, nullptr, 0, nullptr) } -> std::same_as<int>; };
318
319template <RequiresLuaResume54 LUA_RESUME>
320static 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
328static 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
335static 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
345template <size_t N>
346static 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
354template <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
362inline 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
373inline void luaG_setfield(lua_State* const L_, StackIndex const idx_, char const* k_) = delete;
374inline 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
381inline 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
396template <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
405template <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}