Full fixes for everything.

This commit is contained in:
ThePhD 2019-03-09 20:57:49 -05:00
parent b6f40935c8
commit ee13a7812f
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
20 changed files with 1960 additions and 2347 deletions

View File

@ -85,6 +85,7 @@ function (MAKE_EXAMPLE example_source_file example_suffix target_sol)
else() else()
target_compile_options(${example_name} target_compile_options(${example_name}
PRIVATE -std=c++1z PRIVATE -std=c++1z
-ftemplate-backtrace-limit=0
-Wall -Wpedantic -Werror -pedantic -pedantic-errors -Wall -Wpedantic -Werror -pedantic -pedantic-errors
-Wno-noexcept-type -Wno-noexcept-type
-Wno-unknown-warning -Wno-unknown-warning-option) -Wno-unknown-warning -Wno-unknown-warning-option)

View File

@ -44,4 +44,6 @@ int main() {
std::cout << "result2: " << result2 << std::endl; std::cout << "result2: " << result2 << std::endl;
std::cout << "result3: " << result3 << std::endl; std::cout << "result3: " << result3 << std::endl;
std::cout << std::endl; std::cout << std::endl;
return 0;
} }

View File

@ -10,7 +10,7 @@ struct two_things {
}; };
template <typename Handler> template <typename Handler>
bool check(sol::types<two_things>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { bool sol_lua_check(sol::types<two_things>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
// indices can be negative to count backwards from the top of the stack, // indices can be negative to count backwards from the top of the stack,
// rather than the bottom up // rather than the bottom up
// to deal with this, we adjust the index to // to deal with this, we adjust the index to
@ -22,7 +22,7 @@ bool check(sol::types<two_things>, lua_State* L, int index, Handler&& handler, s
return success; return success;
} }
two_things get(sol::types<two_things>, lua_State* L, int index, sol::stack::record& tracking) { two_things sol_lua_get(sol::types<two_things>, lua_State* L, int index, sol::stack::record& tracking) {
int absolute_index = lua_absindex(L, index); int absolute_index = lua_absindex(L, index);
// Get the first element // Get the first element
int a = sol::stack::get<int>(L, absolute_index); int a = sol::stack::get<int>(L, absolute_index);
@ -34,7 +34,7 @@ two_things get(sol::types<two_things>, lua_State* L, int index, sol::stack::reco
return two_things{ a, b }; return two_things{ a, b };
} }
int push(sol::types<two_things>, lua_State* L, const two_things& things) { int sol_lua_push(sol::types<two_things>, lua_State* L, const two_things& things) {
int amount = sol::stack::push(L, things.a); int amount = sol::stack::push(L, things.a);
// amount will be 1: int pushes 1 item // amount will be 1: int pushes 1 item
amount += sol::stack::push(L, things.b); amount += sol::stack::push(L, things.b);

View File

@ -29,6 +29,14 @@
#include <utility> #include <utility>
#include <type_traits> #include <type_traits>
#if defined(SOL_USING_CXX_LUA) && SOL_USING_CXX_LUA
struct lua_State;
#else
extern "C" {
struct lua_State;
}
#endif // C++ Mangling for Lua vs. Not
namespace sol { namespace sol {
template <bool b> template <bool b>

View File

@ -46,14 +46,14 @@ namespace sol {
} }
auto setup_table(std::true_type) { auto setup_table(std::true_type) {
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, tbl.stack_index()); auto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, tbl.stack_index());
lua_pop(lua_state(), p.levels); lua_pop(lua_state(), p.levels);
return p; return p;
} }
bool is_valid(std::false_type) { bool is_valid(std::false_type) {
auto pp = stack::push_pop(tbl); auto pp = stack::push_pop(tbl);
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); auto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, lua_gettop(lua_state()));
lua_pop(lua_state(), p.levels); lua_pop(lua_state(), p.levels);
return p; return p;
} }
@ -69,7 +69,7 @@ namespace sol {
template <typename T> template <typename T>
proxy& set(T&& item) { proxy& set(T&& item) {
tuple_set(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>(), std::forward<T>(item)); tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
return *this; return *this;
} }
@ -79,14 +79,15 @@ namespace sol {
return *this; return *this;
} }
template <typename U, meta::enable<meta::neg<is_lua_reference_or_proxy<meta::unwrap_unqualified_t<U>>>, meta::is_callable<meta::unwrap_unqualified_t<U>>> = meta::enabler> template <typename U>
proxy& operator=(U&& other) { proxy& operator=(U&& other) {
return set_function(std::forward<U>(other)); using uTu = meta::unwrap_unqualified_t<U>;
} if constexpr (!is_lua_reference_or_proxy_v<uTu> && meta::is_callable_v<uTu>) {
return set_function(std::forward<U>(other));
template <typename U, meta::disable<meta::neg<is_lua_reference_or_proxy<meta::unwrap_unqualified_t<U>>>, meta::is_callable<meta::unwrap_unqualified_t<U>>> = meta::enabler> }
proxy& operator=(U&& other) { else {
return set(std::forward<U>(other)); return set(std::forward<U>(other));
}
} }
template <typename T> template <typename T>
@ -193,26 +194,26 @@ namespace sol {
template <typename Table, typename Key, typename T> template <typename Table, typename Key, typename T>
inline bool operator==(T&& left, const proxy<Table, Key>& right) { inline bool operator==(T&& left, const proxy<Table, Key>& right) {
typedef decltype(stack::get<T>(nullptr, 0)) U; using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<U>>() == left; return right.template get<optional<G>>() == left;
} }
template <typename Table, typename Key, typename T> template <typename Table, typename Key, typename T>
inline bool operator==(const proxy<Table, Key>& right, T&& left) { inline bool operator==(const proxy<Table, Key>& right, T&& left) {
typedef decltype(stack::get<T>(nullptr, 0)) U; using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<U>>() == left; return right.template get<optional<G>>() == left;
} }
template <typename Table, typename Key, typename T> template <typename Table, typename Key, typename T>
inline bool operator!=(T&& left, const proxy<Table, Key>& right) { inline bool operator!=(T&& left, const proxy<Table, Key>& right) {
typedef decltype(stack::get<T>(nullptr, 0)) U; using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<U>>() != left; return right.template get<optional<G>>() != left;
} }
template <typename Table, typename Key, typename T> template <typename Table, typename Key, typename T>
inline bool operator!=(const proxy<Table, Key>& right, T&& left) { inline bool operator!=(const proxy<Table, Key>& right, T&& left) {
typedef decltype(stack::get<T>(nullptr, 0)) U; using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<U>>() != left; return right.template get<optional<G>>() != left;
} }
template <typename Table, typename Key> template <typename Table, typename Key>

View File

@ -35,28 +35,25 @@ namespace sol { namespace stack {
template <typename Handler> template <typename Handler>
static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) { static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {
if (!check<T>(L, index, std::forward<Handler>(handler))) { if constexpr (is_lua_reference_v<T>) {
tracking.use(static_cast<int>(!lua_isnone(L, index))); // actually check if it's none here, otherwise
return nullopt; // we'll have a none object inside an optional!
bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, no_panic);
if (!success) {
// expected type, actual type
tracking.use(static_cast<int>(success));
handler(L, index, type::poly, type_of(L, index), "");
return nullopt;
}
return stack_detail::unchecked_get<T>(L, index, tracking);
} }
return stack_detail::unchecked_get<T>(L, index, tracking); else {
} if (!check<T>(L, index, std::forward<Handler>(handler))) {
}; tracking.use(static_cast<int>(!lua_isnone(L, index)));
return nullopt;
template <typename T> }
struct qualified_check_getter<T, std::enable_if_t<is_lua_reference<T>::value>> { return stack_detail::unchecked_get<T>(L, index, tracking);
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
// actually check if it's none here, otherwise
// we'll have a none object inside an optional!
bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, no_panic);
if (!success) {
// expected type, actual type
tracking.use(static_cast<int>(success));
handler(L, index, type::poly, type_of(L, index), "");
return nullopt;
} }
return stack_detail::unchecked_get<T>(L, index, tracking);
} }
}; };

View File

@ -45,100 +45,94 @@ namespace stack {
template <typename Handler> template <typename Handler>
static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) { static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {
if (!unqualified_check<T>(L, index, std::forward<Handler>(handler))) { if constexpr (!meta::meta_detail::is_adl_sol_lua_check_v<T> && !meta::meta_detail::is_adl_sol_lua_get_v<T>) {
tracking.use(static_cast<int>(!lua_isnone(L, index))); if constexpr (is_lua_reference_v<T>) {
return nullopt; // actually check if it's none here, otherwise
} // we'll have a none object inside an optional!
return stack_detail::unchecked_unqualified_get<T>(L, index, tracking); bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, no_panic);
} if (!success) {
}; // expected type, actual type
tracking.use(static_cast<int>(success));
template <typename T> handler(L, index, type::poly, type_of(L, index), "");
struct unqualified_check_getter<T, std::enable_if_t<is_lua_reference<T>::value>> { return nullopt;
template <typename Handler> }
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) { return stack_detail::unchecked_get<T>(L, index, tracking);
// actually check if it's none here, otherwise }
// we'll have a none object inside an optional! else if constexpr (std::is_same_v<T, bool>) {
bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, no_panic); return lua_toboolean(L, index) != 0;
if (!success) { }
// expected type, actual type else if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>) {
tracking.use(static_cast<int>(success)); #if SOL_LUA_VERSION >= 503
handler(L, index, type::poly, type_of(L, index), ""); if (lua_isinteger(L, index) != 0) {
return nullopt; tracking.use(1);
} return static_cast<T>(lua_tointeger(L, index));
return stack_detail::unchecked_get<T>(L, index, tracking); }
} #endif
}; int isnum = 0;
const lua_Number value = lua_tonumberx(L, index, &isnum);
template <typename T> if (isnum != 0) {
struct unqualified_check_getter<T, std::enable_if_t<std::is_integral<T>::value && lua_type_of<T>::value == type::number>> { #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
template <typename Handler> const auto integer_value = llround(value);
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) { if (static_cast<lua_Number>(integer_value) == value) {
#if SOL_LUA_VERSION >= 503 tracking.use(1);
if (lua_isinteger(L, index) != 0) { return static_cast<T>(integer_value);
tracking.use(1); }
return static_cast<T>(lua_tointeger(L, index)); #else
} tracking.use(1);
#endif return static_cast<T>(value);
int isnum = 0; #endif
const lua_Number value = lua_tonumberx(L, index, &isnum); }
if (isnum != 0) { const type t = type_of(L, index);
#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) tracking.use(static_cast<int>(t != type::none));
const auto integer_value = llround(value); handler(L, index, type::number, t, "not an integer");
if (static_cast<lua_Number>(integer_value) == value) { return nullopt;
tracking.use(1); }
return static_cast<T>(integer_value); else if constexpr(std::is_floating_point_v<T>) {
int isnum = 0;
lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum == 0) {
type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t, "not a valid floating point number");
return nullopt;
}
tracking.use(1);
return static_cast<T>(value);
}
else if constexpr (std::is_enum_v<T> && !meta::any_same_v<T, meta_function, type>) {
int isnum = 0;
lua_Integer value = lua_tointegerx(L, index, &isnum);
if (isnum == 0) {
type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t, "not a valid enumeration value");
return nullopt;
}
tracking.use(1);
return static_cast<T>(value);
}
else {
if (!unqualified_check<T>(L, index, std::forward<Handler>(handler))) {
tracking.use(static_cast<int>(!lua_isnone(L, index)));
return nullopt;
}
return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
} }
#else
tracking.use(1);
return static_cast<T>(value);
#endif
} }
const type t = type_of(L, index); else {
tracking.use(static_cast<int>(t != type::none)); if (!unqualified_check<T>(L, index, std::forward<Handler>(handler))) {
handler(L, index, type::number, t, "not an integer"); tracking.use(static_cast<int>(!lua_isnone(L, index)));
return nullopt; return nullopt;
} }
}; return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
template <typename T>
struct unqualified_check_getter<T, std::enable_if_t<std::is_enum<T>::value && !meta::any_same<T, meta_function, type>::value>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
int isnum = 0;
lua_Integer value = lua_tointegerx(L, index, &isnum);
if (isnum == 0) {
type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t, "not a valid enumeration value");
return nullopt;
} }
tracking.use(1);
return static_cast<T>(value);
}
};
template <typename T>
struct unqualified_check_getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
int isnum = 0;
lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum == 0) {
type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t, "not a valid floating point number");
return nullopt;
}
tracking.use(1);
return static_cast<T>(value);
} }
}; };
template <typename T> template <typename T>
struct unqualified_getter<optional<T>> { struct unqualified_getter<optional<T>> {
static decltype(auto) get(lua_State* L, int index, record& tracking) { static decltype(auto) get(lua_State* L, int index, record& tracking) {
return check_get<T>(L, index, no_panic, tracking); return stack::unqualified_check_get<T>(L, index, no_panic, tracking);
} }
}; };

