improve all tests, fix all tests, and improve metatable for GCC builds

This commit is contained in:
ThePhD 2018-12-21 01:07:05 -05:00
parent c35c66baf7
commit 88cafb281f
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
26 changed files with 1394 additions and 1241 deletions

View File

@ -230,11 +230,11 @@ file(TO_CMAKE_PATH "${LUA_JIT_SOURCE_DIR}/${LUA_JIT_PREBUILT_EXE}" LUA_JIT_SOURC
file(TO_CMAKE_PATH "${LUA_JIT_SOURCE_DIR}/${LUA_JIT_PREBUILT_DLL}" LUA_JIT_SOURCE_LUA_DLL)
file(TO_CMAKE_PATH "${LUA_JIT_SOURCE_DIR}/${LUA_JIT_PREBUILT_EXP}" LUA_JIT_SOURCE_LUA_LIB_EXP)
file(TO_CMAKE_PATH "${LUA_JIT_LIB_FILE}" LUA_JIT_DESTINATION_LUA_LIB)
file(TO_CMAKE_PATH "${LUA_JIT_IMP_LIB_FILE}" LUA_JIT_DESTINATION_LUA_IMP_LIB)
file(TO_CMAKE_PATH "${LUA_JIT_EXE_FILE}" LUA_JIT_DESTINATION_LUA_INTERPRETER)
file(TO_CMAKE_PATH "${LUA_JIT_DLL_FILE}" LUA_JIT_DESTINATION_LUA_DLL)
file(TO_CMAKE_PATH "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${LUA_JIT_LIB_EXP_FILENAME}" LUA_JIT_DESTINATION_LUA_LIB_EXP)
file(TO_CMAKE_PATH "${LUA_JIT_IMP_LIB_FILE}" LUA_JIT_DESTINATION_LUA_IMP_LIB)
file(TO_CMAKE_PATH "${LUA_JIT_LIB_FILE}" LUA_JIT_DESTINATION_LUA_LIB)
file(TO_CMAKE_PATH "${LUA_JIT_EXE_FILE}" LUA_JIT_DESTINATION_LUA_INTERPRETER)
if (WIN32 AND NOT MSVC)
string(COMPARE EQUAL ${LUA_JIT_VERSION} ${LUA_JIT_2.0_LATEST_VERSION} lua_jit_same_version_20)
@ -247,14 +247,21 @@ elseif(LUA_JIT_NORMALIZED_LUA_VERSION MATCHES "latest")
set(LUA_JIT_PULL_LATEST TRUE)
endif()
set(LUA_JIT_BYPRODUCTS "${LUA_JIT_SOURCE_LUA_LIB}" "${LUA_JIT_SOURCE_LUA_LIB_EXP}"
set(LUA_JIT_BYPRODUCTS "${LUA_JIT_SOURCE_LUA_LIB}"
"${LUA_JIT_SOURCE_LUA_DLL}" "${LUA_JIT_SOURCE_LUA_INTERPRETER}")
set(LUA_JIT_INSTALL_BYPRODUCTS "${LUA_JIT_DESTINATION_LUA_LIB}" "${LUA_JIT_DESTINATION_LUA_LIB_EXP}"
set(LUA_JIT_INSTALL_BYPRODUCTS "${LUA_JIT_DESTINATION_LUA_LIB}"
"${LUA_JIT_DESTINATION_LUA_DLL}" "${LUA_JIT_DESTINATION_LUA_INTERPRETER}")
if (MSVC)
set(LUA_JIT_BYPRODUCTS "${LUA_JIT_BYPRODUCTS}" "${LUA_JIT_SOURCE_LUA_LIB_EXP}")
set(LUA_JIT_INSTALL_BYPRODUCTS "${LUA_JIT_INSTALL_BYPRODUCTS}" "${LUA_JIT_DESTINATION_LUA_LIB_EXP}")
endif()
if (CMAKE_IMPORT_LIBRARY_SUFFIX)
set(LUA_JIT_BYPRODUCTS "${LUA_JIT_BYPRODUCTS}" "${LUA_JIT_SOURCE_LUA_IMP_LIB}")
if (NOT MSVC)
set(LUA_JIT_BYPRODUCTS "${LUA_JIT_BYPRODUCTS}" "${LUA_JIT_SOURCE_LUA_IMP_LIB}")
endif()
set(LUA_JIT_INSTALL_BYPRODUCTS "${LUA_JIT_INSTALL_BYPRODUCTS}" "${LUA_JIT_DESTINATION_LUA_IMP_LIB}")
endif()
@ -300,7 +307,7 @@ if (LUA_JIT_GIT_COMMIT OR LUA_JIT_PULL_LATEST)
${LUA_JIT_BUILD_COMMAND}
INSTALL_COMMAND ""
TEST_COMMAND ""
BUILD_BYPRODUCTS ${LUA_JIT_BYPRODUCTS})
BUILD_BYPRODUCTS "${LUA_JIT_BYPRODUCTS}")
else()
ExternalProject_Add(LUA_JIT
BUILD_IN_SOURCE TRUE
@ -320,23 +327,24 @@ else()
${LUA_JIT_BUILD_COMMAND}
INSTALL_COMMAND ""
TEST_COMMAND ""
BUILD_BYPRODUCTS ${LUA_JIT_BYPRODUCTS})
BUILD_BYPRODUCTS "${LUA_JIT_BYPRODUCTS}")
endif()
# # MAYBE?:
# Add additional post-build step to move all necessary headers/lua files
# for now, we just point directly to the `src` directory...
add_custom_command(TARGET LUA_JIT
POST_BUILD
add_custom_target(luajit_postbuild
${LUA_JIT_POSTBUILD_COMMANDS}
COMMENT ${LUA_JIT_POSTBUILD_COMMENTS}
BYPRODUCTS ${LUA_JIT_INSTALL_BYPRODUCTS})
DEPENDS "${LUA_JIT_BYPRODUCTS}"
)
# # Lua Library
add_library(${lualib} ${LUA_BUILD_LIBRARY_TYPE} IMPORTED)
# make sure the library we export really does depend on Lua JIT's external project
add_dependencies(${lualib} LUA_JIT)
add_dependencies(${lualib} luajit_postbuild)
# Configure properties
if (BUILD_LUA_AS_DLL)
if (MSVC)
@ -372,7 +380,7 @@ add_executable(${luainterpreter} IMPORTED)
set_target_properties(${luainterpreter}
PROPERTIES
IMPORTED_LOCATION "${LUA_JIT_DESTINATION_LUA_INTERPRETER}")
add_dependencies(${luainterpreter} LUA_JIT)
add_dependencies(${luainterpreter} luajit_postbuild)
# # set externally-visible target indicator
set(LUA_LIBRARIES ${lualib})

View File

