初始化内容
This commit is contained in:
@@ -0,0 +1,756 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// Copyright 2007, Nathan Reed
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FuncTraits.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
/**
|
||||
* @brief Helper for unused vars.
|
||||
*/
|
||||
template <class... Args>
|
||||
constexpr void unused(Args&&...)
|
||||
{
|
||||
}
|
||||
|
||||
// These are for Lua versions prior to 5.2.0.
|
||||
#if LUA_VERSION_NUM < 502
|
||||
using lua_Unsigned = std::make_unsigned_t<lua_Integer>;
|
||||
|
||||
#if ! LUABRIDGE_ON_LUAU
|
||||
inline int lua_absindex(lua_State* L, int idx)
|
||||
{
|
||||
if (idx > LUA_REGISTRYINDEX && idx < 0)
|
||||
return lua_gettop(L) + idx + 1;
|
||||
else
|
||||
return idx;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define LUA_OPEQ 1
|
||||
#define LUA_OPLT 2
|
||||
#define LUA_OPLE 3
|
||||
|
||||
inline int lua_compare(lua_State* L, int idx1, int idx2, int op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case LUA_OPEQ:
|
||||
return lua_equal(L, idx1, idx2);
|
||||
|
||||
case LUA_OPLT:
|
||||
return lua_lessthan(L, idx1, idx2);
|
||||
|
||||
case LUA_OPLE:
|
||||
return lua_equal(L, idx1, idx2) || lua_lessthan(L, idx1, idx2);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if ! LUABRIDGE_ON_LUAJIT
|
||||
inline void* luaL_testudata(lua_State* L, int ud, const char* tname)
|
||||
{
|
||||
void* p = lua_touserdata(L, ud);
|
||||
if (p == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (! lua_getmetatable(L, ud))
|
||||
return nullptr;
|
||||
|
||||
luaL_getmetatable(L, tname);
|
||||
if (! lua_rawequal(L, -1, -2))
|
||||
p = nullptr;
|
||||
|
||||
lua_pop(L, 2);
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline int get_length(lua_State* L, int idx)
|
||||
{
|
||||
return static_cast<int>(lua_objlen(L, idx));
|
||||
}
|
||||
#else // LUA_VERSION_NUM >= 502
|
||||
inline int get_length(lua_State* L, int idx)
|
||||
{
|
||||
return static_cast<int>(lua_rawlen(L, idx));
|
||||
}
|
||||
#endif // LUA_VERSION_NUM < 502
|
||||
|
||||
// These functions and defines are for Luau.
|
||||
#if LUABRIDGE_ON_LUAU
|
||||
inline int luaL_ref(lua_State* L, int idx)
|
||||
{
|
||||
LUABRIDGE_ASSERT(idx == LUA_REGISTRYINDEX);
|
||||
|
||||
const int ref = lua_ref(L, -1);
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
inline void luaL_unref(lua_State* L, int idx, int ref)
|
||||
{
|
||||
unused(idx);
|
||||
|
||||
lua_unref(L, ref);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void* lua_newuserdata_x(lua_State* L, size_t sz)
|
||||
{
|
||||
return lua_newuserdatadtor(L, sz, [](void* x)
|
||||
{
|
||||
T* object = static_cast<T*>(x);
|
||||
object->~T();
|
||||
});
|
||||
}
|
||||
|
||||
inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname)
|
||||
{
|
||||
lua_pushcfunction(L, fn, debugname);
|
||||
}
|
||||
|
||||
inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n)
|
||||
{
|
||||
lua_pushcclosure(L, fn, debugname, n);
|
||||
}
|
||||
|
||||
[[noreturn]] inline void lua_error_x(lua_State* L)
|
||||
{
|
||||
lua_error(L);
|
||||
}
|
||||
|
||||
inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar)
|
||||
{
|
||||
return lua_getinfo(L, level, "nlS", ar);
|
||||
}
|
||||
|
||||
inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar)
|
||||
{
|
||||
return lua_getinfo(L, level, what, ar);
|
||||
}
|
||||
|
||||
inline int lua_rawgetp_x(lua_State* L, int idx, void* p)
|
||||
{
|
||||
return lua_rawgetp(L, idx, p);
|
||||
}
|
||||
|
||||
inline void lua_rawsetp_x(lua_State* L, int idx, void* p)
|
||||
{
|
||||
lua_rawsetp(L, idx, p);
|
||||
}
|
||||
|
||||
#else
|
||||
using ::luaL_ref;
|
||||
using ::luaL_unref;
|
||||
|
||||
template <class T>
|
||||
inline void* lua_newuserdata_x(lua_State* L, size_t sz)
|
||||
{
|
||||
return lua_newuserdata(L, sz);
|
||||
}
|
||||
|
||||
inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname)
|
||||
{
|
||||
unused(debugname);
|
||||
|
||||
lua_pushcfunction(L, fn);
|
||||
}
|
||||
|
||||
inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n)
|
||||
{
|
||||
unused(debugname);
|
||||
|
||||
lua_pushcclosure(L, fn, n);
|
||||
}
|
||||
|
||||
[[noreturn]] inline void lua_error_x(lua_State* L)
|
||||
{
|
||||
lua_error(L);
|
||||
|
||||
detail::unreachable();
|
||||
}
|
||||
|
||||
inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar)
|
||||
{
|
||||
return lua_getstack(L, level, ar);
|
||||
}
|
||||
|
||||
inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar)
|
||||
{
|
||||
lua_getstack(L, level, ar);
|
||||
return lua_getinfo(L, what, ar);
|
||||
}
|
||||
|
||||
inline int lua_rawgetp_x(lua_State* L, int idx, void* p)
|
||||
{
|
||||
#if LUA_VERSION_NUM < 503
|
||||
idx = lua_absindex(L, idx);
|
||||
luaL_checkstack(L, 1, "not enough stack slots");
|
||||
lua_pushlightuserdata(L, p);
|
||||
lua_rawget(L, idx);
|
||||
return lua_type(L, -1);
|
||||
#else
|
||||
return lua_rawgetp(L, idx, p);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void lua_rawsetp_x(lua_State* L, int idx, void* p)
|
||||
{
|
||||
#if LUA_VERSION_NUM < 503
|
||||
idx = lua_absindex(L, idx);
|
||||
luaL_checkstack(L, 1, "not enough stack slots");
|
||||
lua_pushlightuserdata(L, p);
|
||||
lua_insert(L, -2);
|
||||
lua_rawset(L, idx);
|
||||
#else
|
||||
lua_rawsetp(L, idx, p);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // LUABRIDGE_ON_LUAU
|
||||
|
||||
// These are for Lua versions prior to 5.5.0.
|
||||
#if LUA_VERSION_NUM < 505
|
||||
inline lua_State* lua_newstate_x(lua_Alloc f, void* ud, [[maybe_unused]] unsigned seed)
|
||||
{
|
||||
return lua_newstate(f, ud);
|
||||
}
|
||||
#else
|
||||
inline lua_State* lua_newstate_x(lua_Alloc f, void* ud, unsigned seed)
|
||||
{
|
||||
return lua_newstate(f, ud, seed);
|
||||
}
|
||||
#endif
|
||||
|
||||
// These are for Lua versions prior to 5.3.0.
|
||||
#if LUA_VERSION_NUM < 503
|
||||
inline lua_Number to_numberx(lua_State* L, int idx, int* isnum)
|
||||
{
|
||||
lua_Number n = lua_tonumber(L, idx);
|
||||
|
||||
if (isnum)
|
||||
*isnum = (n != 0 || lua_isnumber(L, idx));
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
inline lua_Integer to_integerx(lua_State* L, int idx, int* isnum)
|
||||
{
|
||||
int ok = 0;
|
||||
lua_Number n = to_numberx(L, idx, &ok);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
if (n < static_cast<lua_Number>(std::numeric_limits<lua_Integer>::min()) ||
|
||||
n >= -static_cast<lua_Number>(std::numeric_limits<lua_Integer>::min()))
|
||||
{
|
||||
if (isnum)
|
||||
*isnum = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto int_n = static_cast<lua_Integer>(n);
|
||||
if (n == static_cast<lua_Number>(int_n))
|
||||
{
|
||||
if (isnum)
|
||||
*isnum = 1;
|
||||
|
||||
return int_n;
|
||||
}
|
||||
}
|
||||
|
||||
if (isnum)
|
||||
*isnum = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // LUA_VERSION_NUM < 503
|
||||
|
||||
inline int lua_rawgetp_x(lua_State* L, int idx, const void* p)
|
||||
{
|
||||
return lua_rawgetp_x(L, idx, const_cast<void*>(p));
|
||||
}
|
||||
|
||||
inline void lua_rawsetp_x(lua_State* L, int idx, const void* p)
|
||||
{
|
||||
lua_rawsetp_x(L, idx, const_cast<void*>(p));
|
||||
}
|
||||
|
||||
#ifndef LUA_OK
|
||||
#define LUABRIDGE_LUA_OK 0
|
||||
#else
|
||||
#define LUABRIDGE_LUA_OK LUA_OK
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Helper to throw or return an error code.
|
||||
*/
|
||||
template <class T, class ErrorType>
|
||||
std::error_code throw_or_error_code(ErrorType error)
|
||||
{
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
throw T(makeErrorCode(error).message().c_str());
|
||||
#else
|
||||
return makeErrorCode(error);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T, class ErrorType>
|
||||
std::error_code throw_or_error_code(lua_State* L, ErrorType error)
|
||||
{
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
throw T(L, makeErrorCode(error));
|
||||
#else
|
||||
return unused(L), makeErrorCode(error);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to throw or LUABRIDGE_ASSERT.
|
||||
*/
|
||||
template <class T, class... Args>
|
||||
void throw_or_assert(Args&&... args)
|
||||
{
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
throw T(std::forward<Args>(args)...);
|
||||
#else
|
||||
unused(std::forward<Args>(args)...);
|
||||
LUABRIDGE_ASSERT(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to set unsigned.
|
||||
*/
|
||||
template <class T>
|
||||
void pushunsigned(lua_State* L, T value)
|
||||
{
|
||||
static_assert(std::is_unsigned_v<T>);
|
||||
|
||||
lua_pushinteger(L, static_cast<lua_Integer>(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to convert to integer.
|
||||
*/
|
||||
inline lua_Number tonumber(lua_State* L, int idx, int* isnum)
|
||||
{
|
||||
#if ! LUABRIDGE_ON_LUAU && LUA_VERSION_NUM > 502
|
||||
return lua_tonumberx(L, idx, isnum);
|
||||
#else
|
||||
return to_numberx(L, idx, isnum);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to convert to integer.
|
||||
*/
|
||||
inline lua_Integer tointeger(lua_State* L, int idx, int* isnum)
|
||||
{
|
||||
#if ! LUABRIDGE_ON_LUAU && LUA_VERSION_NUM > 502
|
||||
return lua_tointegerx(L, idx, isnum);
|
||||
#else
|
||||
return to_integerx(L, idx, isnum);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Register main thread, only supported on 5.1.
|
||||
*/
|
||||
inline constexpr char main_thread_name[] = "__luabridge_main_thread";
|
||||
|
||||
inline void register_main_thread(lua_State* threadL)
|
||||
{
|
||||
#if LUA_VERSION_NUM < 502
|
||||
if (threadL == nullptr)
|
||||
lua_pushnil(threadL);
|
||||
else
|
||||
lua_pushthread(threadL);
|
||||
|
||||
lua_setglobal(threadL, main_thread_name);
|
||||
#else
|
||||
unused(threadL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get main thread, not supported on 5.1.
|
||||
*/
|
||||
inline lua_State* main_thread(lua_State* threadL)
|
||||
{
|
||||
#if LUA_VERSION_NUM < 502
|
||||
lua_getglobal(threadL, main_thread_name);
|
||||
if (lua_isthread(threadL, -1))
|
||||
{
|
||||
auto L = lua_tothread(threadL, -1);
|
||||
lua_pop(threadL, 1);
|
||||
return L;
|
||||
}
|
||||
LUABRIDGE_ASSERT(false); // Have you forgot to call luabridge::registerMainThread ?
|
||||
lua_pop(threadL, 1);
|
||||
return threadL;
|
||||
#else
|
||||
lua_rawgeti(threadL, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
|
||||
lua_State* L = lua_tothread(threadL, -1);
|
||||
lua_pop(threadL, 1);
|
||||
return L;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a table value, bypassing metamethods.
|
||||
*/
|
||||
inline int rawgetfield(lua_State* L, int index, const char* key)
|
||||
{
|
||||
LUABRIDGE_ASSERT(lua_istable(L, index));
|
||||
index = lua_absindex(L, index);
|
||||
lua_pushstring(L, key);
|
||||
#if LUA_VERSION_NUM <= 502
|
||||
lua_rawget(L, index);
|
||||
return lua_type(L, -1);
|
||||
#else
|
||||
return lua_rawget(L, index);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a table value, bypassing metamethods.
|
||||
*/
|
||||
inline void rawsetfield(lua_State* L, int index, const char* key)
|
||||
{
|
||||
LUABRIDGE_ASSERT(lua_istable(L, index));
|
||||
index = lua_absindex(L, index);
|
||||
lua_pushstring(L, key);
|
||||
lua_insert(L, -2);
|
||||
lua_rawset(L, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the value is a full userdata (not light).
|
||||
*/
|
||||
[[nodiscard]] inline bool isfulluserdata(lua_State* L, int index)
|
||||
{
|
||||
return lua_isuserdata(L, index) && !lua_islightuserdata(L, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test lua_State objects for global equality.
|
||||
*
|
||||
* This can determine if two different lua_State objects really point
|
||||
* to the same global state, such as when using coroutines.
|
||||
*
|
||||
* @note This is used for assertions.
|
||||
*/
|
||||
[[nodiscard]] inline bool equalstates(lua_State* L1, lua_State* L2)
|
||||
{
|
||||
return lua_topointer(L1, LUA_REGISTRYINDEX) == lua_topointer(L2, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the size of lua table, even if not a sequence { 1=x, 2=y, 3=... }.
|
||||
*/
|
||||
[[nodiscard]] inline int table_length(lua_State* L, int index)
|
||||
{
|
||||
LUABRIDGE_ASSERT(lua_istable(L, index));
|
||||
|
||||
int items_count = 0;
|
||||
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, index) != 0)
|
||||
{
|
||||
++items_count;
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return items_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return an aligned pointer of type T.
|
||||
*/
|
||||
template <class T>
|
||||
[[nodiscard]] T* align(void* ptr) noexcept
|
||||
{
|
||||
const auto address = reinterpret_cast<size_t>(ptr);
|
||||
|
||||
const auto offset = address % alignof(T);
|
||||
const auto aligned_address = (offset == 0) ? address : (address + alignof(T) - offset);
|
||||
|
||||
return reinterpret_cast<T*>(aligned_address);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return if a pointer of type T is aligned.
|
||||
*/
|
||||
template <std::size_t Alignment, class T, std::enable_if_t<std::is_pointer_v<T>, int> = 0>
|
||||
[[nodiscard]] bool is_aligned(T address) noexcept
|
||||
{
|
||||
static_assert(Alignment > 0u);
|
||||
|
||||
return (reinterpret_cast<std::uintptr_t>(address) & (Alignment - 1u)) == 0u;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the space needed to align the type T on an unaligned address.
|
||||
*/
|
||||
template <class T>
|
||||
[[nodiscard]] constexpr size_t maximum_space_needed_to_align() noexcept
|
||||
{
|
||||
return sizeof(T) + alignof(T) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deallocate lua userdata taking into account alignment.
|
||||
*/
|
||||
template <class T>
|
||||
int lua_deleteuserdata_aligned(lua_State* L)
|
||||
{
|
||||
LUABRIDGE_ASSERT(isfulluserdata(L, 1));
|
||||
|
||||
T* aligned = align<T>(lua_touserdata(L, 1));
|
||||
aligned->~T();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate lua userdata taking into account alignment.
|
||||
*
|
||||
* Using this instead of lua_newuserdata directly prevents alignment warnings on 64bits platforms.
|
||||
*/
|
||||
template <class T, class... Args>
|
||||
void* lua_newuserdata_aligned(lua_State* L, Args&&... args)
|
||||
{
|
||||
using U = std::remove_reference_t<T>;
|
||||
|
||||
#if LUABRIDGE_ON_LUAU
|
||||
void* pointer = lua_newuserdatadtor(L, maximum_space_needed_to_align<U>(), [](void* x)
|
||||
{
|
||||
U* aligned = align<U>(x);
|
||||
aligned->~U();
|
||||
});
|
||||
#else
|
||||
void* pointer = lua_newuserdata_x<U>(L, maximum_space_needed_to_align<U>());
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushcfunction_x(L, &lua_deleteuserdata_aligned<U>, "");
|
||||
rawsetfield(L, -2, "__gc");
|
||||
lua_setmetatable(L, -2);
|
||||
#endif
|
||||
|
||||
U* aligned = align<U>(pointer);
|
||||
|
||||
new (aligned) U(std::forward<Args>(args)...);
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Safe error able to walk backwards for error reporting correctly.
|
||||
*/
|
||||
[[noreturn]] inline void raise_lua_error(lua_State* L, const char* fmt, ...)
|
||||
{
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
lua_pushvfstring(L, fmt, argp);
|
||||
va_end(argp);
|
||||
|
||||
const char* message = lua_tostring(L, -1);
|
||||
if (message != nullptr)
|
||||
{
|
||||
if (auto str = std::string_view(message); !str.empty() && str[0] == '[')
|
||||
lua_error_x(L);
|
||||
}
|
||||
|
||||
bool pushed_error = false;
|
||||
for (int level = 1; level <= 2; ++level)
|
||||
{
|
||||
lua_Debug ar;
|
||||
|
||||
#if LUABRIDGE_ON_LUAU
|
||||
if (lua_getinfo(L, level, "sl", &ar) == 0)
|
||||
continue;
|
||||
#else
|
||||
if (lua_getstack(L, level, &ar) == 0 || lua_getinfo(L, "Sl", &ar) == 0)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (ar.currentline <= 0)
|
||||
continue;
|
||||
|
||||
lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
|
||||
pushed_error = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (! pushed_error)
|
||||
lua_pushliteral(L, "");
|
||||
|
||||
lua_pushvalue(L, -2);
|
||||
lua_remove(L, -3);
|
||||
lua_concat(L, 2);
|
||||
|
||||
lua_error_x(L);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the value on the stack is a number type and can fit into the corresponding c++ integral type..
|
||||
*/
|
||||
template <class U = lua_Integer, class T>
|
||||
constexpr bool is_integral_representable_by(T value)
|
||||
{
|
||||
constexpr bool same_signedness = (std::is_unsigned_v<T> && std::is_unsigned_v<U>)
|
||||
|| (!std::is_unsigned_v<T> && !std::is_unsigned_v<U>);
|
||||
|
||||
if constexpr (sizeof(T) == sizeof(U))
|
||||
{
|
||||
if constexpr (same_signedness)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if constexpr (std::is_unsigned_v<T>)
|
||||
{
|
||||
return value <= static_cast<T>((std::numeric_limits<U>::max)());
|
||||
}
|
||||
else
|
||||
{
|
||||
return value >= static_cast<T>((std::numeric_limits<U>::min)())
|
||||
&& static_cast<U>(value) <= (std::numeric_limits<U>::max)();
|
||||
}
|
||||
}
|
||||
else if constexpr (sizeof(T) < sizeof(U))
|
||||
{
|
||||
return static_cast<U>(value) >= (std::numeric_limits<U>::min)()
|
||||
&& static_cast<U>(value) <= (std::numeric_limits<U>::max)();
|
||||
}
|
||||
else if constexpr (std::is_unsigned_v<T>)
|
||||
{
|
||||
return value <= static_cast<T>((std::numeric_limits<U>::max)());
|
||||
}
|
||||
else
|
||||
{
|
||||
return value >= static_cast<T>((std::numeric_limits<U>::min)())
|
||||
&& value <= static_cast<T>((std::numeric_limits<U>::max)());
|
||||
}
|
||||
}
|
||||
|
||||
template <class U = lua_Integer>
|
||||
bool is_integral_representable_by(lua_State* L, int index)
|
||||
{
|
||||
int isValid = 0;
|
||||
|
||||
const auto value = tointeger(L, index, &isValid);
|
||||
|
||||
return isValid ? is_integral_representable_by<U>(value) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the value on the stack is a number type and can fit into the corresponding c++ numerical type..
|
||||
*/
|
||||
template <class U = lua_Number, class T>
|
||||
bool is_floating_point_representable_by(T value)
|
||||
{
|
||||
if constexpr (sizeof(T) == sizeof(U))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if constexpr (sizeof(T) < sizeof(U))
|
||||
{
|
||||
if (std::isnan(value) || std::isinf(value))
|
||||
return true;
|
||||
|
||||
return static_cast<U>(value) >= -(std::numeric_limits<U>::max)()
|
||||
&& static_cast<U>(value) <= (std::numeric_limits<U>::max)();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::isnan(value) || std::isinf(value))
|
||||
return true;
|
||||
|
||||
return value >= static_cast<T>(-(std::numeric_limits<U>::max)())
|
||||
&& value <= static_cast<T>((std::numeric_limits<U>::max)());
|
||||
}
|
||||
}
|
||||
|
||||
template <class U = lua_Number>
|
||||
bool is_floating_point_representable_by(lua_State* L, int index)
|
||||
{
|
||||
int isValid = 0;
|
||||
|
||||
const auto value = tonumber(L, index, &isValid);
|
||||
|
||||
return isValid ? is_floating_point_representable_by<U>(value) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Portable wrapper for lua_resume that normalises calling convention differences
|
||||
* across Lua 5.1/LuaJIT (no from, no nresults), 5.2-5.3 (from but no nresults), and 5.4+ (from + nresults).
|
||||
*
|
||||
* @param L The coroutine thread to resume.
|
||||
* @param from The thread doing the resuming (may be nullptr on older Lua).
|
||||
* @param nargs Number of arguments on L's stack to pass to the resumed function.
|
||||
* @param nresults Output: number of values on L's stack after resume (yielded or returned).
|
||||
* For Lua 5.4+, filled directly by lua_resume. For older versions, computed via lua_gettop.
|
||||
* @returns LUA_OK, LUA_YIELD, or an error code.
|
||||
*/
|
||||
inline int lua_resume_x(lua_State* L, lua_State* from, int nargs, int* nresults = nullptr)
|
||||
{
|
||||
#if LUABRIDGE_ON_LUAJIT || LUA_VERSION_NUM == 501
|
||||
unused(from);
|
||||
int status = lua_resume(L, nargs);
|
||||
if (nresults)
|
||||
*nresults = lua_gettop(L);
|
||||
return status;
|
||||
#elif LUABRIDGE_ON_LUAU || LUABRIDGE_ON_RAVI || LUA_VERSION_NUM < 504
|
||||
int status = lua_resume(L, from, nargs);
|
||||
if (nresults)
|
||||
*nresults = lua_gettop(L);
|
||||
return status;
|
||||
#else
|
||||
int nr = 0;
|
||||
int status = lua_resume(L, from, nargs, &nr);
|
||||
if (nresults)
|
||||
*nresults = nr;
|
||||
return status;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the currently running C function can yield via lua_yieldk.
|
||||
*
|
||||
* Returns false on Lua 5.1, LuaJIT, and Luau where lua_yieldk is unavailable.
|
||||
*/
|
||||
inline bool lua_isyieldable_x(lua_State* L)
|
||||
{
|
||||
#if LUABRIDGE_ON_LUAJIT || LUA_VERSION_NUM == 501 || LUABRIDGE_ON_LUAU
|
||||
unused(L);
|
||||
return false;
|
||||
#elif LUA_VERSION_NUM < 503
|
||||
unused(L);
|
||||
return true; // lua_yieldk exists in 5.2; assume yieldable when reached
|
||||
#else
|
||||
return lua_isyieldable(L) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace luabridge
|
||||
Reference in New Issue
Block a user