View File

@ -29,64 +29,55 @@
namespace sol { namespace sol {
namespace stack { namespace stack {
template <typename X> template <typename X, type expected, typename>
struct qualified_checker<X, type::userdata, std::enable_if_t< struct qualified_checker {
is_unique_usertype<X>::value
&& !std::is_reference<X>::value
>> {
typedef unique_usertype_traits<meta::unqualified_t<X>> u_traits;
typedef typename u_traits::type T;
typedef typename u_traits::template rebind_base<void> rebind_t;
template <typename Handler> template <typename Handler>
static bool check(std::false_type, lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking); if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<X>) {
} using u_traits = unique_usertype_traits<meta::unqualified_t<X>>;
using T = typename u_traits::type;
template <typename Handler> using rebind_t = typename u_traits::template rebind_base<void>;
static bool check(std::true_type, lua_State* L, int index, Handler&& handler, record& tracking) { if constexpr (!std::is_void_v<rebind_t>) {
// we have a unique pointer type that can be // we have a unique pointer type that can be
// rebound to a base/derived type // rebound to a base/derived type
const type indextype = type_of(L, index); const type indextype = type_of(L, index);
tracking.use(1); tracking.use(1);
if (indextype != type::userdata) { if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype, "value is not a userdata"); handler(L, index, type::userdata, indextype, "value is not a userdata");
return false; return false;
} }
void* memory = lua_touserdata(L, index); void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique_destructor(memory); memory = detail::align_usertype_unique_destructor(memory);
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
if (&detail::usertype_unique_alloc_destroy<T, X> == pdx) { if (&detail::usertype_unique_alloc_destroy<T, X> == pdx) {
return true; return true;
} }
if constexpr (derive<T>::value) { if constexpr (derive<T>::value) {
memory = detail::align_usertype_unique_tag<true, false>(memory); memory = detail::align_usertype_unique_tag<true, false>(memory);
detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory); detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory);
string_view ti = usertype_traits<T>::qualified_name(); string_view ti = usertype_traits<T>::qualified_name();
string_view rebind_ti = usertype_traits<rebind_t>::qualified_name(); string_view rebind_ti = usertype_traits<rebind_t>::qualified_name();
if (ic(nullptr, nullptr, ti, rebind_ti) != 0) { if (ic(nullptr, nullptr, ti, rebind_ti) != 0) {
return true; return true;
}
}
handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
return false;
}
else {
return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking);
} }
} }
handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); else if constexpr (!std::is_reference_v<X> && is_container_v<X>) {
return false; if (type_of(L, index) == type::userdata) {
} return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename Handler> else {
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { return stack::unqualified_check<nested<X>>(L, index, std::forward<Handler>(handler), tracking);
return check(meta::neg<std::is_void<rebind_t>>(), L, index, std::forward<Handler>(handler), tracking); }
}
};
template <typename X>
struct qualified_checker<X, type::userdata, std::enable_if_t<is_container<meta::unqualified_t<X>>::value && !std::is_reference<X>::value>> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
if (type_of(L, index) == type::userdata) {
return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking);
} }
else { else {
return stack::unqualified_check<nested<X>>(L, index, std::forward<Handler>(handler), tracking); return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking);
} }
} }
}; };

View File