@ -8,49 +8,38 @@ struct GlobalResource {
int value = 2;
};
// Customize sol2 to handle this type
namespace sol {
template <>
struct lua_type_of<GlobalResource*> : std::integral_constant<sol::type, sol::type::lightuserdata> {};
namespace stack {
template <>
struct checker<GlobalResource*> {
template <typename Handler>
static bool check(lua_State* L, int /*index*/, Handler&& handler, record& tracking) {
tracking.use(0);
// get the field from global storage
stack::get_field<true>(L, script_key);
// verify type
type t = static_cast<type>(lua_type(L, -1));
lua_pop(L, 1);
if (t != type::lightuserdata) {
handler(L, 0, type::lightuserdata, t, "global resource is not present");
return false;
}
return true;
}
};
template <>
struct unqualified_getter<GlobalResource*> {
static GlobalResource* get(lua_State* L, int /*index*/, record& tracking) {
// retrieve the (light) userdata for this type
tracking.use(0); // not actually pulling anything off the stack
stack::get_field<true>(L, script_key);
GlobalResource* ls = static_cast<GlobalResource*>(lua_touserdata(L, -1));
lua_pop(L, 1); // clean up stack value returned by `get_field`
return ls;
};
};
template <>
struct pusher<GlobalResource*> {
static int push(lua_State* L, GlobalResource* ls) {
// push light userdata
return stack::push(L, make_light(ls));;
}
};
template <typename Handler>
bool sol_lua_check(sol::types<GlobalResource*>, lua_State* L, int /*index*/, Handler&& handler, sol::stack::record& tracking) {
// not actually taking anything off the stack
tracking.use(0);
// get the field from global storage
sol::stack::get_field<true>(L, script_key);
// verify type
sol::type t = static_cast<sol::type>(lua_type(L, -1));
lua_pop(L, 1);
if (t != sol::type::lightuserdata) {
handler(L, 0, sol::type::lightuserdata, t, "global resource is not present as a light userdata");
return false;
}
return true;
}
GlobalResource* sol_lua_get(sol::types<GlobalResource*>, lua_State* L, int /*index*/, sol::stack::record& tracking) {
// retrieve the (light) userdata for this type
// not actually pulling anything off the stack
tracking.use(0);
sol::stack::get_field<true>(L, script_key);
GlobalResource* ls = static_cast<GlobalResource*>(lua_touserdata(L, -1));
// clean up stack value returned by `get_field`
lua_pop(L, 1);
return ls;
}
int sol_lua_push(lua_State* L, GlobalResource* ls) {
// push light userdata
return sol::stack::push(L, static_cast<void*>(ls));
}
int main() {
@ -67,7 +56,7 @@ int main() {
lua.set(script_key, &instance);
// note only 1 argument,
// despite being 2
// despite f having 2 arguments to recieve
lua.script("assert(f(1) == 3)");
return 0;

View File

@ -25,7 +25,7 @@ namespace sol {
namespace stack {
template <>
struct checker<two_things> {
struct unqualified_checker<two_things> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
// indices can be negative to count backwards from the top of the stack,

View File

@ -9,41 +9,27 @@ struct number_shim {
double num = 0;
};
namespace sol {
template <typename Handler>
bool sol_lua_check(sol::types<number_shim>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
// check_usertype is a backdoor for directly checking sol2 usertypes
if (!sol::stack::check_usertype<number_shim>(L, index)
&& !sol::stack::check<double>(L, index)) {
handler(L, index, sol::type_of(L, index), sol::type::userdata, "expected a number_shim or a number");
return false;
}
tracking.use(1);
return true;
}
template <>
struct lua_type_of<number_shim> : std::integral_constant<sol::type, sol::type::poly> {};
namespace stack {
template <>
struct checker<number_shim> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
// check_usertype is a backdoor for directly checking sol2 usertypes
if (!check_usertype<number_shim>(L, index) && !stack::check<double>(L, index)) {
handler(L, index, type_of(L, index), type::userdata, "expected a number_shim or a number");
return false;
}
tracking.use(1);
return true;
}
};
template <>
struct unqualified_getter<number_shim> {
static number_shim get(lua_State* L, int index, record& tracking) {
if (check_usertype<number_shim>(L, index)) {
number_shim& ns = get_usertype<number_shim>(L, index, tracking);
return ns;
}
number_shim ns{};
ns.num = stack::get<double>(L, index, tracking);
return ns;
}
};
} // namespace stack
} // namespace sol
number_shim sol_lua_get(sol::types<number_shim>, lua_State* L, int index, sol::stack::record& tracking) {
if (sol::stack::check_usertype<number_shim>(L, index)) {
number_shim& ns = sol::stack::get_usertype<number_shim>(L, index, tracking);
return ns;
}
number_shim ns{};
ns.num = sol::stack::get<double>(L, index, tracking);
return ns;
}
int main() {
sol::state lua;

View File

@ -34,7 +34,7 @@ void register_thing_type(sol::state& lua) {
if (!source.is<thing>()) {
return luaL_error(L, "given an incorrect object for this call");
}
sol::optional<sol::string_view> maybe_svkey = key.as<sol::string_view>();
sol::optional<sol::string_view> maybe_svkey = key.as<sol::optional<sol::string_view>>();
if (maybe_svkey) {
{
// functions are different from variables
@ -77,7 +77,7 @@ void register_thing_type(sol::state& lua) {
return luaL_error(L, "given an incorrect object for this call");
}
// write to member variables, etc. etc...
sol::optional<sol::string_view> maybe_svkey = key.as<sol::string_view>();
sol::optional<sol::string_view> maybe_svkey = key.as<sol::optional<sol::string_view>>();
if (maybe_svkey) {
{
// variables are different than funtions

View File

@ -55,7 +55,9 @@ int main() {
// you must make sure that the name of the function
// goes before the member function pointer
lua.new_usertype<foo, std::string>("foo", "print", &foo::print, "test", &foo::test);
lua.new_usertype<foo>("foo", sol::constructors<foo(std::string)>(),
"print", &foo::print,
"test", &foo::test);
// making the class from lua is simple
// same with calling member functions
@ -83,7 +85,7 @@ int main() {
sol::usertype<vector> utype = lua.new_usertype<vector>("vector", ctor);
// add to it as much as you like
lua["is_unit"] = &vector::is_unit;
utype["is_unit"] = &vector::is_unit;
// You can throw away the usertype after
// you set it: you do NOT
// have to keep it around
@ -111,4 +113,5 @@ int main() {
std::cout << std::endl;
return 0;
}

View File

@ -191,7 +191,7 @@
// Interop allows userdata from external systems
// with external memory layout and metatable names
// to be registered. It costs something to perform
// the checker / differentiation for sol2 usertypes versus
// the unqualified_checker / differentiation for sol2 usertypes versus
// external ones however, so this is off by default
#if !defined(SOL_ENABLE_INTEROP)
// off by default here

View File

@ -26,8 +26,8 @@
#include "traits.hpp"
#include "stack.hpp"
#include "map.hpp"
#include "object.hpp"
#include "map.hpp"
namespace sol {
@ -496,15 +496,16 @@ namespace sol {
template <typename X>
struct container_traits_default<X, std::enable_if_t<meta::all<is_forced_container<meta::unqualified_t<X>>, meta::has_value_type<meta::unqualified_t<container_decay_t<X>>>, meta::has_iterator<meta::unqualified_t<container_decay_t<X>>>>::value>> {
private:
typedef std::remove_pointer_t<meta::unwrap_unqualified_t<container_decay_t<X>>> T;
using T = std::remove_pointer_t<meta::unwrap_unqualified_t<container_decay_t<X>>>;
private:
typedef container_traits<X> deferred_traits;
typedef meta::is_associative<T> is_associative;
typedef meta::is_lookup<T> is_lookup;
typedef meta::is_matched_lookup<T> is_matched_lookup;
typedef typename T::iterator iterator;
typedef typename T::value_type value_type;
using deferred_traits = container_traits<X>;
using is_associative = meta::is_associative<T>;
using is_lookup = meta::is_lookup<T>;
using is_ordered = meta::is_ordered<T>;
using is_matched_lookup = meta::is_matched_lookup<T>;
using iterator = typename T::iterator;
using value_type = typename T::value_type;
typedef std::conditional_t<is_matched_lookup::value,
std::pair<value_type, value_type>,
std::conditional_t<is_associative::value || is_lookup::value,
@ -764,31 +765,49 @@ namespace sol {
template <bool idx_of = false>
static detail::error_result find_has_associative_lookup(std::true_type, lua_State* L, T& self) {
decltype(auto) key = stack::unqualified_get<K>(L, 2);
auto it = self.find(key);
if (it == deferred_traits::end(L, self)) {
return stack::push(L, lua_nil);
}
if constexpr (idx_of) {
return stack::push(L, std::distance(deferred_traits::begin(L, self), it));
if constexpr (!is_ordered::value && idx_of) {
(void)L;
(void)self;
return detail::error_result("cannot perform an 'index_of': '%s's is not an ordered container", detail::demangle<T>().data());
}
else {
return get_associative(is_associative(), L, it);
decltype(auto) key = stack::unqualified_get<K>(L, 2);
auto it = self.find(key);
if (it == deferred_traits::end(L, self)) {
return stack::push(L, lua_nil);
}
if constexpr (idx_of) {
auto dist = std::distance(deferred_traits::begin(L, self), it);
dist -= deferred_traits::index_adjustment(L, self);
return stack::push(L, dist);
}
else {
return get_associative(is_associative(), L, it);
}
}
}
template <bool idx_of = false>
static detail::error_result find_has_associative_lookup(std::false_type, lua_State* L, T& self) {
decltype(auto) value = stack::unqualified_get<V>(L, 2);
auto it = self.find(value);
if (it == deferred_traits::end(L, self)) {
return stack::push(L, lua_nil);
}
if constexpr (idx_of) {
return stack::push(L, std::distance(deferred_traits::begin(L, self), it));
if constexpr (!is_ordered::value && idx_of) {
(void)L;
(void)self;
return detail::error_result("cannot perform an 'index_of': '%s's is not an ordered container", detail::demangle<T>().data());
}
else {
return get_associative(is_associative(), L, it);
decltype(auto) value = stack::unqualified_get<V>(L, 2);
auto it = self.find(value);
if (it == deferred_traits::end(L, self)) {
return stack::push(L, lua_nil);
}
if constexpr (idx_of) {
auto dist = std::distance(deferred_traits::begin(L, self), it);
dist -= deferred_traits::index_adjustment(L, self);
return stack::push(L, dist);
}
else {
return get_associative(is_associative(), L, it);
}
}
}
@ -797,12 +816,13 @@ namespace sol {
return find_has_associative_lookup<idx_of>(meta::any<is_lookup, is_associative>(), L, self);
}
static detail::error_result find_associative_lookup(std::true_type, lua_State* L, iterator& it, std::size_t) {
static detail::error_result find_associative_lookup(std::true_type, lua_State* L, T&, iterator& it, std::size_t) {
return get_associative(is_associative(), L, it);
}
static detail::error_result find_associative_lookup(std::false_type, lua_State* L, iterator&, std::size_t index) {
return stack::push(L, index);
static detail::error_result find_associative_lookup(std::false_type, lua_State* L, T& self, iterator&, std::size_t idx) {
idx -= deferred_traits::index_adjustment(L, self);
return stack::push(L, idx);
}
template <bool = false>
@ -815,8 +835,8 @@ namespace sol {
decltype(auto) value = stack::unqualified_get<V>(L, 2);
auto it = deferred_traits::begin(L, self);
auto e = deferred_traits::end(L, self);
std::size_t index = 1;
for (;; ++it, ++index) {
std::size_t idx = 0;
for (;; ++it, ++idx) {
if (it == e) {
return stack::push(L, lua_nil);
}
@ -824,7 +844,7 @@ namespace sol {
break;
}
}
return find_associative_lookup(meta::any<is_lookup, is_associative, meta::boolean<!idx_of>>(), L, it, index);
return find_associative_lookup(meta::all<meta::boolean<!idx_of>, meta::any<is_lookup, is_associative>>(), L, self, it, idx);
}
template <bool idx_of = false>
@ -1306,7 +1326,8 @@ namespace sol {
for (std::size_t idx = 0; idx < N; ++idx) {
const auto& v = self[idx];
if (v == value) {
return stack::push(L, idx + 1);
idx -= deferred_traits::index_adjustment(L, self);
return stack::push(L, idx);
}
}
return stack::push(L, lua_nil);

View File

@ -28,9 +28,6 @@
#include "reference.hpp"
#include "stack.hpp"
#include "object_base.hpp"
#include "as_args.hpp"
#include "variadic_args.hpp"
#include "optional.hpp"
namespace sol {

View File

@ -60,6 +60,7 @@
#include "thread.hpp"
#include "userdata.hpp"
#include "metatable.hpp"
#include "as_args.hpp"
#include "variadic_args.hpp"
#include "variadic_results.hpp"

View File

@ -80,7 +80,7 @@ namespace stack {
};
template <typename T, type expected, typename>
struct checker {
struct unqualified_checker {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
@ -95,10 +95,10 @@ namespace stack {
};
template <typename T, type expected, typename C>
struct qualified_checker : checker<meta::unqualified_t<T>, lua_type_of<meta::unqualified_t<T>>::value, C> {};
struct qualified_checker : unqualified_checker<meta::unqualified_t<T>, lua_type_of<meta::unqualified_t<T>>::value, C> {};
template <typename T>
struct checker<T, type::number, std::enable_if_t<std::is_integral<T>::value>> {
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);
@ -161,7 +161,7 @@ namespace stack {
};
template <typename T>
struct checker<T, type::number, std::enable_if_t<std::is_floating_point<T>::value>> {
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);
@ -185,7 +185,7 @@ namespace stack {
};
template <type expected, typename C>
struct checker<lua_nil_t, expected, 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);
@ -204,7 +204,7 @@ namespace stack {
};
template <typename C>
struct checker<detail::non_lua_nil_t, type::poly, C> {
struct unqualified_checker<detail::non_lua_nil_t, type::poly, C> {
template <typename Handler>
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);
@ -212,10 +212,10 @@ namespace stack {
};
template <type expected, typename C>
struct checker<nullopt_t, expected, C> : checker<lua_nil_t> {};
struct unqualified_checker<nullopt_t, expected, C> : unqualified_checker<lua_nil_t> {};
template <typename C>
struct checker<this_state, type::poly, C> {
struct unqualified_checker<this_state, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
@ -224,7 +224,7 @@ namespace stack {
};
template <typename C>
struct checker<this_main_state, type::poly, 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);
@ -233,7 +233,7 @@ namespace stack {
};
template <typename C>
struct checker<this_environment, type::poly, C> {
struct unqualified_checker<this_environment, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
@ -242,7 +242,7 @@ namespace stack {
};
template <typename C>
struct checker<variadic_args, type::poly, C> {
struct unqualified_checker<variadic_args, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
@ -251,7 +251,7 @@ namespace stack {
};
template <typename C>
struct checker<type, type::poly, C> {
struct unqualified_checker<type, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
@ -260,7 +260,7 @@ namespace stack {
};
template <typename T, typename C>
struct checker<T, type::poly, 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);
@ -274,7 +274,7 @@ namespace stack {
};
template <typename T, typename C>
struct checker<T, type::lightuserdata, 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);
@ -289,7 +289,7 @@ namespace stack {
};
template <typename C>
struct checker<userdata_value, type::userdata, 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);
@ -304,7 +304,7 @@ namespace stack {
};
template <typename B, typename C>
struct checker<basic_userdata<B>, type::userdata, 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);
@ -312,20 +312,20 @@ namespace stack {
};
template <typename T, typename C>
struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {};
struct unqualified_checker<user<T>, type::userdata, C> : unqualified_checker<user<T>, type::lightuserdata, C> {};
template <typename T, typename C>
struct checker<non_null<T>, type::userdata, C> : checker<T, lua_type_of<T>::value, C> {};
struct unqualified_checker<non_null<T>, type::userdata, C> : unqualified_checker<T, lua_type_of<T>::value, C> {};
template <typename C>
struct checker<lua_CFunction, type::function, C> : stack_detail::basic_check<type::function, lua_iscfunction> {};
struct unqualified_checker<lua_CFunction, type::function, C> : stack_detail::basic_check<type::function, lua_iscfunction> {};
template <typename C>
struct checker<std::remove_pointer_t<lua_CFunction>, type::function, C> : checker<lua_CFunction, type::function, C> {};
struct unqualified_checker<std::remove_pointer_t<lua_CFunction>, type::function, C> : unqualified_checker<lua_CFunction, type::function, C> {};
template <typename C>
struct checker<c_closure, type::function, C> : checker<lua_CFunction, type::function, C> {};
struct unqualified_checker<c_closure, type::function, C> : unqualified_checker<lua_CFunction, type::function, C> {};
template <typename T, typename C>
struct checker<T, type::function, 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);
@ -363,7 +363,7 @@ namespace stack {
};
template <typename T, typename C>
struct checker<T, type::table, C> {
struct unqualified_checker<T, type::table, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
@ -380,7 +380,7 @@ namespace stack {
};
template <type expected, typename C>
struct checker<metatable_t, expected, C> {
struct unqualified_checker<metatable_t, expected, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
@ -402,7 +402,7 @@ namespace stack {
};
template <typename C>
struct checker<env_t, type::poly, C> {
struct unqualified_checker<env_t, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
@ -416,7 +416,7 @@ namespace stack {
};
template <typename E, typename C>
struct checker<basic_environment<E>, type::poly, 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);
@ -438,7 +438,7 @@ namespace stack {
};
template <typename T, typename C>
struct checker<detail::as_value_tag<T>, type::userdata, C> {
struct unqualified_checker<detail::as_value_tag<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
@ -497,7 +497,7 @@ namespace stack {
};
template <typename T, typename C>
struct checker<detail::as_pointer_tag<T>, type::userdata, C> {
struct unqualified_checker<detail::as_pointer_tag<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
if (indextype == type::lua_nil) {
@ -515,7 +515,7 @@ namespace stack {
};
template <typename T, typename C>
struct checker<T, type::userdata, 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);
@ -523,7 +523,7 @@ namespace stack {
};
template <typename T, typename C>
struct checker<T*, type::userdata, 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);
@ -531,7 +531,7 @@ namespace stack {
};
template <typename X>
struct checker<X, type::userdata, std::enable_if_t<is_unique_usertype<X>::value>> {
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) {
@ -571,7 +571,7 @@ namespace stack {
};
template <typename T, typename C>
struct checker<std::reference_wrapper<T>, type::userdata, 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);
@ -579,7 +579,7 @@ namespace stack {
};
template <typename... Args, typename C>
struct checker<std::tuple<Args...>, type::poly, C> {
struct unqualified_checker<std::tuple<Args...>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking);
@ -587,7 +587,7 @@ namespace stack {
};
template <typename A, typename B, typename C>
struct checker<std::pair<A, B>, type::poly, C> {
struct unqualified_checker<std::pair<A, B>, type::poly, C> {
template <typename Handler>
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);
@ -595,7 +595,7 @@ namespace stack {
};
template <typename T, typename C>
struct checker<optional<T>, type::poly, C> {
struct unqualified_checker<optional<T>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&&, record& tracking) {
type t = type_of(L, index);
@ -614,7 +614,7 @@ namespace stack {
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
template <typename T, typename C>
struct checker<std::optional<T>, type::poly, C> {
struct unqualified_checker<std::optional<T>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&&, record& tracking) {
type t = type_of(L, index);
@ -633,7 +633,7 @@ namespace stack {
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn, typename C>
struct checker<std::variant<Tn...>, type::poly, C> {
struct unqualified_checker<std::variant<Tn...>, type::poly, C> {
typedef std::variant<Tn...> V;
typedef std::variant_size<V> V_size;
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;

View File

@ -572,7 +572,7 @@ namespace sol {
template <typename T, typename = void>
struct pusher;
template <typename T, type = lua_type_of<T>::value, typename = void>
struct checker;
struct unqualified_checker;
template <typename T, type = lua_type_of<T>::value, typename = void>
struct qualified_checker;
template <typename T, typename = void>
@ -919,7 +919,7 @@ namespace sol {
return sol_lua_check(types<Tu>(), L, index, std::forward<Handler>(handler), tracking);
}
else {
checker<Tu> c;
unqualified_checker<Tu> c;
// VC++ has a bad warning here: shut it up
(void)c;
return c.check(L, index, std::forward<Handler>(handler), tracking);

View File

@ -862,7 +862,6 @@ namespace sol {
}
static int push(lua_State* L, const char16_t* strb, const char16_t* stre) {
// TODO: use new unicode methods
char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE];
// if our max string space is small enough, use SBO
// right off the bat
@ -940,7 +939,6 @@ namespace sol {
}
static int push(lua_State* L, const char32_t* strb, const char32_t* stre) {
// TODO: use new unicode methods
char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE];
// if our max string space is small enough, use SBO
// right off the bat

View File

@ -355,8 +355,24 @@ namespace sol {
static std::false_type test(...);
};
struct has_key_comp_impl {
template <typename T, typename V = decltype(std::declval<unqualified_t<T>>().key_comp())>
static std::true_type test(int);
template <typename...>
static std::false_type test(...);
};
struct has_load_factor_impl {
template <typename T, typename V = decltype(std::declval<unqualified_t<T>>().load_factor())>
static std::true_type test(int);
template <typename...>
static std::false_type test(...);
};
struct has_mapped_type_impl {
template <typename T, typename U = unqualified_t<T>, typename V = typename U::mapped_type>
template <typename T, typename V = typename unqualified_t<T>::mapped_type>
static std::true_type test(int);
template <typename...>
@ -364,7 +380,7 @@ namespace sol {
};
struct has_value_type_impl {
template <typename T, typename U = unqualified_t<T>, typename V = typename U::value_type>
template <typename T, typename V = typename unqualified_t<T>::value_type>
static std::true_type test(int);
template <typename...>
@ -372,7 +388,7 @@ namespace sol {
};
struct has_iterator_impl {
template <typename T, typename U = unqualified_t<T>, typename V = typename U::iterator>
template <typename T, typename V = typename unqualified_t<T>::iterator>
static std::true_type test(int);
template <typename...>
@ -540,6 +556,12 @@ namespace sol {
template <typename T>
struct has_key_type : decltype(meta_detail::has_key_type_impl::test<T>(0)) {};
template <typename T>
struct has_key_comp : decltype(meta_detail::has_key_comp_impl::test<T>(0)) {};
template <typename T>
struct has_load_factor : decltype(meta_detail::has_load_factor_impl::test<T>(0)) {};
template <typename T>
struct has_mapped_type : decltype(meta_detail::has_mapped_type_impl::test<T>(0)) {};
@ -571,7 +593,10 @@ namespace sol {
using is_lookup = meta::all<has_key_type<T>, has_value_type<T>>;
template <typename T>
struct is_matched_lookup : meta_detail::is_matched_lookup_impl<T, is_lookup<T>::value> {};
using is_ordered = meta::all<has_key_comp<T>, meta::neg<has_load_factor<T>>>;
template <typename T>
using is_matched_lookup = meta_detail::is_matched_lookup_impl<T, is_lookup<T>::value>;
template <typename T>
using is_string_like = any<is_specialization_of<meta::unqualified_t<T>, std::basic_string>,

View File

@ -338,7 +338,9 @@ namespace sol {
std::remove_pointer_t<T>>>
meta_usertype_container;
static const char* metakey = is_shim ? &usertype_traits<as_container_t<std::remove_pointer_t<T>>>::metatable()[0] : &usertype_traits<T>::metatable()[0];
static const std::array<luaL_Reg, 19> reg = { { { "__pairs", &meta_usertype_container::pairs_call },
static const std::array<luaL_Reg, 20> reg = { {
// clang-format off
{ "__pairs", &meta_usertype_container::pairs_call },
{ "__ipairs", &meta_usertype_container::ipairs_call },
{ "__len", &meta_usertype_container::length_call },
{ "__index", &meta_usertype_container::index_call },
@ -354,9 +356,12 @@ namespace sol {
{ "insert", &meta_usertype_container::insert_call },
{ "add", &meta_usertype_container::add_call },
{ "find", &meta_usertype_container::find_call },
{ "index_of", &meta_usertype_container::index_of_call },
{ "erase", &meta_usertype_container::erase_call },
std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct<T> },
{ nullptr, nullptr } } };
{ nullptr, nullptr }
// clang-format on
} };
if (luaL_newmetatable(L, metakey) == 1) {
luaL_setfuncs(L, reg.data(), 0);
@ -434,7 +439,7 @@ namespace sol {
};
template <typename T, typename C>
struct checker<as_container_t<T>, type::userdata, 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);

View File

@ -34,6 +34,7 @@
#include "deprecate.hpp"
#include "object.hpp"
#include "function_types.hpp"
#include "usertype_container.hpp"
#include <sstream>
#include <type_traits>
@ -140,8 +141,7 @@ namespace sol {
ifx(meta_function::equal_to, f);
}
if (fx(meta_function::pairs)) {
// TODO: fix this
//ifx(meta_function::pairs, &usertype_container<as_container_t<T>>::pairs_call);
ifx(meta_function::pairs, &usertype_container<as_container_t<T>>::pairs_call);
}
if (fx(meta_function::length)) {
if constexpr (meta::has_size<const T>::value || meta::has_size<T>::value) {

View File

@ -591,23 +591,8 @@ namespace sol { namespace u_detail {
// and other amenities
return;
}
if (is_destruction
&& (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named
|| smt == submetatable_type::unique)) {
// gc does not apply to us here
// for reference types (raw T*, std::ref)
// for the named metatable itself,
// or for unique_usertypes, which do their own custom destruction
return;
}
int fast_index_table_push = fast_index_table.push();
stack_reference t(L, -fast_index_table_push);
if constexpr (is_lua_c_function_v<ValueU> || is_lua_reference_or_proxy<ValueU>::value) {
stack::set_field<false, true>(L, s, b.data_, t.stack_index());
}
else {
stack::set_field<false, true>(L, s, make_closure(&b.template call<false, is_var_bind::value>, nullptr, ics.binding_data), t.stack_index());
}
if (poison_indexing) {
change_indexing(L,
smt,
@ -618,6 +603,22 @@ namespace sol { namespace u_detail {
&usertype_storage<T>::meta_index_call,
&usertype_storage<T>::meta_new_index_call);
}
if (is_destruction
&& (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named
|| smt == submetatable_type::unique)) {
// gc does not apply to us here
// for reference types (raw T*, std::ref)
// for the named metatable itself,
// or for unique_usertypes, which do their own custom destruction
t.pop();
return;
}
if constexpr (is_lua_c_function_v<ValueU> || is_lua_reference_or_proxy<ValueU>::value) {
stack::set_field<false, true>(L, s, b.data_, t.stack_index());
}
else {
stack::set_field<false, true>(L, s, make_closure(&b.template call<false, is_var_bind::value>, nullptr, ics.binding_data), t.stack_index());
}
t.pop();
};
if (is_index) {

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2018-12-19 18:01:44.554823 UTC
// This header was generated with sol v2.20.6 (revision 9b29277)
// Generated 2018-12-21 06:03:11.681784 UTC
// This header was generated with sol v2.20.6 (revision c35c66b)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP

File diff suppressed because it is too large Load Diff

View File

@ -23,4 +23,4 @@
#include "../sol_defines.hpp"
#include <sol/compatibility\compat-5.3.h>
#include <sol/compatibility/compat-5.3.h>

View File

@ -23,4 +23,4 @@
#include "../sol_defines.hpp"
#include <sol/compatibility\version.hpp>
#include <sol/compatibility/version.hpp>

View File

@ -27,6 +27,7 @@
#include <iostream>
struct non_copyable {
non_copyable() = default;
non_copyable(non_copyable&& other) noexcept = default;
non_copyable& operator=(non_copyable&& other) noexcept = default;
non_copyable(const non_copyable& other) noexcept = delete;

View File

@ -158,6 +158,12 @@ end
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto findex_of = [&]() {
auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.safe_script("v1 = c:get(1)", sol::script_pass_on_error);
REQUIRE(r1.valid());
@ -195,6 +201,7 @@ end
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(findex_of());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
@ -219,6 +226,8 @@ end
const int& last = *backit;
std::size_t i1 = lua["i1"];
std::size_t i2 = lua["i2"];
std::size_t io1 = lua["io1"];
std::size_t io2 = lua["io2"];
std::size_t s1 = lua["s1"];
std::size_t s2 = lua["s2"];
std::size_t s3 = lua["s3"];
@ -244,6 +253,8 @@ end
REQUIRE((last == 18));
REQUIRE((i1 == 1));
REQUIRE((i2 == 4));
REQUIRE((io1 == 2));
REQUIRE((io2 == 3));
REQUIRE((v1 == 11));
REQUIRE((v2 == 13));
REQUIRE((v3 == 18));
@ -268,6 +279,12 @@ end
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto findex_of = [&]() {
auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
@ -305,6 +322,7 @@ end
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(findex_of());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
@ -329,6 +347,8 @@ end
const int& last = *backit;
int i1 = lua["i1"];
int i2 = lua["i2"];
int io1 = lua["io1"];
int io2 = lua["io2"];
std::size_t s1 = lua["s1"];
std::size_t s2 = lua["s2"];
std::size_t s3 = lua["s3"];
@ -354,6 +374,8 @@ end
REQUIRE((last == 20));
REQUIRE((i1 == 11));
REQUIRE((i2 == 14));
REQUIRE((io1 == 2));
REQUIRE((io2 == 3));
REQUIRE((v1 == 11));
REQUIRE((v2 == 13));
REQUIRE((v3 == 20));
@ -368,6 +390,12 @@ void unordered_container_check(sol::state& lua, T& items) {
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto findex_of = [&]() {
auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error);
REQUIRE_FALSE(r1.valid());
auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error);
REQUIRE_FALSE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
@ -405,6 +433,7 @@ void unordered_container_check(sol::state& lua, T& items) {
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(findex_of());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
@ -461,6 +490,12 @@ end
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto findex_of = [&]() {
auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
@ -500,6 +535,7 @@ end
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(findex_of());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
@ -524,6 +560,8 @@ end
const std::pair<const short, int>& last = *backit;
int i1 = lua["i1"];
int i2 = lua["i2"];
int io1 = lua["io1"];
int io2 = lua["io2"];
std::size_t s1 = lua["s1"];
std::size_t s2 = lua["s2"];
std::size_t s3 = lua["s3"];
@ -557,6 +595,8 @@ end
REQUIRE((last.second == 30));
REQUIRE((i1 == 21));
REQUIRE((i2 == 24));
REQUIRE((io1 == 2));
REQUIRE((io2 == 3));
REQUIRE((v1 == 21));
REQUIRE((v2 == 23));
REQUIRE((v3 == 30));
@ -571,6 +611,12 @@ void associative_unordered_container_check(sol::state& lua, T& items) {
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto findex_of = [&]() {
auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error);
REQUIRE_FALSE(r1.valid());
auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error);
REQUIRE_FALSE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
@ -610,6 +656,7 @@ void associative_unordered_container_check(sol::state& lua, T& items) {
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(findex_of());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
@ -694,6 +741,12 @@ end
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto findex_of = [&]() {
auto r1 = lua.safe_script("io1 = c:index_of(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.safe_script("io2 = c:index_of(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.safe_script("v1 = c:get(2)", sol::script_pass_on_error);
REQUIRE(r1.valid());
@ -731,6 +784,7 @@ end
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(findex_of());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());

View File

@ -1,419 +1,267 @@
// sol3
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "sol_test.hpp"
#include <catch.hpp>
#include <unordered_map>
#include <vector>
struct two_things {
int a;
bool b;
};
struct number_shim {
double num = 0;
};
namespace sol {
// First, the expected size
// Specialization of a struct
template <>
struct lua_size<two_things> : std::integral_constant<int, 2> {};
// Then, the expected type
template <>
struct lua_type_of<two_things> : std::integral_constant<sol::type, sol::type::poly> {};
// do note specialize size for this because it is our type
template <>
struct lua_type_of<number_shim> : std::integral_constant<sol::type, sol::type::poly> {};
// Now, specialize various stack structures
namespace stack {
template <>
struct checker<two_things> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
// Check first and second second index for being the proper types
bool success = stack::check<int>(L, index, handler) && stack::check<bool>(L, index + 1, handler);
tracking.use(2);
return success;
}
};
template <>
struct unqualified_getter<two_things> {
static two_things get(lua_State* L, int index, record& tracking) {
// Get the first element
int a = stack::get<int>(L, index);
// Get the second element,
// in the +1 position from the first
bool b = stack::get<bool>(L, index + 1);
// we use 2 slots, each of the previous takes 1
tracking.use(2);
return two_things{ a, b };
}
};
template <>
struct pusher<two_things> {
static int push(lua_State* L, const two_things& things) {
int amount = stack::push(L, things.a);
amount += stack::push(L, things.b);
// Return 2 things
return amount;
}
};
template <>
struct checker<number_shim> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
// check_usertype is a backdoor for directly checking sol2 usertypes
if (!check_usertype<number_shim>(L, index) && !stack::check<double>(L, index)) {
handler(L, index, type_of(L, index), type::userdata, "expected a number_shim or a number");
return false;
}
tracking.use(1);
return true;
}
};
template <>
struct unqualified_getter<number_shim> {
static number_shim get(lua_State* L, int index, record& tracking) {
if (check_usertype<number_shim>(L, index)) {
number_shim& ns = get_usertype<number_shim>(L, index, tracking);
return ns;
}
number_shim ns{};
ns.num = stack::get<double>(L, index, tracking);
return ns;
}
};
} // namespace stack
} // namespace sol
struct custom {
int bweh;
static int get_calls;
static int check_calls;
static int check_get_calls;
static int push_calls;
static int exact_push_calls;
};
int custom::get_calls = 0;
int custom::check_calls = 0;
int custom::check_get_calls = 0;
int custom::push_calls = 0;
int custom::exact_push_calls = 0;
custom sol_lua_get(sol::types<custom>, lua_State* L, int index, sol::stack::record& tracking) {
++custom::get_calls;
return { sol::stack::get<int>(L, index, tracking) };
}
template <typename Handler>
bool sol_lua_check(sol::types<custom>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
++custom::check_calls;
return sol::stack::check<int>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
sol::optional<custom> sol_lua_check_get(sol::types<custom> type_tag, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
++custom::check_get_calls;
if (sol_lua_check(type_tag, L, index, std::forward<Handler>(handler), tracking)) {
return sol_lua_get(type_tag, L, index, tracking);
}
return sol::nullopt;
}
int sol_lua_push(lua_State* L, const custom& c) {
++custom::push_calls;
// ensure there's enough space for 1 more thing on the stack
lua_checkstack(L, 1);
// tell Lua we've left something on
// the stack: return what comes from pushing an integer
return sol::stack::push(L, c.bweh);
}
int sol_lua_push(sol::types<custom>, lua_State* L, const custom& c) {
++custom::exact_push_calls;
// ensure there's enough space for 1 more thing on the stack
lua_checkstack(L, 1);
// tell Lua we've left something on
// the stack: return what comes from pushing an integer
return sol::stack::push(L, c.bweh);
}
struct multi_custom {
int bweh;
bool bwuh;
std::string blah;
static int get_calls;
static int check_calls;
static int check_get_calls;
static int push_calls;
static int exact_push_calls;
};
int multi_custom::get_calls = 0;
int multi_custom::check_calls = 0;
int multi_custom::check_get_calls = 0;
int multi_custom::push_calls = 0;
int multi_custom::exact_push_calls = 0;
multi_custom sol_lua_get(sol::types<multi_custom>, lua_State* L, int index, sol::stack::record& tracking) {
++multi_custom::get_calls;
return {
sol::stack::get<int>(L, index + 0, tracking), sol::stack::get<bool>(L, index + 1, tracking), sol::stack::get<std::string>(L, index + 2, tracking)
};
}
template <typename Handler>
bool sol_lua_check(sol::types<multi_custom>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
++multi_custom::check_calls;
bool success = sol::stack::check<int>(L, index + 0, std::forward<Handler>(handler), tracking)
&& sol::stack::check<bool>(L, index + 1, std::forward<Handler>(handler), tracking)
&& sol::stack::check<std::string>(L, index + 2, std::forward<Handler>(handler), tracking);
return success;
}
int sol_lua_push(lua_State* L, const multi_custom& c) {
++multi_custom::push_calls;
// ensure there's enough space for 1 more thing on the stack
lua_checkstack(L, 3);
int p = sol::stack::push(L, c.bweh);
p += sol::stack::push(L, c.bwuh);
p += sol::stack::push(L, c.blah);
// tell Lua we've left something on
// the stack: return what comes from pushing an integer
return p;
}
struct super_custom {
int bweh;
static int get_calls;
static int check_calls;
static int check_get_calls;
static int push_calls;
static int exact_push_calls;
};
int super_custom::get_calls = 0;
int super_custom::check_calls = 0;
int super_custom::check_get_calls = 0;
int super_custom::push_calls = 0;
int super_custom::exact_push_calls = 0;
super_custom* sol_lua_get(sol::types<super_custom*>, lua_State* L, int index, sol::stack::record& tracking) {
++super_custom::get_calls;
tracking.use(1);
void* vp = lua_touserdata(L, index);
super_custom** pscp = static_cast<super_custom**>(vp);
return *pscp;
}
super_custom& sol_lua_get(sol::types<super_custom>, lua_State* L, int index, sol::stack::record& tracking) {
return *sol_lua_get(sol::types<super_custom*>(), L, index, tracking);
}
template <typename Handler>
bool sol_lua_check(sol::types<super_custom>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
++super_custom::check_calls;
tracking.use(1);
if (luaL_testudata(L, index, "super_custom!") == nullptr) {
if (luaL_testudata(L, index, "super_custom!p") == nullptr) {
handler(L, index, sol::type::userdata, sol::type_of(L, index), "not a super_custom ?!");
return false;
}
}
return true;
}
int sol_lua_push(lua_State* L, const super_custom& c) {
++super_custom::push_calls;
// ensure there's enough space for 1 more thing on the stack
lua_checkstack(L, 1);
// tell Lua we've left something on
// the stack: return what comes from pushing an integer
void* ud = lua_newuserdata(L, sizeof(super_custom*) + sizeof(super_custom));
super_custom* tud = static_cast<super_custom*>(static_cast<void*>(static_cast<char*>(ud) + sizeof(super_custom*)));
*static_cast<super_custom**>(ud) = tud;
*tud = c;
luaL_newmetatable(L, "super_custom!");
lua_setmetatable(L, -2);
return 1;
}
int sol_lua_push(lua_State* L, super_custom* c) {
++super_custom::push_calls;
// ensure there's enough space for 1 more thing on the stack
lua_checkstack(L, 1);
// tell Lua we've left something on
// the stack: return what comes from pushing an integer
void* ud = lua_newuserdata(L, sizeof(super_custom*));
*static_cast<super_custom**>(ud) = c;
luaL_newmetatable(L, "super_custom!p");
lua_setmetatable(L, -2);
return 1;
}
int sol_lua_push(lua_State* L, std::reference_wrapper<super_custom> c) {
return sol::stack::push(L, std::addressof(c.get()));
}
TEST_CASE("customization/split struct", "using the newly documented customization points to handle different kinds of classes") {
sol::state lua;
// Create a pass-through style of function
auto result1 = lua.safe_script("function f ( a, b, c ) return a + c, b end");
REQUIRE(result1.valid());
lua.set_function("g", [](int a, bool b, int c, double d) { return std::make_tuple(a + c, b, d + 2.5); });
// get the function out of Lua
sol::function f = lua["f"];
sol::function g = lua["g"];
two_things thingsf = f(two_things{ 24, true }, 1);
two_things thingsg;
double d;
sol::tie(thingsg, d) = g(two_things{ 25, false }, 2, 34.0);
REQUIRE(thingsf.a == 25);
REQUIRE(thingsf.b);
REQUIRE(thingsg.a == 27);
REQUIRE_FALSE(thingsg.b);
REQUIRE(d == 36.5);
}
TEST_CASE("customization/usertype", "using the newly documented customization points to handle different kinds of classes") {
sol::state lua;
// Create a pass-through style of function
auto result1 = lua.safe_script("function f ( a ) return a end");
REQUIRE(result1.valid());
lua.set_function("g", [](double a) {
number_shim ns;
ns.num = a;
return ns;
});
auto result2 = lua.safe_script("vf = f(25) vg = g(35)", sol::script_pass_on_error);
REQUIRE(result2.valid());
number_shim thingsf = lua["vf"];
number_shim thingsg = lua["vg"];
REQUIRE(thingsf.num == 25);
REQUIRE(thingsg.num == 35);
}
TEST_CASE("customization/overloading", "using multi-size customized types in an overload") {
bool TwoThingsWorks = false, OverloadWorks = false;
sol::state lua;
lua["test_two_things"] = [&](two_things) { TwoThingsWorks = true; };
lua["test_overload"] = sol::overload([&](two_things) { OverloadWorks = true; }, [] {});
lua.script(
"test_two_things(0, true)\n"
"test_overload(0, true)");
REQUIRE(TwoThingsWorks);
REQUIRE(OverloadWorks);
}
TEST_CASE("customization/adl", "using the ADL customization points in various situations") {
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("value-based") {
custom::get_calls = 0;
custom::check_calls = 0;
custom::check_get_calls = 0;
custom::push_calls = 0;
custom::exact_push_calls = 0;
lua["meow"] = custom{ 25 };
custom meow = lua["meow"];
REQUIRE(meow.bweh == 25);
REQUIRE(custom::get_calls > 0);
REQUIRE(custom::check_calls > 0);
REQUIRE(custom::check_get_calls > 0);
REQUIRE(custom::exact_push_calls > 0);
REQUIRE(custom::push_calls == 0);
}
SECTION("multi") {
multi_custom::get_calls = 0;
multi_custom::check_calls = 0;
multi_custom::check_get_calls = 0;
multi_custom::push_calls = 0;
multi_custom::exact_push_calls = 0;
auto result = lua.safe_script("return function (a, b, c) return a, b, c end", sol::script_pass_on_error);
REQUIRE(result.valid());
sol::protected_function f = result;
multi_custom pass_through = f(multi_custom{ 22, false, "miao" });
REQUIRE(pass_through.bweh == 22);
REQUIRE_FALSE(pass_through.bwuh);
REQUIRE(pass_through.blah == "miao");
REQUIRE(multi_custom::get_calls > 0);
REQUIRE(multi_custom::check_calls > 0);
REQUIRE(multi_custom::push_calls > 0);
REQUIRE(multi_custom::check_get_calls == 0);
REQUIRE(multi_custom::exact_push_calls == 0);
}
SECTION("reference-based") {
super_custom::get_calls = 0;
super_custom::check_calls = 0;
super_custom::check_get_calls = 0;
super_custom::push_calls = 0;
super_custom::exact_push_calls = 0;
super_custom meow_original{ 50 };
lua["meow"] = std::ref(meow_original);
super_custom& meow = lua["meow"];
super_custom meow_copy = lua["meow"];
REQUIRE(meow.bweh == 50);
REQUIRE(&meow == &meow_original);
REQUIRE(meow_copy.bweh == 50);
REQUIRE(super_custom::get_calls > 0);
REQUIRE(super_custom::check_calls > 0);
REQUIRE(super_custom::push_calls > 0);
REQUIRE(super_custom::check_get_calls == 0);
REQUIRE(super_custom::exact_push_calls == 0);
}
}
// sol3
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "sol_test.hpp"
#include <catch.hpp>
#include <unordered_map>
#include <vector>
struct custom {
int bweh;
static int get_calls;
static int check_calls;
static int check_get_calls;
static int push_calls;
static int exact_push_calls;
};
int custom::get_calls = 0;
int custom::check_calls = 0;
int custom::check_get_calls = 0;
int custom::push_calls = 0;
int custom::exact_push_calls = 0;
custom sol_lua_get(sol::types<custom>, lua_State* L, int index, sol::stack::record& tracking) {
++custom::get_calls;
return { sol::stack::get<int>(L, index, tracking) };
}
template <typename Handler>
bool sol_lua_check(sol::types<custom>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
++custom::check_calls;
return sol::stack::check<int>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
sol::optional<custom> sol_lua_check_get(sol::types<custom> type_tag, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
++custom::check_get_calls;
if (sol_lua_check(type_tag, L, index, std::forward<Handler>(handler), tracking)) {
return sol_lua_get(type_tag, L, index, tracking);
}
return sol::nullopt;
}
int sol_lua_push(lua_State* L, const custom& c) {
++custom::push_calls;
// ensure there's enough space for 1 more thing on the stack
lua_checkstack(L, 1);
// tell Lua we've left something on
// the stack: return what comes from pushing an integer
return sol::stack::push(L, c.bweh);
}
int sol_lua_push(sol::types<custom>, lua_State* L, const custom& c) {
++custom::exact_push_calls;
// ensure there's enough space for 1 more thing on the stack
lua_checkstack(L, 1);
// tell Lua we've left something on
// the stack: return what comes from pushing an integer
return sol::stack::push(L, c.bweh);
}
struct multi_custom {
int bweh;
bool bwuh;
std::string blah;
static int get_calls;
static int check_calls;
static int check_get_calls;
static int push_calls;
static int exact_push_calls;
};
int multi_custom::get_calls = 0;
int multi_custom::check_calls = 0;
int multi_custom::check_get_calls = 0;
int multi_custom::push_calls = 0;
int multi_custom::exact_push_calls = 0;
multi_custom sol_lua_get(sol::types<multi_custom>, lua_State* L, int index, sol::stack::record& tracking) {
++multi_custom::get_calls;
return {
sol::stack::get<int>(L, index + 0, tracking), sol::stack::get<bool>(L, index + 1, tracking), sol::stack::get<std::string>(L, index + 2, tracking)
};
}
template <typename Handler>
bool sol_lua_check(sol::types<multi_custom>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
++multi_custom::check_calls;
bool success = sol::stack::check<int>(L, index + 0, std::forward<Handler>(handler), tracking)
&& sol::stack::check<bool>(L, index + 1, std::forward<Handler>(handler), tracking)
&& sol::stack::check<std::string>(L, index + 2, std::forward<Handler>(handler), tracking);
return success;
}
int sol_lua_push(lua_State* L, const multi_custom& c) {
++multi_custom::push_calls;
// ensure there's enough space for 1 more thing on the stack
lua_checkstack(L, 3);
int p = sol::stack::push(L, c.bweh);
p += sol::stack::push(L, c.bwuh);
p += sol::stack::push(L, c.blah);
// tell Lua we've left something on
// the stack: return what comes from pushing an integer
return p;
}
struct super_custom {
int bweh;
static int get_calls;
static int check_calls;
static int check_get_calls;
static int push_calls;
static int exact_push_calls;
};
int super_custom::get_calls = 0;
int super_custom::check_calls = 0;
int super_custom::check_get_calls = 0;
int super_custom::push_calls = 0;
int super_custom::exact_push_calls = 0;
super_custom* sol_lua_get(sol::types<super_custom*>, lua_State* L, int index, sol::stack::record& tracking) {
++super_custom::get_calls;
tracking.use(1);
void* vp = lua_touserdata(L, index);
super_custom** pscp = static_cast<super_custom**>(vp);
return *pscp;
}
super_custom& sol_lua_get(sol::types<super_custom>, lua_State* L, int index, sol::stack::record& tracking) {
return *sol_lua_get(sol::types<super_custom*>(), L, index, tracking);
}
template <typename Handler>
bool sol_lua_check(sol::types<super_custom>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
++super_custom::check_calls;
tracking.use(1);
if (luaL_testudata(L, index, "super_custom!") == nullptr) {
if (luaL_testudata(L, index, "super_custom!p") == nullptr) {
handler(L, index, sol::type::userdata, sol::type_of(L, index), "not a super_custom ?!");
return false;
}
}
return true;
}
int sol_lua_push(lua_State* L, const super_custom& c) {
++super_custom::push_calls;
// ensure there's enough space for 1 more thing on the stack
lua_checkstack(L, 1);
// tell Lua we've left something on
// the stack: return what comes from pushing an integer
void* ud = lua_newuserdata(L, sizeof(super_custom*) + sizeof(super_custom));
super_custom* tud = static_cast<super_custom*>(static_cast<void*>(static_cast<char*>(ud) + sizeof(super_custom*)));
*static_cast<super_custom**>(ud) = tud;
*tud = c;
luaL_newmetatable(L, "super_custom!");
lua_setmetatable(L, -2);
return 1;
}
int sol_lua_push(lua_State* L, super_custom* c) {
++super_custom::push_calls;
// ensure there's enough space for 1 more thing on the stack
lua_checkstack(L, 1);
// tell Lua we've left something on
// the stack: return what comes from pushing an integer
void* ud = lua_newuserdata(L, sizeof(super_custom*));
*static_cast<super_custom**>(ud) = c;
luaL_newmetatable(L, "super_custom!p");
lua_setmetatable(L, -2);
return 1;
}
int sol_lua_push(lua_State* L, std::reference_wrapper<super_custom> c) {
return sol::stack::push(L, std::addressof(c.get()));
}
TEST_CASE("customization/adl", "using the ADL customization points in various situations") {
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("value-based") {
custom::get_calls = 0;
custom::check_calls = 0;
custom::check_get_calls = 0;
custom::push_calls = 0;
custom::exact_push_calls = 0;
lua["meow"] = custom{ 25 };
custom meow = lua["meow"];
REQUIRE(meow.bweh == 25);
REQUIRE(custom::get_calls > 0);
REQUIRE(custom::check_calls > 0);
REQUIRE(custom::check_get_calls > 0);
REQUIRE(custom::exact_push_calls > 0);
REQUIRE(custom::push_calls == 0);
}
SECTION("multi") {
multi_custom::get_calls = 0;
multi_custom::check_calls = 0;
multi_custom::check_get_calls = 0;
multi_custom::push_calls = 0;
multi_custom::exact_push_calls = 0;
auto result = lua.safe_script("return function (a, b, c) return a, b, c end", sol::script_pass_on_error);
REQUIRE(result.valid());
sol::protected_function f = result;
multi_custom pass_through = f(multi_custom{ 22, false, "miao" });
REQUIRE(pass_through.bweh == 22);
REQUIRE_FALSE(pass_through.bwuh);
REQUIRE(pass_through.blah == "miao");
REQUIRE(multi_custom::get_calls > 0);
REQUIRE(multi_custom::check_calls > 0);
REQUIRE(multi_custom::push_calls > 0);
REQUIRE(multi_custom::check_get_calls == 0);
REQUIRE(multi_custom::exact_push_calls == 0);
}
SECTION("reference-based") {
super_custom::get_calls = 0;
super_custom::check_calls = 0;
super_custom::check_get_calls = 0;
super_custom::push_calls = 0;
super_custom::exact_push_calls = 0;
super_custom meow_original{ 50 };
lua["meow"] = std::ref(meow_original);
super_custom& meow = lua["meow"];
super_custom meow_copy = lua["meow"];
REQUIRE(meow.bweh == 50);
REQUIRE(&meow == &meow_original);
REQUIRE(meow_copy.bweh == 50);
REQUIRE(super_custom::get_calls > 0);
REQUIRE(super_custom::check_calls > 0);
REQUIRE(super_custom::push_calls > 0);
REQUIRE(super_custom::check_get_calls == 0);
REQUIRE(super_custom::exact_push_calls == 0);
}
}

View File

@ -0,0 +1,169 @@
// sol3
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "sol_test.hpp"
#include <catch.hpp>
#include <unordered_map>
#include <vector>
struct two_things {
int a;
bool b;
};
struct number_shim {
double num = 0;
};
namespace sol {
template <>
struct lua_size<two_things> : std::integral_constant<int, 2> {};
template <>
struct lua_type_of<two_things> : std::integral_constant<sol::type, sol::type::poly> {};
template <>
struct lua_type_of<number_shim> : std::integral_constant<sol::type, sol::type::poly> {};
namespace stack {
template <>
struct unqualified_checker<two_things> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
bool success = stack::check<int>(L, index, handler) && stack::check<bool>(L, index + 1, handler);
tracking.use(2);
return success;
}
};
template <>
struct unqualified_getter<two_things> {
static two_things get(lua_State* L, int index, record& tracking) {
int a = stack::get<int>(L, index);
bool b = stack::get<bool>(L, index + 1);
tracking.use(2);
return two_things{ a, b };
}
};
template <>
struct pusher<two_things> {
static int push(lua_State* L, const two_things& things) {
int amount = stack::push(L, things.a);
amount += stack::push(L, things.b);
return amount;
}
};
template <>
struct unqualified_checker<number_shim> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
if (!check_usertype<number_shim>(L, index) && !stack::check<double>(L, index)) {
handler(L, index, type_of(L, index), type::userdata, "expected a number_shim or a number");
return false;
}
tracking.use(1);
return true;
}
};
template <>
struct unqualified_getter<number_shim> {
static number_shim get(lua_State* L, int index, record& tracking) {
if (check_usertype<number_shim>(L, index)) {
number_shim& ns = get_usertype<number_shim>(L, index, tracking);
return ns;
}
number_shim ns{};
ns.num = stack::get<double>(L, index, tracking);
return ns;
}
};
} // namespace stack
} // namespace sol
TEST_CASE("customization/split struct", "using the newly documented customization points to handle different kinds of classes") {
sol::state lua;
// Create a pass-through style of function
auto result1 = lua.safe_script("function f ( a, b, c ) return a + c, b end");
REQUIRE(result1.valid());
lua.set_function("g", [](int a, bool b, int c, double d) { return std::make_tuple(a + c, b, d + 2.5); });
// get the function out of Lua
sol::function f = lua["f"];
sol::function g = lua["g"];
two_things thingsf = f(two_things{ 24, true }, 1);
two_things thingsg;
double d;
sol::tie(thingsg, d) = g(two_things{ 25, false }, 2, 34.0);
REQUIRE(thingsf.a == 25);
REQUIRE(thingsf.b);
REQUIRE(thingsg.a == 27);
REQUIRE_FALSE(thingsg.b);
REQUIRE(d == 36.5);
}
TEST_CASE("customization/usertype", "using the newly documented customization points to handle different kinds of classes") {
sol::state lua;
// Create a pass-through style of function
auto result1 = lua.safe_script("function f ( a ) return a end");
REQUIRE(result1.valid());
lua.set_function("g", [](double a) {
number_shim ns;
ns.num = a;
return ns;
});
auto result2 = lua.safe_script("vf = f(25) vg = g(35)", sol::script_pass_on_error);
REQUIRE(result2.valid());
number_shim thingsf = lua["vf"];
number_shim thingsg = lua["vg"];
REQUIRE(thingsf.num == 25);
REQUIRE(thingsg.num == 35);
}
TEST_CASE("customization/overloading", "using multi-size customized types in an overload") {
bool TwoThingsWorks = false, OverloadWorks = false;
sol::state lua;
lua["test_two_things"] = [&](two_things) { TwoThingsWorks = true; };
lua["test_overload"] = sol::overload([&](two_things) { OverloadWorks = true; }, [] {});
lua.script(
"test_two_things(0, true)\n"
"test_overload(0, true)");
REQUIRE(TwoThingsWorks);
REQUIRE(OverloadWorks);
}

View File

@ -275,9 +275,7 @@ TEST_CASE("safety/check_stack", "check to make sure that if we overflow the stac
lua["okay"] = []() {
// clang-format off
return std::make_tuple(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37);
return std::make_tuple(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37);
// clang-format on
};
lua["bad"] = [](lua_State* L) {