stack implementation, plus reference semantics within lua for usertypes/data now.

I hate my life.
I hate the projects I'm working on.
Closes #53
Closes #56
Closes #52
This commit is contained in:
ThePhD 2016-04-07 05:21:49 -04:00
parent 204bd5d5ed
commit 9734577fdb
29 changed files with 472 additions and 238 deletions

View File

@ -32,22 +32,23 @@
#include <memory>
namespace sol {
class function : public reference {
template <typename base_t>
class basic_function : public base_t {
private:
void luacall( std::ptrdiff_t argcount, std::ptrdiff_t resultcount ) const {
lua_callk( lua_state( ), static_cast<int>( argcount ), static_cast<int>( resultcount ), 0, nullptr );
lua_callk( base_t::lua_state( ), static_cast<int>( argcount ), static_cast<int>( resultcount ), 0, nullptr );
}
template<std::size_t... I, typename... Ret>
auto invoke( types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n ) const {
luacall( n, sizeof...( Ret ) );
return stack::pop<std::tuple<Ret...>>( lua_state( ) );
return stack::pop<std::tuple<Ret...>>( base_t::lua_state( ) );
}
template<std::size_t I, typename Ret>
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n ) const {
luacall( n, 1 );
return stack::pop<Ret>( lua_state( ) );
return stack::pop<Ret>( base_t::lua_state( ) );
}
template <std::size_t I>
@ -56,21 +57,21 @@ private:
}
function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n ) const {
int stacksize = lua_gettop( lua_state( ) );
int stacksize = lua_gettop( base_t::lua_state( ) );
int firstreturn = std::max( 1, stacksize - static_cast<int>( n ) );
luacall(n, LUA_MULTRET);
int poststacksize = lua_gettop( lua_state( ) );
int poststacksize = lua_gettop( base_t::lua_state( ) );
int returncount = poststacksize - (firstreturn - 1);
return function_result( lua_state( ), firstreturn, returncount );
return function_result( base_t::lua_state( ), firstreturn, returncount );
}
public:
function() = default;
function(const function&) = default;
function& operator=(const function&) = default;
function( function&& ) = default;
function& operator=( function&& ) = default;
function(lua_State* L, int index = -1): reference(L, index) {
basic_function() = default;
basic_function(const basic_function&) = default;
basic_function& operator=(const basic_function&) = default;
basic_function(basic_function&& ) = default;
basic_function& operator=(basic_function&& ) = default;
basic_function(lua_State* L, int index = -1): base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS
type_assert(L, index, type::function);
#endif // Safety
@ -88,8 +89,8 @@ public:
template<typename... Ret, typename... Args>
decltype(auto) call( Args&&... args ) const {
push( );
int pushcount = stack::multi_push( lua_state( ), std::forward<Args>( args )... );
base_t::push( );
int pushcount = stack::multi_push( base_t::lua_state( ), std::forward<Args>( args )... );
return invoke( types<Ret...>( ), std::make_index_sequence<sizeof...(Ret)>(), pushcount );
}
};

View File

