mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
This mega-commit introduces Visual Studio 2015 CTP 6 support.
sol::object had a few reference leaks in the way it retrieved values: it now does it properly without leaving the stack at +1 item sol::stack was drastically cleaned up, with the following key change: * sol::stack::push now returns an integer of the number of things its pushed (usually 1, but can be more) (Thanks, @PrincessNyanara!) * sol::stack::call now calls functions flexibly, and getting is done more reliably * due to the innovation of stack::call and using absolute indices, we no longer have to use reverse_call style programming to deal with lua * sol::reference::get_type is now const-correct * sol::state and sol::table now have a cleaned up `get` implementation since it is no longer held back by the ugliness of VC++'s incapability to handle templates * the name `sol::userdata` now belongs to a type that actually encapsualtes a void* with a pusher/getter than gets a userdata void* value (TODO: give it a template to make it static_cast to that type on get?) * lightuserdata_t -> light_userdata, upvalue_t -> upvalue as type names (mostly details) * pushers for various types were updated to return integers
This commit is contained in:
parent
fa8416168e
commit
bd4492b85b
1
.gitignore
vendored
1
.gitignore
vendored
@ -33,3 +33,4 @@ main.ninja
|
||||
luajit-2.0.3/
|
||||
.dropbox*
|
||||
desktop.ini
|
||||
lua-5.3.0/
|
||||
|
@ -33,6 +33,23 @@ struct default_construct {
|
||||
alloc.construct(obj, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct placement_construct {
|
||||
T obj;
|
||||
|
||||
template <typename... Args>
|
||||
placement_construct( Args&&... args ) : obj(std::forward<Args>(args)...) {
|
||||
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void operator()(Args&&... args) const {
|
||||
std::allocator<Unqualified<T>> alloc{};
|
||||
alloc.construct(obj, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
} // sol
|
||||
|
||||
#endif // SOL_DEFAULT_CONSTRUCTOR_HPP
|
||||
|
@ -39,24 +39,31 @@ private:
|
||||
lua_call(state(), static_cast<uint32_t>(argcount), static_cast<uint32_t>(resultcount));
|
||||
}
|
||||
|
||||
template<typename... Ret>
|
||||
std::tuple<Ret...> invoke(types<Ret...>, std::size_t n) const {
|
||||
template<std::size_t... I, typename... Ret>
|
||||
std::tuple<Ret...> invoke(indices<I...>, types<Ret...>, std::size_t n) const {
|
||||
luacall(n, sizeof...(Ret));
|
||||
return stack::pop_reverse_call(state(), std::make_tuple<Ret...>, types<Ret...>());
|
||||
const int nreturns = static_cast<int>(sizeof...(Ret));
|
||||
const int stacksize = lua_gettop(state());
|
||||
const int firstreturn = std::max(0, stacksize - nreturns) + 1;
|
||||
auto r = std::make_tuple(stack::get<Ret>(state(), firstreturn + I)...);
|
||||
lua_pop(state(), nreturns);
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename Ret>
|
||||
Ret invoke(types<Ret>, std::size_t n) const {
|
||||
template<std::size_t I, typename Ret>
|
||||
Ret invoke(indices<I>, types<Ret>, std::size_t n) const {
|
||||
luacall(n, 1);
|
||||
return stack::pop<Ret>(state());
|
||||
}
|
||||
|
||||
void invoke(types<void>, std::size_t n) const {
|
||||
template <std::size_t I>
|
||||
void invoke(indices<I>, types<void>, std::size_t n) const {
|
||||
luacall(n, 0);
|
||||
}
|
||||
|
||||
void invoke(types<>, std::size_t n) const {
|
||||
luacall(n, 0);
|
||||
void invoke(indices<>, types<>, std::size_t n) const {
|
||||
auto tr = types<void>();
|
||||
invoke(tr, tr, n);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -80,8 +87,9 @@ public:
|
||||
template<typename... Ret, typename... Args>
|
||||
typename return_type<Ret...>::type call(Args&&... args) const {
|
||||
push();
|
||||
stack::push_args(state(), std::forward<Args>(args)...);
|
||||
return invoke(types<Ret...>(), sizeof...(Args));
|
||||
int pushcount = stack::push_args(state(), std::forward<Args>(args)...);
|
||||
auto tr = types<Ret...>();
|
||||
return invoke(tr, tr, pushcount);
|
||||
}
|
||||
};
|
||||
|
||||
@ -175,8 +183,8 @@ struct pusher<function_sig_t<Sigs...>> {
|
||||
lua_CFunction freefunc = &static_member_function<Decay<decltype(*userptr)>, Fx>::call;
|
||||
|
||||
int upvalues = stack::detail::push_as_upvalues(L, memfxptr);
|
||||
stack::push(L, userobjdata);
|
||||
++upvalues;
|
||||
upvalues += stack::push(L, userobjdata);
|
||||
|
||||
stack::push(L, freefunc, upvalues);
|
||||
}
|
||||
|
||||
@ -209,15 +217,17 @@ struct pusher<function_sig_t<Sigs...>> {
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static void push(lua_State* L, Args&&... args) {
|
||||
static int push(lua_State* L, Args&&... args) {
|
||||
// Set will always place one thing (function) on the stack
|
||||
set(L, std::forward<Args>(args)...);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
struct pusher<std::function<Signature>> {
|
||||
static void push(lua_State* L, std::function<Signature> fx) {
|
||||
pusher<function_t>{}.push(L, std::move(fx));
|
||||
static int push(lua_State* L, std::function<Signature> fx) {
|
||||
return pusher<function_t>{}.push(L, std::move(fx));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -46,6 +46,10 @@ struct functor {
|
||||
template<typename... FxArgs>
|
||||
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
bool check () const {
|
||||
return invocation != nullptr;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void call(types<void>, Args&&... args) {
|
||||
T& member = *item;
|
||||
@ -59,7 +63,7 @@ struct functor {
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args) -> decltype(this->call(types<return_type>{}, std::forward<Args>(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)...);
|
||||
}
|
||||
};
|
||||
@ -75,16 +79,25 @@ struct functor<T, Func, typename std::enable_if<std::is_member_object_pointer<Fu
|
||||
template<typename... FxArgs>
|
||||
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
bool check () const {
|
||||
return this->fx.invocation != nullptr;
|
||||
}
|
||||
|
||||
template<typename Arg>
|
||||
void operator()(Arg&& arg) {
|
||||
void call(types<return_type>, Arg&& arg) {
|
||||
T& member = *item;
|
||||
(member.*invocation) = std::forward<Arg>(arg);
|
||||
}
|
||||
|
||||
return_type operator()() {
|
||||
return_type call(types<return_type>) {
|
||||
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)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Func>
|
||||
@ -96,9 +109,24 @@ struct functor<T, Func, typename std::enable_if<std::is_function<Func>::value ||
|
||||
T* item;
|
||||
function_type invocation;
|
||||
|
||||
private:
|
||||
bool check(std::false_type) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check(std::true_type) const {
|
||||
return this->invocation != nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<typename... FxArgs>
|
||||
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
bool check () const {
|
||||
return this->check(std::is_function<Func>());
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void call(types<void>, Args&&... args) {
|
||||
T& member = *item;
|
||||
@ -112,7 +140,7 @@ struct functor<T, Func, typename std::enable_if<std::is_function<Func>::value ||
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args) -> decltype(this->call(types<return_type>{}, std::forward<Args>(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)...);
|
||||
}
|
||||
};
|
||||
@ -125,8 +153,8 @@ struct static_function {
|
||||
typedef function_traits<function_type> traits_type;
|
||||
|
||||
template<typename... Args>
|
||||
static int typed_call(types<void>, types<Args...> t, function_type* fx, lua_State* L) {
|
||||
stack::get_call(L, fx, t);
|
||||
static int typed_call(types<void> tr, types<Args...> ta, function_type* fx, lua_State* L) {
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
std::ptrdiff_t nargs = sizeof...(Args);
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
@ -138,13 +166,12 @@ struct static_function {
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
static int typed_call(types<Ret...>, types<Args...> t, function_type* fx, lua_State* L) {
|
||||
static int typed_call(types<Ret...>, types<Args...> ta, function_type* fx, lua_State* L) {
|
||||
typedef typename return_type<Ret...>::type return_type;
|
||||
return_type r = stack::get_call(L, fx, t);
|
||||
std::ptrdiff_t nargs = sizeof...(Args);
|
||||
return_type r = stack::call(L, 0, types<return_type>(), ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
stack::push(L, detail::return_forward<return_type>{}(r));
|
||||
return sizeof...(Ret);
|
||||
return stack::push(L, detail::return_forward<return_type>{}(r));
|
||||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
@ -165,10 +192,10 @@ struct static_member_function {
|
||||
typedef function_traits<function_type> traits_type;
|
||||
|
||||
template<typename... Args>
|
||||
static int typed_call(types<void>, types<Args...>, T& item, function_type& ifx, lua_State* L) {
|
||||
static int typed_call(types<void> tr, types<Args...> ta, T& item, function_type& ifx, lua_State* L) {
|
||||
auto fx = [&item, &ifx](Args&&... args) -> void { (item.*ifx)(std::forward<Args>(args)...); };
|
||||
stack::get_call(L, fx, types<Args...>());
|
||||
std::ptrdiff_t nargs = sizeof...(Args);
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
@ -179,14 +206,13 @@ struct static_member_function {
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
static int typed_call(types<Ret...>, types<Args...>, T& item, function_type& ifx, lua_State* L) {
|
||||
static int typed_call(types<Ret...> tr, types<Args...> ta, T& item, function_type& ifx, lua_State* L) {
|
||||
typedef typename return_type<Ret...>::type return_type;
|
||||
auto fx = [&item, &ifx](Args&&... args) -> return_type { return (item.*ifx)(std::forward<Args>(args)...); };
|
||||
return_type r = stack::get_call(L, fx, types<Args...>());
|
||||
std::ptrdiff_t nargs = sizeof...(Args);
|
||||
return_type r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
stack::push(L, detail::return_forward<return_type>{}(r));
|
||||
return sizeof...(Ret);
|
||||
return stack::push(L, detail::return_forward<return_type>{}(r));
|
||||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
@ -238,12 +264,12 @@ struct base_function {
|
||||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
void** pinheritancedata = static_cast<void**>(stack::get<upvalue_t>(L, 1).value);
|
||||
void** pinheritancedata = static_cast<void**>(stack::get<upvalue>(L, 1).value);
|
||||
return base_call(L, *pinheritancedata);
|
||||
}
|
||||
|
||||
static int gc(lua_State* L) {
|
||||
void** pudata = static_cast<void**>(stack::get<userdata_t>(L, 1).value);
|
||||
void** pudata = static_cast<void**>(stack::get<userdata>(L, 1).value);
|
||||
return base_gc(L, *pudata);
|
||||
}
|
||||
|
||||
@ -251,11 +277,11 @@ struct base_function {
|
||||
struct usertype {
|
||||
static int call(lua_State* L) {
|
||||
// Zero-based template parameter, but upvalues start at 1
|
||||
return base_call(L, stack::get<upvalue_t>(L, I + 1));
|
||||
return base_call(L, stack::get<upvalue>(L, I + 1));
|
||||
}
|
||||
|
||||
static int ref_call(lua_State* L) {
|
||||
return ref_base_call(L, stack::get<upvalue_t>(L, I + 1));
|
||||
return ref_base_call(L, stack::get<upvalue>(L, I + 1));
|
||||
}
|
||||
|
||||
template <std::size_t limit>
|
||||
@ -267,7 +293,7 @@ struct base_function {
|
||||
static void func_gc (std::false_type, lua_State* L) {
|
||||
// Shut up clang tautological error without throwing out std::size_t
|
||||
for(std::size_t i = 0; i < limit; ++i) {
|
||||
upvalue_t up = stack::get<upvalue_t>(L, i + 1);
|
||||
upvalue up = stack::get<upvalue>(L, i + 1);
|
||||
base_function* obj = static_cast<base_function*>(up.value);
|
||||
std::allocator<base_function> alloc{};
|
||||
alloc.destroy(obj);
|
||||
@ -303,9 +329,9 @@ struct functor_function : public base_function {
|
||||
functor_function(FxArgs&&... fxargs): fx(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
||||
stack::get_call(L, fx, t);
|
||||
std::ptrdiff_t nargs = sizeof...(Args);
|
||||
int operator()(types<void> r, types<Args...> t, lua_State* L) {
|
||||
stack::call(L, 0, r, t, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
@ -316,12 +342,11 @@ struct functor_function : public base_function {
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
|
||||
return_type r = stack::get_call(L, fx, t);
|
||||
std::ptrdiff_t nargs = sizeof...(Args);
|
||||
int operator()(types<Ret...> tr, types<Args...> ta, lua_State* L) {
|
||||
return_type r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
stack::push(L, r);
|
||||
return sizeof...(Ret);
|
||||
return stack::push(L, r);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
@ -355,8 +380,8 @@ struct member_function : public base_function {
|
||||
member_function(Tm&& m, FxArgs&&... fxargs): fx(std::forward<Tm>(m), std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
||||
stack::get_call(L, fx, t);
|
||||
int operator()(types<void> tr, types<Args...> ta, lua_State* L) {
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -366,12 +391,11 @@ struct member_function : public base_function {
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
|
||||
return_type r = stack::get_call(L, fx, t);
|
||||
std::ptrdiff_t nargs = sizeof...(Args);
|
||||
int operator()(types<Ret...> tr, types<Args...> ta, lua_State* L) {
|
||||
return_type r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
stack::push(L, std::move(r));
|
||||
return sizeof...(Ret);
|
||||
return stack::push(L, detail::return_forward<return_type>{}(r));
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
@ -398,7 +422,7 @@ struct usertype_function_core : public base_function {
|
||||
usertype_function_core(FxArgs&&... fxargs): fx(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
template<typename Return, typename Raw = Unqualified<Return>>
|
||||
typename std::enable_if<std::is_same<T, Raw>::value, void>::type push(lua_State* L, Return&& r) {
|
||||
typename std::enable_if<std::is_same<T, Raw>::value, int>::type push(lua_State* L, Return&& r) {
|
||||
if(detail::get_ptr(r) == fx.item) {
|
||||
// push nothing
|
||||
// note that pushing nothing with the ':'
|
||||
@ -408,37 +432,42 @@ struct usertype_function_core : public base_function {
|
||||
// and naturally lua returns that.
|
||||
// It's an "easy" way to return *this,
|
||||
// without allocating an extra userdata, apparently!
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
stack::push(L, std::forward<Return>(r));
|
||||
return stack::push(L, std::forward<Return>(r));
|
||||
}
|
||||
|
||||
template<typename Return, typename Raw = Unqualified<Return>>
|
||||
typename std::enable_if<!std::is_same<T, Raw>::value, void>::type push(lua_State* L, Return&& r) {
|
||||
stack::push(L, std::forward<Return>(r));
|
||||
typename std::enable_if<!std::is_same<T, Raw>::value, int>::type push(lua_State* L, Return&& r) {
|
||||
return stack::push(L, std::forward<Return>(r));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
||||
static const std::size_t skew = static_cast<std::size_t>(std::is_member_object_pointer<function_type>::value);
|
||||
stack::get_call(L, 2 + skew, fx, t);
|
||||
std::ptrdiff_t nargs = sizeof...(Args);
|
||||
int call(types<void> r, types<Args...> t, lua_State* L) {
|
||||
//static const std::size_t skew = static_cast<std::size_t>(std::is_member_object_pointer<function_type>::value);
|
||||
stack::call(L, 0, r, t, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
|
||||
return_type r = stack::get_call(L, 2, fx, t);
|
||||
std::ptrdiff_t nargs = sizeof...(Args);
|
||||
lua_pop(L, nargs);
|
||||
push(L, detail::return_forward<return_type>{}(r));
|
||||
return sizeof...(Ret);
|
||||
template<typename... Args>
|
||||
int call(types<>, types<Args...> t, lua_State* L) {
|
||||
return this->call(types<void>(), t, L);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
int operator()(types<>, types<Args...> t, lua_State* L) {
|
||||
return (*this)(types<void>(), t, L);
|
||||
template<typename... Ret, typename... Args>
|
||||
int call(types<Ret...> tr, types<Args...> ta, lua_State* L) {
|
||||
return_type r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
int pushcount = push(L, detail::return_forward<return_type>{}(r));
|
||||
return pushcount;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...> r, types<Args...> t, lua_State* L) {
|
||||
return this->call(r, t, L);
|
||||
}
|
||||
};
|
||||
|
||||
@ -530,7 +559,7 @@ struct usertype_indexing_function : public usertype_function_core<Function, Tp>
|
||||
auto function = functions.find(accessor);
|
||||
if(function != functions.end()) {
|
||||
if(function->second.second) {
|
||||
stack::push<upvalue_t>(L, function->second.first.get());
|
||||
stack::push<upvalue>(L, function->second.first.get());
|
||||
if(std::is_same<T*, Tx>::value) {
|
||||
stack::push(L, &base_function::usertype<0>::ref_call, 1);
|
||||
}
|
||||
@ -546,7 +575,7 @@ struct usertype_indexing_function : public usertype_function_core<Function, Tp>
|
||||
return (*function->second.first)(L);
|
||||
}
|
||||
}
|
||||
if(this->fx.invocation == nullptr) {
|
||||
if (!this->fx.check()) {
|
||||
throw error("invalid indexing \"" + accessor + "\" on type: " + name);
|
||||
}
|
||||
this->fx.item = detail::get_ptr(stack::get<Tx>(L, 1));
|
||||
|
@ -34,16 +34,16 @@ public:
|
||||
template<typename T>
|
||||
auto as() const -> decltype(stack::get<T>(state())) {
|
||||
push();
|
||||
type_assert(state(), -1, type_of<T>());
|
||||
return stack::get<T>(state());
|
||||
type actual = stack::get<type>(state());
|
||||
type_assert(state(), -1, type_of<T>(), actual);
|
||||
return stack::pop<T>(state());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool is() const {
|
||||
push();
|
||||
auto expected = type_of<T>();
|
||||
auto actual = lua_type(state(), -1);
|
||||
return (static_cast<int>(expected) == actual) || (expected == type::poly);
|
||||
auto actual = get_type();
|
||||
return (expected == actual) || (expected == type::poly);
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
|
@ -79,7 +79,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
type get_type() {
|
||||
type get_type() const {
|
||||
push();
|
||||
int result = lua_type(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
346
sol/stack.hpp
346
sol/stack.hpp
@ -75,18 +75,99 @@ struct return_forward {
|
||||
namespace stack {
|
||||
namespace detail {
|
||||
template<typename T, typename Key, typename... Args>
|
||||
inline void push_userdata(lua_State* L, Key&& metatablekey, Args&&... args) {
|
||||
inline int push_userdata(lua_State* L, Key&& metatablekey, Args&&... args) {
|
||||
T* pdatum = static_cast<T*>(lua_newuserdata(L, sizeof(T)));
|
||||
std::allocator<T> alloc{};
|
||||
alloc.construct(pdatum, std::forward<Args>(args)...);
|
||||
luaL_getmetatable(L, std::addressof(metatablekey[0]));
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
} // detail
|
||||
template<typename T, typename X = void>
|
||||
|
||||
template<typename T, typename = void>
|
||||
struct getter;
|
||||
template<typename T, typename X = void>
|
||||
template<typename T, typename = void>
|
||||
struct pusher;
|
||||
template<typename T, type = lua_type_of<T>::value, typename = void>
|
||||
struct checker;
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline int push(lua_State* L, T&& t, Args&&... args) {
|
||||
return pusher<Unqualified<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T, std::size_t... I>
|
||||
inline int push_tuple(lua_State* L, indices<I...>, T&& tuplen) {
|
||||
using swallow = char[1 + sizeof...(I)];
|
||||
int pushcount = 0;
|
||||
swallow {'\0', (pushcount += sol::stack::push(L, std::get<I>(tuplen)), '\0')... };
|
||||
return pushcount;
|
||||
}
|
||||
|
||||
// overload allows to use a pusher of a specific type, but pass in any kind of args
|
||||
template<typename T, typename Arg, typename... Args>
|
||||
inline int push(lua_State* L, Arg&& arg, Args&&... args) {
|
||||
return pusher<Unqualified<T>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline int push_args(lua_State*) {
|
||||
// do nothing
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline int push_args(lua_State* L, T&& t, Args&&... args) {
|
||||
int pushcount = push(L, std::forward<T>(t));
|
||||
using swallow = char[];
|
||||
void(swallow{'\0', (pushcount += push(L, std::forward<Args>(args)), '\0')... });
|
||||
return pushcount;
|
||||
}
|
||||
|
||||
template<typename T, typename U = Unqualified<T>>
|
||||
inline auto get(lua_State* L, int index = -1) -> decltype(getter<U>{}.get(L, index)) {
|
||||
return getter<U>{}.get(L, index);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto pop(lua_State* L) -> decltype(get<T>(L)) {
|
||||
typedef decltype(get<T>(L)) ret_t;
|
||||
ret_t r = get<T>(L);
|
||||
lua_pop(L, 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct get_return {
|
||||
typedef decltype(get<T>(nullptr)) type;
|
||||
};
|
||||
|
||||
template <typename T, type expected, typename>
|
||||
struct checker {
|
||||
template <typename Handler>
|
||||
static bool check (lua_State* L, int index, const Handler& handler) {
|
||||
const type indextype = type_of(L, index);
|
||||
bool success = expected == indextype;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, expected, indextype);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Handler>
|
||||
bool check(lua_State* L, int index, Handler&& handler) {
|
||||
typedef Unqualified<T> Tu;
|
||||
checker<Tu> c;
|
||||
return c.check(L, index, std::forward<Handler>(handler));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool check(lua_State* L, int index) {
|
||||
auto handler = type_panic;
|
||||
return check<T>(L, index, handler);
|
||||
}
|
||||
|
||||
template<typename T, typename>
|
||||
struct getter {
|
||||
@ -97,12 +178,13 @@ struct getter {
|
||||
|
||||
template<typename U = T, EnableIf<std::is_integral<U>, std::is_signed<U>> = 0>
|
||||
static U get(lua_State* L, int index = -1) {
|
||||
return static_cast<U>(lua_tounsigned(L, index));
|
||||
return static_cast<T>(lua_tointeger(L, index));
|
||||
}
|
||||
|
||||
template<typename U = T, EnableIf<std::is_integral<U>, std::is_unsigned<U>> = 0>
|
||||
static U get(lua_State* L, int index = -1) {
|
||||
return static_cast<T>(lua_tointeger(L, index));
|
||||
typedef typename std::make_signed<U>::type signed_int;
|
||||
return static_cast<U>(stack::get<signed_int>(L, index));
|
||||
}
|
||||
|
||||
template<typename U = T, EnableIf<std::is_base_of<reference, U>> = 0>
|
||||
@ -184,22 +266,22 @@ struct getter<nil_t> {
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<userdata_t> {
|
||||
static userdata_t get(lua_State* L, int index = -1) {
|
||||
struct getter<userdata> {
|
||||
static userdata get(lua_State* L, int index = -1) {
|
||||
return{ lua_touserdata(L, index) };
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<lightuserdata_t> {
|
||||
static lightuserdata_t get(lua_State* L, int index = 1) {
|
||||
struct getter<light_userdata> {
|
||||
static light_userdata get(lua_State* L, int index = 1) {
|
||||
return{ lua_touserdata(L, index) };
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<upvalue_t> {
|
||||
static upvalue_t get(lua_State* L, int index = 1) {
|
||||
struct getter<upvalue> {
|
||||
static upvalue get(lua_State* L, int index = 1) {
|
||||
return{ lua_touserdata(L, lua_upvalueindex(index)) };
|
||||
}
|
||||
};
|
||||
@ -214,22 +296,25 @@ struct getter<void*> {
|
||||
template<typename T, typename>
|
||||
struct pusher {
|
||||
template<typename U = T, EnableIf<std::is_floating_point<U>> = 0>
|
||||
static void push(lua_State* L, const T& value) {
|
||||
static int push(lua_State* L, const T& value) {
|
||||
lua_pushnumber(L, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename U = T, EnableIf<std::is_integral<U>, std::is_signed<U>> = 0>
|
||||
static void push(lua_State* L, const T& value) {
|
||||
static int push(lua_State* L, const T& value) {
|
||||
lua_pushinteger(L, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename U = T, EnableIf<std::is_integral<U>, std::is_unsigned<U>> = 0>
|
||||
static void push(lua_State* L, const T& value) {
|
||||
lua_pushunsigned(L, value);
|
||||
static int push(lua_State* L, const T& value) {
|
||||
typedef typename std::make_signed<T>::type signed_int;
|
||||
return stack::push(L, static_cast<signed_int>(value));
|
||||
}
|
||||
|
||||
template<typename U = T, EnableIf<has_begin_end<U>, Not<has_key_value_pair<U>>> = 0>
|
||||
static void push(lua_State* L, const T& cont) {
|
||||
static int push(lua_State* L, const T& cont) {
|
||||
lua_createtable(L, cont.size(), 0);
|
||||
unsigned index = 1;
|
||||
for(auto&& i : cont) {
|
||||
@ -240,154 +325,139 @@ struct pusher {
|
||||
// set the table
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename U = T, EnableIf<has_begin_end<U>, has_key_value_pair<U>> = 0>
|
||||
static void push(lua_State* L, const T& cont) {
|
||||
static int push(lua_State* L, const T& cont) {
|
||||
lua_createtable(L, cont.size(), 0);
|
||||
for(auto&& pair : cont) {
|
||||
pusher<Unqualified<decltype(pair.first)>>{}.push(L, pair.first);
|
||||
pusher<Unqualified<decltype(pair.second)>>{}.push(L, pair.second);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename U = T, EnableIf<std::is_base_of<reference, U>> = 0>
|
||||
static void push(lua_State*, T& ref) {
|
||||
ref.push();
|
||||
static int push(lua_State*, T& ref) {
|
||||
return ref.push();
|
||||
}
|
||||
|
||||
template<typename U = Unqualified<T>, EnableIf<Not<has_begin_end<U>>, Not<std::is_base_of<reference, U>>, Not<std::is_integral<U>>, Not<std::is_floating_point<U>>> = 0>
|
||||
static void push(lua_State* L, T& t) {
|
||||
detail::push_userdata<U>(L, usertype_traits<T>::metatable, t);
|
||||
static int push(lua_State* L, T& t) {
|
||||
return detail::push_userdata<U>(L, usertype_traits<T>::metatable, t);
|
||||
}
|
||||
|
||||
template<typename U = Unqualified<T>, EnableIf<Not<has_begin_end<U>>, Not<std::is_base_of<reference, U>>, Not<std::is_integral<U>>, Not<std::is_floating_point<U>>> = 0>
|
||||
static void push(lua_State* L, T&& t) {
|
||||
detail::push_userdata<U>(L, usertype_traits<T>::metatable, std::move(t));
|
||||
static int push(lua_State* L, T&& t) {
|
||||
return detail::push_userdata<U>(L, usertype_traits<T>::metatable, std::move(t));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct pusher<T*> {
|
||||
static void push(lua_State* L, T* obj) {
|
||||
detail::push_userdata<T*>(L, usertype_traits<T*>::metatable, obj);
|
||||
static int push(lua_State* L, T* obj) {
|
||||
return detail::push_userdata<T*>(L, usertype_traits<T*>::metatable, obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct pusher<std::reference_wrapper<T>> {
|
||||
static void push(lua_State* L, const std::reference_wrapper<T>& t) {
|
||||
pusher<T*>{}.push(L, std::addressof(t.get()));
|
||||
static int push(lua_State* L, const std::reference_wrapper<T>& t) {
|
||||
return stack::push(L, std::addressof(t.get()));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<bool> {
|
||||
static void push(lua_State* L, const bool& b) {
|
||||
static int push(lua_State* L, const bool& b) {
|
||||
lua_pushboolean(L, b);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<nil_t> {
|
||||
static void push(lua_State* L, const nil_t&) {
|
||||
static int push(lua_State* L, const nil_t&) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<lua_CFunction> {
|
||||
static void push(lua_State* L, lua_CFunction func, int n = 0) {
|
||||
static int push(lua_State* L, lua_CFunction func, int n = 0) {
|
||||
lua_pushcclosure(L, func, n);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<void*> {
|
||||
static void push(lua_State* L, void* userdata) {
|
||||
static int push(lua_State* L, void* userdata) {
|
||||
lua_pushlightuserdata(L, userdata);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<upvalue_t> {
|
||||
static void push(lua_State* L, upvalue_t upvalue) {
|
||||
struct pusher<upvalue> {
|
||||
static int push(lua_State* L, upvalue upvalue) {
|
||||
lua_pushlightuserdata(L, upvalue);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<lightuserdata_t> {
|
||||
static void push(lua_State* L, lightuserdata_t userdata) {
|
||||
struct pusher<light_userdata> {
|
||||
static int push(lua_State* L, light_userdata userdata) {
|
||||
lua_pushlightuserdata(L, userdata);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<userdata_t> {
|
||||
struct pusher<userdata> {
|
||||
template<typename T, typename U = Unqualified<T>>
|
||||
static void push(lua_State* L, T&& data) {
|
||||
static int push(lua_State* L, T&& data) {
|
||||
U* userdata = static_cast<U*>(lua_newuserdata(L, sizeof(U)));
|
||||
new(userdata)U(std::forward<T>(data));
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<const char*> {
|
||||
static void push(lua_State* L, const char* str) {
|
||||
static int push(lua_State* L, const char* str) {
|
||||
lua_pushlstring(L, str, std::char_traits<char>::length(str));
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
struct pusher<char[N]> {
|
||||
static void push(lua_State* L, const char (&str)[N]) {
|
||||
static int push(lua_State* L, const char (&str)[N]) {
|
||||
lua_pushlstring(L, str, N - 1);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<std::string> {
|
||||
static void push(lua_State* L, const std::string& str) {
|
||||
static int push(lua_State* L, const std::string& str) {
|
||||
lua_pushlstring(L, str.c_str(), str.size());
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline void push(lua_State* L, T&& t, Args&&... args) {
|
||||
pusher<Unqualified<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// overload allows to use a pusher of a specific type, but pass in any kind of args
|
||||
template<typename T, typename Arg, typename... Args>
|
||||
inline void push(lua_State* L, Arg&& arg, Args&&... args) {
|
||||
pusher<Unqualified<T>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline void push_args(lua_State*) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline void push_args(lua_State* L, T&& t, Args&&... args) {
|
||||
pusher<Unqualified<T>>{}.push(L, std::forward<T>(t));
|
||||
using swallow = char[];
|
||||
void(swallow{'\0', (pusher<Unqualified<Args>>{}.push(L, std::forward<Args>(args)), '\0')... });
|
||||
}
|
||||
|
||||
template<typename T, typename U = Unqualified<T>>
|
||||
inline auto get(lua_State* L, int index = -1) -> decltype(getter<U>{}.get(L, index)) {
|
||||
return getter<U>{}.get(L, index);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto pop(lua_State* L) -> decltype(get<T>(L)) {
|
||||
typedef decltype(get<T>(L)) ret_t;
|
||||
ret_t r = get<T>(L);
|
||||
lua_pop(L, 1);
|
||||
return r;
|
||||
template<typename... Args>
|
||||
struct pusher<std::tuple<Args...>> {
|
||||
template <typename Tuple>
|
||||
static int push(lua_State* L, Tuple&& tuplen) {
|
||||
return push_tuple(L, build_indices<sizeof...(Args)>(), std::forward<Tuple>(tuplen));
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
@ -401,10 +471,11 @@ inline int push_as_upvalues(lua_State* L, T& item) {
|
||||
|
||||
data_t data{{}};
|
||||
std::memcpy(std::addressof(data[0]), std::addressof(item), itemsize);
|
||||
int pushcount = 0;
|
||||
for(auto&& v : data) {
|
||||
push(L, upvalue_t(v));
|
||||
pushcount += push(L, upvalue(v));
|
||||
}
|
||||
return data_t_count;
|
||||
return pushcount;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@ -413,89 +484,73 @@ inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) {
|
||||
typedef std::array<void*, data_t_count> data_t;
|
||||
data_t voiddata{ {} };
|
||||
for(std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {
|
||||
voiddata[i] = get<upvalue_t>(L, index++);
|
||||
voiddata[i] = get<upvalue>(L, index++);
|
||||
}
|
||||
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
|
||||
}
|
||||
|
||||
template<typename T, std::size_t... I>
|
||||
inline void push_tuple(lua_State* L, indices<I...>, T&& tuplen) {
|
||||
using swallow = char[1 + sizeof...(I)];
|
||||
swallow {'\0', (sol::stack::push(L, std::get<I>(tuplen)), '\0')... };
|
||||
}
|
||||
|
||||
template<typename F, typename... Vs, typename... Args>
|
||||
inline auto ltr_get(lua_State*, int, F&& f, types<Args...>, types<>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)...)) {
|
||||
return f(std::forward<Vs>(vs)...);
|
||||
}
|
||||
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
|
||||
inline auto ltr_get(lua_State* L, int index, F&& f, types<Args...>, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
|
||||
return ltr_get(L, index + 1, std::forward<F>(f), types<Args...>(), types<Tail...>(), std::forward<Vs>(vs)..., stack::get<Head>(L, index));
|
||||
}
|
||||
|
||||
template<typename F, typename... Vs, typename... Args>
|
||||
inline auto ltr_pop(lua_State*, F&& f, types<Args...>, types<>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)...)) {
|
||||
return f(std::forward<Vs>(vs)...);
|
||||
}
|
||||
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
|
||||
inline auto ltr_pop(lua_State* L, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
|
||||
return ltr_pop(L, std::forward<F>(f), t, types<Tail...>(), std::forward<Vs>(vs)..., stack::pop<Head>(L));
|
||||
}
|
||||
|
||||
template<typename F, typename... Vs, typename... Args>
|
||||
inline auto rtl_pop(lua_State*, F&& f, types<Args...>, types<>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)...)) {
|
||||
return f(std::forward<Vs>(vs)...);
|
||||
}
|
||||
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
|
||||
inline auto rtl_pop(lua_State* L, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
|
||||
return rtl_pop(L, std::forward<F>(f), t, types<Tail...>(), stack::pop<Head>(L), std::forward<Vs>(vs)...);
|
||||
}
|
||||
} // detail
|
||||
|
||||
template<typename... Args>
|
||||
struct pusher<std::tuple<Args...>> {
|
||||
static void push(lua_State* L, const std::tuple<Args...>& tuplen) {
|
||||
detail::push_tuple(L, build_indices<sizeof...(Args)>(), tuplen);
|
||||
}
|
||||
|
||||
static void push(lua_State* L, std::tuple<Args...>&& tuplen) {
|
||||
detail::push_tuple(L, build_indices<sizeof...(Args)>(), std::move(tuplen));
|
||||
template <bool b>
|
||||
struct check_arguments {
|
||||
template <std::size_t... I, typename... Args>
|
||||
static bool check(lua_State* L, int firstargument, indices<I...>, types<Args...>) {
|
||||
bool checks = true;
|
||||
using swallow = int[sizeof...(Args)+2];
|
||||
(void)swallow {
|
||||
0, (checks &= stack::check<Args>(L, firstargument + I))..., 0
|
||||
};
|
||||
return checks;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline void push_reverse(lua_State* L, T&& item) {
|
||||
push(L, std::forward<T>(item));
|
||||
template <>
|
||||
struct check_arguments<false> {
|
||||
template <std::size_t... I, typename... Args>
|
||||
static bool check(lua_State*, int, indices<I...>, types<Args...>) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <bool checkargs = false, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = typename std::enable_if<!std::is_void<R>::value>::type>
|
||||
inline R call(lua_State* L, int start, indices<I...>, types<R>, types<Args...> ta, Fx&& fx, FxArgs&&... args) {
|
||||
const int stacksize = lua_gettop(L);
|
||||
const int firstargument = start + stacksize - std::max(sizeof...(Args)-1, static_cast<std::size_t>(0));
|
||||
|
||||
detail::check_arguments<checkargs>{}.check(L, firstargument, ta, ta);
|
||||
|
||||
return fx(std::forward<FxArgs>(args)..., stack::get<Args>(L, firstargument + I)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void push_reverse(lua_State* L, const std::tuple<Args...>& tuplen) {
|
||||
detail::push_tuple(L, build_reverse_indices<sizeof...(Args)>(), tuplen);
|
||||
template <bool checkargs = false, std::size_t... I, typename... Args, typename Fx, typename... FxArgs>
|
||||
inline void call(lua_State* L, int start, indices<I...>, types<void>, types<Args...> ta, Fx&& fx, FxArgs&&... args) {
|
||||
const int stacksize = lua_gettop(L);
|
||||
const int firstargument = start + stacksize - std::max(sizeof...(Args)-1, static_cast<std::size_t>(0));
|
||||
|
||||
bool checks = detail::check_arguments<checkargs>{}.check(L, firstargument, ta, ta);
|
||||
if ( !checks )
|
||||
throw error("Arguments not of the proper types for this function call");
|
||||
|
||||
fx(std::forward<FxArgs>(args)..., stack::get<Args>(L, firstargument + I)...);
|
||||
}
|
||||
} // detail
|
||||
|
||||
template <bool checkargs = false, typename R, typename... Args, typename Fx, typename... FxArgs, typename = typename std::enable_if<!std::is_void<R>::value>::type>
|
||||
inline R call(lua_State* L, int start, types<R> tr, types<Args...> ta, Fx&& fx, FxArgs&&... args) {
|
||||
return detail::call(L, start, ta, tr, ta, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void push_reverse(lua_State* L, std::tuple<Args...>&& tuplen) {
|
||||
detail::push_tuple(L, build_reverse_indices<sizeof...(Args)>(), std::move(tuplen));
|
||||
template <bool checkargs = false, typename R, typename... Args, typename Fx, typename... FxArgs, typename = typename std::enable_if<!std::is_void<R>::value>::type>
|
||||
inline R call(lua_State* L, types<R> tr, types<Args...> ta, Fx&& fx, FxArgs&&... args) {
|
||||
return call(L, 0, ta, tr, ta, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args, typename TFx, typename... Vs>
|
||||
inline auto get_call(lua_State* L, int index, TFx&& fx, types<Args...> t, Vs&&... vs) -> decltype(detail::ltr_get(L, index, std::forward<TFx>(fx), t, t, std::forward<Vs>(vs)...)) {
|
||||
return detail::ltr_get(L, index, std::forward<TFx>(fx), t, t, std::forward<Vs>(vs)...);
|
||||
template <bool checkargs = false, typename... Args, typename Fx, typename... FxArgs>
|
||||
inline void call(lua_State* L, int start, types<void> tr, types<Args...> ta, Fx&& fx, FxArgs&&... args) {
|
||||
detail::call(L, start, ta, tr, ta, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
|
||||
}
|
||||
|
||||
template<typename TFx, typename... Args, typename... Vs>
|
||||
inline auto get_call(lua_State* L, TFx&& fx, types<Args...> t, Vs&&... vs) -> decltype(get_call(L, 1, std::forward<TFx>(fx), t, std::forward<Vs>(vs)...)) {
|
||||
return get_call(L, 1, std::forward<TFx>(fx), t, std::forward<Vs>(vs)...);
|
||||
}
|
||||
|
||||
template<typename... Args, typename TFx>
|
||||
inline auto pop_call(lua_State* L, TFx&& fx, types<Args...> t) -> decltype(detail::ltr_pop(L, std::forward<TFx>(fx), t, t)) {
|
||||
return detail::ltr_pop(L, std::forward<TFx>(fx), t, t);
|
||||
}
|
||||
|
||||
template<typename... Args, typename TFx>
|
||||
inline auto pop_reverse_call(lua_State* L, TFx&& fx, types<Args...> t) -> decltype(detail::rtl_pop(L, std::forward<TFx>(fx), t, reversed<Args...>())) {
|
||||
return detail::rtl_pop(L, std::forward<TFx>(fx), t, reversed<Args...>());
|
||||
template <bool checkargs = false, typename... Args, typename Fx, typename... FxArgs>
|
||||
inline void call(lua_State* L, types<void> tr, types<Args...> ta, Fx&& fx, FxArgs&&... args) {
|
||||
call(L, 0, ta, tr, ta, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
|
||||
}
|
||||
|
||||
inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) {
|
||||
@ -507,11 +562,6 @@ inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) {
|
||||
}
|
||||
return call_syntax::dot;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct get_return {
|
||||
typedef decltype(get<T>(nullptr)) type;
|
||||
};
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
|
@ -138,8 +138,8 @@ public:
|
||||
|
||||
template<typename... Args, typename... Keys>
|
||||
auto get(Keys&&... keys) const
|
||||
-> decltype(global.get(types<Args...>(), std::forward<Keys>(keys)...)) {
|
||||
return global.get(types<Args...>(), std::forward<Keys>(keys)...);
|
||||
-> decltype(global.get<Args...>(std::forward<Keys>(keys)...)) {
|
||||
return global.get<Args...>(std::forward<Keys>(keys)...);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
|
@ -41,27 +41,16 @@ class table : public reference {
|
||||
return result;
|
||||
}
|
||||
|
||||
template<std::size_t I, typename Tup, typename... Ret>
|
||||
typename std::tuple_element<I, std::tuple<typename stack::get_return<Ret>::type...>>::type element_get(types<Ret...>, Tup&& key) const {
|
||||
typedef typename std::tuple_element<I, std::tuple<Ret...>>::type T;
|
||||
return single_get<T>(std::get<I>(key));
|
||||
template<typename Keys, typename... Ret, std::size_t... I>
|
||||
typename return_type<typename stack::get_return<Ret>::type...>::type tuple_get(types<Ret...>, indices<I...>, Keys&& keys) const {
|
||||
return std::make_tuple(single_get<Ret>(std::get<I>(keys))...);
|
||||
}
|
||||
|
||||
template<typename Tup, typename... Ret, std::size_t... I>
|
||||
typename return_type<typename stack::get_return<Ret>::type...>::type tuple_get(types<Ret...> t, indices<I...>, Tup&& tup) const {
|
||||
return std::make_tuple(element_get<I>(t, std::forward<Tup>(tup))...);
|
||||
template<typename Keys, typename Ret>
|
||||
typename stack::get_return<Ret>::type tuple_get(types<Ret>, indices<0>, Keys&& keys) const {
|
||||
return single_get<Ret>(std::get<0>(keys));
|
||||
}
|
||||
|
||||
template<typename Tup, typename Ret>
|
||||
typename stack::get_return<Ret>::type tuple_get(types<Ret> t, indices<0>, Tup&& tup) const {
|
||||
return element_get<0>(t, std::forward<Tup>(tup));
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Keys>
|
||||
typename return_type<typename stack::get_return<Ret>::type...>::type get(types<Ret...> t, Keys&&... keys) const {
|
||||
static_assert(sizeof...(Keys) == sizeof...(Ret), "Must have same number of keys as return values");
|
||||
return tuple_get(t, t, std::make_tuple(std::forward<Keys>(keys)...));
|
||||
}
|
||||
public:
|
||||
table() noexcept : reference() {}
|
||||
table(lua_State* L, int index = -1) : reference(L, index) {
|
||||
@ -70,7 +59,8 @@ public:
|
||||
|
||||
template<typename... Ret, typename... Keys>
|
||||
typename return_type<typename stack::get_return<Ret>::type...>::type get(Keys&&... keys) const {
|
||||
return get(types<Ret...>(), std::forward<Keys>(keys)...);
|
||||
types<Ret...> tr;
|
||||
return tuple_get(tr, tr, std::make_tuple(std::forward<Keys>(keys)...));
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
|
@ -123,6 +123,7 @@ struct return_type<> : types<>{
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T, bool isclass = std::is_class<Unqualified<T>>::value>
|
||||
struct is_function_impl : std::is_function<typename std::remove_pointer<T>::type> {};
|
||||
|
||||
@ -146,10 +147,11 @@ struct is_function_impl<T, true> {
|
||||
|
||||
template<class F>
|
||||
struct check_deducible_signature {
|
||||
struct nat {};
|
||||
template<class G>
|
||||
static auto test(int) -> decltype(&G::operator(), void());
|
||||
template<class>
|
||||
static auto test(...) -> struct nat;
|
||||
static auto test(...) -> nat;
|
||||
|
||||
using type = std::is_void<decltype(test<F>(0))>;
|
||||
};
|
||||
@ -312,6 +314,7 @@ template<typename Arg>
|
||||
Unwrap<Arg> unwrapper(std::reference_wrapper<Arg> arg) {
|
||||
return arg.get();
|
||||
}
|
||||
|
||||
} // sol
|
||||
|
||||
#endif // SOL_TRAITS_HPP
|
||||
|
154
sol/types.hpp
154
sol/types.hpp
@ -29,28 +29,31 @@
|
||||
namespace sol {
|
||||
struct nil_t {};
|
||||
const nil_t nil {};
|
||||
struct void_type {};
|
||||
inline bool operator==(nil_t, nil_t) { return true; }
|
||||
inline bool operator!=(nil_t, nil_t) { return false; }
|
||||
|
||||
struct void_type : types<void> {}; // This is important because it allows myobject.call( Void, ... ) to work
|
||||
const void_type Void {};
|
||||
|
||||
template<typename... T>
|
||||
struct function_sig_t {};
|
||||
using function_t = function_sig_t<>;
|
||||
|
||||
struct upvalue_t {
|
||||
struct upvalue {
|
||||
void* value;
|
||||
upvalue_t(void* data) : value(data) {}
|
||||
upvalue(void* data) : value(data) {}
|
||||
operator void*() const { return value; }
|
||||
};
|
||||
|
||||
struct lightuserdata_t {
|
||||
struct light_userdata {
|
||||
void* value;
|
||||
lightuserdata_t(void* data) : value(data) {}
|
||||
light_userdata(void* data) : value(data) {}
|
||||
operator void*() const { return value; }
|
||||
};
|
||||
|
||||
struct userdata_t {
|
||||
struct userdata {
|
||||
void* value;
|
||||
userdata_t(void* data) : value(data) {}
|
||||
userdata(void* data) : value(data) {}
|
||||
operator void*() const { return value; }
|
||||
};
|
||||
|
||||
@ -74,10 +77,29 @@ enum class type : int {
|
||||
table | boolean | function | userdata | lightuserdata
|
||||
};
|
||||
|
||||
inline int type_panic(lua_State* L, int index, type expected, type actual) {
|
||||
return luaL_error(L, "stack index %d, expected %s, received %s", index, lua_typename(L, static_cast<int>(expected)), lua_typename(L, static_cast<int>(actual)));
|
||||
}
|
||||
|
||||
// Specify this function as the handler for lua::check if you know there's nothing wrong
|
||||
inline int no_panic(lua_State*, int, type, type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void type_error(lua_State* L, int expected, int actual) {
|
||||
luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual));
|
||||
}
|
||||
|
||||
inline void type_error(lua_State* L, type expected, type actual) {
|
||||
type_error(L, static_cast<int>(expected), static_cast<int>(actual));
|
||||
}
|
||||
|
||||
inline void type_assert(lua_State* L, int index, type expected, type actual) {
|
||||
if (expected != type::poly && expected != actual) {
|
||||
type_panic(L, index, expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
inline void type_assert(lua_State* L, int index, type expected) {
|
||||
int actual = lua_type(L, index);
|
||||
if(expected != type::poly && static_cast<int>(expected) != actual) {
|
||||
@ -95,70 +117,82 @@ class table;
|
||||
class function;
|
||||
class object;
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
inline type arithmetic(std::true_type) {
|
||||
return type::number;
|
||||
}
|
||||
template <typename T, typename = void>
|
||||
struct lua_type_of : std::integral_constant<type, type::userdata> {
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<std::string> : std::integral_constant<type, type::string> {
|
||||
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct lua_type_of<char[N]> : std::integral_constant<type, type::string> {
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<const char*> : std::integral_constant<type, type::string> {
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<bool> : std::integral_constant<type, type::boolean> {
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<nil_t> : std::integral_constant<type, type::nil> {
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<table> : std::integral_constant<type, type::table> {
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<object> : std::integral_constant<type, type::poly> {
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<light_userdata> : std::integral_constant<type, type::lightuserdata> {
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<function> : std::integral_constant<type, type::function> {
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline type arithmetic(std::false_type) {
|
||||
return type::userdata;
|
||||
}
|
||||
} // detail
|
||||
struct lua_type_of<T*> : std::integral_constant<type, type::userdata> {
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct lua_type_of<T, typename std::enable_if<std::is_arithmetic<T>::value>::type> : std::integral_constant<type, type::number> {
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline type type_of() {
|
||||
return detail::arithmetic<T>(std::is_arithmetic<T>{});
|
||||
return lua_type_of<Unqualified<T>>::value;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline type type_of<table>() {
|
||||
return type::table;
|
||||
inline type type_of(lua_State* L, int index) {
|
||||
return static_cast<type>(lua_type(L, index));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline type type_of<function>() {
|
||||
return type::function;
|
||||
}
|
||||
// All enumerations are given and taken from lua
|
||||
// as numbers as well
|
||||
template <typename T>
|
||||
struct lua_type_of<T, typename std::enable_if<std::is_enum<T>::value>::type> : std::integral_constant<type, type::number> {
|
||||
|
||||
template<>
|
||||
inline type type_of<object>() {
|
||||
return type::poly;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
inline type type_of<const char*>() {
|
||||
return type::string;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline type type_of<std::string>() {
|
||||
return type::string;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline type type_of<nil_t>() {
|
||||
return type::nil;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline type type_of<bool>() {
|
||||
return type::boolean;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline type type_of<lightuserdata_t>() {
|
||||
return type::lightuserdata;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline type type_of<userdata_t>() {
|
||||
return type::userdata;
|
||||
}
|
||||
|
||||
inline bool operator==(nil_t, nil_t) { return true; }
|
||||
inline bool operator!=(nil_t, nil_t) { return false; }
|
||||
} // sol
|
||||
|
||||
#endif // SOL_TYPES_HPP
|
||||
|
@ -104,7 +104,7 @@ private:
|
||||
template<typename... Args>
|
||||
static void do_constructor(lua_State* L, T* obj, call_syntax syntax, int, types<Args...>) {
|
||||
default_construct fx{};
|
||||
stack::get_call(L, 1 + static_cast<int>(syntax), fx, types<Args...>(), obj);
|
||||
stack::call(L, -1 + static_cast<int>(syntax), types<void>(), types<Args...>(), fx, obj);
|
||||
}
|
||||
|
||||
static void match_constructor(lua_State*, T*, call_syntax, int) {
|
||||
@ -143,7 +143,7 @@ private:
|
||||
|
||||
struct destructor {
|
||||
static int destruct(lua_State* L) {
|
||||
userdata_t udata = stack::get<userdata_t>(L, 1);
|
||||
userdata udata = stack::get<userdata>(L, 1);
|
||||
T* obj = static_cast<T*>(udata.value);
|
||||
std::allocator<T> alloc{};
|
||||
alloc.destroy(obj);
|
||||
@ -352,7 +352,7 @@ public:
|
||||
ptrmetafunctiontable.push_back({ nullptr, nullptr });
|
||||
}
|
||||
|
||||
void push(lua_State* L) {
|
||||
int push(lua_State* L) {
|
||||
// push pointer tables first,
|
||||
// but leave the regular T table on last
|
||||
// so it can be linked to a type for usage with `.new(...)` or `:new(...)`
|
||||
@ -363,6 +363,7 @@ public:
|
||||
push_metatable(L, usertype_traits<T>::metatable,
|
||||
metafunctions, metafunctiontable);
|
||||
set_global_deleter(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -394,10 +395,10 @@ private:
|
||||
int n = 0;
|
||||
for(auto& c : cont) {
|
||||
if(release) {
|
||||
stack::push<upvalue_t>(L, c.release());
|
||||
stack::push<upvalue>(L, c.release());
|
||||
}
|
||||
else {
|
||||
stack::push<upvalue_t>(L, c.get());
|
||||
stack::push<upvalue>(L, c.get());
|
||||
}
|
||||
++n;
|
||||
}
|
||||
@ -405,14 +406,11 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using userdata = typename detail::deprecate_type<usertype<T>>::type;
|
||||
|
||||
namespace stack {
|
||||
template<typename T>
|
||||
struct pusher<usertype<T>> {
|
||||
static void push(lua_State* L, usertype<T>& user) {
|
||||
user.push(L);
|
||||
static int push(lua_State* L, usertype<T>& user) {
|
||||
return user.push(L);
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
|
12
tests.cpp
12
tests.cpp
@ -582,7 +582,7 @@ TEST_CASE("tables/usertype", "Show that we can create classes from usertype and
|
||||
sol::object a = lua.get<sol::object>("a");
|
||||
sol::object b = lua.get<sol::object>("b");
|
||||
sol::object c = lua.get<sol::object>("c");
|
||||
REQUIRE((a.is<sol::userdata_t>()));
|
||||
REQUIRE((a.is<sol::userdata>()));
|
||||
auto atype = a.get_type();
|
||||
auto btype = b.get_type();
|
||||
auto ctype = c.get_type();
|
||||
@ -650,7 +650,7 @@ TEST_CASE("tables/usertype utility", "Show internal management of classes regist
|
||||
sol::object a = lua.get<sol::object>("a");
|
||||
sol::object b = lua.get<sol::object>("b");
|
||||
sol::object c = lua.get<sol::object>("c");
|
||||
REQUIRE((a.is<sol::userdata_t>()));
|
||||
REQUIRE((a.is<sol::userdata>()));
|
||||
auto atype = a.get_type();
|
||||
auto btype = b.get_type();
|
||||
auto ctype = c.get_type();
|
||||
@ -750,16 +750,16 @@ TEST_CASE("tables/issue-number-twenty-five", "Using pointers and references from
|
||||
return *this;
|
||||
}
|
||||
|
||||
int fun(int x) {
|
||||
return x * 10;
|
||||
int fun(int xa) {
|
||||
return xa * 10;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<test>("test", "set", &test::set, "get", &test::get, "pointer_get", &test::pget, "fun", &test::fun, "create_get", &test::create_get);
|
||||
REQUIRE_NOTHROW(lua.script("x = test.new()\n"
|
||||
"x:set():get()"));
|
||||
REQUIRE_NOTHROW(lua.script("x = test.new()"));
|
||||
REQUIRE_NOTHROW(lua.script("assert(x:set():get() == 10)"));
|
||||
REQUIRE_NOTHROW(lua.script("y = x:pointer_get()"));
|
||||
REQUIRE_NOTHROW(lua.script("y:set():get()"));
|
||||
REQUIRE_NOTHROW(lua.script("y:fun(10)"));
|
||||
|
Loading…
x
Reference in New Issue
Block a user