mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Merge branch 'develop' into petah
This commit is contained in:
commit
7f7783e158
@ -150,7 +150,11 @@ If you don't specify any constructor options at all and the type is `default_con
|
||||
|
||||
.. _constructor:
|
||||
|
||||
* ``"{name}", constructors<T(), T(arg-1-0), T(arg-2-0, arg-2-1), ...>``
|
||||
- Specify the constructors to be bound under ``name``: list constructors by specifying their function signature with ``class_type(arg0, arg1, ... argN)``
|
||||
- If you pass the ``constructors<...>`` argument first when constructing the usertype, then it will automatically be given a ``"{name}"`` of ``"new"``
|
||||
* ``"{name}", constructors<Type-List-0, Type-List-1, ...>``
|
||||
- This syntax is longer and provided for backwards-compatibility: the above argument syntax is shorter and cleaner
|
||||
- ``Type-List-N`` must be a ``sol::types<Args...>``, where ``Args...`` is a list of types that a constructor takes. Supports overloading by default
|
||||
- If you pass the ``constructors<...>`` argument first when constructing the usertype, then it will automatically be given a ``"{name}"`` of ``"new"``
|
||||
* ``"{name}", sol::initializers( func1, func2, ... )``
|
||||
|
@ -110,7 +110,7 @@ To do this, you bind things using the ``new_usertype`` and ``set_usertype`` meth
|
||||
lua.new_usertype<player>( "player",
|
||||
|
||||
// 3 constructors
|
||||
sol::constructors<sol::types<>, sol::types<int>, sol::types<int, int>>(),
|
||||
sol::constructors<player(), player(int), player(int, int)>(),
|
||||
|
||||
// typical member function that returns a variable
|
||||
"shoot", &player::shoot,
|
||||
|
@ -1,109 +1,113 @@
|
||||
#include <sol.hpp>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
struct foo {
|
||||
private:
|
||||
std::string name;
|
||||
public:
|
||||
foo(std::string name): name(std::string(name)) {}
|
||||
|
||||
void print() {
|
||||
std::cout << name << '\n';
|
||||
}
|
||||
|
||||
int test(int x) {
|
||||
return name.length() + x;
|
||||
}
|
||||
};
|
||||
|
||||
struct vector {
|
||||
private:
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
public:
|
||||
vector() = default;
|
||||
vector(float x): x(x) {}
|
||||
vector(float x, float y): x(x), y(y) {}
|
||||
|
||||
bool is_unit() const {
|
||||
return (x * x + y * y) == 1.f;
|
||||
}
|
||||
};
|
||||
|
||||
struct variables {
|
||||
bool low_gravity = false;
|
||||
int boost_level = 0;
|
||||
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype example ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::math);
|
||||
|
||||
// the simplest way to create a class is through
|
||||
// sol::state::new_userdata
|
||||
// the first template is the class type
|
||||
// the rest are the constructor parameters
|
||||
// using new_userdata you can only have one constructor
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// making the class from lua is simple
|
||||
// same with calling member functions
|
||||
lua.script("x = foo.new('test')\n"
|
||||
"x:print()\n"
|
||||
"y = x:test(10)");
|
||||
|
||||
auto y = lua.get<int>("y");
|
||||
std::cout << y << std::endl; // show 14
|
||||
|
||||
// if you want a class to have more than one constructor
|
||||
// the way to do so is through set_userdata and creating
|
||||
// a userdata yourself with constructor types
|
||||
|
||||
{
|
||||
// Notice the brace: this means we're in a new scope
|
||||
// first, define the different types of constructors
|
||||
sol::constructors<sol::types<>, sol::types<float>, sol::types<float, float>> ctor;
|
||||
|
||||
// the only template parameter is the class type
|
||||
// the first argument of construction is the name
|
||||
// second is the constructor types
|
||||
// then the rest are function name and member function pointer pairs
|
||||
sol::usertype<vector> utype(ctor, "is_unit", &vector::is_unit);
|
||||
|
||||
// then you must register it
|
||||
lua.set_usertype("vector", utype);
|
||||
// You can throw away the usertype after you set it: you do NOT
|
||||
// have to keep it around
|
||||
// cleanup happens automagically
|
||||
}
|
||||
// calling it is the same as new_userdata
|
||||
|
||||
lua.script("v = vector.new()\n"
|
||||
"v = vector.new(12)\n"
|
||||
"v = vector.new(10, 10)\n"
|
||||
"assert(not v:is_unit())\n");
|
||||
|
||||
// You can even have C++-like member-variable-access
|
||||
// just pass is public member variables in the same style as functions
|
||||
lua.new_usertype<variables>("variables", "low_gravity", &variables::low_gravity, "boost_level", &variables::boost_level);
|
||||
|
||||
// making the class from lua is simple
|
||||
// same with calling member functions/variables
|
||||
lua.script("local vars = variables.new()\n"
|
||||
"assert(not vars.low_gravity)\n"
|
||||
"vars.low_gravity = true\n"
|
||||
"local x = vars.low_gravity\n"
|
||||
"assert(x)");
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
}
|
||||
#include <sol.hpp>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
struct foo {
|
||||
private:
|
||||
std::string name;
|
||||
public:
|
||||
foo(std::string name): name(std::string(name)) {}
|
||||
|
||||
void print() {
|
||||
std::cout << name << '\n';
|
||||
}
|
||||
|
||||
int test(int x) {
|
||||
return name.length() + x;
|
||||
}
|
||||
};
|
||||
|
||||
struct vector {
|
||||
private:
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
public:
|
||||
vector() = default;
|
||||
vector(float x): x(x) {}
|
||||
vector(float x, float y): x(x), y(y) {}
|
||||
|
||||
bool is_unit() const {
|
||||
return (x * x + y * y) == 1.f;
|
||||
}
|
||||
};
|
||||
|
||||
struct variables {
|
||||
bool low_gravity = false;
|
||||
int boost_level = 0;
|
||||
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype example ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::math);
|
||||
|
||||
// the simplest way to create a class is through
|
||||
// sol::state::new_userdata
|
||||
// the first template is the class type
|
||||
// the rest are the constructor parameters
|
||||
// using new_userdata you can only have one constructor
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// making the class from lua is simple
|
||||
// same with calling member functions
|
||||
lua.script("x = foo.new('test')\n"
|
||||
"x:print()\n"
|
||||
"y = x:test(10)");
|
||||
|
||||
auto y = lua.get<int>("y");
|
||||
std::cout << y << std::endl; // show 14
|
||||
|
||||
// if you want a class to have more than one constructor
|
||||
// the way to do so is through set_userdata and creating
|
||||
// a userdata yourself with constructor types
|
||||
|
||||
{
|
||||
// Notice the brace: this means we're in a new scope
|
||||
// first, define the different types of constructors
|
||||
// notice here that the return type
|
||||
// on the function-type doesn't exactly matter,
|
||||
// which allows you to use a shorter class name/void
|
||||
// if necessary
|
||||
sol::constructors<vector(), vector(float), void(float, float)> ctor;
|
||||
|
||||
// the only template parameter is the class type
|
||||
// the first argument of construction is the name
|
||||
// second is the constructor types
|
||||
// then the rest are function name and member function pointer pairs
|
||||
sol::usertype<vector> utype(ctor, "is_unit", &vector::is_unit);
|
||||
|
||||
// then you must register it
|
||||
lua.set_usertype("vector", utype);
|
||||
// You can throw away the usertype after you set it: you do NOT
|
||||
// have to keep it around
|
||||
// cleanup happens automagically
|
||||
}
|
||||
// calling it is the same as new_userdata
|
||||
|
||||
lua.script("v = vector.new()\n"
|
||||
"v = vector.new(12)\n"
|
||||
"v = vector.new(10, 10)\n"
|
||||
"assert(not v:is_unit())\n");
|
||||
|
||||
// You can even have C++-like member-variable-access
|
||||
// just pass is public member variables in the same style as functions
|
||||
lua.new_usertype<variables>("variables", "low_gravity", &variables::low_gravity, "boost_level", &variables::boost_level);
|
||||
|
||||
// making the class from lua is simple
|
||||
// same with calling member functions/variables
|
||||
lua.script("local vars = variables.new()\n"
|
||||
"assert(not vars.low_gravity)\n"
|
||||
"vars.low_gravity = true\n"
|
||||
"local x = vars.low_gravity\n"
|
||||
"assert(x)");
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ int main() {
|
||||
lua.new_usertype<player>("player",
|
||||
|
||||
// 3 constructors
|
||||
sol::constructors<sol::types<>, sol::types<int>, sol::types<int, int>>(),
|
||||
sol::constructors<player(), player(int), player(int, int)>(),
|
||||
|
||||
// typical member function that returns a variable
|
||||
"shoot", &player::shoot,
|
||||
|
@ -112,7 +112,7 @@ struct __attribute__((packed, aligned(1))) flags_t {
|
||||
uint8_t Z : 1;
|
||||
uint8_t S : 1;
|
||||
uint16_t D : 14;
|
||||
} flags{};
|
||||
} flags{0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype_bitfields example ===" << std::endl;
|
||||
|
@ -29,7 +29,7 @@ int main() {
|
||||
lua.open_libraries();
|
||||
|
||||
lua.new_usertype<vec>("vec",
|
||||
sol::constructors<sol::types<>, sol::types<double, double>>(),
|
||||
sol::constructors<vec(), vec(double, double)>(),
|
||||
"dot", &dot,
|
||||
"norm", [](const vec& self) { double len = std::sqrt(dot(self, self)); return vec(self.x / len, self.y / len); },
|
||||
// we use `sol::resolve` because other operator+ can exist
|
||||
|
@ -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 2017-02-20 23:06:29.737387 UTC
|
||||
// This header was generated with sol v2.15.9 (revision 889a45d)
|
||||
// Generated 2017-03-16 20:01:20.845488 UTC
|
||||
// This header was generated with sol v2.15.9 (revision 144892c)
|
||||
// https://github.com/ThePhD/sol2
|
||||
|
||||
#ifndef SOL_SINGLE_INCLUDE_HPP
|
||||
@ -3492,14 +3492,19 @@ namespace sol {
|
||||
class basic_function;
|
||||
template <typename T>
|
||||
class basic_protected_function;
|
||||
using function = basic_function<reference>;
|
||||
using protected_function = basic_protected_function<reference>;
|
||||
using stack_function = basic_function<stack_reference>;
|
||||
using stack_protected_function = basic_protected_function<stack_reference>;
|
||||
using unsafe_function = basic_function<reference>;
|
||||
using safe_function = basic_protected_function<reference>;
|
||||
using stack_unsafe_function = basic_function<stack_reference>;
|
||||
using stack_safe_function = basic_protected_function<stack_reference>;
|
||||
#ifdef SOL_SAFE_FUNCTIONS
|
||||
using function = protected_function;
|
||||
using stack_function = stack_protected_function;
|
||||
#else
|
||||
using function = unsafe_function;
|
||||
using stack_function = stack_unsafe_function;
|
||||
#endif
|
||||
template <typename base_t>
|
||||
class basic_object;
|
||||
template <typename base_t>
|
||||
@ -4632,6 +4637,7 @@ namespace sol {
|
||||
// beginning of sol/demangle.hpp
|
||||
|
||||
#include <cctype>
|
||||
#include <locale>
|
||||
|
||||
namespace sol {
|
||||
namespace detail {
|
||||
@ -5276,7 +5282,6 @@ namespace sol {
|
||||
|
||||
#ifdef SOL_CODECVT_SUPPORT
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
namespace sol {
|
||||
@ -7658,7 +7663,7 @@ namespace sol {
|
||||
}
|
||||
|
||||
template <typename T, typename List>
|
||||
struct void_call;
|
||||
struct void_call : void_call<T, meta::function_args_t<List>> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct void_call<T, types<Args...>> {
|
||||
@ -7956,12 +7961,12 @@ namespace sol {
|
||||
|
||||
template <typename V>
|
||||
static int call(lua_State* L, V&& f) {
|
||||
return call_const(std::is_const<typename traits_type::return_type>(), L, f);
|
||||
return call_const(std::is_const<typename traits_type::return_type>(), L, std::forward<V>(f));
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
static int call(lua_State* L, V&& f, object_type& o) {
|
||||
return call_const(std::is_const<typename traits_type::return_type>(), L, f, o);
|
||||
return call_const(std::is_const<typename traits_type::return_type>(), L, std::forward<V>(f), o);
|
||||
}
|
||||
};
|
||||
|
||||
@ -7975,7 +7980,7 @@ namespace sol {
|
||||
static int call(lua_State* L, V&& f, object_type& o) {
|
||||
typedef typename wrap::returns_list returns_list;
|
||||
typedef typename wrap::caller caller;
|
||||
return stack::call_into_lua<checked>(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o);
|
||||
return stack::call_into_lua<checked>(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward<V>(f), o);
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
@ -9904,7 +9909,10 @@ namespace sol {
|
||||
|
||||
template<typename T>
|
||||
bool is() const {
|
||||
if (!base_t::valid())
|
||||
int r = base_t::registry_index();
|
||||
if (r == LUA_REFNIL)
|
||||
return meta::any_same<meta::unqualified_t<T>, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false;
|
||||
if (r == LUA_NOREF)
|
||||
return false;
|
||||
return is_stack<T>(std::is_same<base_t, stack_reference>());
|
||||
}
|
||||
@ -10121,6 +10129,42 @@ namespace sol {
|
||||
|
||||
namespace sol {
|
||||
namespace usertype_detail {
|
||||
const lua_Integer toplevel_magic = static_cast<lua_Integer>(0x00020001);
|
||||
|
||||
struct add_destructor_tag {};
|
||||
struct check_destructor_tag {};
|
||||
struct verified_tag {} const verified{};
|
||||
|
||||
template <typename T>
|
||||
struct is_non_factory_constructor : std::false_type {};
|
||||
|
||||
template <typename... Args>
|
||||
struct is_non_factory_constructor<constructors<Args...>> : std::true_type {};
|
||||
|
||||
template <typename... Args>
|
||||
struct is_non_factory_constructor<constructor_wrapper<Args...>> : std::true_type {};
|
||||
|
||||
template <>
|
||||
struct is_non_factory_constructor<no_construction> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_constructor : is_non_factory_constructor<T> {};
|
||||
|
||||
template <typename... Args>
|
||||
struct is_constructor<factory_wrapper<Args...>> : std::true_type {};
|
||||
|
||||
template <typename... Args>
|
||||
using has_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>;
|
||||
|
||||
template <typename T>
|
||||
struct is_destructor : std::false_type {};
|
||||
|
||||
template <typename Fx>
|
||||
struct is_destructor<destructor_wrapper<Fx>> : std::true_type {};
|
||||
|
||||
template <typename... Args>
|
||||
using has_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>;
|
||||
|
||||
struct no_comp {
|
||||
template <typename A, typename B>
|
||||
bool operator()(A&&, B&&) const {
|
||||
@ -10129,15 +10173,19 @@ namespace sol {
|
||||
};
|
||||
|
||||
typedef void(*base_walk)(lua_State*, bool&, int&, string_detail::string_shim&);
|
||||
typedef int(*member_search)(lua_State*, void*);
|
||||
typedef int(*member_search)(lua_State*, void*, int);
|
||||
|
||||
struct find_call_pair {
|
||||
struct call_information {
|
||||
member_search first;
|
||||
member_search second;
|
||||
int runtime_target;
|
||||
|
||||
find_call_pair(member_search first, member_search second) : first(first), second(second) {}
|
||||
call_information(member_search first, member_search second) : call_information(first, second, -1) {}
|
||||
call_information(member_search first, member_search second, int runtimetarget) : first(first), second(second), runtime_target(runtimetarget) {}
|
||||
};
|
||||
|
||||
typedef std::unordered_map<std::string, call_information> mapping_t;
|
||||
|
||||
inline bool is_indexer(string_detail::string_shim s) {
|
||||
return s == name_of(meta_function::index) || s == name_of(meta_function::new_index);
|
||||
}
|
||||
@ -10183,18 +10231,89 @@ namespace sol {
|
||||
}
|
||||
|
||||
struct registrar {
|
||||
registrar() = default;
|
||||
registrar(const registrar&) = default;
|
||||
registrar(registrar&&) = default;
|
||||
registrar& operator=(const registrar&) = default;
|
||||
registrar& operator=(registrar&&) = default;
|
||||
virtual int push_um(lua_State* L) = 0;
|
||||
virtual ~registrar() {}
|
||||
};
|
||||
|
||||
inline int runtime_object_call(lua_State* L, void*, int runtimetarget) {
|
||||
std::vector<object>& runtime = stack::get<light<std::vector<object>>>(L, lua_upvalueindex(2));
|
||||
return stack::push(L, runtime[runtimetarget]);
|
||||
}
|
||||
|
||||
template <bool is_index>
|
||||
inline int indexing_fail(lua_State* L) {
|
||||
auto maybeaccessor = stack::get<optional<string_detail::string_shim>>(L, is_index ? -1 : -2);
|
||||
string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
|
||||
if (is_index)
|
||||
if (is_index) {
|
||||
#if 0//def SOL_SAFE_USERTYPE
|
||||
auto maybeaccessor = stack::get<optional<string_detail::string_shim>>(L, is_index ? -1 : -2);
|
||||
string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
|
||||
return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str());
|
||||
else
|
||||
#else
|
||||
// With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately...
|
||||
return stack::push(L, lua_nil);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
auto maybeaccessor = stack::get<optional<string_detail::string_shim>>(L, is_index ? -1 : -2);
|
||||
string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
|
||||
return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, bool is_simple>
|
||||
inline int metatable_newindex(lua_State* L) {
|
||||
int isnum = 0;
|
||||
lua_Integer magic = lua_tointegerx(L, upvalue_index(4), &isnum);
|
||||
if (isnum != 0 && magic == toplevel_magic) {
|
||||
bool mustindex = lua_isboolean(L, upvalue_index(5)) != 0 && (lua_toboolean(L, upvalue_index(5)) != 0);
|
||||
if (!is_simple && mustindex) {
|
||||
mapping_t& mapping = stack::get<light<mapping_t>>(L, upvalue_index(3));
|
||||
std::vector<object>& runtime = stack::get<light<std::vector<object>>>(L, upvalue_index(2));
|
||||
int target = static_cast<int>(runtime.size());
|
||||
std::string accessor = stack::get<std::string>(L, 2);
|
||||
auto preexistingit = mapping.find(accessor);
|
||||
if (preexistingit == mapping.cend()) {
|
||||
runtime.emplace_back(L, 3);
|
||||
mapping.emplace_hint(mapping.cend(), accessor, call_information(&runtime_object_call, &runtime_object_call, target));
|
||||
}
|
||||
else {
|
||||
target = preexistingit->second.runtime_target;
|
||||
runtime[target] = sol::object(L, 3);
|
||||
preexistingit->second = call_information(&runtime_object_call, &runtime_object_call, target);
|
||||
}
|
||||
}
|
||||
for (std::size_t i = 0; i < 4; lua_pop(L, 1), ++i) {
|
||||
const char* metakey = nullptr;
|
||||
switch (i) {
|
||||
case 0:
|
||||
metakey = &usertype_traits<T*>::metatable()[0];
|
||||
break;
|
||||
case 1:
|
||||
metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0];
|
||||
break;
|
||||
case 2:
|
||||
metakey = &usertype_traits<T>::user_metatable()[0];
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
metakey = &usertype_traits<T>::metatable()[0];
|
||||
break;
|
||||
}
|
||||
luaL_getmetatable(L, metakey);
|
||||
int tableindex = lua_gettop(L);
|
||||
if (type_of(L, tableindex) == type::lua_nil) {
|
||||
continue;
|
||||
}
|
||||
stack::set_field<false, true>(L, stack_reference(L, 2), stack_reference(L, 3), tableindex);
|
||||
}
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
return indexing_fail<false>(L);
|
||||
}
|
||||
|
||||
template <bool is_index, typename Base>
|
||||
@ -10266,41 +10385,6 @@ namespace sol {
|
||||
inline void make_reg_op(Regs&, int&, const char*) {
|
||||
// Do nothing if there's no support
|
||||
}
|
||||
|
||||
struct add_destructor_tag {};
|
||||
struct check_destructor_tag {};
|
||||
struct verified_tag {} const verified{};
|
||||
|
||||
template <typename T>
|
||||
struct is_non_factory_constructor : std::false_type {};
|
||||
|
||||
template <typename... Args>
|
||||
struct is_non_factory_constructor<constructors<Args...>> : std::true_type {};
|
||||
|
||||
template <typename... Args>
|
||||
struct is_non_factory_constructor<constructor_wrapper<Args...>> : std::true_type {};
|
||||
|
||||
template <>
|
||||
struct is_non_factory_constructor<no_construction> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_constructor : is_non_factory_constructor<T> {};
|
||||
|
||||
template <typename... Args>
|
||||
struct is_constructor<factory_wrapper<Args...>> : std::true_type {};
|
||||
|
||||
template <typename... Args>
|
||||
using has_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>;
|
||||
|
||||
template <typename T>
|
||||
struct is_destructor : std::false_type {};
|
||||
|
||||
template <typename Fx>
|
||||
struct is_destructor<destructor_wrapper<Fx>> : std::true_type {};
|
||||
|
||||
template <typename... Args>
|
||||
using has_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>;
|
||||
|
||||
} // usertype_detail
|
||||
|
||||
template <typename T>
|
||||
@ -10323,9 +10407,9 @@ namespace sol {
|
||||
typedef std::tuple<clean_type_t<Tn> ...> Tuple;
|
||||
template <std::size_t Idx>
|
||||
struct check_binding : is_variable_binding<meta::unqualified_tuple_element_t<Idx, Tuple>> {};
|
||||
typedef std::unordered_map<std::string, usertype_detail::find_call_pair> mapping_t;
|
||||
usertype_detail::mapping_t mapping;
|
||||
std::vector<object> runtime;
|
||||
Tuple functions;
|
||||
mapping_t mapping;
|
||||
lua_CFunction indexfunc;
|
||||
lua_CFunction newindexfunc;
|
||||
lua_CFunction destructfunc;
|
||||
@ -10442,27 +10526,33 @@ namespace sol {
|
||||
}
|
||||
|
||||
template <typename... Args, typename = std::enable_if_t<sizeof...(Args) == sizeof...(Tn)>>
|
||||
usertype_metatable(Args&&... args) : functions(std::forward<Args>(args)...),
|
||||
usertype_metatable(Args&&... args) :
|
||||
mapping(),
|
||||
indexfunc(usertype_detail::indexing_fail<true>), newindexfunc(usertype_detail::indexing_fail<false>),
|
||||
functions(std::forward<Args>(args)...),
|
||||
indexfunc(&usertype_detail::indexing_fail<true>), newindexfunc(&usertype_detail::metatable_newindex<T, false>),
|
||||
destructfunc(nullptr), callconstructfunc(nullptr),
|
||||
indexbase(&core_indexing_call<true>), newindexbase(&core_indexing_call<false>),
|
||||
indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(usertype_detail::walk_all_bases<false>),
|
||||
baseclasscheck(nullptr), baseclasscast(nullptr),
|
||||
mustindex(contains_variable() || contains_index()), secondarymeta(contains_variable()),
|
||||
hasequals(false), hasless(false), haslessequals(false) {
|
||||
std::initializer_list<typename mapping_t::value_type> ilist{ {
|
||||
std::pair<std::string, usertype_detail::find_call_pair>(
|
||||
std::initializer_list<typename usertype_detail::mapping_t::value_type> ilist{ {
|
||||
std::pair<std::string, usertype_detail::call_information>(
|
||||
usertype_detail::make_string(std::get<I * 2>(functions)),
|
||||
usertype_detail::find_call_pair(&usertype_metatable::real_find_call<I * 2, I * 2 + 1, false>,
|
||||
usertype_detail::call_information(&usertype_metatable::real_find_call<I * 2, I * 2 + 1, false>,
|
||||
&usertype_metatable::real_find_call<I * 2, I * 2 + 1, true>)
|
||||
)
|
||||
}... };
|
||||
mapping.insert(ilist);
|
||||
}
|
||||
|
||||
usertype_metatable(const usertype_metatable&) = default;
|
||||
usertype_metatable(usertype_metatable&&) = default;
|
||||
usertype_metatable& operator=(const usertype_metatable&) = default;
|
||||
usertype_metatable& operator=(usertype_metatable&&) = default;
|
||||
|
||||
template <std::size_t I0, std::size_t I1, bool is_index>
|
||||
static int real_find_call(lua_State* L, void* um) {
|
||||
static int real_find_call(lua_State* L, void* um, int) {
|
||||
auto& f = *static_cast<usertype_metatable*>(um);
|
||||
if (is_variable_binding<decltype(std::get<I1>(f.functions))>::value) {
|
||||
return real_call_with<I1, is_index, true>(L, f);
|
||||
@ -10480,8 +10570,9 @@ namespace sol {
|
||||
std::string name = stack::get<std::string>(L, keyidx);
|
||||
auto memberit = f.mapping.find(name);
|
||||
if (memberit != f.mapping.cend()) {
|
||||
auto& member = is_index ? memberit->second.second : memberit->second.first;
|
||||
return (member)(L, static_cast<void*>(&f));
|
||||
const usertype_detail::call_information& ci = memberit->second;
|
||||
const usertype_detail::member_search& member = is_index ? ci.second : ci.first;
|
||||
return (member)(L, static_cast<void*>(&f), ci.runtime_target);
|
||||
}
|
||||
string_detail::string_shim accessor = name;
|
||||
int ret = 0;
|
||||
@ -10633,14 +10724,14 @@ namespace sol {
|
||||
stack::set_field(L, detail::base_class_cast_key(), um.baseclasscast, t.stack_index());
|
||||
}
|
||||
|
||||
stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, make_light(um)), t.stack_index());
|
||||
stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, make_light(um)), t.stack_index());
|
||||
stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, make_light(um), make_light(um.runtime)), t.stack_index());
|
||||
stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, make_light(um), make_light(um.runtime)), t.stack_index());
|
||||
|
||||
if (mustindex) {
|
||||
// Basic index pushing: specialize
|
||||
// index and newindex to give variables and stuff
|
||||
stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um)), t.stack_index());
|
||||
stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um)), t.stack_index());
|
||||
stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um), make_light(um.runtime)), t.stack_index());
|
||||
stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um), make_light(um.runtime)), t.stack_index());
|
||||
}
|
||||
else {
|
||||
// If there's only functions, we can use the fast index version
|
||||
@ -10651,11 +10742,11 @@ namespace sol {
|
||||
lua_createtable(L, 0, 3);
|
||||
stack_reference metabehind(L, -1);
|
||||
if (um.callconstructfunc != nullptr) {
|
||||
stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um)), metabehind.stack_index());
|
||||
stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um), make_light(um.runtime)), metabehind.stack_index());
|
||||
}
|
||||
if (um.secondarymeta) {
|
||||
stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um)), metabehind.stack_index());
|
||||
stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um)), metabehind.stack_index());
|
||||
stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um), make_light(um.runtime)), metabehind.stack_index());
|
||||
stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um), make_light(um.runtime)), metabehind.stack_index());
|
||||
}
|
||||
stack::set_field(L, metatable_key, metabehind, t.stack_index());
|
||||
metabehind.pop();
|
||||
@ -10673,12 +10764,12 @@ namespace sol {
|
||||
lua_createtable(L, 0, 3);
|
||||
stack_reference metabehind(L, -1);
|
||||
if (um.callconstructfunc != nullptr) {
|
||||
stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um)), metabehind.stack_index());
|
||||
}
|
||||
if (um.secondarymeta) {
|
||||
stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um)), metabehind.stack_index());
|
||||
stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um)), metabehind.stack_index());
|
||||
stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um), static_cast<void*>(&um.runtime)), metabehind.stack_index());
|
||||
}
|
||||
|
||||
stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um), static_cast<void*>(&um.runtime), static_cast<void*>(&um.mapping), usertype_detail::toplevel_magic, um.mustindex), metabehind.stack_index());
|
||||
stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um), static_cast<void*>(&um.runtime), static_cast<void*>(&um.mapping), usertype_detail::toplevel_magic, um.mustindex), metabehind.stack_index());
|
||||
|
||||
stack::set_field(L, metatable_key, metabehind, t.stack_index());
|
||||
metabehind.pop();
|
||||
}
|
||||
@ -10698,8 +10789,6 @@ namespace sol {
|
||||
namespace sol {
|
||||
|
||||
namespace usertype_detail {
|
||||
const lua_Integer toplevel_magic = static_cast<lua_Integer>(0x00000001);
|
||||
|
||||
struct variable_wrapper {
|
||||
virtual int index(lua_State* L) = 0;
|
||||
virtual int new_index(lua_State* L) = 0;
|
||||
@ -10735,43 +10824,6 @@ namespace sol {
|
||||
simple_map(const char* mkey, base_walk index, base_walk newindex, variable_map&& vars, function_map&& funcs) : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline int simple_metatable_newindex(lua_State* L) {
|
||||
int isnum = 0;
|
||||
lua_Integer magic = lua_tointegerx(L, lua_upvalueindex(4), &isnum);
|
||||
if (isnum != 0 && magic == toplevel_magic) {
|
||||
for (std::size_t i = 0; i < 3; lua_pop(L, 1), ++i) {
|
||||
// Pointer types, AKA "references" from C++
|
||||
const char* metakey = nullptr;
|
||||
switch (i) {
|
||||
case 0:
|
||||
metakey = &usertype_traits<T*>::metatable()[0];
|
||||
break;
|
||||
case 1:
|
||||
metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0];
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
metakey = &usertype_traits<T>::metatable()[0];
|
||||
break;
|
||||
}
|
||||
luaL_getmetatable(L, metakey);
|
||||
int tableindex = lua_gettop(L);
|
||||
if (type_of(L, tableindex) == type::lua_nil) {
|
||||
continue;
|
||||
}
|
||||
stack::set_field<false, true>(L, stack_reference(L, 2), stack_reference(L, 3), tableindex);
|
||||
}
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
return indexing_fail<false>(L);
|
||||
}
|
||||
|
||||
inline int simple_indexing_fail(lua_State* L) {
|
||||
return stack::push(L, sol::lua_nil);
|
||||
}
|
||||
|
||||
template <bool is_index, bool toplevel = false>
|
||||
inline int simple_core_indexing_call(lua_State* L) {
|
||||
simple_map& sm = toplevel ? stack::get<user<simple_map>>(L, upvalue_index(1)) : stack::pop<user<simple_map>>(L);
|
||||
@ -10995,7 +11047,7 @@ namespace sol {
|
||||
template<std::size_t... I, typename Tuple>
|
||||
simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
|
||||
: callconstructfunc(lua_nil),
|
||||
indexfunc(&usertype_detail::simple_indexing_fail), newindexfunc(&usertype_detail::simple_metatable_newindex<T>),
|
||||
indexfunc(&usertype_detail::indexing_fail<true>), newindexfunc(&usertype_detail::metatable_newindex<T, true>),
|
||||
indexbase(&usertype_detail::simple_core_indexing_call<true>), newindexbase(&usertype_detail::simple_core_indexing_call<false>),
|
||||
indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>),
|
||||
baseclasscheck(nullptr), baseclasscast(nullptr),
|
||||
@ -11034,6 +11086,11 @@ namespace sol {
|
||||
template<typename... Args, typename... Fxs>
|
||||
simple_usertype_metatable(lua_State* L, constructor_wrapper<Fxs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
|
||||
|
||||
simple_usertype_metatable(const simple_usertype_metatable&) = default;
|
||||
simple_usertype_metatable(simple_usertype_metatable&&) = default;
|
||||
simple_usertype_metatable& operator=(const simple_usertype_metatable&) = default;
|
||||
simple_usertype_metatable& operator=(simple_usertype_metatable&&) = default;
|
||||
|
||||
virtual int push_um(lua_State* L) override {
|
||||
return stack::push(L, std::move(*this));
|
||||
}
|
||||
@ -11360,7 +11417,7 @@ namespace sol {
|
||||
return *p.value();
|
||||
#else
|
||||
return stack::get<T>(L, 1);
|
||||
#endif
|
||||
#endif // Safe getting with error
|
||||
}
|
||||
|
||||
static int real_index_call_associative(std::true_type, lua_State* L) {
|
||||
@ -11399,12 +11456,9 @@ namespace sol {
|
||||
using std::begin;
|
||||
auto it = begin(src);
|
||||
K k = *maybek;
|
||||
#ifdef SOL_SAFE_USERTYPE
|
||||
if (k > src.size() || k < 1) {
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
#else
|
||||
#endif // Safety
|
||||
--k;
|
||||
std::advance(it, k);
|
||||
return stack::push_reference(L, *it);
|
||||
@ -11462,7 +11516,7 @@ namespace sol {
|
||||
#ifdef SOL_SAFE_USERTYPE
|
||||
auto maybek = stack::check_get<K>(L, 2);
|
||||
if (!maybek) {
|
||||
return stack::push(L, lua_nil);
|
||||
return 0;
|
||||
}
|
||||
K k = *maybek;
|
||||
#else
|
||||
@ -11775,7 +11829,9 @@ namespace sol {
|
||||
}
|
||||
|
||||
int push(lua_State* L) {
|
||||
return metatableregister->push_um(L);
|
||||
int r = metatableregister->push_um(L);
|
||||
metatableregister = nullptr;
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -47,7 +47,7 @@ namespace sol {
|
||||
}
|
||||
|
||||
template <typename T, typename List>
|
||||
struct void_call;
|
||||
struct void_call : void_call<T, meta::function_args_t<List>> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct void_call<T, types<Args...>> {
|
||||
@ -345,12 +345,12 @@ namespace sol {
|
||||
|
||||
template <typename V>
|
||||
static int call(lua_State* L, V&& f) {
|
||||
return call_const(std::is_const<typename traits_type::return_type>(), L, f);
|
||||
return call_const(std::is_const<typename traits_type::return_type>(), L, std::forward<V>(f));
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
static int call(lua_State* L, V&& f, object_type& o) {
|
||||
return call_const(std::is_const<typename traits_type::return_type>(), L, f, o);
|
||||
return call_const(std::is_const<typename traits_type::return_type>(), L, std::forward<V>(f), o);
|
||||
}
|
||||
};
|
||||
|
||||
@ -364,7 +364,7 @@ namespace sol {
|
||||
static int call(lua_State* L, V&& f, object_type& o) {
|
||||
typedef typename wrap::returns_list returns_list;
|
||||
typedef typename wrap::caller caller;
|
||||
return stack::call_into_lua<checked>(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o);
|
||||
return stack::call_into_lua<checked>(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward<V>(f), o);
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
|
@ -132,7 +132,7 @@ namespace sol {
|
||||
return *p.value();
|
||||
#else
|
||||
return stack::get<T>(L, 1);
|
||||
#endif
|
||||
#endif // Safe getting with error
|
||||
}
|
||||
|
||||
static int real_index_call_associative(std::true_type, lua_State* L) {
|
||||
@ -171,12 +171,9 @@ namespace sol {
|
||||
using std::begin;
|
||||
auto it = begin(src);
|
||||
K k = *maybek;
|
||||
#ifdef SOL_SAFE_USERTYPE
|
||||
if (k > src.size() || k < 1) {
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
#else
|
||||
#endif // Safety
|
||||
--k;
|
||||
std::advance(it, k);
|
||||
return stack::push_reference(L, *it);
|
||||
@ -234,7 +231,7 @@ namespace sol {
|
||||
#ifdef SOL_SAFE_USERTYPE
|
||||
auto maybek = stack::check_get<K>(L, 2);
|
||||
if (!maybek) {
|
||||
return stack::push(L, lua_nil);
|
||||
return 0;
|
||||
}
|
||||
K k = *maybek;
|
||||
#else
|
||||
|
@ -174,15 +174,24 @@ namespace sol {
|
||||
template <typename T, bool is_simple>
|
||||
inline int metatable_newindex(lua_State* L) {
|
||||
int isnum = 0;
|
||||
lua_Integer magic = lua_tointegerx(L, lua_upvalueindex(4), &isnum);
|
||||
lua_Integer magic = lua_tointegerx(L, upvalue_index(4), &isnum);
|
||||
if (isnum != 0 && magic == toplevel_magic) {
|
||||
bool mustindex = lua_isboolean(L, lua_upvalueindex(5)) != 0 && (lua_toboolean(L, lua_upvalueindex(5)) != 0);
|
||||
bool mustindex = lua_isboolean(L, upvalue_index(5)) != 0 && (lua_toboolean(L, upvalue_index(5)) != 0);
|
||||
if (!is_simple && mustindex) {
|
||||
mapping_t& mapping = stack::get<light<mapping_t>>(L, lua_upvalueindex(3));
|
||||
std::vector<object>& runtime = stack::get<light<std::vector<object>>>(L, lua_upvalueindex(2));
|
||||
mapping_t& mapping = stack::get<light<mapping_t>>(L, upvalue_index(3));
|
||||
std::vector<object>& runtime = stack::get<light<std::vector<object>>>(L, upvalue_index(2));
|
||||
int target = static_cast<int>(runtime.size());
|
||||
runtime.emplace_back(L, 3);
|
||||
mapping.emplace_hint(mapping.cend(), stack::get<std::string>(L, 2), call_information(&runtime_object_call, &runtime_object_call, target));
|
||||
std::string accessor = stack::get<std::string>(L, 2);
|
||||
auto preexistingit = mapping.find(accessor);
|
||||
if (preexistingit == mapping.cend()) {
|
||||
runtime.emplace_back(L, 3);
|
||||
mapping.emplace_hint(mapping.cend(), accessor, call_information(&runtime_object_call, &runtime_object_call, target));
|
||||
}
|
||||
else {
|
||||
target = preexistingit->second.runtime_target;
|
||||
runtime[target] = sol::object(L, 3);
|
||||
preexistingit->second = call_information(&runtime_object_call, &runtime_object_call, target);
|
||||
}
|
||||
}
|
||||
for (std::size_t i = 0; i < 4; lua_pop(L, 1), ++i) {
|
||||
const char* metakey = nullptr;
|
||||
|
@ -490,3 +490,35 @@ TEST_CASE("containers/to_args", "Test that the to_args abstractions works") {
|
||||
REQUIRE(d == 12);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("containers/ipairs-test", "ensure that abstractions roundtrip properly and push nils to stop pairs / ipairs") {
|
||||
struct thing {
|
||||
int x = 20;
|
||||
};
|
||||
thing t{};
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua.set_function("f", [&t]() {
|
||||
return std::vector<thing*>(5, &t);
|
||||
});
|
||||
|
||||
lua.script(R"(
|
||||
c = f()
|
||||
)");
|
||||
|
||||
lua.script(R"(
|
||||
check = {}
|
||||
local i = 1
|
||||
while c[i] do
|
||||
check[i] = c[i]
|
||||
i = i + 1
|
||||
end
|
||||
)");
|
||||
sol::table c = lua["check"];
|
||||
for (std::size_t i = 1; i < 6; ++i) {
|
||||
thing& ct = c[i];
|
||||
REQUIRE(&t == &ct);
|
||||
REQUIRE(ct.x == 20);
|
||||
}
|
||||
}
|
||||
|
@ -715,7 +715,6 @@ TEST_CASE("usertype/overloading", "Check if overloading works properly for usert
|
||||
REQUIRE((lua["a"] == 1));
|
||||
REQUIRE((lua["b"] == 3.5));
|
||||
REQUIRE((lua["c"] == bark_58));
|
||||
|
||||
REQUIRE_THROWS(lua.script("r:func(1,2,'meow')"));
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user