@ -103,7 +103,7 @@ struct pusher<function_sig<Sigs...>> {
template <typename Fx, typename T, typename... Args>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef meta::Bool<meta::is_specialization_of<meta::Unqualified<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
typedef meta::Bool<meta::is_specialization_of<std::reference_wrapper, meta::Unqualified<T>>::value || std::is_pointer<T>::value> is_reference;
select_reference_member_variable(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}
@ -141,7 +141,7 @@ struct pusher<function_sig<Sigs...>> {
template <typename Fx, typename T, typename... Args>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef meta::Bool<meta::is_specialization_of<meta::Unqualified<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
typedef meta::Bool<meta::is_specialization_of<std::reference_wrapper, meta::Unqualified<T>>::value || std::is_pointer<T>::value> is_reference;
select_reference_member_function(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}

View File

@ -45,7 +45,7 @@ struct constructor_match {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
default_construct func{};
return stack::call_into_lua<0, false>(r, a, func, L, start, obj);
return stack::call_into_lua<0, false>(r, a, L, start, func, obj);
}
};
} // detail
@ -115,7 +115,7 @@ struct usertype_constructor_function : base_function {
userdataref.pop();
auto& func = std::get<I>(overloads);
stack::call_into_lua<false>(r, a, func, L, start, function_detail::implicit_wrapper<T>(obj));
stack::call_into_lua<false>(r, a, L, start, func, function_detail::implicit_wrapper<T>(obj));
userdataref.push();
luaL_getmetatable(L, &meta[0]);

View File

@ -34,7 +34,7 @@ struct upvalue_free_function {
static int real_call(lua_State* L) {
auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);
function_type* fx = udata.first;
int r = stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), fx, L, 1);
int r = stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L, 1, fx);
return r;
}
@ -65,7 +65,7 @@ struct upvalue_member_function {
auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type {
return (item.*memfx)(std::forward<decltype(args)>(args)...);
};
return stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), fx, L, 1);
return stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L, 1, fx);
}
static int call (lua_State* L) {
@ -124,11 +124,11 @@ struct upvalue_this_member_function {
// idx 1...n: verbatim data of member variable pointer
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
function_type& memfx = memberdata.first;
auto fx = [&memfx](lua_State* L, auto&&... args) -> typename traits_type::return_type {
auto fx = [&L, &memfx](auto&&... args) -> typename traits_type::return_type {
auto& item = stack::get<T>(L, 1);
return (item.*memfx)(std::forward<decltype(args)>(args)...);
};
int n = stack::call_into_lua<1>(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), fx, L, 2, L);
int n = stack::call_into_lua<1>(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L, 2, fx);
return n;
}

View File

@ -97,19 +97,19 @@ struct functor<T, Func, std::enable_if_t<std::is_member_object_pointer<Func>::va
}
template<typename Arg>
void call(types<return_type>, Arg&& arg) {
void call(Arg&& arg) {
T& member = *item;
(member.*invocation) = std::forward<Arg>(arg);
}
return_type call(types<return_type>) {
return_type& call() {
T& member = *item;
return (member.*invocation);
}
template<typename... Args>
auto operator()(Args&&... args) -> decltype(std::declval<functor>().call(types<return_type>{}, std::forward<Args>(args)...)) {
return this->call(types<return_type>{}, std::forward<Args>(args)...);
decltype(auto) operator()(Args&&... args) {
return this->call(std::forward<Args>(args)...);
}
};

View File

@ -38,7 +38,7 @@ struct functor_function : public base_function {
functor_function(Args&&... args): fx(std::forward<Args>(args)...) {}
int call(lua_State* L) {
return stack::call_into_lua(meta::tuple_types<return_type>(), args_types(), fx, L, 1);
return stack::call_into_lua(meta::tuple_types<return_type>(), args_types(), L, 1, fx);
}
virtual int operator()(lua_State* L) override {
@ -70,7 +70,7 @@ struct member_function : public base_function {
member_function(F&& f, Args&&... args) : fx(std::forward<F>(f), std::forward<Args>(args)...) {}
int call(lua_State* L) {
return stack::call_into_lua(meta::tuple_types<return_type>(), args_types(), fx, L, 1);
return stack::call_into_lua(meta::tuple_types<return_type>(), args_types(), L, 1, fx);
}
virtual int operator()(lua_State* L) override {
@ -86,21 +86,39 @@ struct member_variable : public base_function {
typedef typename meta::bind_traits<function_type>::args_type args_types;
function_type var;
T member;
typedef std::add_lvalue_reference_t<meta::Unwrapped<std::remove_reference_t<decltype(detail::deref(member))>>> M;
template<typename Fx, typename... Args>
member_variable(Fx&& fx, Args&&... args): var(std::forward<Fx>(fx)), member(std::forward<Args>(args)...) {}
template<typename V, typename... Args>
member_variable(V&& v, Args&&... args): var(std::forward<V>(v)), member(std::forward<Args>(args)...) {}
int set_assignable(std::false_type, lua_State* L, M) {
lua_pop(L, 1);
return luaL_error(L, "cannot write to this type: copy assignment/constructor not available");
}
int set_assignable(std::true_type, lua_State* L, M mem) {
(mem.*var) = stack::get<return_type>(L, 1);
lua_pop(L, 1);
return 0;
}
int set_variable(std::true_type, lua_State* L, M mem) {
return set_assignable(std::is_assignable<std::add_lvalue_reference_t<return_type>, return_type>(), L, mem);
}
int set_variable(std::false_type, lua_State* L, M) {
lua_pop(L, 1);
return luaL_error(L, "cannot write to a const variable");
}
int call(lua_State* L) {
auto& mem = detail::unwrap(detail::deref(member));
M mem = detail::unwrap(detail::deref(member));
switch (lua_gettop(L)) {
case 0: {
case 0:
stack::push(L, (mem.*var));
return 1;
}
return 1;
case 1:
(mem.*var) = stack::get<return_type>(L, 1);
lua_pop(L, 1);
return 0;
return set_variable(meta::Not<std::is_const<return_type>>(), L, mem);
default:
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
}

View File

@ -92,7 +92,7 @@ struct overloaded_function : base_function {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int call(types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
auto& func = std::get<I>(overloads);
return stack::call_into_lua<0, false>(r, a, func, L, start);
return stack::call_into_lua<0, false>(r, a, L, start, func);
}
virtual int operator()(lua_State* L) override {
@ -113,7 +113,7 @@ struct usertype_overloaded_function : base_function {
int call(types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
auto& func = std::get<I>(overloads);
func.item = detail::ptr(stack::get<T>(L, 1));
return stack::call_into_lua<0, false>(r, a, func, L, start);
return stack::call_into_lua<0, false>(r, a, L, start, func);
}
virtual int operator()(lua_State* L) override {

View File

@ -34,6 +34,30 @@ namespace function_detail {
return stack::call_into_lua(return_type(), args_type(), fx, L, 1);
}
template <typename R, typename V, V, typename T>
inline int call_set_assignable(std::false_type, T&&, lua_State* L) {
lua_pop(L, 2);
return luaL_error(L, "cannot write to this type: copy assignment/constructor not available");
}
template <typename R, typename V, V variable, typename T>
inline int call_set_assignable(std::true_type, lua_State* L, T&& mem) {
(mem.*variable) = stack::get<R>(L, 2);
lua_pop(L, 2);
return 0;
}
template <typename R, typename V, V, typename T>
inline int call_set_variable(std::false_type, lua_State* L, T&&) {
lua_pop(L, 2);
return luaL_error(L, "cannot write to a const variable");
}
template <typename R, typename V, V variable, typename T>
inline int call_set_variable(std::true_type, lua_State* L, T&& mem) {
return call_set_assignable<R, V, variable>(std::is_assignable<std::add_lvalue_reference_t<R>, R>(), L, std::forward<T>(mem));
}
template <typename V, V variable>
inline int call_wrapper_variable(std::true_type, lua_State* L) {
typedef meta::bind_traits<meta::Unqualified<V>> traits_type;
@ -41,14 +65,13 @@ namespace function_detail {
typedef typename traits_type::return_type R;
auto& mem = stack::get<T>(L, 1);
switch (lua_gettop(L)) {
case 1:
case 1: {
decltype(auto) r = (mem.*variable);
lua_pop(L, 1);
stack::push(L, (mem.*variable));
return 1;
stack::push_reference(L, std::forward<decltype(r)>(r));
return 1; }
case 2:
(mem.*variable) = stack::get<R>(L, 2);
lua_pop(L, 2);
return 0;
return call_set_variable<R, V, variable>(meta::Not<std::is_const<R>>(), L, mem);
default:
return luaL_error(L, "incorrect number of arguments to member variable function call");
}
@ -70,7 +93,7 @@ namespace function_detail {
auto& member = stack::get<T>(L, 1);
return (member.*fx)(std::forward<decltype(args)>(args)...);
};
int n = stack::call_into_lua<1>(return_type_list(), args_type(), mfx, L, 2);
int n = stack::call_into_lua<1>(return_type_list(), args_type(), L, 2, mfx);
return n;
}

View File

@ -55,17 +55,17 @@ struct usertype_function_core : public base_function {
// without allocating an extra userdata, apparently!
return 1;
}
return stack::push(L, std::forward<Return>(r));
return stack::push_reference(L, std::forward<Return>(r));
}
template<typename Return, typename Raw = meta::Unqualified<Return>>
std::enable_if_t<!std::is_same<T, Raw>::value, int> push(lua_State* L, Return&& r) {
return stack::push(L, std::forward<Return>(r));
return stack::push_reference(L, std::forward<Return>(r));
}
template<typename... Args, std::size_t Start>
int operator()(types<void> tr, types<Args...> ta, Index<Start>, lua_State* L) {
stack::call(tr, ta, L, static_cast<int>(Start), fx);
stack::call_into_lua(tr, ta, L, static_cast<int>(Start), fx);
int nargs = static_cast<int>(sizeof...(Args));
lua_pop(L, nargs);
return 0;
@ -113,6 +113,24 @@ struct usertype_variable_function : public usertype_function_core<Function, Tp>
template<typename... Args>
usertype_variable_function(Args&&... args): base_t(std::forward<Args>(args)...) {}
int set_assignable(std::false_type, lua_State* L) {
lua_pop(L, 2);
return luaL_error(L, "cannot write to this type: copy assignment/constructor not available");
}
int set_assignable(std::true_type, lua_State* L) {
return static_cast<base_t&>(*this)(meta::tuple_types<void>(), args_type(), Index<3>(), L);
}
int set_variable(std::false_type, lua_State* L) {
lua_pop(L, 2);
return luaL_error(L, "cannot write to a const variable");
}
int set_variable(std::true_type, lua_State* L) {
return set_assignable(std::is_assignable<std::add_lvalue_reference_t<return_type>, return_type>(), L);
}
int prelude(lua_State* L) {
int argcount = lua_gettop(L);
this->fx.item = stack::get<T*>(L, 1);
@ -120,7 +138,7 @@ struct usertype_variable_function : public usertype_function_core<Function, Tp>
case 2:
return static_cast<base_t&>(*this)(meta::tuple_types<return_type>(), types<>(), Index<2>(), L);
case 3:
return static_cast<base_t&>(*this)(meta::tuple_types<void>(), args_type(), Index<3>(), L);
return set_variable(meta::Not<std::is_const<return_type>>(), L);
default:
return luaL_error(L, "sol: cannot get/set userdata member variable with inappropriate number of arguments");
}

View File

@ -27,23 +27,46 @@
#include "stack.hpp"
namespace sol {
class object : public reference {
public:
using reference::reference;
template <typename base_t>
class basic_object : public base_t {
private:
template<typename T>
decltype(auto) as_stack(std::true_type) const {
return stack::get<T>(lua_state(), base_t::stack_index());
}
template<typename T>
decltype(auto) as() const {
push();
decltype(auto) as_stack(std::false_type) const {
base_t::push();
return stack::pop<T>(lua_state());
}
template<typename T>
bool is() const {
if (!valid())
return false;
bool is_stack(std::true_type) const {
return stack::check<T>(lua_state(), base_t::stack_index(), no_panic);
}
template<typename T>
bool is_stack(std::false_type) const {
auto pp = stack::push_pop(*this);
return stack::check<T>(lua_state(), -1, no_panic);
}
public:
using base_t::base_t;
using base_t::lua_state;
template<typename T>
decltype(auto) as() const {
return as_stack<T>( std::is_same<base_t, stack_reference>() );
}
template<typename T>
bool is() const {
if (!base_t::valid())
return false;
return is_stack<T>(std::is_same<base_t, stack_reference>());
}
};
inline bool operator==(const object& lhs, const nil_t&) {

View File

@ -28,7 +28,8 @@
#include <cstdint>
namespace sol {
class protected_function : public reference {
template <typename base_t>
class basic_protected_function : public base_t {
private:
static reference& handler_storage() {
static sol::reference h;
@ -62,19 +63,19 @@ private:
};
int luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, handler& h) const {
return lua_pcallk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr);
return lua_pcallk(base_t::lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr);
}
template<std::size_t... I, typename... Ret>
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, handler& h) const {
luacall(n, sizeof...(Ret), h);
return stack::pop<std::tuple<Ret...>>(lua_state());
return stack::pop<std::tuple<Ret...>>(base_t::lua_state());
}
template<std::size_t I, typename Ret>
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, handler& h) const {
luacall(n, 1, h);
return stack::pop<Ret>(lua_state());
return stack::pop<Ret>(base_t::lua_state());
}
template <std::size_t I>
@ -83,7 +84,7 @@ private:
}
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, handler& h) const {
int stacksize = lua_gettop(lua_state());
int stacksize = lua_gettop(base_t::lua_state());
int firstreturn = std::max(1, stacksize - static_cast<int>(n) - 1);
int returncount = 0;
call_status code = call_status::ok;
@ -92,49 +93,49 @@ private:
h.stackindex = 0;
if (h.target.valid()) {
h.target.push();
stack::push(lua_state(), error);
lua_call(lua_state(), 1, 1);
stack::push(base_t::lua_state(), error);
lua_call(base_t::lua_state(), 1, 1);
}
else {
stack::push(lua_state(), error);
stack::push(base_t::lua_state(), error);
}
};
try {
#endif // No Exceptions
code = static_cast<call_status>(luacall(n, LUA_MULTRET, h));
int poststacksize = lua_gettop(lua_state());
int poststacksize = lua_gettop(base_t::lua_state());
returncount = poststacksize - (stacksize - 1);
#ifndef SOL_NO_EXCEPTIONS
}
// Handle C++ errors thrown from C++ functions bound inside of lua
catch (const char* error) {
onexcept(error);
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
firstreturn = lua_gettop(base_t::lua_state());
return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime);
}
catch (const std::exception& error) {
onexcept(error.what());
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
firstreturn = lua_gettop(base_t::lua_state());
return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime);
}
catch (...) {
onexcept("caught (...) unknown error during protected_function call");
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
firstreturn = lua_gettop(base_t::lua_state());
return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime);
}
#endif // No Exceptions
return protected_function_result(lua_state(), firstreturn, returncount, returncount, code);
return protected_function_result(base_t::lua_state(), firstreturn, returncount, returncount, code);
}
public:
reference error_handler;
protected_function() = default;
protected_function(const protected_function&) = default;
protected_function& operator=(const protected_function&) = default;
protected_function( protected_function&& ) = default;
protected_function& operator=( protected_function&& ) = default;
protected_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) {
basic_protected_function() = default;
basic_protected_function(const basic_protected_function&) = default;
basic_protected_function& operator=(const basic_protected_function&) = default;
basic_protected_function(basic_protected_function&& ) = default;
basic_protected_function& operator=(basic_protected_function&& ) = default;
basic_protected_function(lua_State* L, int index = -1): base_t(L, index), error_handler(get_default_handler()) {
#ifdef SOL_CHECK_ARGUMENTS
type_assert(L, index, type::function);
#endif // Safety
@ -153,8 +154,8 @@ public:
template<typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) const {
handler h(error_handler);
push();
int pushcount = stack::multi_push(lua_state(), std::forward<Args>(args)...);
base_t::push();
int pushcount = stack::multi_push(base_t::lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
}
};

View File

@ -32,7 +32,7 @@ namespace sol {
template<typename Table, typename Key>
struct proxy : public proxy_base<proxy<Table, Key>> {
private:
typedef meta::If<meta::is_specialization_of<Key, std::tuple>, Key, std::tuple<meta::If<std::is_array<meta::Unqualified<Key>>, Key&, meta::Unqualified<Key>>>> key_type;
typedef meta::If<meta::is_specialization_of<std::tuple, Key>, Key, std::tuple<meta::If<std::is_array<meta::Unqualified<Key>>, Key&, meta::Unqualified<Key>>>> key_type;
template<typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) const {

View File

@ -23,6 +23,7 @@
#define SOL_REFERENCE_HPP
#include "types.hpp"
#include "stack_reference.hpp"
namespace sol {
namespace stack {
@ -65,9 +66,14 @@ protected:
ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
int stack_index() const noexcept {
return -1;
}
public:
reference() noexcept = default;
reference(const stack_reference& r) noexcept : reference(r.lua_state(), r.stack_index()) {}
reference(stack_reference&& r) noexcept : reference(r.lua_state(), r.stack_index()) {}
reference(lua_State* L, int index = -1) noexcept : L(L) {
lua_pushvalue(L, index);
ref = luaL_ref(L, LUA_REGISTRYINDEX);

View File

@ -68,7 +68,7 @@ inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) {
}
template <bool checkargs = default_check_arguments, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline R call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
check_types<checkargs>{}.check(ta, tai, L, start, type_panic);
return fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I)...);
}
@ -103,13 +103,13 @@ inline void remove( lua_State* L, int index, int count ) {
}
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline R call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
typedef typename types<Args...>::indices args_indices;
return stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline R call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
return call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
@ -125,7 +125,7 @@ inline void call(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArg
}
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline R call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
return call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
@ -135,16 +135,16 @@ inline void call_from_top(types<void> tr, types<Args...> ta, lua_State* L, Fx&&
}
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline int call_into_lua(types<void> tr, types<Args...> ta, Fx&& fx, lua_State* L, int start, FxArgs&&... fxargs) {
call<check_args>(tr, ta, L, start, fx, std::forward<FxArgs>(fxargs)...);
inline int call_into_lua(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
int nargs = static_cast<int>(sizeof...(Args)) + additionalpop;
lua_pop(L, nargs);
return 0;
}
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::Not<std::is_void<Ret0>>::value>>
inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, Fx&& fx, lua_State* L, int start, FxArgs&&... fxargs) {
decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, fx, std::forward<FxArgs>(fxargs)...);
inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
int nargs = static_cast<int>(sizeof...(Args)) + additionalpop;
lua_pop(L, nargs);
return push(L, std::forward<decltype(r)>(r));

View File

@ -182,8 +182,7 @@ struct checker<T, type::userdata, C> {
if (meta::Or<std::is_same<T, light_userdata_value>, std::is_same<T, userdata_value>>::value)
return true;
if (lua_getmetatable(L, index) == 0) {
handler(L, index, type::userdata, indextype);
return false;
return true;
}
if (stack_detail::check_metatable<U>(L))
return true;

View File

@ -32,6 +32,8 @@
namespace sol {
namespace detail {
struct as_reference_tag{};
using special_destruct_func = void(*)(void*);
template <typename T, typename Real>
@ -134,6 +136,16 @@ inline int multi_push(lua_State* L, T&& t, Args&&... args) {
return pushcount;
}
template<typename T, typename... Args>
inline int push_reference(lua_State* L, T&& t, Args&&... args) {
typedef meta::And<
std::is_lvalue_reference<T>,
meta::Not<std::is_const<T>>,
meta::Not<is_lua_primitive<T>>
> use_reference_tag;
return pusher<std::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::Unqualified<T>>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
}
template <typename T, typename Handler>
bool check(lua_State* L, int index, Handler&& handler) {
typedef meta::Unqualified<T> Tu;

View File

@ -69,6 +69,13 @@ struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
}
};
template<typename T>
struct getter<T, std::enable_if_t<std::is_base_of<stack_reference, T>::value>> {
static T get(lua_State* L, int index = -1) {
return T(L, index);
}
};
template<>
struct getter<stack_reference> {
static stack_reference get(lua_State* L, int index = -1) {
@ -143,9 +150,9 @@ struct getter<lua_CFunction> {
template<>
struct getter<c_closure> {
static c_closure get(lua_State* L, int index = -1) {
return c_closure(lua_tocfunction(L, index), -1);
}
static c_closure get(lua_State* L, int index = -1) {
return c_closure(lua_tocfunction(L, index), -1);
}
};
template<>

View File

@ -34,7 +34,7 @@ inline void stack_fail(int, int) {
#else
// Lol, what do you want, an error printout? :3c
// There's no sane default here. The right way would be C-style abort(), and that's not acceptable, so
// hopefully someone will register their own stack_fail thing here
// hopefully someone will register their own stack_fail thing for the `fx` parameter of stack_guard.
#endif // No Exceptions
}
} // detail
@ -42,16 +42,16 @@ inline void stack_fail(int, int) {
struct stack_guard {
lua_State* L;
int top;
std::function<void(int, int)> fx;
std::function<void(int, int)> on_mismatch;
stack_guard(lua_State* L) : stack_guard(L, lua_gettop(L)) {}
stack_guard(lua_State* L, int top, std::function<void(int, int)> fx = detail::stack_fail) : L(L), top(top), fx(std::move(fx)) {}
stack_guard(lua_State* L, int top, std::function<void(int, int)> fx = detail::stack_fail) : L(L), top(top), on_mismatch(std::move(fx)) {}
~stack_guard() {
int bottom = lua_gettop(L);
if (top == bottom) {
return;
}
fx(top, bottom);
on_mismatch(top, bottom);
}
};
} // sol

View File

@ -55,6 +55,11 @@ struct popper<std::pair<A, B>> {
return r;
}
};
template <typename T>
struct popper<T, std::enable_if_t<std::is_base_of<stack_reference, meta::Unqualified<T>>::value>> {
static_assert(meta::Not<std::is_base_of<stack_reference, meta::Unqualified<T>>>::value, "You cannot pop something that derives from stack_reference: it will not remain on the stack and thusly will go out of scope!");
};
} // stack
} // sol

View File

@ -50,6 +50,14 @@ struct pusher {
}
};
template <>
struct pusher<detail::as_reference_tag> {
template <typename T>
static int push(lua_State* L, T&& obj) {
return stack::push(L, detail::ptr(obj));
}
};
template<typename T>
struct pusher<T*> {
static int push(lua_State* L, T* obj) {

View File

@ -22,8 +22,6 @@
#ifndef SOL_STACK_REFERENCE_HPP
#define SOL_STACK_REFERENCE_HPP
#include "reference.hpp"
namespace sol {
class stack_reference {
private:
@ -31,6 +29,9 @@ private:
int index = 0;
protected:
int registry_index () const noexcept {
return LUA_NOREF;
}
public:
stack_reference() noexcept = default;
@ -45,6 +46,10 @@ public:
return 1;
}
int stack_index () const noexcept {
return index;
}
type get_type() const noexcept {
int result = lua_type(L, index);
return static_cast<type>(result);

View File

@ -25,11 +25,28 @@
#include "state_view.hpp"
namespace sol {
inline int default_at_panic(lua_State* L) {
#ifdef SOL_NO_EXCEPTIONS
(void)L;
return -1;
#else
const char* message = lua_tostring(L, -1);
std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic";
throw error(err);
#endif
}
class state : private std::unique_ptr<lua_State, void(*)(lua_State*)>, public state_view {
private:
typedef std::unique_ptr<lua_State, void(*)(lua_State*)> unique_base;
public:
state(lua_CFunction panic = detail::atpanic) : unique_base(luaL_newstate(), lua_close),
state(lua_CFunction panic = default_at_panic) : unique_base(luaL_newstate(), lua_close),
state_view(unique_base::get()) {
set_panic(panic);
stack::luajit_exception_handler(unique_base::get());
}
state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) : unique_base(lua_newstate(alfunc, alpointer), lua_close),
state_view(unique_base::get()) {
set_panic(panic);
stack::luajit_exception_handler(unique_base::get());

View File

@ -27,19 +27,6 @@
#include <memory>
namespace sol {
namespace detail {
inline int atpanic(lua_State* L) {
#ifdef SOL_NO_EXCEPTIONS
(void)L;
return -1;
#else
const char* message = lua_tostring(L, -1);
std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic";
throw error(err);
#endif
}
} // detail
enum class lib : char {
base,
package,
@ -60,6 +47,9 @@ private:
table reg;
global_table global;
public:
typedef typename global_table::iterator iterator;
typedef typename global_table::const_iterator const_iterator;
state_view(lua_State* L):
L(L),
reg(L, LUA_REGISTRYINDEX),
@ -152,19 +142,19 @@ public:
}
}
table_iterator begin () const {
iterator begin () const {
return global.begin();
}
table_iterator end() const {
iterator end() const {
return global.end();
}
table_iterator cbegin() const {
const_iterator cbegin() const {
return global.cbegin();
}
table_iterator cend() const {
const_iterator cend() const {
return global.cend();
}

View File

@ -34,8 +34,9 @@ template <std::size_t n>
struct clean { lua_State* L; clean(lua_State* L) : L(L) {} ~clean() { lua_pop(L, static_cast<int>(n)); } };
struct ref_clean { lua_State* L; int& n; ref_clean(lua_State* L, int& n) : L(L), n(n) {} ~ref_clean() { lua_pop(L, static_cast<int>(n)); } };
}
template <bool top_level>
class table_core : public reference {
template <bool top_level, typename base_t>
class basic_table_core : public base_t {
friend class state;
friend class state_view;
@ -45,25 +46,25 @@ class table_core : public reference {
template<typename Fx>
void for_each(std::true_type, Fx&& fx) const {
auto pp = stack::push_pop( *this );
stack::push( lua_state( ), nil );
while ( lua_next( this->lua_state( ), -2 ) ) {
sol::object key( lua_state( ), -2 );
sol::object value( lua_state( ), -1 );
stack::push( base_t::lua_state( ), nil );
while ( lua_next( base_t::lua_state( ), -2 ) ) {
sol::object key( base_t::lua_state( ), -2 );
sol::object value( base_t::lua_state( ), -1 );
std::pair<sol::object&, sol::object&> keyvalue(key, value);
fx( keyvalue );
lua_pop( lua_state( ), 1 );
lua_pop( base_t::lua_state( ), 1 );
}
}
template<typename Fx>
void for_each(std::false_type, Fx&& fx) const {
auto pp = stack::push_pop( *this );
stack::push( lua_state( ), nil );
while ( lua_next( this->lua_state( ), -2 ) ) {
sol::object key( lua_state( ), -2 );
sol::object value( lua_state( ), -1 );
stack::push( base_t::lua_state( ), nil );
while ( lua_next( base_t::lua_state( ), -2 ) ) {
sol::object key( base_t::lua_state( ), -2 );
sol::object value( base_t::lua_state( ), -1 );
fx( key, value );
lua_pop( lua_state( ), 1 );
lua_pop( base_t::lua_state( ), 1 );
}
}
@ -72,21 +73,21 @@ class table_core : public reference {
-> decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)){
typedef decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)) Tup;
return Tup(
traverse_get_optional<top_level, Ret0>(meta::is_specialization_of<meta::Unqualified<Ret0>, sol::optional>(), detail::forward_get<0>(keys)),
traverse_get_optional<top_level, Ret1>(meta::is_specialization_of<meta::Unqualified<Ret1>, sol::optional>(), detail::forward_get<1>(keys)),
traverse_get_optional<top_level, Ret>(meta::is_specialization_of<meta::Unqualified<Ret>, sol::optional>(), detail::forward_get<I>(keys))...
traverse_get_optional<top_level, Ret0>(meta::is_specialization_of<sol::optional, meta::Unqualified<Ret0>>(), detail::forward_get<0>(keys)),
traverse_get_optional<top_level, Ret1>(meta::is_specialization_of<sol::optional, meta::Unqualified<Ret1>>(), detail::forward_get<1>(keys)),
traverse_get_optional<top_level, Ret>(meta::is_specialization_of<sol::optional, meta::Unqualified<Ret>>(), detail::forward_get<I>(keys))...
);
}
template<typename Ret, std::size_t I, typename Keys>
decltype(auto) tuple_get( types<Ret>, std::index_sequence<I>, Keys&& keys ) const {
return traverse_get_optional<top_level, Ret>( meta::is_specialization_of<meta::Unqualified<Ret>, sol::optional>(), detail::forward_get<I>(keys) );
return traverse_get_optional<top_level, Ret>( meta::is_specialization_of<sol::optional, meta::Unqualified<Ret>>(), detail::forward_get<I>(keys) );
}
template<typename Pairs, std::size_t... I>
void tuple_set( std::index_sequence<I...>, Pairs&& pairs ) {
auto pp = stack::push_pop<top_level && (is_global<decltype(detail::forward_get<I * 2>(pairs))...>::value)>(*this);
void(detail::swallow{ (stack::set_field<top_level>(lua_state(),
void(detail::swallow{ (stack::set_field<top_level>(base_t::lua_state(),
detail::forward_get<I * 2>(pairs),
detail::forward_get<I * 2 + 1>(pairs)
), 0)... });
@ -94,28 +95,28 @@ class table_core : public reference {
template <bool global, typename T, typename Key>
decltype(auto) traverse_get_deep( Key&& key ) const {
stack::get_field<global>( lua_state( ), std::forward<Key>( key ) );
return stack::get<T>( lua_state( ) );
stack::get_field<global>( base_t::lua_state( ), std::forward<Key>( key ) );
return stack::get<T>( base_t::lua_state( ) );
}
template <bool global, typename T, typename Key, typename... Keys>
decltype(auto) traverse_get_deep( Key&& key, Keys&&... keys ) const {
stack::get_field<global>( lua_state( ), std::forward<Key>( key ) );
stack::get_field<global>( base_t::lua_state( ), std::forward<Key>( key ) );
return traverse_get_deep<false, T>(std::forward<Keys>(keys)...);
}
template <bool global, typename T, std::size_t I, typename Key>
decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key ) const {
auto p = stack::probe_get_field<global>(lua_state(), std::forward<Key>(key), -1);
auto p = stack::probe_get_field<global>(base_t::lua_state(), std::forward<Key>(key), -1);
popcount += p.levels;
if (!p.success)
return T(nullopt);
return stack::get<T>( lua_state( ) );
return stack::get<T>( base_t::lua_state( ) );
}
template <bool global, typename T, std::size_t I, typename Key, typename... Keys>
decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key, Keys&&... keys ) const {
auto p = I > 0 ? stack::probe_get_field<global>(lua_state(), std::forward<Key>(key), - 1) : stack::probe_get_field<global>( lua_state( ), std::forward<Key>( key ) );
auto p = I > 0 ? stack::probe_get_field<global>(base_t::lua_state(), std::forward<Key>(key), - 1) : stack::probe_get_field<global>( base_t::lua_state( ), std::forward<Key>( key ) );
popcount += p.levels;
if (!p.success)
return T(nullopt);
@ -124,52 +125,57 @@ class table_core : public reference {
template <bool global, typename T, typename... Keys>
decltype(auto) traverse_get_optional( std::false_type, Keys&&... keys ) const {
detail::clean<sizeof...(Keys)> c(lua_state());
detail::clean<sizeof...(Keys)> c(base_t::lua_state());
return traverse_get_deep<top_level, T>(std::forward<Keys>(keys)...);
}
template <bool global, typename T, typename... Keys>
decltype(auto) traverse_get_optional( std::true_type, Keys&&... keys ) const {
int popcount = 0;
detail::ref_clean c(lua_state(), popcount);
detail::ref_clean c(base_t::lua_state(), popcount);
return traverse_get_deep_optional<top_level, T, 0>(popcount, std::forward<Keys>(keys)...);
}
template <bool global, typename Key, typename Value>
void traverse_set_deep( Key&& key, Value&& value ) const {
stack::set_field<global>( lua_state( ), std::forward<Key>( key ), std::forward<Value>(value) );
stack::set_field<global>( base_t::lua_state( ), std::forward<Key>( key ), std::forward<Value>(value) );
}
template <bool global, typename Key, typename... Keys>
void traverse_set_deep( Key&& key, Keys&&... keys ) const {
stack::get_field<global>( lua_state( ), std::forward<Key>( key ) );
stack::get_field<global>( base_t::lua_state( ), std::forward<Key>( key ) );
traverse_set_deep<false>(std::forward<Keys>(keys)...);
}
table_core(lua_State* L, detail::global_tag t) noexcept : reference(L, t) { }
basic_table_core(lua_State* L, detail::global_tag t) noexcept : reference(L, t) { }
public:
table_core( ) noexcept : reference( ) { }
table_core( const table_core<true>& global ) noexcept : reference( global ) { }
table_core( lua_State* L, int index = -1 ) : reference( L, index ) {
typedef basic_table_iterator<base_t> iterator;
typedef iterator const_iterator;
basic_table_core( ) noexcept : base_t( ) { }
basic_table_core( const table_core<true>& global ) noexcept : base_t( global ) { }
basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
basic_table_core( lua_State* L, int index = -1 ) : base_t( L, index ) {
#ifdef SOL_CHECK_ARGUMENTS
type_assert( L, index, type::table );
#endif // Safety
}
table_iterator begin () const {
return table_iterator(*this);
iterator begin () const {
return iterator(*this);
}
table_iterator end() const {
return table_iterator();
iterator end() const {
return iterator();
}
table_iterator cbegin() const {
const_iterator cbegin() const {
return begin();
}
table_iterator cend() const {
const_iterator cend() const {
return end();
}
@ -202,48 +208,48 @@ public:
template <typename T, typename... Keys>
decltype(auto) traverse_get( Keys&&... keys ) const {
auto pp = stack::push_pop<is_global<Keys...>::value>(*this);
return traverse_get_optional<top_level, T>(meta::is_specialization_of<meta::Unqualified<T>, sol::optional>(), std::forward<Keys>(keys)...);
return traverse_get_optional<top_level, T>(meta::is_specialization_of<sol::optional, meta::Unqualified<T>>(), std::forward<Keys>(keys)...);
}
template <typename... Keys>
table_core& traverse_set( Keys&&... keys ) {
basic_table_core& traverse_set( Keys&&... keys ) {
auto pp = stack::push_pop<is_global<Keys...>::value>(*this);
traverse_set_deep<top_level>(std::forward<Keys>(keys)...);
lua_pop(lua_state(), static_cast<int>(sizeof...(Keys)-2));
lua_pop(base_t::lua_state(), static_cast<int>(sizeof...(Keys)-2));
return *this;
}
template<typename... Args>
table_core& set( Args&&... args ) {
basic_table_core& set( Args&&... args ) {
tuple_set(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...));
return *this;
}
template<typename T>
table_core& set_usertype( usertype<T>& user ) {
basic_table_core& set_usertype( usertype<T>& user ) {
return set_usertype(usertype_traits<T>::name, user);
}
template<typename Key, typename T>
table_core& set_usertype( Key&& key, usertype<T>& user ) {
basic_table_core& set_usertype( Key&& key, usertype<T>& user ) {
return set(std::forward<Key>(key), user);
}
template<typename Class, typename... Args>
table_core& new_usertype(const std::string& name, Args&&... args) {
basic_table_core& new_usertype(const std::string& name, Args&&... args) {
usertype<Class> utype(std::forward<Args>(args)...);
set_usertype(name, utype);
return *this;
}
template<typename Class, typename CTor0, typename... CTor, typename... Args>
table_core& new_usertype(const std::string& name, Args&&... args) {
basic_table_core& new_usertype(const std::string& name, Args&&... args) {
constructors<types<CTor0, CTor...>> ctor{};
return new_usertype<Class>(name, ctor, std::forward<Args>(args)...);
}
template<typename Class, typename... CArgs, typename... Args>
table_core& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
basic_table_core& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
usertype<Class> utype(ctor, std::forward<Args>(args)...);
set_usertype(name, utype);
return *this;
@ -257,7 +263,7 @@ public:
size_t size( ) const {
auto pp = stack::push_pop( *this );
return lua_rawlen(lua_state(), -1);
return lua_rawlen(base_t::lua_state(), -1);
}
bool empty() const {
@ -265,28 +271,28 @@ public:
}
template<typename T>
proxy<table_core&, T> operator[]( T&& key ) & {
return proxy<table_core&, T>( *this, std::forward<T>( key ) );
proxy<basic_table_core&, T> operator[]( T&& key ) & {
return proxy<basic_table_core&, T>( *this, std::forward<T>( key ) );
}
template<typename T>
proxy<const table_core&, T> operator[]( T&& key ) const & {
return proxy<const table_core&, T>( *this, std::forward<T>( key ) );
proxy<const basic_table_core&, T> operator[]( T&& key ) const & {
return proxy<const basic_table_core&, T>( *this, std::forward<T>( key ) );
}
template<typename T>
proxy<table_core, T> operator[]( T&& key ) && {
return proxy<table_core, T>( *this, std::forward<T>( key ) );
proxy<basic_table_core, T> operator[]( T&& key ) && {
return proxy<basic_table_core, T>( *this, std::forward<T>( key ) );
}
template<typename Sig, typename Key, typename... Args>
table_core& set_function( Key&& key, Args&&... args ) {
basic_table_core& set_function( Key&& key, Args&&... args ) {
set_fx( types<Sig>( ), std::forward<Key>( key ), std::forward<Args>( args )... );
return *this;
}
template<typename Key, typename... Args>
table_core& set_function( Key&& key, Args&&... args ) {
basic_table_core& set_function( Key&& key, Args&&... args ) {
set_fx( types<>( ), std::forward<Key>( key ), std::forward<Args>( args )... );
return *this;
}
@ -297,12 +303,12 @@ private:
set_resolved_function<R( Args... )>( std::forward<Key>( key ), std::forward<Fx>( fx ) );
}
template<typename Fx, typename Key, meta::EnableIf<meta::is_specialization_of<meta::Unqualified<Fx>, overload_set>> = 0>
template<typename Fx, typename Key, meta::EnableIf<meta::is_specialization_of<overload_set, meta::Unqualified<Fx>>> = 0>
void set_fx( types<>, Key&& key, Fx&& fx ) {
set(std::forward<Key>(key), std::forward<Fx>(fx));
}
template<typename Fx, typename Key, typename... Args, meta::DisableIf<meta::is_specialization_of<meta::Unqualified<Fx>, overload_set>> = 0>
template<typename Fx, typename Key, typename... Args, meta::DisableIf<meta::is_specialization_of<overload_set, meta::Unqualified<Fx>>> = 0>
void set_fx( types<>, Key&& key, Fx&& fx, Args&&... args ) {
set(std::forward<Key>(key), function_args(std::forward<Fx>(fx), std::forward<Args>(args)...));
}
@ -336,31 +342,31 @@ public:
}
table create(int narr = 0, int nrec = 0) {
return create(lua_state(), narr, nrec);
return create(base_t::lua_state(), narr, nrec);
}
template <typename Key, typename Value, typename... Args>
table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
return create(lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
return create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
}
template <typename Name>
table create(Name&& name, int narr = 0, int nrec = 0) {
table x = create(lua_state(), narr, nrec);
table x = create(base_t::lua_state(), narr, nrec);
this->set(std::forward<Name>(name), x);
return x;
}
template <typename Name, typename Key, typename Value, typename... Args>
table create(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
table x = create(lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
table x = create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
this->set(std::forward<Name>(name), x);
return x;
}
template <typename... Args>
table create_with(Args&&... args) {
return create_with(lua_state(), std::forward<Args>(args)...);
return create_with(base_t::lua_state(), std::forward<Args>(args)...);
}
template <typename Name, typename... Args>

View File

@ -27,7 +27,8 @@
namespace sol {
class table_iterator : public std::iterator<std::input_iterator_tag, std::pair<object, object>> {
template <typename reference_type>
class basic_table_iterator : public std::iterator<std::input_iterator_tag, std::pair<object, object>> {
private:
typedef std::iterator<std::input_iterator_tag, std::pair<object, object>> base_t;
public:
@ -41,19 +42,18 @@ public:
typedef const value_type& const_reference;
private:
typedef ::sol::reference ref_t;
std::pair<object, object> kvp;
ref_t ref;
reference_type ref;
int tableidx = 0;
std::ptrdiff_t idx = 0;
public:
table_iterator () : idx(-1) {
basic_table_iterator () : idx(-1) {
}
table_iterator(ref_t x) : ref(std::move(x)) {
basic_table_iterator(reference_type x) : ref(std::move(x)) {
ref.push();
tableidx = lua_gettop(ref.lua_state());
stack::push(ref.lua_state(), nil);
@ -64,7 +64,7 @@ public:
--idx;
}
table_iterator& operator++() {
basic_table_iterator& operator++() {
if (idx == -1)
return *this;
@ -80,7 +80,7 @@ public:
return *this;
}
table_iterator operator++(int) {
basic_table_iterator operator++(int) {
auto saved = *this;
this->operator++();
return saved;
@ -94,15 +94,15 @@ public:
return kvp;
}
bool operator== (const table_iterator& right) const {
bool operator== (const basic_table_iterator& right) const {
return idx == right.idx;
}
bool operator!= (const table_iterator& right) const {
bool operator!= (const basic_table_iterator& right) const {
return idx != right.idx;
}
~table_iterator() {
~basic_table_iterator() {
if (ref.valid()) {
stack::remove(ref.lua_state(), tableidx, 1);
}

View File

@ -70,10 +70,10 @@ struct remove_member_pointer<R T::* const> {
template<typename T>
using remove_member_pointer_t = remove_member_pointer<T>;
template<typename T, template<typename...> class Templ>
template<template<typename...> class Templ, typename T>
struct is_specialization_of : std::false_type { };
template<typename... T, template<typename...> class Templ>
struct is_specialization_of<Templ<T...>, Templ> : std::true_type { };
struct is_specialization_of<Templ, Templ<T...>> : std::true_type { };
template<class T, class...>
struct are_same : std::true_type { };
@ -380,12 +380,12 @@ using is_c_str = Or<
>;
namespace meta_detail {
template <typename T, meta::DisableIf<meta::is_specialization_of<meta::Unqualified<T>, std::tuple>> = 0>
template <typename T, meta::DisableIf<meta::is_specialization_of<std::tuple, meta::Unqualified<T>>> = 0>
decltype(auto) force_tuple(T&& x) {
return std::forward_as_tuple(std::forward<T>(x));
}
template <typename T, meta::EnableIf<meta::is_specialization_of<meta::Unqualified<T>, std::tuple>> = 0>
template <typename T, meta::EnableIf<meta::is_specialization_of<std::tuple, meta::Unqualified<T>>> = 0>
decltype(auto) force_tuple(T&& x) {
return std::forward<T>(x);
}

View File

@ -105,6 +105,12 @@ struct up_value_index {
operator int() const { return index; }
};
struct absolute_index {
int index;
absolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) {}
operator int() const { return index; }
};
struct light_userdata_value {
void* value;
light_userdata_value(void* data) : value(data) {}
@ -203,17 +209,38 @@ class reference;
class stack_reference;
template<typename T>
class usertype;
template <bool>
class table_core;
template <bool, typename T>
class basic_table_core;
template <bool b>
using table_core = basic_table_core<b, reference>;
template <bool b>
using stack_table_core = basic_table_core<b, stack_reference>;
typedef table_core<false> table;
typedef table_core<true> global_table;
class function;
class protected_function;
typedef stack_table_core<false> stack_table;
typedef stack_table_core<true> stack_global_table;
template <typename T>
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>;
template <typename base_t>
class basic_object;
template <typename base_t>
class basic_userdata;
template <typename base_t>
class basic_lightuserdata;
using object = basic_object<reference>;
using stack_object = basic_object<stack_reference>;
using userdata = basic_userdata<reference>;
using stack_userdata = basic_userdata<stack_reference>;
using lightuserdata = basic_lightuserdata<reference>;
using stack_lightuserdata = basic_lightuserdata<stack_reference>;
class coroutine;
class thread;
class object;
class userdata;
class lightuserdata;
template <typename T, typename = void>
struct lua_type_of : std::integral_constant<type, type::userdata> {};
@ -242,14 +269,20 @@ struct lua_type_of<table> : std::integral_constant<type, type::table> { };
template <>
struct lua_type_of<global_table> : std::integral_constant<type, type::table> { };
template <>
struct lua_type_of<stack_table> : std::integral_constant<type, type::table> { };
template <>
struct lua_type_of<stack_global_table> : std::integral_constant<type, type::table> { };
template <>
struct lua_type_of<reference> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<stack_reference> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<object> : std::integral_constant<type, type::poly> {};
template <typename Base>
struct lua_type_of<basic_object<Base>> : std::integral_constant<type, type::poly> {};
template <typename... Args>
struct lua_type_of<std::tuple<Args...>> : std::integral_constant<type, type::poly> {};
@ -263,17 +296,20 @@ struct lua_type_of<light_userdata_value> : std::integral_constant<type, type::li
template <>
struct lua_type_of<userdata_value> : std::integral_constant<type, type::userdata> {};
template <>
struct lua_type_of<lightuserdata> : std::integral_constant<type, type::lightuserdata> {};
template <typename Base>
struct lua_type_of<basic_lightuserdata<Base>> : std::integral_constant<type, type::lightuserdata> {};
template <>
struct lua_type_of<userdata> : std::integral_constant<type, type::userdata> {};
template <typename Base>
struct lua_type_of<basic_userdata<Base>> : std::integral_constant<type, type::userdata> {};
template <>
struct lua_type_of<lua_CFunction> : std::integral_constant<type, type::function> {};
template <>
struct lua_type_of<function> : std::integral_constant<type, type::function> {};
template <typename Base>
struct lua_type_of<basic_function<Base>> : std::integral_constant<type, type::function> {};
template <typename Base>
struct lua_type_of<basic_protected_function<Base>> : std::integral_constant<type, type::function> {};
template <>
struct lua_type_of<coroutine> : std::integral_constant<type, type::function> {};
@ -281,9 +317,6 @@ struct lua_type_of<coroutine> : std::integral_constant<type, type::function> {};
template <>
struct lua_type_of<thread> : std::integral_constant<type, type::thread> {};
template <>
struct lua_type_of<protected_function> : std::integral_constant<type, type::function> {};
template <typename Signature>
struct lua_type_of<std::function<Signature>> : std::integral_constant<type, type::function>{};
@ -303,10 +336,15 @@ template <typename T>
struct is_lua_primitive : std::integral_constant<bool,
type::userdata != lua_type_of<meta::Unqualified<T>>::value
|| std::is_base_of<reference, meta::Unqualified<T>>::value
|| meta::is_specialization_of<meta::Unqualified<T>, std::tuple>::value
|| meta::is_specialization_of<meta::Unqualified<T>, std::pair>::value
|| std::is_base_of<stack_reference, meta::Unqualified<T>>::value
|| meta::is_specialization_of<std::tuple, meta::Unqualified<T>>::value
|| meta::is_specialization_of<std::pair, meta::Unqualified<T>>::value
> { };
template <typename T>
struct is_lua_primitive<std::reference_wrapper<T>> : std::true_type { };
template <typename T>
struct is_lua_primitive<optional<T>> : std::true_type {};
template <typename T>
struct is_lua_primitive<T*> : std::true_type {};
template <>
@ -319,12 +357,6 @@ struct is_lua_primitive<non_null<T>> : is_lua_primitive<T*> {};
template <typename T>
struct is_proxy_primitive : is_lua_primitive<T> { };
template <typename T>
struct is_proxy_primitive<std::reference_wrapper<T>> : std::true_type { };
template <typename T>
struct is_proxy_primitive<optional<T>> : std::true_type {};
template <typename T>
struct is_unique_usertype : std::false_type {};

View File

@ -25,28 +25,34 @@
#include "reference.hpp"
namespace sol {
class userdata : public reference {
template <typename base_t>
class basic_userdata : public base_t {
public:
userdata () noexcept = default;
userdata(const userdata&) = default;
userdata(userdata&&) = default;
userdata& operator=(const userdata&) = default;
userdata& operator=(userdata&&) = default;
userdata(lua_State* L, int index = -1) : reference(L, index) {
basic_userdata () noexcept = default;
basic_userdata(const basic_userdata&) = default;
basic_userdata(basic_userdata&&) = default;
basic_userdata& operator=(const basic_userdata&) = default;
basic_userdata& operator=(basic_userdata&&) = default;
basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
basic_userdata(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS
type_assert(L, index, type::userdata);
#endif // Safety
}
};
class lightuserdata : public reference {
template <typename base_t>
class basic_lightuserdata : public base_t {
public:
lightuserdata () noexcept = default;
lightuserdata(const lightuserdata&) = default;
lightuserdata(lightuserdata&&) = default;
lightuserdata& operator=(const lightuserdata&) = default;
lightuserdata& operator=(lightuserdata&&) = default;
lightuserdata(lua_State* L, int index = -1) : reference(L, index) {
basic_lightuserdata () noexcept = default;
basic_lightuserdata(const basic_lightuserdata&) = default;
basic_lightuserdata(basic_lightuserdata&&) = default;
basic_lightuserdata& operator=(const basic_lightuserdata&) = default;
basic_lightuserdata& operator=(basic_lightuserdata&&) = default;
basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS
type_assert(L, index, type::lightuserdata);
#endif // Safety

View File

@ -801,3 +801,60 @@ TEST_CASE("usertype/overloading", "Check if overloading works properly for usert
REQUIRE_THROWS(lua.script("r:func(1,2,'meow')"));
}
TEST_CASE("usertype/reference-and-constness", "Make sure constness compiles properly and errors out at runtime") {
struct bark {
int var = 50;
};
struct woof {
bark b;
};
struct nested {
const int f = 25;
};
struct outer {
nested n;
};
bool caughterror = false;
std::string msg;
sol::state lua;
lua.new_usertype<woof>("woof",
"b", &woof::b);
lua.new_usertype<bark>("bark",
"var", &bark::var);
lua.new_usertype<outer>("outer",
"n", &outer::n);
lua.set("w", woof());
lua.set("n", nested());
lua.set("o", outer());
lua.set("f", sol::c_call<decltype(&nested::f), &nested::f>);
try {
lua.script(R"(
x = w.b
x.var = 20
val = w.b.var == x.var
v = f(n);
f(n, 50)
)");
}
catch (const sol::error& e) {
msg = e.what();
caughterror = true;
}
REQUIRE(caughterror);
REQUIRE(!msg.empty());
woof& w = lua["w"];
bark& x = lua["x"];
nested& n = lua["n"];
int v = lua["v"];
bool val = lua["val"];
// enforce reference semantics
REQUIRE(std::addressof(w.b) == std::addressof(x));
REQUIRE(n.f == 25);
REQUIRE(v == 25);
REQUIRE(val);
REQUIRE_THROWS(lua.script("o.n = 25"));
}