@ -90,367 +90,317 @@ namespace sol { namespace stack {
struct unqualified_checker { struct unqualified_checker {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); if constexpr (std::is_same_v<T, bool>) {
const type indextype = type_of(L, index);
bool success = expected == indextype;
if (!success) {
// expected type, actual type, message
handler(L, index, expected, indextype, "");
}
return success;
}
};
template <typename T, type expected, typename C>
struct qualified_checker {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::unqualified_check<T>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T>
struct unqualified_checker<T, type::number, std::enable_if_t<std::is_integral<T>::value>> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
#if SOL_LUA_VERSION >= 503
#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
int isnum = 0;
lua_tointegerx(L, index, &isnum);
const bool success = isnum != 0;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
}
#elif (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
// this check is precise, does not convert
if (lua_isinteger(L, index) == 1) {
return true;
}
const bool success = false;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric (integral) type");
}
#else
type t = type_of(L, index);
const bool success = t == type::number;
#endif // If numbers are enabled, use the imprecise check
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type");
}
return success;
#else
#if !defined(SOL_STRINGS_ARE_NUMBERS) || !SOL_STRINGS_ARE_NUMBERS
// must pre-check, because it will convert
type t = type_of(L, index);
if (t != type::number) {
// expected type, actual type
handler(L, index, type::number, t, "not a numeric type");
return false;
}
#endif // Do not allow strings to be numbers
#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
int isnum = 0;
const lua_Number v = lua_tonumberx(L, index, &isnum);
const bool success = isnum != 0 && static_cast<lua_Number>(llround(v)) == v;
#else
const bool success = true;
#endif // Safe numerics and number precision checking
if (!success) {
// expected type, actual type
#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
#else
handler(L, index, type::number, t, "not a numeric type");
#endif
}
return success;
#endif // Lua Version 5.3 versus others
}
};
template <typename T>
struct unqualified_checker<T, type::number, std::enable_if_t<std::is_floating_point<T>::value>> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
bool success = lua_isnumber(L, index) == 1;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
}
return success;
#else
type t = type_of(L, index);
bool success = t == type::number;
if (!success) {
// expected type, actual type
handler(L, index, type::number, t, "not a numeric type");
}
return success;
#endif // Strings are Numbers
}
};
template <type expected, typename C>
struct unqualified_checker<lua_nil_t, expected, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
bool success = lua_isnil(L, index);
if (success) {
tracking.use(1); tracking.use(1);
bool success = lua_isboolean(L, index) == 1;
if (!success) {
// expected type, actual type
handler(L, index, expected, type_of(L, index), "");
}
return success; return success;
} }
tracking.use(0); else if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>) {
success = lua_isnone(L, index); tracking.use(1);
if (!success) { #if SOL_LUA_VERSION >= 503
// expected type, actual type #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
handler(L, index, expected, type_of(L, index), ""); int isnum = 0;
lua_tointegerx(L, index, &isnum);
const bool success = isnum != 0;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
}
#elif (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
// this check is precise, does not convert
if (lua_isinteger(L, index) == 1) {
return true;
}
const bool success = false;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric (integral) type");
}
#else
type t = type_of(L, index);
const bool success = t == type::number;
#endif // If numbers are enabled, use the imprecise check
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type");
}
return success;
#else
#if !defined(SOL_STRINGS_ARE_NUMBERS) || !SOL_STRINGS_ARE_NUMBERS
// must pre-check, because it will convert
type t = type_of(L, index);
if (t != type::number) {
// expected type, actual type
handler(L, index, type::number, t, "not a numeric type");
return false;
}
#endif // Do not allow strings to be numbers
#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
int isnum = 0;
const lua_Number v = lua_tonumberx(L, index, &isnum);
const bool success = isnum != 0 && static_cast<lua_Number>(llround(v)) == v;
#else
const bool success = true;
#endif // Safe numerics and number precision checking
if (!success) {
// expected type, actual type
#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
#else
handler(L, index, type::number, t, "not a numeric type");
#endif
}
return success;
#endif // Lua Version 5.3 versus others
} }
return success; else if constexpr (std::is_floating_point_v<T>) {
} tracking.use(1);
}; #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
bool success = lua_isnumber(L, index) == 1;
template <typename C> if (!success) {
struct unqualified_checker<detail::non_lua_nil_t, type::poly, C> { // expected type, actual type
template <typename Handler> handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { }
return !stack::unqualified_check<lua_nil_t>(L, index, std::forward<Handler>(handler), tracking); return success;
} #else
}; type t = type_of(L, index);
bool success = t == type::number;
template <type expected, typename C> if (!success) {
struct unqualified_checker<nullopt_t, expected, C> : unqualified_checker<lua_nil_t> {}; // expected type, actual type
handler(L, index, type::number, t, "not a numeric type");
template <typename C> }
struct unqualified_checker<this_state, type::poly, C> { return success;
template <typename Handler> #endif // Strings are Numbers
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct unqualified_checker<this_main_state, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct unqualified_checker<this_environment, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct unqualified_checker<variadic_args, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct unqualified_checker<type, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename T, typename C>
struct unqualified_checker<T, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
bool success = is_lua_reference<T>::value || !lua_isnone(L, index);
if (!success) {
// expected type, actual type
handler(L, index, type::poly, type_of(L, index), "");
} }
return success; else if constexpr(meta::any_same_v<T, type, this_state, this_main_state, this_environment, variadic_args>) {
} tracking.use(0);
};
template <typename T, typename C>
struct unqualified_checker<T, type::lightuserdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
bool success = t == type::userdata || t == type::lightuserdata;
if (!success) {
// expected type, actual type
handler(L, index, type::lightuserdata, t, "");
}
return success;
}
};
template <typename C>
struct unqualified_checker<userdata_value, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
bool success = t == type::userdata;
if (!success) {
// expected type, actual type
handler(L, index, type::userdata, t, "");
}
return success;
}
};
template <typename B, typename C>
struct unqualified_checker<basic_userdata<B>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::check<userdata_value>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T, typename C>
struct unqualified_checker<user<T>, type::userdata, C> : unqualified_checker<user<T>, type::lightuserdata, C> {};
template <typename T, typename C>
struct unqualified_checker<non_null<T>, type::userdata, C> : unqualified_checker<T, lua_type_of<T>::value, C> {};
template <typename C>
struct unqualified_checker<lua_CFunction, type::function, C> : stack_detail::basic_check<type::function, lua_iscfunction> {};
template <typename C>
struct unqualified_checker<std::remove_pointer_t<lua_CFunction>, type::function, C> : unqualified_checker<lua_CFunction, type::function, C> {};
template <typename C>
struct unqualified_checker<c_closure, type::function, C> : unqualified_checker<lua_CFunction, type::function, C> {};
template <typename T, typename C>
struct unqualified_checker<T, type::function, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::lua_nil || t == type::none || t == type::function) {
// allow for lua_nil to be returned
return true; return true;
} }
if (t != type::userdata && t != type::table) { else if constexpr (is_unique_usertype_v<T>) {
handler(L, index, type::function, t, "must be a function or table or a userdata"); using proper_T = typename unique_usertype_traits<T>::type;
return false; const type indextype = type_of(L, index);
} tracking.use(1);
// Do advanced check for call-style userdata? if (indextype != type::userdata) {
static const auto& callkey = to_string(meta_function::call); handler(L, index, type::userdata, indextype, "value is not a userdata");
if (lua_getmetatable(L, index) == 0) { return false;
// No metatable, no __call key possible }
handler(L, index, type::function, t, "value is not a function and does not have overriden metatable"); if (lua_getmetatable(L, index) == 0) {
return false; return true;
} }
if (lua_isnoneornil(L, -1)) { int metatableindex = lua_gettop(L);
if (stack_detail::check_metatable<detail::unique_usertype<proper_T>>(L, metatableindex)) {
void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique_destructor(memory);
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
bool success = &detail::usertype_unique_alloc_destroy<proper_T, T> == pdx;
if (!success) {
memory = detail::align_usertype_unique_tag<true>(memory);
#if 0
// New version
#else
const char*& name_tag = *static_cast<const char**>(memory);
success = usertype_traits<T>::qualified_name() == name_tag;
#endif
if (!success) {
handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
}
}
return success;
}
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, type::function, t, "value is not a function and does not have valid metatable"); handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)");
return false; return false;
} }
lua_getfield(L, -1, &callkey[0]); else if constexpr (meta::any_same_v<T, lua_nil_t,
if (lua_isnoneornil(L, -1)) { #if defined(SOL_CXX_17_FEATURES) && SOL_CXX_17_FEATURES
lua_pop(L, 2); std::nullopt_t,
handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type"); #endif
return false; nullopt_t>) {
bool success = lua_isnil(L, index);
if (success) {
tracking.use(1);
return success;
}
tracking.use(0);
success = lua_isnone(L, index);
if (!success) {
// expected type, actual type
handler(L, index, expected, type_of(L, index), "");
}
return success;
}
else if constexpr (std::is_same_v<T, env_key_t>) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) {
return true;
}
handler(L, index, type::table, t, "value cannot not have a valid environment");
return true;
}
else if constexpr (std::is_same_v<T, detail::non_lua_nil_t>) {
return !stack::unqualified_check<lua_nil_t>(L, index, std::forward<Handler>(handler), tracking);
}
else if constexpr(meta::is_specialization_of_v<T, basic_environment>) {
tracking.use(1);
if (lua_getmetatable(L, index) == 0) {
return true;
}
type t = type_of(L, -1);
if (t == type::table || t == type::none || t == type::lua_nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, type::table, t, "value does not have a valid metatable");
return false;
}
return true;
}
else if constexpr (std::is_same_v<T, metatable_key_t>) {
tracking.use(1);
if (lua_getmetatable(L, index) == 0) {
return true;
}
type t = type_of(L, -1);
if (t == type::table || t == type::none || t == type::lua_nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, expected, t, "value does not have a valid metatable");
return false;
}
return true;
}
else if constexpr (expected == type::userdata) {
if constexpr (meta::any_same_v<T, userdata_value> || meta::is_specialization_of_v<T, basic_userdata>) {
tracking.use(1);
type t = type_of(L, index);
bool success = t == type::userdata;
if (!success) {
// expected type, actual type
handler(L, index, type::userdata, t, "");
}
return success;
}
else if constexpr (meta::is_specialization_of_v<T, user>) {
unqualified_checker<lightuserdata_value> c;
(void)c;
return c.check(L, index, std::forward<Handler>(handler), tracking);
}
else {
if constexpr (std::is_pointer_v<T>) {
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
}
else if constexpr (meta::is_specialization_of_v<T, std::reference_wrapper>) {
using T_internal = typename T::type;
return stack::check<T_internal>(L, index, std::forward<Handler>(handler), tracking);
}
else {
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
}
}
}
else if constexpr (expected == type::poly) {
tracking.use(1);
bool success = is_lua_reference_v<T> || !lua_isnone(L, index);
if (!success) {
// expected type, actual type
handler(L, index, type::poly, type_of(L, index), "");
}
return success;
}
else if constexpr (expected == type::lightuserdata) {
tracking.use(1);
type t = type_of(L, index);
bool success = t == type::userdata || t == type::lightuserdata;
if (!success) {
// expected type, actual type
handler(L, index, type::lightuserdata, t, "");
}
return success;
}
else if constexpr (expected == type::function) {
if constexpr (meta::any_same_v<T, lua_CFunction, std::remove_pointer_t<lua_CFunction>, c_closure>) {
tracking.use(1);
bool success = lua_iscfunction(L, index) == 1;
if (!success) {
// expected type, actual type
handler(L, index, expected, type_of(L, index), "");
}
return success;
}
else {
tracking.use(1);
type t = type_of(L, index);
if (t == type::lua_nil || t == type::none || t == type::function) {
// allow for lua_nil to be returned
return true;
}
if (t != type::userdata && t != type::table) {
handler(L, index, type::function, t, "must be a function or table or a userdata");
return false;
}
// Do advanced check for call-style userdata?
static const auto& callkey = to_string(meta_function::call);
if (lua_getmetatable(L, index) == 0) {
// No metatable, no __call key possible
handler(L, index, type::function, t, "value is not a function and does not have overriden metatable");
return false;
}
if (lua_isnoneornil(L, -1)) {
lua_pop(L, 1);
handler(L, index, type::function, t, "value is not a function and does not have valid metatable");
return false;
}
lua_getfield(L, -1, &callkey[0]);
if (lua_isnoneornil(L, -1)) {
lua_pop(L, 2);
handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type");
return false;
}
// has call, is definitely a function
lua_pop(L, 2);
return true;
}
}
else if constexpr (expected == type::table) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::table) {
return true;
}
if (t != type::userdata) {
handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one");
return false;
}
return true;
}
else {
tracking.use(1);
const type indextype = type_of(L, index);
bool success = expected == indextype;
if (!success) {
// expected type, actual type, message
handler(L, index, expected, indextype, "");
}
return success;
} }
// has call, is definitely a function
lua_pop(L, 2);
return true;
} }
}; };
template <typename T, typename C> template <typename T>
struct unqualified_checker<T, type::table, C> { struct unqualified_checker<non_null<T>, type::userdata> : unqualified_checker<T, lua_type_of_v<T>> {};
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::table) {
return true;
}
if (t != type::userdata) {
handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one");
return false;
}
return true;
}
};
template <type expected, typename C> template <typename T>
struct unqualified_checker<metatable_key_t, expected, C> { struct unqualified_checker<detail::as_value_tag<T>, type::userdata> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
if (lua_getmetatable(L, index) == 0) {
return true;
}
type t = type_of(L, -1);
if (t == type::table || t == type::none || t == type::lua_nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, expected, t, "value does not have a valid metatable");
return false;
}
return true;
}
};
template <typename C>
struct unqualified_checker<env_key_t, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) {
return true;
}
handler(L, index, type::table, t, "value cannot not have a valid environment");
return true;
}
};
template <typename E, typename C>
struct unqualified_checker<basic_environment<E>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
if (lua_getmetatable(L, index) == 0) {
return true;
}
type t = type_of(L, -1);
if (t == type::table || t == type::none || t == type::lua_nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, type::table, t, "value does not have a valid metatable");
return false;
}
return true;
}
};
template <typename T, typename C>
struct unqualified_checker<detail::as_value_tag<T>, type::userdata, C> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index); const type indextype = type_of(L, index);
@ -507,8 +457,8 @@ namespace sol { namespace stack {
} }
}; };
template <typename T, typename C> template <typename T>
struct unqualified_checker<detail::as_pointer_tag<T>, type::userdata, C> { struct unqualified_checker<detail::as_pointer_tag<T>, type::userdata> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
if (indextype == type::lua_nil) { if (indextype == type::lua_nil) {
@ -525,88 +475,24 @@ namespace sol { namespace stack {
} }
}; };
template <typename T, typename C> template <typename... Args>
struct unqualified_checker<T, type::userdata, C> { struct unqualified_checker<std::tuple<Args...>, type::poly> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T, typename C>
struct unqualified_checker<T*, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return check_usertype<T*>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename X>
struct unqualified_checker<X, type::userdata, std::enable_if_t<is_unique_usertype<X>::value>> {
typedef typename unique_usertype_traits<X>::type T;
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
tracking.use(1);
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype, "value is not a userdata");
return false;
}
if (lua_getmetatable(L, index) == 0) {
return true;
}
int metatableindex = lua_gettop(L);
if (stack_detail::check_metatable<detail::unique_usertype<T>>(L, metatableindex)) {
void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique_destructor(memory);
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
bool success = &detail::usertype_unique_alloc_destroy<T, X> == pdx;
if (!success) {
memory = detail::align_usertype_unique_tag<true>(memory);
#if 0
// New version
#else
const char*& name_tag = *static_cast<const char**>(memory);
success = usertype_traits<X>::qualified_name() == name_tag;
#endif
if (!success) {
handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
}
}
return success;
}
lua_pop(L, 1);
handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)");
return false;
}
};
template <typename T, typename C>
struct unqualified_checker<std::reference_wrapper<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::check<T>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename... Args, typename C>
struct unqualified_checker<std::tuple<Args...>, type::poly, C> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking); return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking);
} }
}; };
template <typename A, typename B, typename C> template <typename A, typename B>
struct unqualified_checker<std::pair<A, B>, type::poly, C> { struct unqualified_checker<std::pair<A, B>, type::poly> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking); return stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking);
} }
}; };
template <typename T, typename C> template <typename T>
struct unqualified_checker<optional<T>, type::poly, C> { struct unqualified_checker<optional<T>, type::poly> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&&, record& tracking) { static bool check(lua_State* L, int index, Handler&&, record& tracking) {
type t = type_of(L, index); type t = type_of(L, index);
@ -618,14 +504,14 @@ namespace sol { namespace stack {
tracking.use(1); tracking.use(1);
return true; return true;
} }
return stack::check<T>(L, index, no_panic, tracking); return stack::unqualified_check<T>(L, index, no_panic, tracking);
} }
}; };
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
template <typename T, typename C> template <typename T>
struct unqualified_checker<std::optional<T>, type::poly, C> { struct unqualified_checker<std::optional<T>, type::poly> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&&, record& tracking) { static bool check(lua_State* L, int index, Handler&&, record& tracking) {
type t = type_of(L, index); type t = type_of(L, index);
@ -643,8 +529,8 @@ namespace sol { namespace stack {
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn, typename C> template <typename... Tn>
struct unqualified_checker<std::variant<Tn...>, type::poly, C> { struct unqualified_checker<std::variant<Tn...>, type::poly> {
typedef std::variant<Tn...> V; typedef std::variant<Tn...> V;
typedef std::variant_size<V> V_size; typedef std::variant_size<V> V_size;
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty; typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;

View File

@ -594,15 +594,11 @@ namespace sol {
struct popper; struct popper;
template <typename T, typename = void> template <typename T, typename = void>
struct unqualified_pusher; struct unqualified_pusher;
template <typename T, type = lua_type_of<T>::value, typename = void> template <typename X, type t = lua_type_of_v<X>, typename C = void>
struct unqualified_checker; struct unqualified_checker;
template <typename T, type = lua_type_of<T>::value, typename = void> template <typename X, type t = lua_type_of_v<X>, typename C = void>
struct qualified_checker; struct qualified_checker;
template <typename T, typename = void> template <typename T, typename = void>
struct qualified_interop_checker;
template <typename T, typename = void>
struct unqualified_interop_checker;
template <typename T, typename = void>
struct unqualified_check_getter; struct unqualified_check_getter;
template <typename T, typename = void> template <typename T, typename = void>
struct qualified_check_getter; struct qualified_check_getter;
@ -634,116 +630,50 @@ namespace sol {
} // namespace stack } // namespace stack
namespace meta { namespace meta_detail { namespace meta { namespace meta_detail {
template <typename T>
struct is_adl_sol_lua_get {
private:
template <typename C>
static meta::sfinae_yes_t test(
std::remove_reference_t<decltype(sol_lua_get(types<C>(), static_cast<lua_State*>(nullptr), -1, std::declval<stack::record&>()))>*);
template <typename C>
static meta::sfinae_no_t test(...);
public:
static constexpr bool value = std::is_same_v<decltype(test<T>(nullptr)), meta::sfinae_yes_t>;
};
template <typename T> template <typename T>
struct is_adl_sol_lua_interop_get { using adl_sol_lua_get_test_t = decltype(sol_lua_get(types<T>(), static_cast<lua_State*>(nullptr), -1, std::declval<stack::record&>()));
private:
template <typename C>
static meta::sfinae_yes_t test(
std::remove_reference_t<decltype(sol_lua_interop_get(types<C>(), static_cast<lua_State*>(nullptr), -1, static_cast<void*>(nullptr), std::declval<stack::record&>()))>*);
template <typename C>
static meta::sfinae_no_t test(...);
public:
static constexpr bool value = std::is_same_v<decltype(test<T>(nullptr)), meta::sfinae_yes_t>;
};
template <typename T> template <typename T>
struct is_adl_sol_lua_check { using adl_sol_lua_interop_get_test_t
private: = decltype(sol_lua_interop_get(types<T>(), static_cast<lua_State*>(nullptr), -1, static_cast<void*>(nullptr), std::declval<stack::record&>()));
template <typename C>
static meta::sfinae_yes_t test(std::remove_reference_t<decltype(
sol_lua_check(types<C>(), static_cast<lua_State*>(nullptr), -1, no_panic, std::declval<stack::record&>()))>*);
template <typename C>
static meta::sfinae_no_t test(...);
public:
static constexpr bool value = std::is_same_v<decltype(test<T>(nullptr)), meta::sfinae_yes_t>;
};
template <typename T> template <typename T>
struct is_adl_sol_lua_interop_check { using adl_sol_lua_check_test_t = decltype(sol_lua_check(types<T>(), static_cast<lua_State*>(nullptr), -1, no_panic, std::declval<stack::record&>()));
private:
template <typename C>
static meta::sfinae_yes_t test(std::remove_reference_t<decltype(
sol_lua_interop_check(types<C>(), static_cast<lua_State*>(nullptr), -1, type::none, no_panic, std::declval<stack::record&>()))>*);
template <typename C>
static meta::sfinae_no_t test(...);
public:
static constexpr bool value = std::is_same_v<decltype(test<T>(nullptr)), meta::sfinae_yes_t>;
};
template <typename T> template <typename T>
struct is_adl_sol_lua_check_get { using adl_sol_lua_interop_check_test_t
private: = decltype(sol_lua_interop_check(types<T>(), static_cast<lua_State*>(nullptr), -1, type::none, no_panic, std::declval<stack::record&>()));
template <typename C>
static meta::sfinae_yes_t test(std::remove_reference_t<decltype(
sol_lua_check_get(types<C>(), static_cast<lua_State*>(nullptr), -1, no_panic, std::declval<stack::record&>()))>*);
template <typename C>
static meta::sfinae_no_t test(...);
public: template <typename T>
static constexpr bool value = std::is_same_v<decltype(test<T>(nullptr)), meta::sfinae_yes_t>; using adl_sol_lua_check_get_test_t = decltype(sol_lua_check_get(types<T>(), static_cast<lua_State*>(nullptr), -1, no_panic, std::declval<stack::record&>()));
};
template <typename... Args> template <typename... Args>
struct is_adl_sol_lua_push { using adl_sol_lua_push_test_t = decltype(sol_lua_push(static_cast<lua_State*>(nullptr), std::declval<Args>()...));
private:
template <typename... C>
static meta::sfinae_yes_t test(std::remove_reference_t<decltype(sol_lua_push(static_cast<lua_State*>(nullptr), std::declval<C>()...))>*);
template <typename... C>
static meta::sfinae_no_t test(...);
public:
static constexpr bool value = std::is_same_v<decltype(test<Args...>(nullptr)), meta::sfinae_yes_t>;
};
template <typename T, typename... Args> template <typename T, typename... Args>
struct is_adl_sol_lua_push_exact { using adl_sol_lua_push_exact_test_t = decltype(sol_lua_push(types<T>(), static_cast<lua_State*>(nullptr), std::declval<Args>()...));
private:
template <typename... C>
static meta::sfinae_yes_t test(
std::remove_reference_t<decltype(sol_lua_push(types<T>(), static_cast<lua_State*>(nullptr), std::declval<C>()...))>*);
template <typename... C>
static meta::sfinae_no_t test(...);
public:
static constexpr bool value = std::is_same_v<decltype(test<Args...>(nullptr)), meta::sfinae_yes_t>;
};
template <typename T> template <typename T>
inline constexpr bool is_adl_sol_lua_get_v = is_adl_sol_lua_get<T>::value; inline constexpr bool is_adl_sol_lua_get_v = meta::is_detected_v<adl_sol_lua_get_test_t, T>;
template <typename T> template <typename T>
inline constexpr bool is_adl_sol_lua_interop_get_v = is_adl_sol_lua_interop_get<T>::value; inline constexpr bool is_adl_sol_lua_interop_get_v = meta::is_detected_v<adl_sol_lua_interop_get_test_t, T>;
template <typename T> template <typename T>
inline constexpr bool is_adl_sol_lua_check_v = is_adl_sol_lua_check<T>::value; inline constexpr bool is_adl_sol_lua_check_v = meta::is_detected_v<adl_sol_lua_check_test_t, T>;
template <typename T> template <typename T>
inline constexpr bool is_adl_sol_lua_interop_check_v = is_adl_sol_lua_interop_check<T>::value; inline constexpr bool is_adl_sol_lua_interop_check_v = meta::is_detected_v<adl_sol_lua_interop_check_test_t, T>;
template <typename T> template <typename T>
inline constexpr bool is_adl_sol_lua_check_get_v = is_adl_sol_lua_check_get<T>::value; inline constexpr bool is_adl_sol_lua_check_get_v = meta::is_detected_v<adl_sol_lua_check_get_test_t, T>;
template <typename... Args> template <typename... Args>
inline constexpr bool is_adl_sol_lua_push_v = is_adl_sol_lua_push<Args...>::value; inline constexpr bool is_adl_sol_lua_push_v = meta::is_detected_v<adl_sol_lua_push_test_t, Args...>;
template <typename T, typename... Args> template <typename T, typename... Args>
inline constexpr bool is_adl_sol_lua_push_exact_v = is_adl_sol_lua_push_exact<T, Args...>::value; inline constexpr bool is_adl_sol_lua_push_exact_v = meta::is_detected_v<adl_sol_lua_push_exact_test_t, T, Args...>;
}} // namespace meta::meta_detail }} // namespace meta::meta_detail
@ -791,7 +721,7 @@ namespace sol {
using strip_extensible_t = typename strip_extensible<T>::type; using strip_extensible_t = typename strip_extensible<T>::type;
template <typename C> template <typename C>
static int get_size_hint(const C& c) { static int get_size_hint(C& c) {
return static_cast<int>(c.size()); return static_cast<int>(c.size());
} }
@ -833,9 +763,12 @@ namespace sol {
return sol_lua_interop_get(types<Tu>(), L, index, unadjusted_pointer, tracking); return sol_lua_interop_get(types<Tu>(), L, index, unadjusted_pointer, tracking);
} }
else { else {
unqualified_interop_getter<Tu> g{}; (void)L;
(void)g; (void)index;
return g.get(L, index, unadjusted_pointer, tracking); (void)unadjusted_pointer;
(void)tracking;
using Ti = stack_detail::strip_extensible_t<Tu>;
return std::pair<bool, Ti*>{ false, nullptr };
} }
} }
@ -845,9 +778,7 @@ namespace sol {
return sol_lua_interop_get(types<T>(), L, index, unadjusted_pointer, tracking); return sol_lua_interop_get(types<T>(), L, index, unadjusted_pointer, tracking);
} }
else { else {
qualified_interop_getter<T> g{}; return unqualified_interop_get<T>(L, index, unadjusted_pointer, tracking);
(void)g;
return g.get(L, index, unadjusted_pointer, tracking);
} }
} }
@ -858,10 +789,12 @@ namespace sol {
return sol_lua_interop_check(types<Tu>(), L, index, index_type, std::forward<Handler>(handler), tracking); return sol_lua_interop_check(types<Tu>(), L, index, index_type, std::forward<Handler>(handler), tracking);
} }
else { else {
unqualified_interop_checker<Tu> c; (void)L;
// VC++ has a bad warning here: shut it up (void)index;
(void)c; (void)index_type;
return c.check(L, index, index_type, std::forward<Handler>(handler), tracking); (void)handler;
(void)tracking;
return false;
} }
} }
@ -871,10 +804,7 @@ namespace sol {
return sol_lua_interop_check(types<T>(), L, index, index_type, std::forward<Handler>(handler), tracking); return sol_lua_interop_check(types<T>(), L, index, index_type, std::forward<Handler>(handler), tracking);
} }
else { else {
qualified_interop_checker<T> c; return unqualified_interop_check<T>(L, index, index_type, std::forward<Handler>(handler), tracking);
// VC++ has a bad warning here: shut it up
(void)c;
return c.check(L, index, index_type, std::forward<Handler>(handler), tracking);
} }
} }
} // namespace stack_detail } // namespace stack_detail
@ -1435,11 +1365,11 @@ namespace sol {
return stack::push(L, false); return stack::push(L, false);
} }
else { else {
auto maybel = stack::unqualified_check_get<T&>(L, 1); auto maybel = stack::unqualified_check_get<T>(L, 1);
if (!maybel) { if (!maybel) {
return stack::push(L, false); return stack::push(L, false);
} }
auto mayber = stack::unqualified_check_get<T&>(L, 2); auto mayber = stack::unqualified_check_get<T>(L, 2);
if (!mayber) { if (!mayber) {
return stack::push(L, false); return stack::push(L, false);
} }

View File

@ -29,78 +29,6 @@
namespace sol { namespace sol {
namespace stack { namespace stack {
template <typename X>
struct qualified_getter<X, std::enable_if_t<
!std::is_reference<X>::value
&& is_unique_usertype<meta::unqualified_t<X>>::value
&& !std::is_void<typename unique_usertype_traits<meta::unqualified_t<X>>::template rebind_base<void>>::value
>> {
typedef unique_usertype_traits<meta::unqualified_t<X>> u_traits;
typedef typename u_traits::type T;
typedef typename u_traits::actual_type Real;
typedef typename u_traits::template rebind_base<void> rebind_t;
static Real get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique_destructor(memory);
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
if (&detail::usertype_unique_alloc_destroy<T, X> == pdx) {
memory = detail::align_usertype_unique_tag<true, false>(memory);
memory = detail::align_usertype_unique<Real, true, false>(memory);
Real* mem = static_cast<Real*>(memory);
return *mem;
}
Real r(nullptr);
if constexpr (!derive<T>::value) {
// TODO: abort / terminate, maybe only in debug modes?
return r;
}
else {
memory = detail::align_usertype_unique_tag<true, false>(memory);
detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory);
memory = detail::align_usertype_unique<Real, true, false>(memory);
string_view ti = usertype_traits<T>::qualified_name();
string_view rebind_ti = usertype_traits<rebind_t>::qualified_name();
int cast_operation = ic(memory, &r, ti, rebind_ti);
switch (cast_operation) {
case 1: {
// it's a perfect match,
// alias memory directly
Real* mem = static_cast<Real*>(memory);
return *mem;
}
case 2:
// it's a base match, return the
// aliased creation
return std::move(r);
default:
// uh oh..
break;
}
// TODO: abort / terminate, maybe only in debug modes?
return r;
}
}
};
template <typename T>
struct qualified_getter<T, std::enable_if_t<
!std::is_reference<T>::value
&& is_container<meta::unqualified_t<T>>::value
&& std::is_default_constructible<meta::unqualified_t<T>>::value
&& !is_lua_primitive<T>::value
&& !is_transparent_argument<T>::value
>> {
static T get(lua_State* L, int index, record& tracking) {
if (type_of(L, index) == type::userdata) {
return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
}
else {
return stack_detail::unchecked_unqualified_get<sol::nested<T>>(L, index, tracking);
}
}
};
} }
} // namespace sol::stack } // namespace sol::stack

View File

@ -118,60 +118,110 @@ namespace sol { namespace stack {
template <typename T, typename> template <typename T, typename>
struct unqualified_getter { struct unqualified_getter {
static T& get(lua_State* L, int index, record& tracking) { static decltype(auto) get(lua_State* L, int index, record& tracking) {
return unqualified_getter<detail::as_value_tag<T>>{}.get(L, index, tracking); if constexpr (std::is_same_v<T, bool>) {
tracking.use(1);
return lua_toboolean(L, index) != 0;
}
else if constexpr (std::is_enum_v<T>) {
tracking.use(1);
return static_cast<T>(lua_tointegerx(L, index, nullptr));
}
else if constexpr (std::is_integral_v<T>) {
tracking.use(1);
#if SOL_LUA_VERSION >= 503
if (lua_isinteger(L, index) != 0) {
return static_cast<T>(lua_tointeger(L, index));
}
#endif
return static_cast<T>(llround(lua_tonumber(L, index)));
}
else if constexpr (std::is_floating_point_v<T>) {
tracking.use(1);
return static_cast<T>(lua_tonumber(L, index));
}
else if constexpr (is_lua_reference_v<T>) {
tracking.use(1);
return T(L, index);
}
else if constexpr (is_unique_usertype_v<T>) {
using Real = typename unique_usertype_traits<T>::actual_type;
tracking.use(1);
void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique<Real>(memory);
Real* mem = static_cast<Real*>(memory);
return *mem;
}
else {
return stack_detail::unchecked_unqualified_get<detail::as_value_tag<T>>(L, index, tracking);
}
} }
}; };
template <typename T, typename C> template <typename X, typename>
struct qualified_getter { struct qualified_getter {
static decltype(auto) get(lua_State* L, int index, record& tracking) { static decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack::unqualified_get<T>(L, index, tracking); using Tu = meta::unqualified_t<X>;
} if constexpr (!std::is_reference_v<X> && is_container_v<Tu>
}; && std::is_default_constructible_v<Tu> && !is_lua_primitive_v<Tu> && !is_transparent_argument_v<Tu>) {
if (type_of(L, index) == type::userdata) {
template <typename U, typename> return static_cast<Tu>(stack_detail::unchecked_unqualified_get<Tu>(L, index, tracking));
struct unqualified_interop_getter { }
using T = stack_detail::strip_extensible_t<U>; else {
return stack_detail::unchecked_unqualified_get<sol::nested<Tu>>(L, index, tracking);
static std::pair<bool, T*> get(lua_State*, int, void*, record&) { }
return { false, nullptr }; }
} else if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<Tu>
}; && !std::is_void_v<typename unique_usertype_traits<Tu>::template rebind_base<void>>) {
using u_traits = unique_usertype_traits<Tu>;
template <typename T, typename> using T = typename u_traits::type;
struct qualified_interop_getter { using Real = typename u_traits::actual_type;
static decltype(auto) get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { using rebind_t = typename u_traits::template rebind_base<void>;
return stack_detail::unqualified_interop_get<T>(L, index, unadjusted_pointer, tracking); tracking.use(1);
} void* memory = lua_touserdata(L, index);
}; memory = detail::align_usertype_unique_destructor(memory);
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
template <typename T> if (&detail::usertype_unique_alloc_destroy<T, X> == pdx) {
struct unqualified_getter<T, std::enable_if_t<std::is_floating_point<T>::value>> { memory = detail::align_usertype_unique_tag<true, false>(memory);
static T get(lua_State* L, int index, record& tracking) { memory = detail::align_usertype_unique<Real, true, false>(memory);
tracking.use(1); Real* mem = static_cast<Real*>(memory);
return static_cast<T>(lua_tonumber(L, index)); return static_cast<Real>(*mem);
} }
}; Real r(nullptr);
if constexpr (!derive<T>::value) {
template <typename T> // TODO: abort / terminate, maybe only in debug modes?
struct unqualified_getter<T, std::enable_if_t<std::is_integral<T>::value>> { return static_cast<Real>(r);
static T get(lua_State* L, int index, record& tracking) { }
tracking.use(1); else {
#if SOL_LUA_VERSION >= 503 memory = detail::align_usertype_unique_tag<true, false>(memory);
if (lua_isinteger(L, index) != 0) { detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory);
return static_cast<T>(lua_tointeger(L, index)); memory = detail::align_usertype_unique<Real, true, false>(memory);
string_view ti = usertype_traits<T>::qualified_name();
string_view rebind_ti = usertype_traits<rebind_t>::qualified_name();
int cast_operation = ic(memory, &r, ti, rebind_ti);
switch (cast_operation) {
case 1: {
// it's a perfect match,
// alias memory directly
Real* mem = static_cast<Real*>(memory);
return static_cast<Real>(*mem);
}
case 2:
// it's a base match, return the
// aliased creation
return static_cast<Real>(std::move(r));
default:
// uh oh..
break;
}
// TODO: abort / terminate, maybe only in debug modes?
return static_cast<Real>(r);
}
}
else {
return stack::unqualified_get<Tu>(L, index, tracking);
} }
#endif
return static_cast<T>(llround(lua_tonumber(L, index)));
}
};
template <typename T>
struct unqualified_getter<T, std::enable_if_t<std::is_enum<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return static_cast<T>(lua_tointegerx(L, index, nullptr));
} }
}; };
@ -487,44 +537,47 @@ namespace sol { namespace stack {
}; };
template <typename T> template <typename T>
struct unqualified_getter<nested<T>, std::enable_if_t<!is_container<T>::value>> { struct unqualified_getter<nested<T>> {
static T get(lua_State* L, int index, record& tracking) { static T get(lua_State* L, int index, record& tracking) {
unqualified_getter<T> g; using Tu = meta::unqualified_t<T>;
// VC++ has a bad warning here: shut it up if constexpr (is_container_v<Tu>) {
(void)g; if constexpr (meta::is_associative<Tu>::value) {
return g.get(L, index, tracking); typedef typename T::value_type P;
} typedef typename P::first_type K;
}; typedef typename P::second_type V;
unqualified_getter<as_table_t<T>> g;
template <typename T> // VC++ has a bad warning here: shut it up
struct unqualified_getter<nested<T>, std::enable_if_t<is_container<T>::value>> { (void)g;
using Tu = meta::unqualified_t<T>; return g.get(types<K, nested<V>>(), L, index, tracking);
}
static T get(lua_State* L, int index, record& tracking) { else {
if constexpr(meta::is_associative<Tu>::value) { typedef typename T::value_type V;
typedef typename T::value_type P; unqualified_getter<as_table_t<T>> g;
typedef typename P::first_type K; // VC++ has a bad warning here: shut it up
typedef typename P::second_type V; (void)g;
unqualified_getter<as_table_t<T>> g; return g.get(types<nested<V>>(), L, index, tracking);
// VC++ has a bad warning here: shut it up }
(void)g;
return g.get(types<K, nested<V>>(), L, index, tracking);
} }
else { else {
typedef typename T::value_type V; unqualified_getter<Tu> g;
unqualified_getter<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up // VC++ has a bad warning here: shut it up
(void)g; (void)g;
return g.get(types<nested<V>>(), L, index, tracking); return g.get(L, index, tracking);
} }
} }
}; };
template <typename T> template <typename T>
struct unqualified_getter<T, std::enable_if_t<is_lua_reference<T>::value>> { struct unqualified_getter<as_container_t<T>> {
static T get(lua_State* L, int index, record& tracking) { static decltype(auto) get(lua_State* L, int index, record& tracking) {
tracking.use(1); return stack::unqualified_get<T>(L, index, tracking);
return T(L, index); }
};
template <typename T>
struct unqualified_getter<as_container_t<T>*> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack::unqualified_get<T*>(L, index, tracking);
} }
}; };
@ -581,14 +634,6 @@ namespace sol { namespace stack {
} }
}; };
template <>
struct unqualified_getter<bool> {
static bool get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return lua_toboolean(L, index) != 0;
}
};
template <> template <>
struct unqualified_getter<std::string> { struct unqualified_getter<std::string> {
static std::string get(lua_State* L, int index, record& tracking) { static std::string get(lua_State* L, int index, record& tracking) {
@ -894,20 +939,6 @@ namespace sol { namespace stack {
} }
}; };
template <typename T>
struct unqualified_getter<T, std::enable_if_t<is_unique_usertype<T>::value>> {
typedef typename unique_usertype_traits<T>::type P;
typedef typename unique_usertype_traits<T>::actual_type Real;
static Real& get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique<Real>(memory);
Real* mem = static_cast<Real*>(memory);
return *mem;
}
};
template <typename... Tn> template <typename... Tn>
struct unqualified_getter<std::tuple<Tn...>> { struct unqualified_getter<std::tuple<Tn...>> {
typedef std::tuple<decltype(stack::get<Tn>(nullptr, 0))...> R; typedef std::tuple<decltype(stack::get<Tn>(nullptr, 0))...> R;

View File

@ -49,7 +49,7 @@ namespace sol {
namespace stack_detail { namespace stack_detail {
template <typename T> template <typename T>
inline bool integer_value_fits(const T& value) { inline bool integer_value_fits(const T& value) {
if constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed<T>::value && sizeof(T) == sizeof(lua_Integer))) { if constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed_v<T> && sizeof(T) == sizeof(lua_Integer))) {
(void)value; (void)value;
return true; return true;
} }
@ -61,6 +61,21 @@ namespace sol {
return (u_min <= t_min || value >= static_cast<T>(u_min)) && (u_max >= t_max || value <= static_cast<T>(u_max)); return (u_min <= t_min || value >= static_cast<T>(u_min)) && (u_max >= t_max || value <= static_cast<T>(u_max));
} }
} }
template <typename T>
int msvc_is_ass_with_if_constexpr_push_enum(std::true_type, lua_State* L, const T& value) {
if constexpr (std::is_same_v<std::underlying_type_t<T>, char>) {
return stack::push(L, static_cast<int>(value));
}
else {
return stack::push(L, static_cast<std::underlying_type_t<T>>(value));
}
}
template <typename T>
int msvc_is_ass_with_if_constexpr_push_enum(std::false_type, lua_State*, const T&) {
return 0;
}
} }
inline int push_environment_of(lua_State* L, int index = -1) { inline int push_environment_of(lua_State* L, int index = -1) {
@ -112,19 +127,19 @@ namespace sol {
return push_fx(L, fx, std::forward<Args>(args)...); return push_fx(L, fx, std::forward<Args>(args)...);
} }
template <typename Arg, typename... Args, typename = std::enable_if_t<!std::is_same_v<meta::unqualified_t<Arg>, detail::with_function_tag>>> template <typename Arg, typename... Args>
static int push(lua_State* L, Arg&& arg, Args&&... args) { static int push(lua_State* L, Arg&& arg, Args&&... args) {
return push_keyed(L, usertype_traits<T>::metatable(), std::forward<Arg>(arg), std::forward<Args>(args)...); if constexpr (std::is_same_v<meta::unqualified_t<Arg>, detail::with_function_tag>) {
return push_fx(L, std::forward<Args>(args)...);
}
else {
return push_keyed(L, usertype_traits<T>::metatable(), std::forward<Arg>(arg), std::forward<Args>(args)...);
}
} }
static int push(lua_State* L) { static int push(lua_State* L) {
return push_keyed(L, usertype_traits<T>::metatable()); return push_keyed(L, usertype_traits<T>::metatable());
} }
template <typename... Args>
static int push(lua_State* L, detail::with_function_tag, Args&&... args) {
return push_fx(L, std::forward<Args>(args)...);
}
}; };
template <typename T> template <typename T>
@ -150,14 +165,14 @@ namespace sol {
return push_fx(L, fx, obj); return push_fx(L, fx, obj);
} }
template <typename Arg, typename... Args, typename = std::enable_if_t<!std::is_same_v<meta::unqualified_t<Arg>, detail::with_function_tag>>> template <typename Arg, typename... Args>
static int push(lua_State* L, Arg&& arg, Args&&... args) { static int push(lua_State* L, Arg&& arg, Args&&... args) {
return push_keyed(L, usertype_traits<U*>::metatable(), std::forward<Arg>(arg), std::forward<Args>(args)...); if constexpr (std::is_same_v<meta::unqualified_t<Arg>, detail::with_function_tag>) {
} return push_fx(L, std::forward<Args>(args)...);
}
template <typename... Args> else {
static int push(lua_State* L, detail::with_function_tag, Args&&... args) { return push_keyed(L, usertype_traits<U*>::metatable(), std::forward<Arg>(arg), std::forward<Args>(args)...);
return push_fx(L, std::forward<Args>(args)...); }
} }
}; };
@ -169,67 +184,118 @@ namespace sol {
} }
}; };
namespace stack_detail {
template <typename T>
struct uu_pusher {
using u_traits = unique_usertype_traits<T>;
using P = typename u_traits::type;
using Real = typename u_traits::actual_type;
using rebind_t = typename u_traits::template rebind_base<void>;
template <typename Arg, typename... Args>
static int push(lua_State* L, Arg&& arg, Args&&... args) {
if constexpr (std::is_base_of_v<Real, meta::unqualified_t<Arg>>) {
if (u_traits::is_null(arg)) {
return stack::push(L, lua_nil);
}
return push_deep(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
else {
return push_deep(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
}
template <typename... Args>
static int push_deep(lua_State* L, Args&&... args) {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata);
#endif // make sure stack doesn't overflow
P** pref = nullptr;
detail::unique_destructor* fx = nullptr;
detail::unique_tag* id = nullptr;
Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id);
*fx = detail::usertype_unique_alloc_destroy<P, Real>;
*id = &detail::inheritance<P>::template type_unique_cast<Real>;
detail::default_construct::construct(mem, std::forward<Args>(args)...);
*pref = unique_usertype_traits<T>::get(*mem);
if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) {
detail::lua_reg_table l{};
int index = 0;
detail::indexed_insert insert_fx(l, index);
detail::insert_default_registrations<P>(insert_fx, detail::property_always_true);
l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() };
luaL_setfuncs(L, l, 0);
}
lua_setmetatable(L, -2);
return 1;
}
};
} // namespace stack_detail
template <typename T, typename> template <typename T, typename>
struct unqualified_pusher { struct unqualified_pusher {
template <typename... Args> template <typename... Args>
static int push(lua_State* L, Args&&... args) { static int push(lua_State* L, Args&&... args) {
return stack::push<detail::as_value_tag<T>>(L, std::forward<Args>(args)...); using Tu = meta::unqualified_t<T>;
} if constexpr (is_lua_reference_v<Tu>) {
}; using int_arr = int[];
int_arr p{ (std::forward<Args>(args).push(L))... };
template <typename T> return p[0];
struct unqualified_pusher<T*,
meta::disable_if_t<meta::any<is_container<meta::unqualified_t<T>>, std::is_function<meta::unqualified_t<T>>,
is_lua_reference<meta::unqualified_t<T>>>::value>> {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
return stack::push<detail::as_pointer_tag<T>>(L, std::forward<Args>(args)...);
}
};
template <typename T>
struct unqualified_pusher<T, std::enable_if_t<is_unique_usertype<T>::value>> {
typedef unique_usertype_traits<T> u_traits;
typedef typename u_traits::type P;
typedef typename u_traits::actual_type Real;
typedef typename u_traits::template rebind_base<void> rebind_t;
template <typename Arg, meta::enable<std::is_base_of<Real, meta::unqualified_t<Arg>>> = meta::enabler>
static int push(lua_State* L, Arg&& arg) {
if (unique_usertype_traits<T>::is_null(arg)) {
return stack::push(L, lua_nil);
} }
return push_deep(L, std::forward<Arg>(arg)); else if constexpr (std::is_same_v<Tu, bool>) {
}
template <typename Arg0, typename Arg1, typename... Args>
static int push(lua_State* L, Arg0&& arg0, Arg0&& arg1, Args&&... args) {
return push_deep(L, std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...);
}
template <typename... Args>
static int push_deep(lua_State* L, Args&&... args) {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); luaL_checkstack(L, 1, detail::not_enough_stack_space_generic);
#endif // make sure stack doesn't overflow #endif // make sure stack doesn't overflow
P** pref = nullptr; lua_pushboolean(L, std::forward<Args>(args)...);
detail::unique_destructor* fx = nullptr; return 1;
detail::unique_tag* id = nullptr; }
Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id); else if constexpr (std::is_integral_v<Tu>) {
*fx = detail::usertype_unique_alloc_destroy<P, Real>; const Tu& value(std::forward<Args>(args)...);
*id = &detail::inheritance<P>::template type_unique_cast<Real>; #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
detail::default_construct::construct(mem, std::forward<Args>(args)...); luaL_checkstack(L, 1, detail::not_enough_stack_space_integral);
*pref = unique_usertype_traits<T>::get(*mem); #endif // make sure stack doesn't overflow
if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) { #if SOL_LUA_VERSION >= 503
detail::lua_reg_table l{}; if (stack_detail::integer_value_fits<Tu>(value)) {
int index = 0; lua_pushinteger(L, static_cast<lua_Integer>(value));
detail::indexed_insert insert_fx(l, index); return 1;
detail::insert_default_registrations<P>(insert_fx, detail::property_always_true); }
l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() }; #endif // Lua 5.3 and above
luaL_setfuncs(L, l, 0); #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) {
#if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS
// Is this really worth it?
assert(false && "integer value will be misrepresented in lua");
lua_pushnumber(L, static_cast<lua_Number>(std::forward<Args>(args)...));
return 1;
#else
throw error(detail::direct_error, "integer value will be misrepresented in lua");
#endif // No Exceptions
}
#endif // Safe Numerics and Number Precision Check
lua_pushnumber(L, static_cast<lua_Number>(value));
return 1;
}
else if constexpr (std::is_floating_point_v<Tu>) {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_floating);
#endif // make sure stack doesn't overflow
lua_pushnumber(L, std::forward<Args>(args)...);
return 1;
}
else if constexpr (std::is_enum_v<Tu>) {
return stack_detail::msvc_is_ass_with_if_constexpr_push_enum(std::true_type(), L, std::forward<Args>(args)...);
}
else if constexpr (std::is_pointer_v<Tu>) {
return stack::push<detail::as_pointer_tag<std::remove_pointer_t<T>>>(L, std::forward<Args>(args)...);
}
else if constexpr (is_unique_usertype_v<Tu>) {
stack_detail::uu_pusher<T> p;
(void)p;
return p.push(L, std::forward<Args>(args)...);
}
else {
return stack::push<detail::as_value_tag<T>>(L, std::forward<Args>(args)...);
} }
lua_setmetatable(L, -2);
return 1;
} }
}; };
@ -240,70 +306,19 @@ namespace sol {
} }
}; };
template <typename T>
struct unqualified_pusher<T, std::enable_if_t<std::is_floating_point<T>::value>> {
static int push(lua_State* L, const T& value) {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_floating);
#endif // make sure stack doesn't overflow
lua_pushnumber(L, value);
return 1;
}
};
template <typename T>
struct unqualified_pusher<T, std::enable_if_t<std::is_integral<T>::value>> {
static int push(lua_State* L, const T& value) {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_integral);
#endif // make sure stack doesn't overflow
#if SOL_LUA_VERSION >= 503
if (stack_detail::integer_value_fits<T>(value)) {
lua_pushinteger(L, static_cast<lua_Integer>(value));
return 1;
}
#endif // Lua 5.3 and above
#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) {
#if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS
// Is this really worth it?
assert(false && "integer value will be misrepresented in lua");
lua_pushnumber(L, static_cast<lua_Number>(value));
return 1;
#else
throw error(detail::direct_error, "integer value will be misrepresented in lua");
#endif // No Exceptions
}
#endif // Safe Numerics and Number Precision Check
lua_pushnumber(L, static_cast<lua_Number>(value));
return 1;
}
};
template <typename T>
struct unqualified_pusher<T, std::enable_if_t<std::is_enum<T>::value>> {
static int push(lua_State* L, const T& value) {
if (std::is_same<char, std::underlying_type_t<T>>::value) {
return stack::push(L, static_cast<int>(value));
}
return stack::push(L, static_cast<std::underlying_type_t<T>>(value));
}
};
template <typename T> template <typename T>
struct unqualified_pusher<detail::as_table_tag<T>> { struct unqualified_pusher<detail::as_table_tag<T>> {
using has_kvp = meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>>;
static int push(lua_State* L, const T& tablecont) { static int push(lua_State* L, const T& tablecont) {
typedef meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>> has_kvp;
return push(has_kvp(), std::false_type(), L, tablecont); return push(has_kvp(), std::false_type(), L, tablecont);
} }
static int push(std::true_type, lua_State* L, const T& tablecont) { static int push(std::true_type, lua_State* L, const T& tablecont) {
typedef meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>> has_kvp;
return push(has_kvp(), std::true_type(), L, tablecont); return push(has_kvp(), std::true_type(), L, tablecont);
} }
static int push(std::false_type, lua_State* L, const T& tablecont) { static int push(std::false_type, lua_State* L, const T& tablecont) {
typedef meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>> has_kvp;
return push(has_kvp(), std::false_type(), L, tablecont); return push(has_kvp(), std::false_type(), L, tablecont);
} }
@ -368,36 +383,28 @@ namespace sol {
}; };
template <typename T> template <typename T>
struct unqualified_pusher<as_table_t<T>, std::enable_if_t<is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { struct unqualified_pusher<as_table_t<T>> {
static int push(lua_State* L, const T& tablecont) {
return stack::push<detail::as_table_tag<T>>(L, tablecont);
}
};
template <typename T>
struct unqualified_pusher<as_table_t<T>, std::enable_if_t<!is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> {
static int push(lua_State* L, const T& v) { static int push(lua_State* L, const T& v) {
return stack::push(L, v); using inner_t = std::remove_pointer_t<meta::unwrap_unqualified_t<T>>;
if constexpr (is_container_v<inner_t>) {
return stack::push<detail::as_table_tag<T>>(L, v);
}
else {
return stack::push(L, v);
}
} }
}; };
template <typename T> template <typename T>
struct unqualified_pusher<nested<T>, std::enable_if_t<is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { struct unqualified_pusher<nested<T>> {
static int push(lua_State* L, const T& tablecont) { static int push(lua_State* L, const T& tablecont) {
unqualified_pusher<detail::as_table_tag<T>> p{}; using inner_t = std::remove_pointer_t<meta::unwrap_unqualified_t<T>>;
// silence annoying VC++ warning if constexpr (is_container_v<inner_t>) {
(void)p; return stack::push<detail::as_table_tag<T>>(L, tablecont);
return p.push(std::true_type(), L, tablecont); }
} else {
}; return stack::push<inner_t>(L, tablecont);
}
template <typename T>
struct unqualified_pusher<nested<T>, std::enable_if_t<!is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> {
static int push(lua_State* L, const T& tablecont) {
unqualified_pusher<meta::unqualified_t<T>> p{};
// silence annoying VC++ warning
(void)p;
return p.push(L, tablecont);
} }
}; };
@ -411,28 +418,6 @@ namespace sol {
} }
}; };
template <typename T>
struct unqualified_pusher<T, std::enable_if_t<is_lua_reference<T>::value>> {
static int push(lua_State* L, const T& ref) {
return ref.push(L);
}
static int push(lua_State* L, T&& ref) {
return ref.push(L);
}
};
template <>
struct unqualified_pusher<bool> {
static int push(lua_State* L, bool b) {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_generic);
#endif // make sure stack doesn't overflow
lua_pushboolean(L, b);
return 1;
}
};
template <> template <>
struct unqualified_pusher<lua_nil_t> { struct unqualified_pusher<lua_nil_t> {
static int push(lua_State* L, lua_nil_t) { static int push(lua_State* L, lua_nil_t) {
@ -604,22 +589,20 @@ namespace sol {
return 1; return 1;
} }
template <typename Arg, typename... Args, meta::disable<meta::any_same<meta::unqualified_t<Arg>, no_metatable_t, metatable_key_t>> = meta::enabler> template <typename Arg, typename... Args>
static int push(lua_State* L, Arg&& arg, Args&&... args) { static int push(lua_State* L, Arg&& arg, Args&&... args) {
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; if constexpr (std::is_same_v<meta::unqualified_t<Arg>, metatable_key_t>) {
return push_with(L, name, std::forward<Arg>(arg), std::forward<Args>(args)...); const auto name = &arg[0];
} return push_with<true>(L, name, std::forward<Args>(args)...);
}
template <typename... Args> else if constexpr (std::is_same_v<meta::unqualified_t<Arg>, no_metatable_t>) {
static int push(lua_State* L, no_metatable_t, Args&&... args) { const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; return push_with<false>(L, name, std::forward<Args>(args)...);
return push_with<false>(L, name, std::forward<Args>(args)...); }
} else {
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
template <typename Key, typename... Args> return push_with(L, name, std::forward<Arg>(arg), std::forward<Args>(args)...);
static int push(lua_State* L, metatable_key_t, Key&& key, Args&&... args) { }
const auto name = &key[0];
return push_with<true>(L, name, std::forward<Args>(args)...);
} }
static int push(lua_State* L, const user<T>& u) { static int push(lua_State* L, const user<T>& u) {
@ -734,22 +717,32 @@ namespace sol {
} }
}; };
template <typename Traits, typename Al> template <typename Ch, typename Traits, typename Al>
struct unqualified_pusher<std::basic_string<char, Traits, Al>> { struct unqualified_pusher<std::basic_string<Ch, Traits, Al>> {
static int push(lua_State* L, const std::basic_string<char, Traits, Al>& str) { static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& str) {
if constexpr (!std::is_same_v<Ch, char>) {
return stack::push(str.data(), str.size());
}
else {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_string); luaL_checkstack(L, 1, detail::not_enough_stack_space_string);
#endif // make sure stack doesn't overflow #endif // make sure stack doesn't overflow
lua_pushlstring(L, str.c_str(), str.size()); lua_pushlstring(L, str.c_str(), str.size());
return 1; return 1;
}
} }
static int push(lua_State* L, const std::basic_string<char, Traits, Al>& str, std::size_t sz) { static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& str, std::size_t sz) {
if constexpr (!std::is_same_v<Ch, char>) {
return stack::push(str.data(), sz);
}
else {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_string); luaL_checkstack(L, 1, detail::not_enough_stack_space_string);
#endif // make sure stack doesn't overflow #endif // make sure stack doesn't overflow
lua_pushlstring(L, str.c_str(), sz); lua_pushlstring(L, str.c_str(), sz);
return 1; return 1;
}
} }
}; };
@ -1066,17 +1059,6 @@ namespace sol {
} }
}; };
template <typename Ch, typename Traits, typename Al>
struct unqualified_pusher<std::basic_string<Ch, Traits, Al>, std::enable_if_t<!std::is_same<Ch, char>::value>> {
static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& wstr) {
return push(L, wstr, wstr.size());
}
static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& wstr, std::size_t sz) {
return stack::push(L, wstr.data(), wstr.data() + sz);
}
};
template <typename... Args> template <typename... Args>
struct unqualified_pusher<std::tuple<Args...>> { struct unqualified_pusher<std::tuple<Args...>> {
template <std::size_t... I, typename T> template <std::size_t... I, typename T>

View File

@ -72,13 +72,13 @@ namespace sol {
inline int default_traceback_error_handler(lua_State* L) { inline int default_traceback_error_handler(lua_State* L) {
std::string msg = "An unknown error has triggered the default error handler"; std::string msg = "An unknown error has triggered the default error handler";
optional<string_view> maybetopmsg = stack::check_get<string_view>(L, 1); optional<string_view> maybetopmsg = stack::unqualified_check_get<string_view>(L, 1, no_panic);
if (maybetopmsg) { if (maybetopmsg) {
const string_view& topmsg = maybetopmsg.value(); const string_view& topmsg = maybetopmsg.value();
msg.assign(topmsg.data(), topmsg.size()); msg.assign(topmsg.data(), topmsg.size());
} }
luaL_traceback(L, L, msg.c_str(), 1); luaL_traceback(L, L, msg.c_str(), 1);
optional<string_view> maybetraceback = stack::check_get<string_view>(L, -1); optional<string_view> maybetraceback = stack::unqualified_check_get<string_view>(L, -1, no_panic);
if (maybetraceback) { if (maybetraceback) {
const string_view& traceback = maybetraceback.value(); const string_view& traceback = maybetraceback.value();
msg.assign(traceback.data(), traceback.size()); msg.assign(traceback.data(), traceback.size());
@ -141,7 +141,7 @@ namespace sol {
#endif // serialize exception information if possible #endif // serialize exception information if possible
if (t == type::string) { if (t == type::string) {
err += ": "; err += ": ";
string_view serr = stack::get<string_view>(L, result.stack_index()); string_view serr = stack::unqualified_get<string_view>(L, result.stack_index());
err.append(serr.data(), serr.size()); err.append(serr.data(), serr.size());
} }
#if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS #if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS

View File

@ -47,6 +47,23 @@ namespace sol {
using sfinae_yes_t = std::true_type; using sfinae_yes_t = std::true_type;
using sfinae_no_t = std::false_type; using sfinae_no_t = std::false_type;
template <typename T>
using void_t = void;
namespace meta_detail {
template <template <class...> class Test, class, class... Args>
struct is_detected : std::false_type {};
template <template <class...> class Test, class... Args>
struct is_detected<Test, void_t<Test<Args...>>, Args...> : std::true_type {};
} // namespace detail
template <template <class...> class Trait, class... Args>
using is_detected = typename meta_detail::is_detected<Trait, void, Args...>::type;
template <template <class...> class Trait, class... Args>
constexpr inline bool is_detected_v = is_detected<Trait, Args...>::value;
template <std::size_t I> template <std::size_t I>
using index_value = std::integral_constant<std::size_t, I>; using index_value = std::integral_constant<std::size_t, I>;
@ -130,18 +147,21 @@ namespace sol {
template <typename T> template <typename T>
using remove_member_pointer_t = remove_member_pointer<T>; using remove_member_pointer_t = remove_member_pointer<T>;
template <class T, class...> template <typename T, typename...>
struct all_same : std::true_type {}; struct all_same : std::true_type {};
template <class T, class U, class... Args> template <typename T, typename U, typename... Args>
struct all_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value && all_same<T, Args...>::value> {}; struct all_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value && all_same<T, Args...>::value> {};
template <class T, class...> template <typename T, typename...>
struct any_same : std::false_type {}; struct any_same : std::false_type {};
template <class T, class U, class... Args> template <typename T, typename U, typename... Args>
struct any_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value || any_same<T, Args...>::value> {}; struct any_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value || any_same<T, Args...>::value> {};
template <typename T, typename...Args>
constexpr inline bool any_same_v = any_same<T, Args...>::value;
template <bool B> template <bool B>
using boolean = std::integral_constant<bool, B>; using boolean = std::integral_constant<bool, B>;
@ -151,6 +171,9 @@ namespace sol {
template <typename T> template <typename T>
using neg = boolean<!T::value>; using neg = boolean<!T::value>;
template <typename T>
constexpr inline bool neg_v = neg<T>::value;
template <typename Condition, typename Then, typename Else> template <typename Condition, typename Then, typename Else>
using condition = conditional_t<Condition::value, Then, Else>; using condition = conditional_t<Condition::value, Then, Else>;
@ -166,6 +189,12 @@ namespace sol {
template <typename T, typename... Args> template <typename T, typename... Args>
struct any<T, Args...> : condition<T, boolean<true>, any<Args...>> {}; struct any<T, Args...> : condition<T, boolean<true>, any<Args...>> {};
template <typename T, typename... Args>
constexpr inline bool all_v = all<T, Args...>::value;
template <typename T, typename... Args>
constexpr inline bool any_v = any<T, Args...>::value;
enum class enable_t { _ }; enum class enable_t { _ };
constexpr const auto enabler = enable_t::_; constexpr const auto enabler = enable_t::_;
@ -538,11 +567,17 @@ namespace sol {
using supports_to_string_member = meta::boolean<meta_detail::has_to_string_test<meta_detail::non_void_t<T>>::value>; using supports_to_string_member = meta::boolean<meta_detail::has_to_string_test<meta_detail::non_void_t<T>>::value>;
template <typename T> template <typename T>
struct is_callable : boolean<meta_detail::is_callable<T>::value> {}; using is_callable = boolean<meta_detail::is_callable<T>::value>;
template <typename T>
constexpr inline bool is_callable_v = is_callable<T>::value;
template <typename T> template <typename T>
struct has_begin_end : decltype(meta_detail::has_begin_end_impl::test<T>(0)) {}; struct has_begin_end : decltype(meta_detail::has_begin_end_impl::test<T>(0)) {};
template <typename T>
constexpr inline bool has_begin_end_v = has_begin_end<T>::value;
template <typename T> template <typename T>
struct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test<T>(0)) {}; struct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test<T>(0)) {};
@ -592,28 +627,76 @@ namespace sol {
using is_matched_lookup = meta_detail::is_matched_lookup_impl<T, is_lookup<T>::value>; using is_matched_lookup = meta_detail::is_matched_lookup_impl<T, is_lookup<T>::value>;
template <typename T> template <typename T>
using is_string_like = any<is_specialization_of<meta::unqualified_t<T>, std::basic_string>, using is_initializer_list = meta::is_specialization_of<T, std::initializer_list>;
template <typename T>
constexpr inline bool is_initializer_list_v = is_initializer_list<T>::value;
template <typename T, typename CharT = char>
using is_string_literal_array_of = boolean<std::is_array_v<T> && std::is_same_v<std::remove_all_extents_t<T>, CharT>>;
template <typename T, typename CharT = char>
constexpr inline bool is_string_literal_array_of_v = is_string_literal_array_of<T, CharT>::value;
template <typename T>
using is_string_literal_array = boolean<std::is_array_v<T> && any_same_v<std::remove_all_extents_t<T>, char, char16_t, char32_t, wchar_t>>;
template <typename T>
constexpr inline bool is_string_literal_array_v = is_string_literal_array<T>::value;
template <typename T, typename CharT>
struct is_string_of : std::false_type {};
template <typename CharT, typename CharTargetT, typename TraitsT, typename AllocT>
struct is_string_of<std::basic_string<CharT, TraitsT, AllocT>, CharTargetT> : std::is_same<CharT, CharTargetT> {};
template <typename T, typename CharT>
constexpr inline bool is_string_of_v = is_string_of<T, CharT>::value;
template <typename T, typename CharT>
struct is_string_view_of : std::false_type {};
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
is_specialization_of<meta::unqualified_t<T>, std::basic_string_view>, template <typename CharT, typename CharTargetT, typename TraitsT>
struct is_string_view_of<std::basic_string_view<CharT, TraitsT>, CharTargetT> : std::is_same<CharT, CharTargetT> {};
#else #else
is_specialization_of<meta::unqualified_t<T>, basic_string_view>, template <typename CharT, typename CharTargetT, typename TraitsT>
struct is_string_view_of<basic_string_view<CharT, TraitsT>, CharTargetT> : std::is_same<CharT, CharTargetT> {};
#endif #endif
meta::all<std::is_array<unqualified_t<T>>,
meta::any_same<meta::unqualified_t<std::remove_all_extents_t<meta::unqualified_t<T>>>, char, char16_t, char32_t, wchar_t>>>; template <typename T, typename CharT>
constexpr inline bool is_string_view_of_v = is_string_view_of<T, CharT>::value;
template <typename T> template <typename T>
using is_string_constructible using is_string_like = meta::boolean<
= any<meta::all<std::is_array<unqualified_t<T>>, std::is_same<meta::unqualified_t<std::remove_all_extents_t<meta::unqualified_t<T>>>, char>>, is_specialization_of_v<T, std::basic_string>
std::is_same<unqualified_t<T>, const char*>, std::is_same<unqualified_t<T>, char>, std::is_same<unqualified_t<T>, std::string>,
std::is_same<unqualified_t<T>, std::initializer_list<char>>
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
, || is_specialization_of_v<T, std::basic_string_view>
std::is_same<unqualified_t<T>, std::string_view> #else
|| is_specialization_of_v<T, basic_string_view>
#endif #endif
>; || is_string_literal_array_v<T>>;
template <typename T> template <typename T>
using is_string_like_or_constructible = any<is_string_like<T>, is_string_constructible<T>>; constexpr inline bool is_string_like_v = is_string_like<T>::value;
template <typename T, typename CharT = char>
using is_string_constructible = meta::boolean<
is_string_literal_array_of_v<T, CharT>
|| std::is_same_v<T, const CharT*>
|| std::is_same_v<T, CharT>
|| is_string_of_v<T, CharT>
|| std::is_same_v<T, std::initializer_list<CharT>>
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
|| is_string_view_of_v<T, CharT>
#endif
>;
template <typename T, typename CharT = char>
constexpr inline bool is_string_constructible_v = is_string_constructible<T, CharT>::value;
template <typename T>
using is_string_like_or_constructible = meta::boolean<is_string_like_v<T> || is_string_constructible_v<T>>;
template <typename T> template <typename T>
struct is_pair : std::false_type {}; struct is_pair : std::false_type {};

View File

@ -480,6 +480,8 @@ namespace sol {
T value_; T value_;
public: public:
using type = T;
as_container_t() = default; as_container_t() = default;
as_container_t(const as_container_t&) = default; as_container_t(const as_container_t&) = default;
as_container_t(as_container_t&&) = default; as_container_t(as_container_t&&) = default;
@ -909,21 +911,25 @@ namespace sol {
template <typename T> template <typename T>
struct is_lua_reference : std::integral_constant<bool, struct is_lua_reference : std::integral_constant<bool,
std::is_base_of<reference, meta::unqualified_t<T>>::value || std::is_base_of<main_reference, meta::unqualified_t<T>>::value std::is_base_of_v<reference, T> || std::is_base_of_v<main_reference, T>
|| std::is_base_of<stack_reference, meta::unqualified_t<T>>::value> {}; || std::is_base_of_v<stack_reference, T>> {};
template <typename T> template <typename T>
inline constexpr bool is_lua_reference_v = is_lua_reference<T>::value; inline constexpr bool is_lua_reference_v = is_lua_reference<T>::value;
template <typename T> template <typename T>
struct is_lua_reference_or_proxy struct is_lua_reference_or_proxy
: std::integral_constant<bool, is_lua_reference<meta::unqualified_t<T>>::value || meta::is_specialization_of<meta::unqualified_t<T>, proxy>::value> {}; : std::integral_constant<bool, is_lua_reference_v<T> || meta::is_specialization_of_v<T, proxy>> {};
template <typename T> template <typename T>
inline constexpr bool is_lua_reference_or_proxy_v = is_lua_reference_or_proxy<T>::value; inline constexpr bool is_lua_reference_or_proxy_v = is_lua_reference_or_proxy<T>::value;
template <typename T> template <typename T>
struct is_transparent_argument : std::false_type {}; struct is_transparent_argument : std::false_type {};
template <typename T>
constexpr inline bool is_transparent_argument_v = is_transparent_argument<T>::value;
template <> template <>
struct is_transparent_argument<this_state> : std::true_type {}; struct is_transparent_argument<this_state> : std::true_type {};
template <> template <>
@ -933,38 +939,13 @@ namespace sol {
template <> template <>
struct is_transparent_argument<variadic_args> : std::true_type {}; struct is_transparent_argument<variadic_args> : std::true_type {};
template <typename T> template <typename T>
struct is_variadic_arguments : std::is_same<meta::unqualified_t<T>, variadic_args> {}; struct is_variadic_arguments : std::is_same<T, variadic_args> {};
namespace detail {
template <typename T>
struct is_initializer_list : std::false_type {};
template <typename T>
struct is_initializer_list<std::initializer_list<T>> : std::true_type {};
template <typename T, typename C = void>
struct is_container : std::false_type {};
template <typename T>
struct is_container<std::initializer_list<T>> : std::false_type {};
template <typename T>
struct is_container<T, std::enable_if_t<meta::is_string_like<meta::unqualified_t<T>>::value>> : std::false_type {};
template <typename T>
struct is_container<T,
std::enable_if_t<meta::all<std::is_array<meta::unqualified_t<T>>,
meta::neg<meta::any_same<std::remove_all_extents_t<meta::unqualified_t<T>>, char, wchar_t, char16_t, char32_t>>>::value>> : std::true_type {
};
template <typename T>
struct is_container<T,
std::enable_if_t<meta::all<meta::has_begin_end<meta::unqualified_t<T>>, meta::neg<is_initializer_list<meta::unqualified_t<T>>>,
meta::neg<meta::is_string_like<meta::unqualified_t<T>>>>::value>> : std::true_type {};
} // namespace detail
template <typename T> template <typename T>
struct is_container : detail::is_container<T> {}; struct is_container : std::integral_constant<bool, !meta::is_initializer_list_v<T> && !meta::is_string_like_v<T> && !meta::is_string_literal_array_v<T> && !is_transparent_argument_v<T> && !is_lua_reference_v<T> && (meta::has_begin_end_v<T> || std::is_array_v<T>)> {};
template <typename T>
constexpr inline bool is_container_v = is_container<T>::value;
template <typename T> template <typename T>
struct is_to_stringable : meta::any<meta::supports_to_string_member<meta::unqualified_t<T>>, meta::supports_adl_to_string<meta::unqualified_t<T>>, struct is_to_stringable : meta::any<meta::supports_to_string_member<meta::unqualified_t<T>>, meta::supports_adl_to_string<meta::unqualified_t<T>>,
@ -1224,17 +1205,23 @@ namespace sol {
struct has_internal_marker_impl<T, typename void_<typename T::SOL_INTERNAL_UNSPECIALIZED_MARKER_>::type> : std::true_type {}; struct has_internal_marker_impl<T, typename void_<typename T::SOL_INTERNAL_UNSPECIALIZED_MARKER_>::type> : std::true_type {};
template <typename T> template <typename T>
struct has_internal_marker : has_internal_marker_impl<T> {}; using has_internal_marker = has_internal_marker_impl<T>;
template <typename T>
constexpr inline bool has_internal_marker_v = has_internal_marker<T>::value;
} // namespace detail } // namespace detail
template <typename T> template <typename T>
struct is_lua_primitive struct is_lua_primitive
: std::integral_constant<bool, : std::integral_constant<bool,
type::userdata != lua_type_of<meta::unqualified_t<T>>::value type::userdata != lua_type_of_v<T>
|| ((type::userdata == lua_type_of<meta::unqualified_t<T>>::value) && detail::has_internal_marker<lua_type_of<meta::unqualified_t<T>>>::value || ((type::userdata == lua_type_of_v<T>) && detail::has_internal_marker_v<lua_type_of<T>>
&& !detail::has_internal_marker<lua_size<meta::unqualified_t<T>>>::value) && !detail::has_internal_marker_v<lua_size<T>>)
|| is_lua_reference<meta::unqualified_t<T>>::value || meta::is_specialization_of<meta::unqualified_t<T>, std::tuple>::value || is_lua_reference_v<T> || meta::is_specialization_of_v<T, std::tuple>
|| meta::is_specialization_of<meta::unqualified_t<T>, std::pair>::value> {}; || meta::is_specialization_of_v<T, std::pair>> {};
template <typename T>
constexpr inline bool is_lua_primitive_v = is_lua_primitive<T>::value;
template <typename T> template <typename T>
struct is_main_threaded : std::is_base_of<main_reference, T> {}; struct is_main_threaded : std::is_base_of<main_reference, T> {};

View File

@ -1080,7 +1080,7 @@ namespace sol {
return stack::push(L, lua_nil); return stack::push(L, lua_nil);
} }
int p; int p;
if (ip) { if constexpr (ip) {
++i.i; ++i.i;
p = stack::push_reference(L, i.i); p = stack::push_reference(L, i.i);
} }
@ -1102,7 +1102,12 @@ namespace sol {
return stack::push(L, lua_nil); return stack::push(L, lua_nil);
} }
int p; int p;
p = stack::push_reference(L, k + 1); if constexpr (std::is_integral_v<next_K>) {
p = stack::push_reference(L, k + 1);
}
else {
p = stack::stack_detail::push_reference(L, k + 1);
}
p += stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(*it)); p += stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(*it));
std::advance(it, 1); std::advance(it, 1);
return p; return p;
@ -1137,7 +1142,7 @@ namespace sol {
auto& self = get_src(L); auto& self = get_src(L);
detail::error_result er; detail::error_result er;
{ {
std::ptrdiff_t pos = stack::unqualified_get<std::ptrdiff_t>(L); std::ptrdiff_t pos = stack::unqualified_get<std::ptrdiff_t>(L, 2);
er = at_start(L, self, pos); er = at_start(L, self, pos);
} }
return handle_errors(L, er); return handle_errors(L, er);
@ -1315,7 +1320,7 @@ namespace sol {
return 0; return 0;
} }
int p; int p;
p = stack::push_reference(L, k + 1); p = stack::push(L, k + 1);
p += stack::push_reference(L, detail::deref_non_pointer(*it)); p += stack::push_reference(L, detail::deref_non_pointer(*it));
std::advance(it, 1); std::advance(it, 1);
return p; return p;

View File

@ -365,7 +365,7 @@ namespace sol {
template <typename T> template <typename T>
struct unqualified_pusher<as_container_t<T>> { struct unqualified_pusher<as_container_t<T>> {
typedef meta::unqualified_t<T> C; using C = meta::unqualified_t<T>;
static int push_lvalue(std::true_type, lua_State* L, const C& cont) { static int push_lvalue(std::true_type, lua_State* L, const C& cont) {
stack_detail::metatable_setup<C*, true> fx(L); stack_detail::metatable_setup<C*, true> fx(L);
@ -397,7 +397,7 @@ namespace sol {
template <typename T> template <typename T>
struct unqualified_pusher<as_container_t<T*>> { struct unqualified_pusher<as_container_t<T*>> {
typedef std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>> C; using C = std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>>;
static int push(lua_State* L, T* cont) { static int push(lua_State* L, T* cont) {
stack_detail::metatable_setup<C> fx(L); stack_detail::metatable_setup<C> fx(L);
@ -406,8 +406,8 @@ namespace sol {
}; };
template <typename T> template <typename T>
struct unqualified_pusher<T, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<is_lua_reference<meta::unqualified_t<T>>>>::value>> { struct unqualified_pusher<T, std::enable_if_t<is_container_v<T>>> {
typedef meta::unqualified_t<T> C; using C = T;
static int push(lua_State* L, const T& cont) { static int push(lua_State* L, const T& cont) {
stack_detail::metatable_setup<C> fx(L); stack_detail::metatable_setup<C> fx(L);
@ -421,36 +421,14 @@ namespace sol {
}; };
template <typename T> template <typename T>
struct unqualified_pusher<T*, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<is_lua_reference<meta::unqualified_t<T>>>>::value>> { struct unqualified_pusher<T*, std::enable_if_t<is_container_v<T>>> {
typedef std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>> C; using C = std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>>;
static int push(lua_State* L, T* cont) { static int push(lua_State* L, T* cont) {
stack_detail::metatable_setup<C> fx(L); stack_detail::metatable_setup<C> fx(L);
return stack::push<detail::as_pointer_tag<T>>(L, detail::with_function_tag(), fx, cont); return stack::push<detail::as_pointer_tag<T>>(L, detail::with_function_tag(), fx, cont);
} }
}; };
template <typename T, typename C>
struct unqualified_checker<as_container_t<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::check<T>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T>
struct unqualified_getter<as_container_t<T>> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack::unqualified_get<T>(L, index, tracking);
}
};
template <typename T>
struct unqualified_getter<as_container_t<T>*> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack::unqualified_get<T*>(L, index, tracking);
}
};
} // namespace stack } // namespace stack
} // namespace sol } // namespace sol

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2019-02-16 22:26:16.417718 UTC // Generated 2019-03-10 01:57:28.833449 UTC
// This header was generated with sol v3.0.0 (revision 95ffd10) // This header was generated with sol v3.0.0 (revision b6f4093)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
@ -245,6 +245,14 @@
#include <utility> #include <utility>
#include <type_traits> #include <type_traits>
#if defined(SOL_USING_CXX_LUA) && SOL_USING_CXX_LUA
struct lua_State;
#else
extern "C" {
struct lua_State;
}
#endif // C++ Mangling for Lua vs. Not
namespace sol { namespace sol {
template <bool b> template <bool b>

File diff suppressed because it is too large Load Diff