mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Upgrading simple_usertype implementation with BREAKING changes. Docs now include that information too. as_function now works with usertypes for limited cases.
This commit is contained in:
parent
a7f43991eb
commit
0de30f3b3a
|
@ -1,4 +1,4 @@
|
||||||
## Sol 2.12
|
## Sol 2.14
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/ThePhD/sol2.svg?branch=develop)](https://travis-ci.org/ThePhD/sol2)
|
[![Build Status](https://travis-ci.org/ThePhD/sol2.svg?branch=develop)](https://travis-ci.org/ThePhD/sol2)
|
||||||
[![Documentation Status](https://readthedocs.org/projects/sol2/badge/?version=latest)](http://sol2.readthedocs.io/en/latest/?badge=latest)
|
[![Documentation Status](https://readthedocs.org/projects/sol2/badge/?version=latest)](http://sol2.readthedocs.io/en/latest/?badge=latest)
|
||||||
|
|
|
@ -8,23 +8,60 @@ make sure an object is pushed as a function
|
||||||
template <typename Sig = sol::function_sig<>, typename... Args>
|
template <typename Sig = sol::function_sig<>, typename... Args>
|
||||||
function_argumants<Sig, Args...> as_function ( Args&& ... );
|
function_argumants<Sig, Args...> as_function ( Args&& ... );
|
||||||
|
|
||||||
This function serves the purpose of ensuring that a callable struct (like a lambda) can be passed to the ``set( key, value )`` calls on :ref:`sol::table<set-value>` and be treated like a function binding instead of a userdata. It is recommended that one uses the :ref:`sol::table::set_function<set-function>` call instead, but if for some reason one must use `set`, then `as_function` can help ensure a callable struct is handled like a lambda / callable, and not as just a userdata structure.
|
This function serves the purpose of ensuring that a callable struct (like a lambda) can be passed to the ``set( key, value )`` calls on :ref:`sol::table<set-value>` and be treated like a function binding instead of a userdata. It is recommended that one uses the :ref:`sol::table::set_function<set-function>` call instead, but if for some reason one must use ``set``, then ``as_function`` can help ensure a callable struct is handled like a lambda / callable, and not as just a userdata structure.
|
||||||
|
|
||||||
|
This class can also make it so usertypes bind variable types as functions to for usertype bindings.
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
struct callable {
|
#include <sol.hpp>
|
||||||
int operator()( int a, bool b ) {
|
|
||||||
return a + b ? 10 : 20;
|
int main () {
|
||||||
}
|
struct callable {
|
||||||
};
|
int operator()( int a, bool b ) {
|
||||||
|
return a + b ? 10 : 20;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
// Binds struct as userdata
|
// Binds struct as userdata
|
||||||
lua.set( "not_func", callable() );
|
lua.set( "not_func", callable() );
|
||||||
// Binds struct as function
|
// Binds struct as function
|
||||||
lua.set( "func", sol::as_function( callable() ) );
|
lua.set( "func", sol::as_function( callable() ) );
|
||||||
// equivalent: lua.set_function( "func", callable() );
|
// equivalent: lua.set_function( "func", callable() );
|
||||||
// equivalent: lua["func"] = callable();
|
// equivalent: lua["func"] = callable();
|
||||||
|
}
|
||||||
|
|
||||||
Note that if you actually want a userdata, but you want it to be callable, you simply need to create a :ref:`sol::table::new_usertype<new-usertype>` and then bind the ``"__call"`` metamethod (or just use ``sol::meta_function::call`` :ref:`enumeration<meta_function_enum>`).
|
Note that if you actually want a userdata, but you want it to be callable, you simply need to create a :ref:`sol::table::new_usertype<new-usertype>` and then bind the ``"__call"`` metamethod (or just use ``sol::meta_function::call`` :ref:`enumeration<meta_function_enum>`).
|
||||||
|
|
||||||
|
Here's an example of binding a variable as a function to a usertype:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <sol.hpp>
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
class B {
|
||||||
|
public:
|
||||||
|
int bvar = 24;
|
||||||
|
};
|
||||||
|
|
||||||
|
sol::state lua;
|
||||||
|
lua.open_libraries();
|
||||||
|
lua.new_usertype<B>("B",
|
||||||
|
// bind as variable
|
||||||
|
"b", &B::bvar,
|
||||||
|
// bind as function
|
||||||
|
"f", sol::as_function(&B::bvar)
|
||||||
|
);
|
||||||
|
|
||||||
|
B b;
|
||||||
|
lua.set("b", &b);
|
||||||
|
lua.script("x = b:f()");
|
||||||
|
lua.script("y = b.b");
|
||||||
|
int x = lua["x"];
|
||||||
|
int y = lua["y"];
|
||||||
|
assert(x == 24);
|
||||||
|
assert(y == 24);
|
||||||
|
}
|
||||||
|
|
|
@ -4,13 +4,6 @@ structures and classes from C++ made available to Lua code (simpler)
|
||||||
--------------------------------------------------------------------
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
This type is no different from :doc:`regular usertype<usertype>`, but with the following caveats:
|
This type is no different from :doc:`regular usertype<usertype>`, but allows much of its work to be done at runtime instead of compile-time. The goal here was to avoid compiler complaints about too-large usertypes (some individuals needed to register 190+ functions, and the compiler choked from the templated implementation of ``usertype``). As of Sol 2.14, this implementation has been heavily refactored to allow for all the same syntax and uses of usertype to apply here, with no caveats.
|
||||||
|
|
||||||
* Dot (".") syntax is not natively supported for simple usertypes (e.g., typical member variable / property bindings)
|
Some developers used ``simple_usertype`` to have variables autoamtically be functions. To achieve this behavior, wrap the desired variable into :doc:`sol::as_function<as_function>`.
|
||||||
- All member variables become functions of that name and are get/set in Lua with the syntax ``local v = obj:value()`` to get, and ``obj:value(24)`` to set
|
|
||||||
- :doc:`properties<property>` also become functions, similar to how member variables are treated above
|
|
||||||
- ``sol::var`` takes the wrapped up type and pushes it directly into that named slot
|
|
||||||
* Automatic "__index" and "__newindex" handling is not done
|
|
||||||
- Overriding either of these properties leaves it entirely up to you to handle how you find variables
|
|
||||||
- This also means *no base class method lookup is done whatsoever*; please specify all base class variables/methods on the class itself
|
|
||||||
- If you override "__index" or "__newindex", you must perform a raw get on the original table and return a valid function / value if you want it to find the members you already set on the ``simple_usertype``
|
|
|
@ -203,6 +203,8 @@ Otherwise, the following is used to specify functions to bind on the specific us
|
||||||
- Binds a typical member function or variable to ``"{name}"``. In the case of a member variable or member function, ``type`` must be ``T`` or a base of ``T``
|
- Binds a typical member function or variable to ``"{name}"``. In the case of a member variable or member function, ``type`` must be ``T`` or a base of ``T``
|
||||||
* ``"{name}", sol::readonly( &type::member_variable )``
|
* ``"{name}", sol::readonly( &type::member_variable )``
|
||||||
- Binds a typical variable to ``"{name}"``. Similar to the above, but the variable will be read-only, meaning an error will be generated if anything attemps to write to this variable
|
- Binds a typical variable to ``"{name}"``. Similar to the above, but the variable will be read-only, meaning an error will be generated if anything attemps to write to this variable
|
||||||
|
* ``"{name}", sol::as_function( &type::member_variable )``
|
||||||
|
- Binds a typical variable to ``"{name}"`` *but forces the syntax to be callable like a function*. This produces a getter and a setter accessible by ``obj:name()`` to get and ``obj::name(value)`` to set.
|
||||||
* ``"{name}", sol::property( getter_func, setter_func )``
|
* ``"{name}", sol::property( getter_func, setter_func )``
|
||||||
- Binds a typical variable to ``"{name}"``, but gets and sets using the specified setter and getter functions. Not that if you do not pass a setter function, the variable will be read-only. Also not that if you do not pass a getter function, it will be write-only
|
- Binds a typical variable to ``"{name}"``, but gets and sets using the specified setter and getter functions. Not that if you do not pass a setter function, the variable will be read-only. Also not that if you do not pass a getter function, it will be write-only
|
||||||
* ``"{name}", sol::var( some_value )`` or ``"{name}", sol::var( std::ref( some_value ) )``
|
* ``"{name}", sol::var( some_value )`` or ``"{name}", sol::var( std::ref( some_value ) )``
|
||||||
|
@ -220,6 +222,7 @@ usertype arguments - simple usertype
|
||||||
- Only allowed as the first argument to the usertype constructor, must be accompanied by a ``lua_State*``
|
- Only allowed as the first argument to the usertype constructor, must be accompanied by a ``lua_State*``
|
||||||
- This tag triggers the :doc:`simple usertype<simple_usertype>` changes / optimizations
|
- This tag triggers the :doc:`simple usertype<simple_usertype>` changes / optimizations
|
||||||
- Only supported when directly invoking the constructor (e.g. not when calling ``sol::table::new_usertype`` or ``sol::table::new_simple_usertype``)
|
- Only supported when directly invoking the constructor (e.g. not when calling ``sol::table::new_usertype`` or ``sol::table::new_simple_usertype``)
|
||||||
|
- Should probably not be used directly. Use ``sol::table::new_usertype`` or ``sol::table::new_simple_usertype`` instead
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -59,9 +59,9 @@ author = 'ThePhD'
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '2.12'
|
version = '2.14'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '2.12.3'
|
release = '2.14.0'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
:target: https://github.com/ThePhD/sol2
|
:target: https://github.com/ThePhD/sol2
|
||||||
:alt: sol2 repository
|
:alt: sol2 repository
|
||||||
|
|
||||||
Sol 2.12
|
Sol 2.14
|
||||||
========
|
========
|
||||||
a fast, simple C++ and Lua Binding
|
a fast, simple C++ and Lua Binding
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
|
@ -527,6 +527,14 @@ namespace sol {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, typename C>
|
||||||
|
struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, C> {
|
||||||
|
template <typename F>
|
||||||
|
static int call(lua_State* L, F&& f) {
|
||||||
|
return lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::get<0>(f.params));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T, bool is_index, bool is_variable, int boost = 0, typename Fx, typename... Args>
|
template <typename T, bool is_index, bool is_variable, int boost = 0, typename Fx, typename... Args>
|
||||||
inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) {
|
inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) {
|
||||||
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||||
|
|
|
@ -25,35 +25,157 @@
|
||||||
#include "usertype_metatable.hpp"
|
#include "usertype_metatable.hpp"
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
|
|
||||||
|
namespace usertype_detail {
|
||||||
|
struct variable_wrapper {
|
||||||
|
virtual int index(lua_State* L) = 0;
|
||||||
|
virtual int new_index(lua_State* L) = 0;
|
||||||
|
virtual ~variable_wrapper() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename F>
|
||||||
|
struct callable_binding : variable_wrapper {
|
||||||
|
F fx;
|
||||||
|
|
||||||
|
template <typename Arg>
|
||||||
|
callable_binding(Arg&& arg) : fx(std::forward<Arg>(arg)) {}
|
||||||
|
|
||||||
|
virtual int index(lua_State* L) override {
|
||||||
|
return call_detail::call_wrapped<T, true, true>(L, fx);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int new_index(lua_State* L) override {
|
||||||
|
return call_detail::call_wrapped<T, false, true>(L, fx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<std::string, std::unique_ptr<variable_wrapper>, std::less<>> variable_map;
|
||||||
|
typedef std::map<std::string, object, std::less<>> function_map;
|
||||||
|
|
||||||
|
struct simple_map {
|
||||||
|
variable_map variables;
|
||||||
|
function_map functions;
|
||||||
|
base_walk indexbaseclasspropogation;
|
||||||
|
base_walk newindexbaseclasspropogation;
|
||||||
|
|
||||||
|
simple_map(base_walk index, base_walk newindex, variable_map&& vars, function_map&& funcs) : variables(std::move(vars)), functions(std::move(funcs)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
variable_map& variables = sm.variables;
|
||||||
|
function_map& functions = sm.functions;
|
||||||
|
static const int keyidx = -2 + static_cast<int>(is_index);
|
||||||
|
if (toplevel) {
|
||||||
|
if (stack::get<type>(L, keyidx) != type::string) {
|
||||||
|
lua_CFunction indexingfunc = is_index ? stack::get<lua_CFunction>(L, upvalue_index(2)) : stack::get<lua_CFunction>(L, upvalue_index(3));
|
||||||
|
return indexingfunc(L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string_detail::string_shim accessor = stack::get<string_detail::string_shim>(L, keyidx);
|
||||||
|
auto vit = variables.find(accessor.c_str());
|
||||||
|
if (vit != variables.cend()) {
|
||||||
|
auto& varwrap = *(vit->second);
|
||||||
|
if (is_index) {
|
||||||
|
return varwrap.index(L);
|
||||||
|
}
|
||||||
|
return varwrap.new_index(L);
|
||||||
|
}
|
||||||
|
auto fit = functions.find(accessor.c_str());
|
||||||
|
if (fit != functions.cend()) {
|
||||||
|
auto& func = (fit->second);
|
||||||
|
return stack::push(L, func);
|
||||||
|
}
|
||||||
|
int ret = 0;
|
||||||
|
bool found = false;
|
||||||
|
// Otherwise, we need to do propagating calls through the bases
|
||||||
|
if (is_index) {
|
||||||
|
sm.indexbaseclasspropogation(L, found, ret, accessor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sm.newindexbaseclasspropogation(L, found, ret, accessor);
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (toplevel) {
|
||||||
|
lua_CFunction indexingfunc = is_index ? stack::get<lua_CFunction>(L, upvalue_index(2)) : stack::get<lua_CFunction>(L, upvalue_index(3));
|
||||||
|
return indexingfunc(L);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int simple_real_index_call(lua_State* L) {
|
||||||
|
return simple_core_indexing_call<true, true>(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int simple_real_new_index_call(lua_State* L) {
|
||||||
|
return simple_core_indexing_call<false, true>(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int simple_index_call(lua_State* L) {
|
||||||
|
return detail::static_trampoline<(&simple_real_index_call)>(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int simple_new_index_call(lua_State* L) {
|
||||||
|
return detail::static_trampoline<(&simple_real_new_index_call)>(L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct simple_tag {} const simple{};
|
struct simple_tag {} const simple{};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct simple_usertype_metatable : usertype_detail::registrar {
|
struct simple_usertype_metatable : usertype_detail::registrar {
|
||||||
std::vector<std::pair<object, object>> registrations;
|
public:
|
||||||
|
usertype_detail::function_map registrations;
|
||||||
|
usertype_detail::variable_map varmap;
|
||||||
object callconstructfunc;
|
object callconstructfunc;
|
||||||
|
lua_CFunction indexfunc;
|
||||||
|
lua_CFunction newindexfunc;
|
||||||
|
lua_CFunction indexbase;
|
||||||
|
lua_CFunction newindexbase;
|
||||||
|
usertype_detail::base_walk indexbaseclasspropogation;
|
||||||
|
usertype_detail::base_walk newindexbaseclasspropogation;
|
||||||
|
void* baseclasscheck;
|
||||||
|
void* baseclasscast;
|
||||||
|
bool mustindex;
|
||||||
|
bool secondarymeta;
|
||||||
|
|
||||||
template <typename N, typename F, meta::enable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler>
|
template <typename N, typename F, meta::enable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler>
|
||||||
void add(lua_State* L, N&& n, F&& f) {
|
void add_function(lua_State* L, N&& n, F&& f) {
|
||||||
registrations.emplace_back(make_object(L, std::forward<N>(n)), make_object(L, as_function(std::forward<F>(f))));
|
registrations.emplace(usertype_detail::make_string(std::forward<N>(n)), make_object(L, as_function_reference(std::forward<F>(f))));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename N, typename F, meta::disable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler>
|
template <typename N, typename F, meta::disable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler>
|
||||||
|
void add_function(lua_State* L, N&& n, F&& f) {
|
||||||
|
registrations.emplace(usertype_detail::make_string(std::forward<N>(n)), make_object(L, std::forward<F>(f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename N, typename F, meta::disable<is_variable_binding<meta::unqualified_t<F>>> = meta::enabler>
|
||||||
void add(lua_State* L, N&& n, F&& f) {
|
void add(lua_State* L, N&& n, F&& f) {
|
||||||
registrations.emplace_back(make_object(L, std::forward<N>(n)), make_object(L, std::forward<F>(f)));
|
add_function(L, std::forward<N>(n), std::forward<F>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename N, typename F, meta::enable<is_variable_binding<meta::unqualified_t<F>>> = meta::enabler>
|
||||||
|
void add(lua_State*, N&& n, F&& f) {
|
||||||
|
varmap.emplace(usertype_detail::make_string(std::forward<N>(n)), std::make_unique<usertype_detail::callable_binding<T, std::decay_t<F>>>(std::forward<F>(f)));
|
||||||
|
mustindex = true;
|
||||||
|
secondarymeta = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename N, typename... Fxs>
|
template <typename N, typename... Fxs>
|
||||||
void add(lua_State* L, N&& n, constructor_wrapper<Fxs...> c) {
|
void add(lua_State* L, N&& n, constructor_wrapper<Fxs...> c) {
|
||||||
registrations.emplace_back(make_object(L, std::forward<N>(n)), make_object(L, detail::tagged<T, constructor_wrapper<Fxs...>>{std::move(c)}));
|
registrations.emplace(usertype_detail::make_string(std::forward<N>(n)), make_object(L, detail::tagged<T, constructor_wrapper<Fxs...>>{std::move(c)}));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename N, typename... Lists>
|
template <typename N, typename... Lists>
|
||||||
void add(lua_State* L, N&& n, constructor_list<Lists...> c) {
|
void add(lua_State* L, N&& n, constructor_list<Lists...> c) {
|
||||||
registrations.emplace_back(make_object(L, std::forward<N>(n)), make_object(L, detail::tagged<T, constructor_list<Lists...>>{std::move(c)}));
|
registrations.emplace(usertype_detail::make_string(std::forward<N>(n)), make_object(L, detail::tagged<T, constructor_list<Lists...>>{std::move(c)}));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
|
@ -61,15 +183,37 @@ namespace sol {
|
||||||
callconstructfunc = make_object(L, std::forward<F>(f));
|
callconstructfunc = make_object(L, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Bases>
|
||||||
|
void add(lua_State*, base_classes_tag, bases<Bases...>) {
|
||||||
|
static_assert(sizeof(usertype_detail::base_walk) <= sizeof(void*), "size of function pointer is greater than sizeof(void*); cannot work on this platform");
|
||||||
|
if (sizeof...(Bases) < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mustindex = true;
|
||||||
|
(void)detail::swallow{ 0, ((detail::has_derived<Bases>::value = true), 0)... };
|
||||||
|
|
||||||
|
static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
|
||||||
|
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
|
||||||
|
baseclasscheck = (void*)&detail::inheritance<T, Bases...>::type_check;
|
||||||
|
baseclasscast = (void*)&detail::inheritance<T, Bases...>::type_cast;
|
||||||
|
indexbaseclasspropogation = usertype_detail::walk_all_bases<true, Bases...>;
|
||||||
|
newindexbaseclasspropogation = usertype_detail::walk_all_bases<false, Bases...>;
|
||||||
|
}
|
||||||
|
|
||||||
template<std::size_t... I, typename Tuple>
|
template<std::size_t... I, typename Tuple>
|
||||||
simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
|
simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
|
||||||
: callconstructfunc(nil) {
|
: callconstructfunc(nil),
|
||||||
registrations.reserve(std::tuple_size<meta::unqualified_t<Tuple>>::value);
|
indexfunc(&usertype_detail::indexing_fail<true>), newindexfunc(&usertype_detail::indexing_fail<false>),
|
||||||
|
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),
|
||||||
|
mustindex(false), secondarymeta(false) {
|
||||||
(void)detail::swallow{ 0,
|
(void)detail::swallow{ 0,
|
||||||
(add(L, detail::forward_get<I * 2>(args), detail::forward_get<I * 2 + 1>(args)),0)...
|
(add(L, detail::forward_get<I * 2>(args), detail::forward_get<I * 2 + 1>(args)),0)...
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
simple_usertype_metatable(lua_State* L, usertype_detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence<sizeof...(Args) / 2>(), L, std::forward_as_tuple(std::forward<Args>(args)...)) {}
|
simple_usertype_metatable(lua_State* L, usertype_detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence<sizeof...(Args) / 2>(), L, std::forward_as_tuple(std::forward<Args>(args)...)) {}
|
||||||
|
|
||||||
|
@ -109,7 +253,32 @@ namespace sol {
|
||||||
struct pusher<simple_usertype_metatable<T>> {
|
struct pusher<simple_usertype_metatable<T>> {
|
||||||
typedef simple_usertype_metatable<T> umt_t;
|
typedef simple_usertype_metatable<T> umt_t;
|
||||||
|
|
||||||
|
static usertype_detail::simple_map& make_cleanup(lua_State* L, umt_t& umx) {
|
||||||
|
static int uniqueness = 0;
|
||||||
|
std::string uniquegcmetakey = usertype_traits<T>::user_gc_metatable;
|
||||||
|
// std::to_string doesn't exist in android still, with NDK, so this bullshit
|
||||||
|
// is necessary
|
||||||
|
// thanks, Android :v
|
||||||
|
int appended = snprintf(nullptr, 0, "%d", uniqueness);
|
||||||
|
std::size_t insertionpoint = uniquegcmetakey.length() - 1;
|
||||||
|
uniquegcmetakey.append(appended, '\0');
|
||||||
|
char* uniquetarget = &uniquegcmetakey[insertionpoint];
|
||||||
|
snprintf(uniquetarget, uniquegcmetakey.length(), "%d", uniqueness);
|
||||||
|
++uniqueness;
|
||||||
|
|
||||||
|
const char* gcmetakey = &usertype_traits<T>::gc_table[0];
|
||||||
|
stack::push<user<usertype_detail::simple_map>>(L, metatable_key, uniquegcmetakey, umx.indexbaseclasspropogation, umx.newindexbaseclasspropogation, std::move(umx.varmap), std::move(umx.registrations));
|
||||||
|
stack_reference stackvarmap(L, -1);
|
||||||
|
stack::set_field<true>(L, gcmetakey, stackvarmap);
|
||||||
|
stackvarmap.pop();
|
||||||
|
|
||||||
|
stack::get_field<true>(L, gcmetakey);
|
||||||
|
usertype_detail::simple_map& varmap = stack::pop<light<usertype_detail::simple_map>>(L);
|
||||||
|
return varmap;
|
||||||
|
}
|
||||||
|
|
||||||
static int push(lua_State* L, umt_t&& umx) {
|
static int push(lua_State* L, umt_t&& umx) {
|
||||||
|
auto& varmap = make_cleanup(L, umx);
|
||||||
bool hasequals = false;
|
bool hasequals = false;
|
||||||
bool hasless = false;
|
bool hasless = false;
|
||||||
bool haslessequals = false;
|
bool haslessequals = false;
|
||||||
|
@ -130,36 +299,41 @@ namespace sol {
|
||||||
}
|
}
|
||||||
luaL_newmetatable(L, metakey);
|
luaL_newmetatable(L, metakey);
|
||||||
stack_reference t(L, -1);
|
stack_reference t(L, -1);
|
||||||
for (auto& kvp : umx.registrations) {
|
for (auto& kvp : varmap.functions) {
|
||||||
if (kvp.first.template is<std::string>()) {
|
auto& first = std::get<0>(kvp);
|
||||||
std::string regname = kvp.first.template as<std::string>();
|
auto& second = std::get<1>(kvp);
|
||||||
if (regname == name_of(meta_function::equal_to)) {
|
if (first == name_of(meta_function::equal_to)) {
|
||||||
hasequals = true;
|
hasequals = true;
|
||||||
}
|
|
||||||
else if (regname == name_of(meta_function::less_than)) {
|
|
||||||
hasless = true;
|
|
||||||
}
|
|
||||||
else if (regname == name_of(meta_function::less_than_or_equal_to)) {
|
|
||||||
haslessequals = true;
|
|
||||||
}
|
|
||||||
switch (i) {
|
|
||||||
case 0:
|
|
||||||
if (regname == name_of(meta_function::garbage_collect)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (regname == name_of(meta_function::garbage_collect)) {
|
|
||||||
stack::set_field(L, kvp.first, detail::unique_destruct<T>, t.stack_index());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
stack::set_field(L, kvp.first, kvp.second, t.stack_index());
|
else if (first == name_of(meta_function::less_than)) {
|
||||||
|
hasless = true;
|
||||||
|
}
|
||||||
|
else if (first == name_of(meta_function::less_than_or_equal_to)) {
|
||||||
|
haslessequals = true;
|
||||||
|
}
|
||||||
|
else if (first == name_of(meta_function::index)) {
|
||||||
|
umx.indexfunc = second.template as<lua_CFunction>();
|
||||||
|
}
|
||||||
|
else if (first == name_of(meta_function::new_index)) {
|
||||||
|
umx.newindexfunc = second.template as<lua_CFunction>();
|
||||||
|
}
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
if (first == name_of(meta_function::garbage_collect)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (first == name_of(meta_function::garbage_collect)) {
|
||||||
|
stack::set_field(L, first, detail::unique_destruct<T>, t.stack_index());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stack::set_field(L, first, second, t.stack_index());
|
||||||
}
|
}
|
||||||
luaL_Reg opregs[4]{};
|
luaL_Reg opregs[4]{};
|
||||||
int opregsindex = 0;
|
int opregsindex = 0;
|
||||||
|
@ -178,9 +352,38 @@ namespace sol {
|
||||||
t.push();
|
t.push();
|
||||||
luaL_setfuncs(L, opregs, 0);
|
luaL_setfuncs(L, opregs, 0);
|
||||||
t.pop();
|
t.pop();
|
||||||
// Metatable indexes itself
|
|
||||||
stack::set_field(L, meta_function::index, t, t.stack_index());
|
|
||||||
|
|
||||||
|
if (umx.baseclasscheck != nullptr) {
|
||||||
|
stack::set_field(L, detail::base_class_check_key(), umx.baseclasscheck, t.stack_index());
|
||||||
|
}
|
||||||
|
if (umx.baseclasscast != nullptr) {
|
||||||
|
stack::set_field(L, detail::base_class_cast_key(), umx.baseclasscast, t.stack_index());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base class propagation features
|
||||||
|
stack::set_field(L, detail::base_class_index_propogation_key(), umx.indexbase, t.stack_index());
|
||||||
|
stack::set_field(L, detail::base_class_new_index_propogation_key(), umx.newindexbase, t.stack_index());
|
||||||
|
|
||||||
|
if (umx.mustindex) {
|
||||||
|
// use indexing function
|
||||||
|
static_assert(sizeof(usertype_detail::base_walk) <= sizeof(void*), "The size of this data pointer is too small to fit the base class index propagation key: file a bug report.");
|
||||||
|
stack::set_field(L, meta_function::index,
|
||||||
|
make_closure(&usertype_detail::simple_index_call,
|
||||||
|
make_light(varmap),
|
||||||
|
umx.indexfunc,
|
||||||
|
umx.newindexfunc
|
||||||
|
), t.stack_index());
|
||||||
|
stack::set_field(L, meta_function::new_index,
|
||||||
|
make_closure(&usertype_detail::simple_new_index_call,
|
||||||
|
make_light(varmap),
|
||||||
|
umx.indexfunc,
|
||||||
|
umx.newindexfunc
|
||||||
|
), t.stack_index());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Metatable indexes itself
|
||||||
|
stack::set_field(L, meta_function::index, t, t.stack_index());
|
||||||
|
}
|
||||||
// metatable on the metatable
|
// metatable on the metatable
|
||||||
// for call constructor purposes and such
|
// for call constructor purposes and such
|
||||||
lua_createtable(L, 0, 1);
|
lua_createtable(L, 0, 1);
|
||||||
|
@ -188,6 +391,20 @@ namespace sol {
|
||||||
if (umx.callconstructfunc.valid()) {
|
if (umx.callconstructfunc.valid()) {
|
||||||
stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index());
|
stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index());
|
||||||
}
|
}
|
||||||
|
if (umx.secondarymeta) {
|
||||||
|
stack::set_field(L, meta_function::index,
|
||||||
|
make_closure(&usertype_detail::simple_index_call,
|
||||||
|
make_light(varmap),
|
||||||
|
umx.indexfunc,
|
||||||
|
umx.newindexfunc
|
||||||
|
), metabehind.stack_index());
|
||||||
|
stack::set_field(L, meta_function::new_index,
|
||||||
|
make_closure(&usertype_detail::simple_new_index_call,
|
||||||
|
make_light(varmap),
|
||||||
|
umx.indexfunc,
|
||||||
|
umx.newindexfunc
|
||||||
|
), metabehind.stack_index());
|
||||||
|
}
|
||||||
stack::set_field(L, metatable_key, metabehind, t.stack_index());
|
stack::set_field(L, metatable_key, metabehind, t.stack_index());
|
||||||
metabehind.pop();
|
metabehind.pop();
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,15 @@ namespace sol {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, bool global, typename C>
|
||||||
|
struct field_getter<T, global, true, C> {
|
||||||
|
template <typename Key>
|
||||||
|
void get(lua_State* L, Key&& key, int tableindex = -2) {
|
||||||
|
push(L, std::forward<Key>(key));
|
||||||
|
lua_rawget(L, tableindex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <bool b, bool raw, typename C>
|
template <bool b, bool raw, typename C>
|
||||||
struct field_getter<metatable_key_t, b, raw, C> {
|
struct field_getter<metatable_key_t, b, raw, C> {
|
||||||
void get(lua_State* L, metatable_key_t, int tableindex = -1) {
|
void get(lua_State* L, metatable_key_t, int tableindex = -1) {
|
||||||
|
|
|
@ -374,12 +374,12 @@ namespace sol {
|
||||||
|
|
||||||
template<typename Fx, typename Key, typename... Args, meta::disable<meta::is_specialization_of<overload_set, meta::unqualified_t<Fx>>> = meta::enabler>
|
template<typename Fx, typename Key, typename... Args, meta::disable<meta::is_specialization_of<overload_set, meta::unqualified_t<Fx>>> = meta::enabler>
|
||||||
void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) {
|
void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) {
|
||||||
set(std::forward<Key>(key), as_function(std::forward<Fx>(fx), std::forward<Args>(args)...));
|
set(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Sig, typename... Args, typename Key>
|
template<typename... Sig, typename... Args, typename Key>
|
||||||
void set_resolved_function(Key&& key, Args&&... args) {
|
void set_resolved_function(Key&& key, Args&&... args) {
|
||||||
set(std::forward<Key>(key), as_function<function_sig<Sig...>>(std::forward<Args>(args)...));
|
set(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -165,7 +165,7 @@ namespace sol {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct non_null {};
|
struct non_null {};
|
||||||
|
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
struct function_sig {};
|
struct function_sig {};
|
||||||
|
|
||||||
struct upvalue_index {
|
struct upvalue_index {
|
||||||
|
@ -262,12 +262,17 @@ namespace sol {
|
||||||
template <typename Sig, typename... Ps>
|
template <typename Sig, typename... Ps>
|
||||||
struct function_arguments {
|
struct function_arguments {
|
||||||
std::tuple<Ps...> params;
|
std::tuple<Ps...> params;
|
||||||
template <typename... Args>
|
template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, function_arguments>> = meta::enabler>
|
||||||
function_arguments(Args&&... args) : params(std::forward<Args>(args)...) {}
|
function_arguments(Arg&& arg, Args&&... args) : params(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Sig = function_sig<>, typename... Args>
|
template <typename Sig = function_sig<>, typename... Args>
|
||||||
function_arguments<Sig, Args...> as_function(Args&&... args) {
|
function_arguments<Sig, std::decay_t<Args>...> as_function(Args&&... args) {
|
||||||
|
return function_arguments<Sig, std::decay_t<Args>...>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Sig = function_sig<>, typename... Args>
|
||||||
|
function_arguments<Sig, Args...> as_function_reference(Args&&... args) {
|
||||||
return function_arguments<Sig, Args...>(std::forward<Args>(args)...);
|
return function_arguments<Sig, Args...>(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,6 +574,9 @@ namespace sol {
|
||||||
template <typename A, typename B>
|
template <typename A, typename B>
|
||||||
struct lua_type_of<std::pair<A, B>> : std::integral_constant<type, type::poly> {};
|
struct lua_type_of<std::pair<A, B>> : std::integral_constant<type, type::poly> {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct lua_type_of<void*> : std::integral_constant<type, type::lightuserdata> {};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct lua_type_of<lightuserdata_value> : std::integral_constant<type, type::lightuserdata> {};
|
struct lua_type_of<lightuserdata_value> : std::integral_constant<type, type::lightuserdata> {};
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@ namespace sol {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef void(*base_walk)(lua_State*, bool&, int&, string_detail::string_shim&);
|
||||||
|
|
||||||
inline bool is_indexer(string_detail::string_shim s) {
|
inline bool is_indexer(string_detail::string_shim s) {
|
||||||
return s == name_of(meta_function::index) || s == name_of(meta_function::new_index);
|
return s == name_of(meta_function::index) || s == name_of(meta_function::new_index);
|
||||||
}
|
}
|
||||||
|
@ -74,6 +76,12 @@ namespace sol {
|
||||||
return string_detail::string_shim(detail::base_class_cast_key());
|
return string_detail::string_shim(detail::base_class_cast_key());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Arg>
|
||||||
|
inline std::string make_string(Arg&& arg) {
|
||||||
|
string_detail::string_shim s = make_shim(arg);
|
||||||
|
return std::string(s.c_str(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename N>
|
template <typename N>
|
||||||
inline luaL_Reg make_reg(N&& n, lua_CFunction f) {
|
inline luaL_Reg make_reg(N&& n, lua_CFunction f) {
|
||||||
luaL_Reg l{ make_shim(std::forward<N>(n)).c_str(), f };
|
luaL_Reg l{ make_shim(std::forward<N>(n)).c_str(), f };
|
||||||
|
@ -95,6 +103,57 @@ namespace sol {
|
||||||
return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data());
|
return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool is_index, typename Base>
|
||||||
|
static void walk_single_base(lua_State* L, bool& found, int& ret, string_detail::string_shim& accessor) {
|
||||||
|
if (found)
|
||||||
|
return;
|
||||||
|
const char* metakey = &usertype_traits<Base>::metatable[0];
|
||||||
|
const char* gcmetakey = &usertype_traits<Base>::gc_table[0];
|
||||||
|
const char* basewalkkey = is_index ? detail::base_class_index_propogation_key() : detail::base_class_new_index_propogation_key();
|
||||||
|
|
||||||
|
luaL_getmetatable(L, metakey);
|
||||||
|
if (type_of(L, -1) == type::nil) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stack::get_field<false, true>(L, accessor.c_str(), lua_gettop(L));
|
||||||
|
if (type_of(L, -1) == type::nil) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Probably a function. Probably.
|
||||||
|
// Kick off metatable
|
||||||
|
lua_remove(L, -2);
|
||||||
|
// Return the field (which is probably a function) itself
|
||||||
|
found = true;
|
||||||
|
ret = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stack::get_field(L, basewalkkey);
|
||||||
|
if (type_of(L, -1) == type::nil) {
|
||||||
|
lua_pop(L, 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lua_CFunction basewalkfunc = stack::pop<lua_CFunction>(L);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
stack::get_field<true>(L, gcmetakey);
|
||||||
|
int value = basewalkfunc(L);
|
||||||
|
if (value > -1) {
|
||||||
|
found = true;
|
||||||
|
ret = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool is_index, typename... Bases>
|
||||||
|
static void walk_all_bases(lua_State* L, bool& found, int& ret, string_detail::string_shim& accessor) {
|
||||||
|
(void)L;
|
||||||
|
(void)found;
|
||||||
|
(void)ret;
|
||||||
|
(void)accessor;
|
||||||
|
(void)detail::swallow{ 0, (walk_single_base<is_index, Bases>(L, found, ret, accessor), 0)... };
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, typename Op>
|
template <typename T, typename Op>
|
||||||
inline int operator_wrap(lua_State* L) {
|
inline int operator_wrap(lua_State* L) {
|
||||||
auto maybel = stack::check_get<T>(L, 1);
|
auto maybel = stack::check_get<T>(L, 1);
|
||||||
|
@ -179,7 +238,6 @@ namespace sol {
|
||||||
typedef std::tuple<clean_type_t<Tn> ...> Tuple;
|
typedef std::tuple<clean_type_t<Tn> ...> Tuple;
|
||||||
template <std::size_t Idx>
|
template <std::size_t Idx>
|
||||||
struct check_binding : is_variable_binding<meta::unqualified_tuple_element_t<Idx, Tuple>> {};
|
struct check_binding : is_variable_binding<meta::unqualified_tuple_element_t<Idx, Tuple>> {};
|
||||||
typedef void (*base_walk)(lua_State*, bool&, int&, string_detail::string_shim&);
|
|
||||||
Tuple functions;
|
Tuple functions;
|
||||||
lua_CFunction indexfunc;
|
lua_CFunction indexfunc;
|
||||||
lua_CFunction newindexfunc;
|
lua_CFunction newindexfunc;
|
||||||
|
@ -187,8 +245,8 @@ namespace sol {
|
||||||
lua_CFunction callconstructfunc;
|
lua_CFunction callconstructfunc;
|
||||||
lua_CFunction indexbase;
|
lua_CFunction indexbase;
|
||||||
lua_CFunction newindexbase;
|
lua_CFunction newindexbase;
|
||||||
base_walk indexbaseclasspropogation;
|
usertype_detail::base_walk indexbaseclasspropogation;
|
||||||
base_walk newindexbaseclasspropogation;
|
usertype_detail::base_walk newindexbaseclasspropogation;
|
||||||
void* baseclasscheck;
|
void* baseclasscheck;
|
||||||
void* baseclasscast;
|
void* baseclasscast;
|
||||||
bool mustindex;
|
bool mustindex;
|
||||||
|
@ -256,8 +314,8 @@ namespace sol {
|
||||||
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
|
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
|
||||||
baseclasscheck = (void*)&detail::inheritance<T, Bases...>::type_check;
|
baseclasscheck = (void*)&detail::inheritance<T, Bases...>::type_check;
|
||||||
baseclasscast = (void*)&detail::inheritance<T, Bases...>::type_cast;
|
baseclasscast = (void*)&detail::inheritance<T, Bases...>::type_cast;
|
||||||
indexbaseclasspropogation = walk_all_bases<true, Bases...>;
|
indexbaseclasspropogation = usertype_detail::walk_all_bases<true, Bases...>;
|
||||||
newindexbaseclasspropogation = walk_all_bases<false, Bases...>;
|
newindexbaseclasspropogation = usertype_detail::walk_all_bases<false, Bases...>;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t Idx, typename N, typename F, typename = std::enable_if_t<!meta::any_same<meta::unqualified_t<N>, base_classes_tag, call_construction>::value>>
|
template <std::size_t Idx, typename N, typename F, typename = std::enable_if_t<!meta::any_same<meta::unqualified_t<N>, base_classes_tag, call_construction>::value>>
|
||||||
|
@ -301,7 +359,7 @@ namespace sol {
|
||||||
indexfunc(usertype_detail::indexing_fail<true>), newindexfunc(usertype_detail::indexing_fail<false>),
|
indexfunc(usertype_detail::indexing_fail<true>), newindexfunc(usertype_detail::indexing_fail<false>),
|
||||||
destructfunc(nullptr), callconstructfunc(nullptr),
|
destructfunc(nullptr), callconstructfunc(nullptr),
|
||||||
indexbase(&core_indexing_call<true>), newindexbase(&core_indexing_call<false>),
|
indexbase(&core_indexing_call<true>), newindexbase(&core_indexing_call<false>),
|
||||||
indexbaseclasspropogation(walk_all_bases<true>), newindexbaseclasspropogation(walk_all_bases<false>),
|
indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(usertype_detail::walk_all_bases<false>),
|
||||||
baseclasscheck(nullptr), baseclasscast(nullptr),
|
baseclasscheck(nullptr), baseclasscast(nullptr),
|
||||||
mustindex(contains_variable() || contains_index()), secondarymeta(contains_variable()),
|
mustindex(contains_variable() || contains_index()), secondarymeta(contains_variable()),
|
||||||
hasequals(false), hasless(false), haslessequals(false) {
|
hasequals(false), hasless(false), haslessequals(false) {
|
||||||
|
@ -328,72 +386,34 @@ namespace sol {
|
||||||
ret = real_find_call<I0, I1>(idx, L);
|
ret = real_find_call<I0, I1>(idx, L);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool b>
|
template <bool is_index>
|
||||||
void propogating_call(lua_State* L, bool& found, int& ret, string_detail::string_shim& accessor) {
|
void propogating_call(lua_State* L, bool& found, int& ret, string_detail::string_shim& accessor) {
|
||||||
(void)detail::swallow{ 0, (find_call<I * 2, I * 2 + 1>(std::integral_constant<bool, b>(), L, found, ret, accessor), 0)... };
|
(void)detail::swallow{ 0, (find_call<I * 2, I * 2 + 1>(std::integral_constant<bool, is_index>(), L, found, ret, accessor), 0)... };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool b, typename Base>
|
template <bool is_index, bool toplevel = false>
|
||||||
static void walk_single_base(lua_State* L, bool& found, int& ret, string_detail::string_shim&) {
|
|
||||||
if (found)
|
|
||||||
return;
|
|
||||||
const char* metakey = &usertype_traits<Base>::metatable[0];
|
|
||||||
const char* gcmetakey = &usertype_traits<Base>::gc_table[0];
|
|
||||||
const char* basewalkkey = b ? detail::base_class_index_propogation_key() : detail::base_class_new_index_propogation_key();
|
|
||||||
|
|
||||||
luaL_getmetatable(L, metakey);
|
|
||||||
if (type_of(L, -1) == type::nil) {
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stack::get_field(L, basewalkkey);
|
|
||||||
if (type_of(L, -1) == type::nil) {
|
|
||||||
lua_pop(L, 2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lua_CFunction basewalkfunc = stack::pop<lua_CFunction>(L);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
|
|
||||||
stack::get_field<true>(L, gcmetakey);
|
|
||||||
int value = basewalkfunc(L);
|
|
||||||
if (value > -1) {
|
|
||||||
found = true;
|
|
||||||
ret = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool b, typename... Bases>
|
|
||||||
static void walk_all_bases(lua_State* L, bool& found, int& ret, string_detail::string_shim& accessor) {
|
|
||||||
(void)L;
|
|
||||||
(void)found;
|
|
||||||
(void)ret;
|
|
||||||
(void)accessor;
|
|
||||||
(void)detail::swallow{ 0, (walk_single_base<b, Bases>(L, found, ret, accessor), 0)... };
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool b, bool toplevel = false>
|
|
||||||
static int core_indexing_call(lua_State* L) {
|
static int core_indexing_call(lua_State* L) {
|
||||||
usertype_metatable& f = toplevel ? stack::get<light<usertype_metatable>>(L, upvalue_index(1)) : stack::pop<light<usertype_metatable>>(L);
|
usertype_metatable& f = toplevel ? stack::get<light<usertype_metatable>>(L, upvalue_index(1)) : stack::pop<light<usertype_metatable>>(L);
|
||||||
static const int keyidx = -2 + static_cast<int>(b);
|
static const int keyidx = -2 + static_cast<int>(is_index);
|
||||||
if (toplevel && stack::get<type>(L, keyidx) != type::string) {
|
if (toplevel && stack::get<type>(L, keyidx) != type::string) {
|
||||||
return b ? f.indexfunc(L) : f.newindexfunc(L);
|
return is_index ? f.indexfunc(L) : f.newindexfunc(L);
|
||||||
}
|
}
|
||||||
string_detail::string_shim accessor = stack::get<string_detail::string_shim>(L, keyidx);
|
string_detail::string_shim accessor = stack::get<string_detail::string_shim>(L, keyidx);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
f.propogating_call<b>(L, found, ret, accessor);
|
f.propogating_call<is_index>(L, found, ret, accessor);
|
||||||
if (found) {
|
if (found) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
// Otherwise, we need to do propagating calls through the bases
|
// Otherwise, we need to do propagating calls through the bases
|
||||||
if (b)
|
if (is_index)
|
||||||
f.indexbaseclasspropogation(L, found, ret, accessor);
|
f.indexbaseclasspropogation(L, found, ret, accessor);
|
||||||
else
|
else
|
||||||
f.newindexbaseclasspropogation(L, found, ret, accessor);
|
f.newindexbaseclasspropogation(L, found, ret, accessor);
|
||||||
if (found) {
|
if (found) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return toplevel ? (b ? f.indexfunc(L) : f.newindexfunc(L)) : -1;
|
return toplevel ? (is_index ? f.indexfunc(L) : f.newindexfunc(L)) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int real_index_call(lua_State* L) {
|
static int real_index_call(lua_State* L) {
|
||||||
|
@ -522,15 +542,9 @@ namespace sol {
|
||||||
if (um.baseclasscheck != nullptr) {
|
if (um.baseclasscheck != nullptr) {
|
||||||
stack::set_field(L, detail::base_class_check_key(), um.baseclasscheck, t.stack_index());
|
stack::set_field(L, detail::base_class_check_key(), um.baseclasscheck, t.stack_index());
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
stack::set_field(L, detail::base_class_check_key(), nil, t.stack_index());
|
|
||||||
}
|
|
||||||
if (um.baseclasscast != nullptr) {
|
if (um.baseclasscast != nullptr) {
|
||||||
stack::set_field(L, detail::base_class_cast_key(), um.baseclasscast, t.stack_index());
|
stack::set_field(L, detail::base_class_cast_key(), um.baseclasscast, t.stack_index());
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
stack::set_field(L, detail::base_class_cast_key(), nil, 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_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_new_index_propogation_key(), make_closure(um.newindexbase, make_light(um)), t.stack_index());
|
||||||
|
|
|
@ -42,12 +42,12 @@ TEST_CASE("usertypes/simple-usertypes", "Ensure that simple usertypes properly w
|
||||||
lua.new_simple_usertype<bark>("bark",
|
lua.new_simple_usertype<bark>("bark",
|
||||||
"fun", &bark::fun,
|
"fun", &bark::fun,
|
||||||
"get", &bark::get,
|
"get", &bark::get,
|
||||||
"var", &bark::var,
|
"var", sol::as_function( &bark::var ),
|
||||||
"the_marker", &bark::the_marker,
|
"the_marker", sol::as_function(&bark::the_marker),
|
||||||
"x", sol::property(&bark::get),
|
"x", sol::overload(&bark::get),
|
||||||
"y", sol::property(&bark::set),
|
"y", sol::overload(&bark::set),
|
||||||
"z", sol::property(&bark::get, &bark::set)
|
"z", sol::overload(&bark::get, &bark::set)
|
||||||
);
|
);
|
||||||
|
|
||||||
lua.script("b = bark.new()");
|
lua.script("b = bark.new()");
|
||||||
bark& b = lua["b"];
|
bark& b = lua["b"];
|
||||||
|
@ -60,6 +60,7 @@ TEST_CASE("usertypes/simple-usertypes", "Ensure that simple usertypes properly w
|
||||||
lua.script("v = b:var()");
|
lua.script("v = b:var()");
|
||||||
int v = lua["v"];
|
int v = lua["v"];
|
||||||
REQUIRE(v == 20);
|
REQUIRE(v == 20);
|
||||||
|
REQUIRE(b.var == 20);
|
||||||
|
|
||||||
lua.script("m = b:the_marker()");
|
lua.script("m = b:the_marker()");
|
||||||
marker& m = lua["m"];
|
marker& m = lua["m"];
|
||||||
|
@ -124,12 +125,12 @@ TEST_CASE("usertypes/simple-usertypes-constructors", "Ensure that calls with spe
|
||||||
sol::constructors<sol::types<>, sol::types<int>>(),
|
sol::constructors<sol::types<>, sol::types<int>>(),
|
||||||
"fun", sol::protect( &bark::fun ),
|
"fun", sol::protect( &bark::fun ),
|
||||||
"get", &bark::get,
|
"get", &bark::get,
|
||||||
"var", &bark::var,
|
"var", sol::as_function( &bark::var ),
|
||||||
"the_marker", &bark::the_marker,
|
"the_marker", &bark::the_marker,
|
||||||
"x", sol::property(&bark::get),
|
"x", sol::overload(&bark::get),
|
||||||
"y", sol::property(&bark::set),
|
"y", sol::overload(&bark::set),
|
||||||
"z", sol::property(&bark::get, &bark::set)
|
"z", sol::overload(&bark::get, &bark::set)
|
||||||
);
|
);
|
||||||
|
|
||||||
lua.script("bx = bark.new(760)");
|
lua.script("bx = bark.new(760)");
|
||||||
bark& bx = lua["bx"];
|
bark& bx = lua["bx"];
|
||||||
|
@ -210,7 +211,7 @@ TEST_CASE("usertype/simple-shared-ptr-regression", "simple usertype metatables s
|
||||||
REQUIRE(destroyed == 1);
|
REQUIRE(destroyed == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("usertypes/simple=vars", "simple usertype vars can bind various values (no ref)") {
|
TEST_CASE("usertypes/simple-vars", "simple usertype vars can bind various values (no ref)") {
|
||||||
int muh_variable = 10;
|
int muh_variable = 10;
|
||||||
int through_variable = 25;
|
int through_variable = 25;
|
||||||
|
|
||||||
|
@ -222,7 +223,7 @@ TEST_CASE("usertypes/simple=vars", "simple usertype vars can bind various values
|
||||||
"straight", sol::var(2),
|
"straight", sol::var(2),
|
||||||
"global", sol::var(muh_variable),
|
"global", sol::var(muh_variable),
|
||||||
"global2", sol::var(through_variable)
|
"global2", sol::var(through_variable)
|
||||||
);
|
);
|
||||||
|
|
||||||
lua.script(R"(
|
lua.script(R"(
|
||||||
s = test.straight
|
s = test.straight
|
||||||
|
@ -237,3 +238,76 @@ g2 = test.global2
|
||||||
REQUIRE(g == 10);
|
REQUIRE(g == 10);
|
||||||
REQUIRE(g2 == 25);
|
REQUIRE(g2 == 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("simple_usertypes/variable-control", "test to see if usertypes respond to inheritance and variable controls") {
|
||||||
|
class A {
|
||||||
|
public:
|
||||||
|
virtual void a() { throw std::runtime_error("entered base pure virtual implementation"); };
|
||||||
|
};
|
||||||
|
|
||||||
|
class B : public A {
|
||||||
|
public:
|
||||||
|
virtual void a() override { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class sA {
|
||||||
|
public:
|
||||||
|
virtual void a() { throw std::runtime_error("entered base pure virtual implementation"); };
|
||||||
|
};
|
||||||
|
|
||||||
|
class sB : public sA {
|
||||||
|
public:
|
||||||
|
virtual void a() override { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sV {
|
||||||
|
int a = 10;
|
||||||
|
int b = 20;
|
||||||
|
|
||||||
|
int get_b() const {
|
||||||
|
return b + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_b(int value) {
|
||||||
|
b = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sW : sV {};
|
||||||
|
|
||||||
|
sol::state lua;
|
||||||
|
lua.open_libraries();
|
||||||
|
|
||||||
|
lua.new_usertype<A>("A", "a", &A::a);
|
||||||
|
lua.new_usertype<B>("B", sol::base_classes, sol::bases<A>());
|
||||||
|
lua.new_simple_usertype<sA>("sA", "a", &sA::a);
|
||||||
|
lua.new_simple_usertype<sB>("sB", sol::base_classes, sol::bases<sA>());
|
||||||
|
lua.new_simple_usertype<sV>("sV", "a", &sV::a, "b", &sV::b, "pb", sol::property(&sV::get_b, &sV::set_b));
|
||||||
|
lua.new_simple_usertype<sW>("sW", sol::base_classes, sol::bases<sV>());
|
||||||
|
|
||||||
|
B b;
|
||||||
|
lua.set("b", &b);
|
||||||
|
lua.script("b:a()");
|
||||||
|
|
||||||
|
sB sb;
|
||||||
|
lua.set("sb", &sb);
|
||||||
|
lua.script("sb:a()");
|
||||||
|
|
||||||
|
sV sv;
|
||||||
|
lua.set("sv", &sv);
|
||||||
|
lua.script("print(sv.b)assert(sv.b == 20)");
|
||||||
|
|
||||||
|
sW sw;
|
||||||
|
lua.set("sw", &sw);
|
||||||
|
lua.script("print(sw.a)assert(sw.a == 10)");
|
||||||
|
lua.script("print(sw.b)assert(sw.b == 20)");
|
||||||
|
lua.script("print(sw.pb)assert(sw.pb == 22)");
|
||||||
|
lua.script("sw.a = 11");
|
||||||
|
lua.script("sw.b = 21");
|
||||||
|
lua.script("print(sw.a)assert(sw.a == 11)");
|
||||||
|
lua.script("print(sw.b)assert(sw.b == 21)");
|
||||||
|
lua.script("print(sw.pb)assert(sw.pb == 23)");
|
||||||
|
lua.script("sw.pb = 25");
|
||||||
|
lua.script("print(sw.b)assert(sw.b == 25)");
|
||||||
|
lua.script("print(sw.pb)assert(sw.pb == 27)");
|
||||||
|
}
|
||||||
|
|
|
@ -1419,7 +1419,6 @@ TEST_CASE("usertype/unique_usertype-check", "make sure unique usertypes don't ge
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("usertype/abstract-base-class", "Ensure that abstract base classes and such can be registered") {
|
TEST_CASE("usertype/abstract-base-class", "Ensure that abstract base classes and such can be registered") {
|
||||||
|
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
lua.new_usertype<abstract_A>("A", "a", &abstract_A::a);
|
lua.new_usertype<abstract_A>("A", "a", &abstract_A::a);
|
||||||
lua.new_usertype<abstract_B>("B", sol::base_classes, sol::bases<abstract_A>());
|
lua.new_usertype<abstract_B>("B", sol::base_classes, sol::bases<abstract_A>());
|
||||||
|
@ -1427,3 +1426,23 @@ TEST_CASE("usertype/abstract-base-class", "Ensure that abstract base classes and
|
||||||
b:a()
|
b:a()
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("usertype/as_function", "Ensure that variables can be turned into functions by as_function") {
|
||||||
|
class B {
|
||||||
|
public:
|
||||||
|
int bvar = 24;
|
||||||
|
};
|
||||||
|
|
||||||
|
sol::state lua;
|
||||||
|
lua.open_libraries();
|
||||||
|
lua.new_usertype<B>("B", "b", &B::bvar, "f", sol::as_function(&B::bvar));
|
||||||
|
|
||||||
|
B b;
|
||||||
|
lua.set("b", &b);
|
||||||
|
lua.script("x = b:f()");
|
||||||
|
lua.script("y = b.b");
|
||||||
|
int x = lua["x"];
|
||||||
|
int y = lua["y"];
|
||||||
|
REQUIRE(x == 24);
|
||||||
|
REQUIRE(y == 24);
|
||||||
|
}
|
||||||
|
|
|
@ -615,7 +615,7 @@ TEST_CASE("optional/left-out-args", "Make sure arguments can be left out of opti
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
lua.open_libraries(sol::lib::base);
|
lua.open_libraries(sol::lib::base);
|
||||||
|
|
||||||
// sol::optional needs an argument no matter what
|
// sol::optional needs an argument no matter what?
|
||||||
lua.set_function("func_opt_ret_bool", func_opt_ret_bool);
|
lua.set_function("func_opt_ret_bool", func_opt_ret_bool);
|
||||||
REQUIRE_NOTHROW(
|
REQUIRE_NOTHROW(
|
||||||
lua.script(R"(
|
lua.script(R"(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user