Documentation updates and new stack::check_get API.

This commit is contained in:
ThePhD 2016-03-24 15:45:44 -04:00
parent dd977a40d1
commit 09a0a5051a
31 changed files with 1662 additions and 953 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "Catch"]
path = Catch
url = https://github.com/philsquared/Catch.git
[submodule "Optional"]
path = Optional
url = https://github.com/ThePhD/Optional.git

1
Optional Submodule

@ -0,0 +1 @@
Subproject commit dfd239237279fe3e1793daf23fffbe92209c8ae2

View File

@ -21,7 +21,7 @@ functions
template <typename T>
auto get( lua_State* L, int index = -1 )
Retrieves the value of the object at ``index`` in the stack. The return type varies based on ``T``: with primitive types, it is usually ``T``: for all unrecognized ``T``, it is generally a ``T&`` or whatever the extension point :ref:`stack::getter\<T><getter>` implementation returns. The type ``T`` has top-level ``const`` qualifiers and reference modifiers removed before being forwarded to the extension point :ref:`stack::getter\<T><getter>` struct.
Retrieves the value of the object at ``index`` in the stack. The return type varies based on ``T``: with primitive types, it is usually ``T``: for all unrecognized ``T``, it is generally a ``T&`` or whatever the extension point :ref:`stack::getter\<T><getter>` implementation returns. The type ``T`` has top-level ``const`` qualifiers and reference modifiers removed before being forwarded to the extension point :ref:`stack::getter\<T><getter>` struct. ``stack::get`` will default to forwarding all arguments to the :ref:`stack::check_get<stack-check-get>` function with a handler of ``type_panic`` to strongly alert for errors, if you ask for the :ref:`safety<safety>`.
.. code-block:: cpp
:caption: function: check
@ -53,6 +53,17 @@ Checks if the object at ``index`` is of type ``T``. If it is not, it will call t
Based on how it is called, pushes a variable amount of objects onto the stack. in 99% of cases, returns for 1 object pushed onto the stack. For the case of a ``std::tuple<...>``, it recursively pushes each object contained inside the tuple, from left to right, resulting in a variable number of things pushed onto the stack (this enables multi-valued returns when binding a C++ function to a Lua). Can be called with ``sol::stack::push<T>( L, args... )`` to have arguments different from the type that wants to be pushed, or ``sol::stack::push( L, arg, args... )`` where ``T`` will be inferred from ``arg``. The final form of this function is ``sol::stack::multi_push``, which will call one ``sol::stack::push`` for each argument. The ``T`` that describes what to push is first sanitized by removing top-level ``const`` qualifiers and reference qualifiers before being forwarded to the extension point :ref:`stack::pusher\<T><pusher>` struct.
.. code-block:: cpp
:caption: function: check_get
:name: stack-check-get
template <typename T>
auto check_get( lua_State* L, int index = -1 )
template <typename T, typename Handler>
auto check_get( lua_State* L, int index, Handler&& handler )
Retrieves the value of the object at ``index`` in the stack, but does so safely. It returns an ``optional<U>``, where ``U`` in this case is the return type deduced from ``stack::get<T>``. This allows a person to properly check if the type they're getting is what they actually want, and gracefully handle errors when working with the stack if they so choose to. You can define ``SOL_CHECK_ARGUMENTS`` to turn on additional :ref:`safety<safety>`, in which ``stack::get`` will default to calling this version of the function with a handler of ``type_panic`` to strongly alert for errors and help you track bugs if you suspect something might be going wrong in your system.
.. code-block:: cpp
:caption: function: set_field

View File

@ -121,4 +121,18 @@ Sets the desired function to the specified key value. Note that it also allows f
Creates a table, optionally with the specified values pre-set into the table. If ``narr`` or ``nrec`` are 0, then compile-time shenanigans are used to guess the amount of array entries (e.g., integer keys) and the amount of hashable entries (e.g., all other entries).
.. code-block:: cpp
:caption: function: create a table with compile-time defaults assumed
:name: table-create-with
table create(int narr = 0, int nrec = 0);
template <typename Key, typename Value, typename... Args>
table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args);
static table create(lua_State* L, int narr = 0, int nrec = 0);
template <typename Key, typename Value, typename... Args>
static table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args);
Creates a table, optionally with the specified values pre-set into the table. If ``narr`` or ``nrec`` are 0, then compile-time shenanigans are used to guess the amount of array entries (e.g., integer keys) and the amount of hashable entries (e.g., all other entries).
.. _input iterators: http://en.cppreference.com/w/cpp/concept/InputIterator

View File

@ -85,7 +85,7 @@ The below feature table checks for the presence of something. It, however, does
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
| inheritance | ~ | ✗ | ✗ | ✔ | ✔ | ✔ | ~ | ~ | ✔ |
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
| overloading | ~ | ✗ | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ | |
| overloading | ~ | ✗ | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ | |
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
| thread | ✔ | ✗ | ✗ | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ |
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
@ -171,7 +171,6 @@ kaguya -
TODO:
* SWIG - http://www.swig.org/Doc1.3/Lua.html#Lua_nn2
* SLB3 - https://code.google.com/archive/p/slb/
* Luwra - https://github.com/vapourismo/luwra
.. _Go read the docs.: https://oolua.org/docs/index.html

View File

@ -24,6 +24,7 @@ get going:
api/top
features
benchmarks
safety
exceptions
rtti
licenses

10
docs/source/safety.rst Normal file
View File

@ -0,0 +1,10 @@
safety
======
Sol was designed to be correct and fast, and in the pursuit of both uses the regular ``lua_to{x}`` functions of Lua rather than the checking versions (``lua_check{X}``) functions. The API defaults to safe alternatives if you have a ``#define SOL_CHECK_ARGUMENTS`` before you include Sol, or if you pass the ``SOL_CHECK_ARGUMENTS`` define on the build command for your build system. By default, it is off and remains off unless you define this, even in debug mode.
``SOL_CHECK_ARGUMENTS`` triggers the following changes:
* ``stack::get`` (used everywhere) defaults to using ``stack::check_get`` and dereferencing the argument. It uses ``type_panic`` as the handler if something goes wrong.
* ``stack::call`` will, if no template boolean is specified, check all of the arguments for a function call.
Remember that if you want these features, you must explicitly turn them on.

View File

@ -43,22 +43,48 @@
#endif // Lua Version 502, 501 || luajit, 500
#ifdef _MSC_VER
#ifdef _DEBUG
#ifndef SOL_CHECK_ARGUMENTS
// Do not define by default: let user turn it on
//#define SOL_CHECK_ARGUMENTS
#endif // Check Arguments
#endif // Debug
#ifndef _CPPUNWIND
#ifndef SOL_NO_EXCEPTIONS
#define SOL_NO_EXCEPTIONS 1
#endif // No
#endif
#endif // Automatic Exceptions
#ifndef _CPPRTTI
#ifndef SOL_NO_RTTI
#define SOL_NO_RTTI 1
#endif
#endif // Automatic RTTI
#elif defined(__GNUC__) || defined(__clang__)
#ifndef NDEBUG
#ifndef __OPTIMIZE__
#ifndef SOL_CHECK_ARGUMENTS
// Do not define by default: let user choose
//#define SOL_CHECK_ARGUMENTS
#endif // Check Arguments
#endif // g++ optimizer flag
#endif // Not Debug
#ifndef __EXCEPTIONS
#ifndef SOL_NO_EXCEPTIONS
#define SOL_NO_EXCEPTIONS 1
#endif
#endif // No Exceptions
#ifndef __GXX_RTTI
#ifndef SOL_NO_RTII
#define SOL_NO_RTTI 1
#endif
#endif // No RTTI
#endif // vc++ || clang++/g++
#endif // SOL_VERSION_HPP

View File

@ -43,11 +43,7 @@ private:
template<std::size_t... I, typename... Ret>
auto invoke( types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n ) {
luacall(n, sizeof...(Ret));
int stacksize = lua_gettop(lua_state());
int firstreturn = std::max(1, stacksize - static_cast<int>(sizeof...(Ret)) + 1);
auto r = stack::get<std::tuple<Ret...>>(lua_state(), firstreturn);
lua_pop(lua_state(), static_cast<int>(sizeof...(Ret)));
return r;
return stack::pop<std::tuple<Ret...>>(lua_state());
}
template<std::size_t I, typename Ret>

View File

@ -113,7 +113,7 @@ inline std::string get_type_name() {
#endif // No Runtime Type information
template <typename T>
inline std::string demangle() {
inline std::string demangle_once() {
#ifndef SOL_NO_RTTI
std::string realname = get_type_name(typeid(T));
#else
@ -139,6 +139,12 @@ inline std::string demangle() {
return realname;
}
template <typename T>
inline std::string demangle() {
static const std::string d = demangle_once<T>();
return d;
}
} // detail
} // sol

View File

@ -53,11 +53,7 @@ private:
template<std::size_t... I, typename... Ret>
auto invoke( types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n ) const {
luacall( n, sizeof...( Ret ) );
int stacksize = lua_gettop( lua_state( ) );
int firstreturn = std::max(1, stacksize - static_cast<int>(sizeof...(Ret)) + 1);
auto r = stack::get<std::tuple<Ret...>>( lua_state( ), firstreturn );
lua_pop(lua_state(), static_cast<int>(sizeof...(Ret)));
return r;
return stack::pop<std::tuple<Ret...>>( lua_state( ) );
}
template<std::size_t I, typename Ret>
@ -129,6 +125,24 @@ struct pusher<function_sig<Sigs...>> {
set_fx(std::false_type(), L, fxptr);
}
template<typename... Args, typename R, typename C>
static void set(lua_State* L, R (C::*memfxptr)(Args...)) {
// Layout:
// idx 1...n: verbatim data of member function pointer
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, R(C::*)(Args...)>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
stack::push(L, freefunc, upvalues);
}
template<typename Sig, typename C>
static void set(lua_State* L, Sig C::* memfxptr) {
// Layout:
// idx 1...n: verbatim data of member function pointer
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Sig C::*>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
stack::push(L, freefunc, upvalues);
}
template<typename... Args, typename R, typename C, typename T>
static void set(lua_State* L, R (C::*memfxptr)(Args...), T&& obj) {
typedef meta::Bool<meta::is_specialization_of<meta::Unqualified<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
@ -148,7 +162,7 @@ struct pusher<function_sig<Sigs...>> {
template<typename Fx, typename R, typename... Args>
static void set_isconvertible_fx(std::true_type, types<R(Args...)>, lua_State* L, Fx&& fx) {
typedef R(* fx_ptr_t)(Args...);
using fx_ptr_t = R(*)(Args...);
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
set(L, fxptr);
}
@ -203,7 +217,7 @@ struct pusher<function_sig<Sigs...>> {
static void set_fx(lua_State* L, std::unique_ptr<function_detail::base_function> luafunc) {
function_detail::base_function* target = luafunc.release();
void* targetdata = reinterpret_cast<void*>(target);
void* targetdata = static_cast<void*>(target);
lua_CFunction freefunc = function_detail::call;
stack::push(L, userdata_value(targetdata));

View File

@ -23,6 +23,7 @@
#define SOL_FUNCTION_TYPES_ALLOCATOR_HPP
#include "raii.hpp"
#include "stack.hpp"
#include "function_types_overload.hpp"
namespace sol {

View File

@ -46,6 +46,37 @@ struct functor_function : public base_function {
}
};
template<typename Function, typename T>
struct this_member_function : public base_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef meta::function_return_t<function_type> return_type;
typedef meta::function_args_t<function_type> args_types;
struct functor {
function_type invocation;
template<typename... Args>
functor(Args&&... args): invocation(std::forward<Args>(args)...) {}
template<typename... Args>
return_type operator()(lua_State* L, Args&&... args) {
auto& mem = detail::unwrap(stack::get<T&>(L, 1));
return (mem.*invocation)(std::forward<Args>(args)...);
}
} fx;
template<typename... Args>
this_member_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, 2, L);
}
virtual int operator()(lua_State* L) override {
auto f = [&](lua_State* L) -> int { return this->call(L);};
return detail::trampoline(L, f);
}
};
template<typename Function, typename T>
struct member_function : public base_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;

View File

@ -57,7 +57,9 @@ struct upvalue_member_function {
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
function_type& memfx = memberdata.first;
T& item = *objdata.first;
auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type { return (item.*memfx)(std::forward<decltype(args)>(args)...); };
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);
}
@ -69,6 +71,30 @@ struct upvalue_member_function {
return call(L);
}
};
template<typename T, typename Function>
struct upvalue_this_member_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef meta::function_traits<function_type> traits_type;
static int real_call(lua_State* L) {
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 {
T& item = stack::get<T>(L, 1);
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, 2, L);
}
static int call (lua_State* L) {
return detail::static_trampoline<(&real_call)>(L);
}
int operator()(lua_State* L) {
return call(L);
}
};
} // function_detail
} // sol

42
sol/optional.hpp Normal file
View File

@ -0,0 +1,42 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_OPTIONAL_HPP
#define SOL_OPTIONAL_HPP
#if __cplusplus > 201402L
#include <optional>
#else
#include "Optional/optional.hpp"
#endif // C++ 14
namespace sol {
#if __cplusplus > 201402L
template <typename T>
using optional = sol::optional<T>;
using nullopt_t = std::nullopt_t;
constexpr nullopt_t nullopt = std::experimental::nullopt;
#else
#endif // C++ 14
}
#endif // SOL_OPTIONAL_HPP

View File

@ -68,11 +68,7 @@ private:
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);
int stacksize = lua_gettop(lua_state());
int firstreturn = std::max(0, stacksize - static_cast<int>(sizeof...(Ret)) + 1);
auto r = stack::get<std::tuple<Ret...>>(lua_state(), firstreturn);
lua_pop(lua_state(), static_cast<int>(sizeof...(Ret)));
return r;
return stack::pop<std::tuple<Ret...>>(lua_state());
}
template<std::size_t I, typename Ret>

View File

@ -114,6 +114,7 @@ template<typename Table, typename Key, typename T>
inline bool operator!=(const proxy<Table, Key>& right, T&& left) {
return right.template get<std::decay_t<T>>() != left;
}
namespace stack {
template <typename Table, typename Key>
struct pusher<proxy<Table, Key>> {

View File

@ -22,868 +22,18 @@
#ifndef SOL_STACK_HPP
#define SOL_STACK_HPP
#include "error.hpp"
#include "reference.hpp"
#include "userdata.hpp"
#include "tuple.hpp"
#include "traits.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include "overload.hpp"
#include "raii.hpp"
#include <utility>
#include <array>
#include "stack_core.hpp"
#include "stack_check.hpp"
#include "stack_get.hpp"
#include "stack_check_get.hpp"
#include "stack_push.hpp"
#include "stack_pop.hpp"
#include "stack_field.hpp"
#include <cstring>
#include <functional>
#include <array>
namespace sol {
namespace stack {
template<typename T, bool global = false, typename = void>
struct field_getter;
template<typename T, bool global = false, typename = void>
struct field_setter;
template<typename T, typename = void>
struct getter;
template<typename T, typename = void>
struct popper;
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<meta::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 int push(lua_State* L, Arg&& arg, Args&&... args) {
return pusher<meta::Unqualified<T>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
inline int multi_push(lua_State*) {
// do nothing
return 0;
}
template<typename T, typename... Args>
inline int multi_push(lua_State* L, T&& t, Args&&... args) {
int pushcount = push(L, std::forward<T>(t));
void(sol::detail::swallow{(pushcount += sol::stack::push(L, std::forward<Args>(args)), 0)... });
return pushcount;
}
template<typename T>
inline decltype(auto) get(lua_State* L, int index = -1) {
return getter<meta::Unqualified<T>>{}.get(L, index);
}
template<typename T>
inline decltype(auto) pop(lua_State* L) {
return popper<meta::Unqualified<T>>{}.pop(L);
}
template <typename T, typename Handler>
bool check(lua_State* L, int index, Handler&& handler) {
typedef meta::Unqualified<T> Tu;
checker<Tu> c;
// VC++ has a bad warning here: shut it up
(void)c;
return c.check(L, index, std::forward<Handler>(handler));
}
template <typename T>
bool check(lua_State* L, int index = -1) {
auto handler = no_panic;
return check<T>(L, index, handler);
}
template <bool global = false, typename Key>
void get_field(lua_State* L, Key&& key) {
field_getter<meta::Unqualified<Key>, global>{}.get(L, std::forward<Key>(key));
}
template <bool global = false, typename Key>
void get_field(lua_State* L, Key&& key, int tableindex) {
field_getter<meta::Unqualified<Key>, global>{}.get(L, std::forward<Key>(key), tableindex);
}
template <bool global = false, typename Key, typename Value>
void set_field(lua_State* L, Key&& key, Value&& value) {
field_setter<meta::Unqualified<Key>, global>{}.set(L, std::forward<Key>(key), std::forward<Value>(value));
}
template <bool global = false, typename Key, typename Value>
void set_field(lua_State* L, Key&& key, Value&& value, int tableindex) {
field_setter<meta::Unqualified<Key>, global>{}.set(L, std::forward<Key>(key), std::forward<Value>(value), tableindex);
}
namespace stack_detail {
const bool default_check_arguments =
#ifdef SOL_CHECK_ARGUMENTS
true;
#else
false;
#endif
template <typename T>
inline bool check_metatable(lua_State* L, int index = -2) {
luaL_getmetatable(L, &usertype_traits<T>::metatable[0]);
const type expectedmetatabletype = static_cast<type>(lua_type(L, -1));
if (expectedmetatabletype != type::nil) {
if (lua_rawequal(L, -1, index) == 1) {
lua_pop(L, 2);
return true;
}
}
lua_pop(L, 1);
return false;
}
template<bool releasemem = false, typename TCont>
inline int push_upvalues(lua_State* L, TCont&& cont) {
int n = 0;
for(auto& c : cont) {
if(releasemem) {
stack::push<light_userdata_value>(L, c.release());
}
else {
stack::push<light_userdata_value>(L, c.get());
}
++n;
}
return n;
}
} // stack_detail
template<typename T, typename>
struct getter {
static T& get(lua_State* L, int index = -1) {
return getter<T&>{}.get(L, index);
}
};
template<typename T>
struct getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
static T get(lua_State* L, int index = -1) {
return static_cast<T>(lua_tonumber(L, index));
}
};
template<typename T>
struct getter<T, std::enable_if_t<meta::And<std::is_integral<T>, std::is_signed<T>>::value>> {
static T get(lua_State* L, int index = -1) {
return static_cast<T>(lua_tointeger(L, index));
}
};
template<typename T>
struct getter<T, std::enable_if_t<meta::And<std::is_integral<T>, std::is_unsigned<T>>::value>> {
static T get(lua_State* L, int index = -1) {
return static_cast<T>(lua_tointeger(L, index));
}
};
template<typename T>
struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
static T get(lua_State* L, int index = -1) {
return T(L, index);
}
};
template<>
struct getter<userdata_value> {
static userdata_value get(lua_State* L, int index = -1) {
return{ lua_touserdata(L, index) };
}
};
template<>
struct getter<light_userdata_value> {
static light_userdata_value get(lua_State* L, int index = -1) {
return{ lua_touserdata(L, index) };
}
};
template<>
struct getter<void*> {
static void* get(lua_State* L, int index = -1) {
return lua_touserdata(L, index);
}
};
} // stack
namespace detail {
// This needs to be here, specifically, so that it can use get<userdata_value>
using special_destruct_func = void(*)(void*);
template <typename T, typename Real>
inline void special_destruct(void* memory) {
T** pointerpointer = static_cast<T**>(memory);
special_destruct_func* dx = static_cast<special_destruct_func*>(static_cast<void*>(pointerpointer + 1));
Real* target = static_cast<Real*>(static_cast<void*>(dx + 1));
target->~Real();
}
template <typename T>
inline int unique_destruct(lua_State* L) {
void* memory = stack::get<userdata_value>(L, 1);
T** pointerpointer = static_cast<T**>(memory);
special_destruct_func& dx = *static_cast<special_destruct_func*>( static_cast<void*>( pointerpointer + 1 ) );
(dx)(memory);
return 0;
}
} // detail
namespace stack {
template<typename T>
struct getter<T*> {
static T* get_no_nil(lua_State* L, int index = -1) {
void** pudata = static_cast<void**>(lua_touserdata(L, index));
void* udata = *pudata;
return get_no_nil_from(L, udata, index);
}
static T* get_no_nil_from(lua_State* L, void* udata, int index = -1) {
#ifndef SOL_NO_EXCEPTIONS
if (luaL_getmetafield(L, index, &detail::base_class_check_key()[0]) != 0) {
void* basecastdata = stack::get<light_userdata_value>(L);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
// use the casting function to properly adjust the pointer for the desired T
udata = detail::catch_cast<T>(udata, basecast);
lua_pop(L, 1);
}
#elif !defined(SOL_NO_RTTI)
if (luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
void* basecastdata = stack::get<light_userdata_value>(L);
detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata;
// use the casting function to properly adjust the pointer for the desired T
udata = ic(udata, typeid(T));
lua_pop(L, 1);
}
#else
// Lol, you motherfucker
if (luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
void* basecastdata = stack::get<light_userdata_value>(L);
detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata;
// use the casting function to properly adjust the pointer for the desired T
udata = ic(udata, detail::id_for<T>::value);
lua_pop(L, 1);
}
#endif // No Runtime Type Information || Exceptions
T* obj = static_cast<T*>(udata);
return obj;
}
static T* get(lua_State* L, int index = -1) {
type t = type_of(L, index);
if (t == type::nil)
return nullptr;
return get_no_nil(L, index);
}
};
template<typename T, typename Real>
struct getter<unique_usertype<T, Real>> {
static Real& get(lua_State* L, int index = -1) {
T** pref = static_cast<T**>(lua_touserdata(L, index));
detail::special_destruct_func* fx = static_cast<detail::special_destruct_func*>(static_cast<void*>(pref + 1));
Real* mem = static_cast<Real*>(static_cast<void*>(fx + 1));
return *mem;
}
};
template<typename T>
struct getter<non_null<T*>> {
static T* get(lua_State* L, int index = -1) {
return getter<T*>::get_no_nil(L, index);
}
};
template<typename T>
struct getter<T&> {
static T& get(lua_State* L, int index = -1) {
return *getter<T*>::get_no_nil(L, index);
}
};
template<typename T>
struct getter<std::shared_ptr<T>> {
static std::shared_ptr<T>& get(lua_State* L, int index = -1) {
return getter<unique_usertype<T, std::shared_ptr<T>>>::get(L, index);
}
};
template<typename T, typename D>
struct getter<std::unique_ptr<T, D>> {
static std::unique_ptr<T, D>& get(lua_State* L, int index = -1) {
return getter<unique_usertype<T, std::unique_ptr<T, D>>>::get(L, index);
}
};
template<typename T>
struct getter<std::reference_wrapper<T>> {
static T& get(lua_State* L, int index = -1) {
return getter<T&>{}.get(L, index);
}
};
template<>
struct getter<type> {
static type get(lua_State *L, int index){
return static_cast<type>(lua_type(L, index));
}
};
template<>
struct getter<bool> {
static bool get(lua_State* L, int index) {
return lua_toboolean(L, index) != 0;
}
};
template<>
struct getter<std::string> {
static std::string get(lua_State* L, int index = -1) {
std::size_t len;
auto str = lua_tolstring(L, index, &len);
return { str, len };
}
};
template<>
struct getter<const char*> {
static const char* get(lua_State* L, int index = -1) {
return lua_tostring(L, index);
}
};
template<>
struct getter<nil_t> {
static nil_t get(lua_State*, int = -1) {
return nil_t{ };
}
};
template<>
struct getter<lua_CFunction> {
static lua_CFunction get(lua_State* L, int index = -1) {
return lua_tocfunction(L, index);
}
};
template<>
struct getter<c_closure> {
static c_closure get(lua_State* L, int index = -1) {
return c_closure(lua_tocfunction(L, index), -1);
}
};
template<typename... Args>
struct getter<std::tuple<Args...>> {
template <std::size_t... I>
static decltype(auto) apply(std::index_sequence<I...>, lua_State* L, int index = -1) {
index = lua_absindex(L, index);
return std::tuple<decltype(stack::get<Args>(L, index + I))...>(stack::get<Args>(L, index + I)...);
}
static decltype(auto) get(lua_State* L, int index = -1) {
return apply(std::index_sequence_for<Args...>(), L, index);
}
};
template<typename A, typename B>
struct getter<std::pair<A, B>> {
static decltype(auto) get(lua_State* L, int index = -1) {
index = lua_absindex(L, index);
return std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))>(stack::get<A>(L, index), stack::get<B>(L, index + 1));
}
};
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 C>
struct checker<T*, type::userdata, C> {
template <typename Handler>
static bool check (lua_State* L, int index, const Handler& handler) {
const type indextype = type_of(L, index);
// Allow nil to be transformed to nullptr
if (indextype == type::nil) {
return true;
}
return checker<T, type::userdata, C>{}.check(types<T>(), L, indextype, index, handler);
}
};
template <typename T, typename C>
struct checker<T, type::userdata, C> {
template <typename U, typename Handler>
static bool check (types<U>, lua_State* L, type indextype, int index, const Handler& handler) {
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype);
return false;
}
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;
}
if (stack_detail::check_metatable<U>(L))
return true;
if (stack_detail::check_metatable<U*>(L))
return true;
if (stack_detail::check_metatable<unique_usertype<U>>(L))
return true;
#ifndef SOL_NO_EXCEPTIONS
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
void* basecastdata = stack::get<light_userdata_value>(L);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
bool success = detail::catch_check<T>(basecast);
#elif !defined(SOL_NO_RTTI)
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
}
void* basecastdata = stack::get<light_userdata_value>(L);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
bool success = ic(typeid(T));
#else
// Topkek
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
}
void* basecastdata = stack::get<light_userdata_value>(L);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
bool success = ic(detail::id_for<T>::value);
#endif // No Runtime Type Information || Exceptions
lua_pop(L, 2);
if (!success) {
handler(L, index, type::userdata, indextype);
return false;
}
return true;
}
template <typename Handler>
static bool check (lua_State* L, int index, const Handler& handler) {
const type indextype = type_of(L, index);
return check(types<T>(), L, indextype, index, handler);
}
};
template <typename T, typename>
struct popper {
inline decltype(auto) pop(lua_State* L) {
decltype(auto) r = get<T>(L);
lua_pop(L, 1);
return r;
}
};
template <typename... Args>
struct popper<std::tuple<Args...>> {
inline decltype(auto) pop(lua_State* L) {
decltype(auto) r = get<std::tuple<Args...>>(L, lua_gettop(L) - sizeof...(Args) + 1);
lua_pop(L, static_cast<int>(sizeof...(Args)));
return r;
}
};
template <typename A, typename B>
struct popper<std::pair<A, B>> {
inline decltype(auto) pop(lua_State* L) {
decltype(auto) r = get<std::pair<A, B>>(L, lua_gettop(L) - 2 + 1);
lua_pop(L, 2);
return r;
}
};
template<typename T, typename>
struct pusher {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
// Basically, we store all user-data like this:
// If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new
// data in the first sizeof(T*) bytes, and then however many bytes it takes to
// do the actual object. Things that are std::ref or plain T* are stored as
// just the sizeof(T*), and nothing else.
T** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
T*& referencereference = *pointerpointer;
T* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1);
referencereference = allocationtarget;
std::allocator<T> alloc{};
alloc.construct(allocationtarget, std::forward<Args>(args)...);
luaL_getmetatable(L, &usertype_traits<T>::metatable[0]);
lua_setmetatable(L, -2);
return 1;
}
};
template<typename T>
struct pusher<T*> {
static int push(lua_State* L, T* obj) {
if (obj == nullptr)
return stack::push(L, nil);
T** pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));
*pref = obj;
luaL_getmetatable(L, &usertype_traits<T*>::metatable[0]);
lua_setmetatable(L, -2);
return 1;
}
};
template<typename T, typename Real>
struct pusher<unique_usertype<T, Real>> {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
T** pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(detail::special_destruct_func) + sizeof(Real)));
detail::special_destruct_func* fx = static_cast<detail::special_destruct_func*>(static_cast<void*>(pref + 1));
Real* mem = static_cast<Real*>(static_cast<void*>(fx + 1));
*fx = detail::special_destruct<T, Real>;
detail::default_construct::construct(mem, std::forward<Args>(args)...);
*pref = std::addressof(detail::deref(*mem));
if (luaL_newmetatable(L, &usertype_traits<unique_usertype<T>>::metatable[0]) == 1) {
set_field(L, "__gc", detail::unique_destruct<T>);
}
lua_setmetatable(L, -2);
return 1;
}
};
template<typename T>
struct pusher<T, std::enable_if_t<is_unique_usertype<T>::value>> {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
typedef typename is_unique_usertype<T>::metatable_type meta_type;
return stack::push<unique_usertype<meta_type, T>>(L, std::forward<Args>(args)...);
}
};
template<typename T, typename D>
struct pusher<std::unique_ptr<T, D>> {
static int push(lua_State* L, std::unique_ptr<T, D> obj) {
if (obj == nullptr)
return stack::push(L, nil);
return stack::push<unique_usertype<T, std::unique_ptr<T, D>>>(L, std::move(obj));
}
};
template<typename T>
struct pusher<std::shared_ptr<T>> {
template <typename S>
static int push(lua_State* L, S&& s) {
if (s == nullptr)
return stack::push(L, nil);
return stack::push<unique_usertype<T, std::shared_ptr<T>>>(L, std::forward<S>(s));
}
};
template<typename T>
struct pusher<std::reference_wrapper<T>> {
static int push(lua_State* L, const std::reference_wrapper<T>& t) {
return stack::push(L, std::addressof(detail::deref(t.get())));
}
};
template<typename T>
struct pusher<T, std::enable_if_t<std::is_floating_point<T>::value>> {
static int push(lua_State* L, const T& value) {
lua_pushnumber(L, value);
return 1;
}
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::And<std::is_integral<T>, std::is_signed<T>>::value>> {
static int push(lua_State* L, const T& value) {
lua_pushinteger(L, static_cast<lua_Integer>(value));
return 1;
}
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::And<std::is_integral<T>, std::is_unsigned<T>>::value>> {
static int push(lua_State* L, const T& value) {
typedef std::make_signed_t<T> signed_int;
return stack::push(L, static_cast<signed_int>(value));
}
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::And<meta::has_begin_end<T>, meta::Not<meta::has_key_value_pair<T>>, meta::Not<std::is_base_of<reference, T>>>::value>> {
static int push(lua_State* L, const T& cont) {
lua_createtable(L, static_cast<int>(cont.size()), 0);
int tableindex = lua_gettop(L);
unsigned index = 1;
for(auto&& i : cont) {
set_field(L, index++, i, tableindex);
}
return 1;
}
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::And<meta::has_begin_end<T>, meta::has_key_value_pair<T>, meta::Not<std::is_base_of<reference, T>>>::value>> {
static int push(lua_State* L, const T& cont) {
lua_createtable(L, static_cast<int>(cont.size()), 0);
int tableindex = lua_gettop(L);
for(auto&& pair : cont) {
set_field(L, pair.first, pair.second, tableindex);
}
return 1;
}
};
template<typename T>
struct pusher<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
static int push(lua_State*, T& ref) {
return ref.push();
}
static int push(lua_State*, T&& ref) {
return ref.push();
}
};
template<>
struct pusher<bool> {
static int push(lua_State* L, bool b) {
lua_pushboolean(L, b);
return 1;
}
};
template<>
struct pusher<nil_t> {
static int push(lua_State* L, nil_t) {
lua_pushnil(L);
return 1;
}
};
template<>
struct pusher<std::remove_pointer_t<lua_CFunction>> {
static int push(lua_State* L, lua_CFunction func, int n = 0) {
lua_pushcclosure(L, func, n);
return 1;
}
};
template<>
struct pusher<lua_CFunction> {
static int push(lua_State* L, lua_CFunction func, int n = 0) {
lua_pushcclosure(L, func, n);
return 1;
}
};
template<>
struct pusher<c_closure> {
static int push(lua_State* L, c_closure closure) {
lua_pushcclosure(L, closure.c_function, closure.upvalues);
return 1;
}
};
template<>
struct pusher<void*> {
static int push(lua_State* L, void* userdata) {
lua_pushlightuserdata(L, userdata);
return 1;
}
};
template<>
struct pusher<light_userdata_value> {
static int push(lua_State* L, light_userdata_value userdata) {
lua_pushlightuserdata(L, userdata);
return 1;
}
};
template<>
struct pusher<userdata_value> {
static int push(lua_State* L, userdata_value data) {
void** ud = static_cast<void**>(lua_newuserdata(L, sizeof(void*)));
*ud = data.value;
return 1;
}
};
template<>
struct pusher<const char*> {
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 int push(lua_State* L, const char (&str)[N]) {
lua_pushlstring(L, str, N - 1);
return 1;
}
};
template<>
struct pusher<std::string> {
static int push(lua_State* L, const std::string& str) {
lua_pushlstring(L, str.c_str(), str.size());
return 1;
}
};
template<typename... Args>
struct pusher<std::tuple<Args...>> {
template <std::size_t... I, typename T>
static int push(std::index_sequence<I...>, lua_State* L, T&& t) {
int pushcount = 0;
(void)detail::swallow{ 0, (pushcount += stack::push(L,
detail::forward_get<I>(t)
), 0)... };
return pushcount;
}
template <typename T>
static int push(lua_State* L, T&& t) {
return push(std::index_sequence_for<Args...>(), L, std::forward<T>(t));
}
};
template<typename A, typename B>
struct pusher<std::pair<A, B>> {
template <typename T>
static int push(lua_State* L, T&& t) {
int pushcount = stack::push(L, detail::forward_get<0>(t));
pushcount += stack::push(L, detail::forward_get<1>(t));
return pushcount;
}
};
template <typename T, bool, typename>
struct field_getter {
template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = -2) {
push( L, std::forward<Key>( key ) );
lua_gettable( L, tableindex );
}
};
template <typename... Args, bool b, typename C>
struct field_getter<std::tuple<Args...>, b, C> {
template <std::size_t... I, typename Keys>
void apply(std::index_sequence<I...>, lua_State* L, Keys&& keys, int tableindex) {
tableindex = lua_absindex(L, tableindex);
void(detail::swallow{ (get_field<I < 1 && b>(L, detail::forward_get<I>(keys), tableindex), 0)... });
reference saved(L, -1);
lua_pop(L, static_cast<int>(sizeof...(I) + 1));
saved.push();
}
template <typename Keys>
void get(lua_State* L, Keys&& keys, int tableindex = -2) {
apply(std::index_sequence_for<Args...>(), L, std::forward<Keys>(keys), tableindex);
}
};
template <typename A, typename B, bool b, typename C>
struct field_getter<std::pair<A, B>, b, C> {
template <typename Keys>
void apply(lua_State* L, Keys&& keys, int tableindex) {
tableindex = lua_absindex(L, tableindex);
get_field<b>(L, detail::forward_get<0>(keys), tableindex);
get_field<false>(L, detail::forward_get<1>(keys), tableindex + 1);
reference saved(L, -1);
lua_pop(L, static_cast<int>(2 + 1));
saved.push();
}
};
template <typename T>
struct field_getter<T, true, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key>
void get(lua_State* L, Key&& key, int = -1) {
lua_getglobal(L, &key[0]);
}
};
template <typename T>
struct field_getter<T, false, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = -1) {
lua_getfield(L, tableindex, &key[0]);
}
};
#if SOL_LUA_VERSION >= 503
template <typename T>
struct field_getter<T, false, std::enable_if_t<std::is_integral<T>::value>> {
template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = -1) {
lua_geti(L, tableindex, static_cast<lua_Integer>(key));
}
};
#endif // Lua 5.3.x
template <typename T, bool, typename>
struct field_setter {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -3) {
push(L, std::forward<Key>(key));
push(L, std::forward<Value>(value));
lua_settable(L, tableindex);
}
};
template <typename T>
struct field_setter<T, true, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int = -2) {
push(L, std::forward<Value>(value));
lua_setglobal(L, &key[0]);
}
};
template <typename T>
struct field_setter<T, false, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) {
push(L, std::forward<Value>(value));
lua_setfield(L, tableindex, &key[0]);
}
};
#if SOL_LUA_VERSION >= 503
template <typename T>
struct field_setter<T, false, std::enable_if_t<std::is_integral<T>::value>> {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) {
push(L, std::forward<Value>(value));
lua_seti(L, tableindex, static_cast<lua_Integer>(key));
}
};
#endif // Lua 5.3.x
namespace stack_detail {
template<typename T>
inline int push_as_upvalues(lua_State* L, T& item) {
@ -914,39 +64,16 @@ inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) {
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
}
template <bool b>
struct check_types {
template <std::size_t I0, std::size_t... I, typename Arg0, typename... Args, typename Handler>
static bool check(types<Arg0, Args...>, std::index_sequence<I0, I...>, lua_State* L, int firstargument, Handler&& handler) {
if (!stack::check<Arg0>(L, firstargument + I0, handler))
return false;
return check(types<Args...>(), std::index_sequence<I...>(), L, firstargument, std::forward<Handler>(handler));
}
template <typename Handler>
static bool check(types<>, std::index_sequence<>, lua_State*, int, Handler&&) {
return true;
}
};
template <>
struct check_types<false> {
template <std::size_t... I, typename... Args, typename Handler>
static bool check(types<Args...>, std::index_sequence<I...>, lua_State*, int, Handler&&) {
return true;
}
};
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) {
check_types<checkargs>{}.check(ta, tai, L, start, type_panic);
return fx(std::forward<FxArgs>(args)..., stack::get<Args>(L, start + I)...);
return fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I)...);
}
template <bool checkargs = default_check_arguments, std::size_t... I, typename... Args, typename Fx, typename... FxArgs>
inline void call(types<void>, 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);
fx(std::forward<FxArgs>(args)..., stack::get<Args>(L, start + I)...);
fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I)...);
}
} // stack_detail

288
sol/stack_check.hpp Normal file
View File

@ -0,0 +1,288 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_CHECK_HPP
#define SOL_STACK_CHECK_HPP
#include "stack_core.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include <memory>
#include <functional>
#include <utility>
namespace sol {
namespace stack {
namespace stack_detail {
template <typename T>
inline bool check_metatable(lua_State* L, int index = -2) {
luaL_getmetatable(L, &usertype_traits<T>::metatable[0]);
const type expectedmetatabletype = static_cast<type>(lua_type(L, -1));
if (expectedmetatabletype != type::nil) {
if (lua_rawequal(L, -1, index) == 1) {
lua_pop(L, 2);
return true;
}
}
lua_pop(L, 1);
return false;
}
template <type expected, int(*check_func)(lua_State*, int)>
struct basic_check {
template <typename Handler>
static bool check (lua_State* L, int index, Handler&& handler) {
bool success = check_func(L, index) == 1;
if (!success) {
// expected type, actual type
handler(L, index, expected, type_of(L, index));
}
return success;
}
};
template <bool b>
struct check_types {
template <std::size_t I0, std::size_t... I, typename Arg0, typename... Args, typename Handler>
static bool check(types<Arg0, Args...>, std::index_sequence<I0, I...>, lua_State* L, int firstargument, Handler&& handler) {
if (!stack::check<Arg0>(L, firstargument + I0, handler))
return false;
return check(types<Args...>(), std::index_sequence<I...>(), L, firstargument, std::forward<Handler>(handler));
}
template <typename Handler>
static bool check(types<>, std::index_sequence<>, lua_State*, int, Handler&&) {
return true;
}
};
template <>
struct check_types<false> {
template <std::size_t... I, typename... Args, typename Handler>
static bool check(types<Args...>, std::index_sequence<I...>, lua_State*, int, Handler&&) {
return true;
}
};
} // stack_detail
template <typename T, type expected, typename>
struct checker {
template <typename Handler>
static bool check (lua_State* L, int index, 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 <type expected, typename C>
struct checker<type, expected, C> {
template <typename Handler>
static bool check (lua_State*, int, Handler&&) {
return true;
}
};
template <type expected, typename C>
struct checker<nil_t, expected, C> {
template <typename Handler>
static bool check (lua_State* L, int index, Handler&& handler) {
bool success = lua_isnoneornil(L, index);
if (!success) {
// expected type, actual type
handler(L, index, expected, type_of(L, index));
}
return success;
}
};
template <typename T, typename C>
struct checker<T, type::poly, C> {
template <typename Handler>
static bool check (lua_State* L, int index, Handler&& handler) {
bool success = !lua_isnone(L, index);
if (!success) {
// expected type, actual type
handler(L, index, type::none, type_of(L, index));
}
return success;
}
};
template <typename T, typename C>
struct checker<T, type::lightuserdata, C> {
template <typename Handler>
static bool check (lua_State* L, int index, Handler&& handler) {
type t = type_of(L, index);
bool success = t == type::userdata || t == type::lightuserdata;
if (!success) {
// expected type, actual type
handler(L, index, type::lightuserdata, t);
}
return success;
}
};
template <typename T, typename C>
struct checker<non_null<T>, type::userdata, C> : checker<T, lua_type_of<T>::value, C> {};
template <type X, typename C>
struct checker<lua_CFunction, X, C> : stack_detail::basic_check<type::function, lua_iscfunction> {};
template <type X, typename C>
struct checker<std::remove_pointer_t<lua_CFunction>, X, C> : checker<lua_CFunction, X, C> {};
template <type X, typename C>
struct checker<c_closure, X, C> : checker<lua_CFunction, X, C> {};
template <typename T, typename C>
struct checker<T*, type::userdata, C> {
template <typename Handler>
static bool check (lua_State* L, int index, Handler&& handler) {
const type indextype = type_of(L, index);
// Allow nil to be transformed to nullptr
if (indextype == type::nil) {
return true;
}
return checker<T, type::userdata, C>{}.check(types<T>(), L, indextype, index, std::forward<Handler>(handler));
}
};
template <typename T, typename C>
struct checker<T, type::userdata, C> {
template <typename U, typename Handler>
static bool check (types<U>, lua_State* L, type indextype, int index, Handler&& handler) {
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype);
return false;
}
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;
}
if (stack_detail::check_metatable<U>(L))
return true;
if (stack_detail::check_metatable<U*>(L))
return true;
if (stack_detail::check_metatable<unique_usertype<U>>(L))
return true;
#ifndef SOL_NO_EXCEPTIONS
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
void* basecastdata = lua_touserdata(L, -1);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
bool success = detail::catch_check<T>(basecast);
#elif !defined(SOL_NO_RTTI)
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
}
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
bool success = ic(typeid(T));
#else
// Topkek
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
}
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
bool success = ic(detail::id_for<T>::value);
#endif // No Runtime Type Information || Exceptions
lua_pop(L, 2);
if (!success) {
handler(L, index, type::userdata, indextype);
return false;
}
return true;
}
template <typename Handler>
static bool check (lua_State* L, int index, Handler&& handler) {
const type indextype = type_of(L, index);
return check(types<T>(), L, indextype, index, std::forward<Handler>(handler));
}
};
template<typename T, typename Real, typename C>
struct checker<unique_usertype<T, Real>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler) {
return checker<T, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler));
}
};
template<typename T, typename C>
struct checker<std::shared_ptr<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler) {
return checker<unique_usertype<T, std::shared_ptr<T>>, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler));
}
};
template<typename T, typename D, typename C>
struct checker<std::unique_ptr<T, D>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler) {
return checker<unique_usertype<T, std::unique_ptr<T, D>>, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler));
}
};
template<typename T, typename C>
struct checker<std::reference_wrapper<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler) {
return checker<T, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler));
}
};
template<typename... Args, typename C>
struct checker<std::tuple<Args...>, type::poly, C> {
template <std::size_t... I, typename Handler>
static bool apply(std::index_sequence<I...> is, lua_State* L, int index, Handler&& handler) {
index = index < 0 ? lua_absindex(L, index) - ( sizeof...(I) - 1 ) : index;
return stack_detail::check_types<true>{}.check(types<Args...>(), is, L, index, handler);
}
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler) {
return apply(std::index_sequence_for<Args...>(), L, index, std::forward<Handler>(handler));
}
};
template<typename A, typename B, typename C>
struct checker<std::pair<A, B>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler) {
index = index < 0 ? lua_absindex(L, index) - 1 : index;
return stack::check<A>(L, index, handler) && stack::check<B>(L, index + 1, handler);
}
};
} // stack
} // sol
#endif // SOL_STACK_CHECK_HPP

75
sol/stack_check_get.hpp Normal file
View File

@ -0,0 +1,75 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_CHECK_GET_HPP
#define SOL_STACK_CHECK_GET_HPP
#include "stack_core.hpp"
#include "stack_get.hpp"
#include "stack_check.hpp"
#include "optional.hpp"
namespace sol {
namespace stack {
template <typename T, typename>
struct check_getter {
typedef stack_detail::strip_t<T> U;
typedef std::conditional_t<is_proxy_primitive<T>::value, U, U&> R;
template <typename Handler>
static optional<R> get( lua_State* L, int index, Handler&& handler) {
if (!check<T>(L, index, std::forward<Handler>(handler)))
return nullopt;
return stack_detail::unchecked_get<T>(L, index);
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && !std::is_same<T, bool>::value>> {
template <typename Handler>
static optional<T> get( lua_State* L, int index, Handler&& handler) {
int isnum = 0;
lua_Integer value = lua_tointegerx(L, index, &isnum);
if (isnum == 0) {
handler(L, index, type::number, type_of(L, index));
return nullopt;
}
return static_cast<T>(value);
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
template <typename Handler>
static optional<T> get( lua_State* L, int index, Handler&& handler) {
int isnum = 0;
lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum == 0) {
handler(L, index, type::number, type_of(L, index));
return nullopt;
}
return static_cast<T>(value);
}
};
} // stack
} // sol
#endif // SOL_STACK_CHECK_GET_HPP

183
sol/stack_core.hpp Normal file
View File

@ -0,0 +1,183 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_CORE_HPP
#define SOL_STACK_CORE_HPP
#include "types.hpp"
#include "reference.hpp"
#include "userdata.hpp"
#include "tuple.hpp"
#include "traits.hpp"
namespace sol {
namespace detail {
using special_destruct_func = void(*)(void*);
template <typename T, typename Real>
inline void special_destruct(void* memory) {
T** pointerpointer = static_cast<T**>(memory);
special_destruct_func* dx = static_cast<special_destruct_func*>(static_cast<void*>(pointerpointer + 1));
Real* target = static_cast<Real*>(static_cast<void*>(dx + 1));
target->~Real();
}
template <typename T>
inline int unique_destruct(lua_State* L) {
void* memory = lua_touserdata(L, 1);
T** pointerpointer = static_cast<T**>(memory);
special_destruct_func& dx = *static_cast<special_destruct_func*>( static_cast<void*>( pointerpointer + 1 ) );
(dx)(memory);
return 0;
}
} // detail
namespace stack {
template<typename T, bool global = false, typename = void>
struct field_getter;
template<typename T, bool global = false, typename = void>
struct field_setter;
template<typename T, typename = void>
struct getter;
template<typename T, typename = void>
struct popper;
template<typename T, typename = void>
struct pusher;
template<typename T, type = lua_type_of<T>::value, typename = void>
struct checker;
template<typename T, typename = void>
struct check_getter;
namespace stack_detail {
template <typename T>
struct strip {
typedef T type;
};
template <typename T>
struct strip<std::reference_wrapper<T>> {
typedef T& type;
};
template <typename T>
struct strip<non_null<T>> {
typedef T type;
};
template <typename T>
using strip_t = typename strip<T>::type;
const bool default_check_arguments =
#ifdef SOL_CHECK_ARGUMENTS
true;
#else
false;
#endif
template<typename T>
inline decltype(auto) unchecked_get(lua_State* L, int index = -1) {
return getter<meta::Unqualified<T>>{}.get(L, index);
}
} // stack_detail
template<typename T, typename... Args>
inline int push(lua_State* L, T&& t, Args&&... args) {
return pusher<meta::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 int push(lua_State* L, Arg&& arg, Args&&... args) {
return pusher<meta::Unqualified<T>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
inline int multi_push(lua_State*) {
// do nothing
return 0;
}
template<typename T, typename... Args>
inline int multi_push(lua_State* L, T&& t, Args&&... args) {
int pushcount = push(L, std::forward<T>(t));
void(sol::detail::swallow{(pushcount += sol::stack::push(L, std::forward<Args>(args)), 0)... });
return pushcount;
}
template <typename T, typename Handler>
bool check(lua_State* L, int index, Handler&& handler) {
typedef meta::Unqualified<T> Tu;
checker<Tu> c;
// VC++ has a bad warning here: shut it up
(void)c;
return c.check(L, index, std::forward<Handler>(handler));
}
template <typename T>
bool check(lua_State* L, int index = -1) {
auto handler = no_panic;
return check<T>(L, index, handler);
}
template<typename T, typename Handler>
inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler) {
return check_getter<meta::Unqualified<T>>{}.get(L, index, std::forward<Handler>(handler));
}
template<typename T>
inline decltype(auto) check_get(lua_State* L, int index = -1) {
auto handler = no_panic;
return check_get<T>(L, index, handler);
}
template<typename T>
inline decltype(auto) get(lua_State* L, int index = -1) {
#ifdef SOL_CHECK_ARGUMENTS
auto op = check_get<T>(L, index, type_panic);
typedef typename meta::Unqualified<decltype(op)>::value_type U;
return static_cast<U>(*op);
#else
return stack_detail::unchecked_get<T>(L, index);
#endif
}
template<typename T>
inline decltype(auto) pop(lua_State* L) {
return popper<meta::Unqualified<T>>{}.pop(L);
}
template <bool global = false, typename Key>
void get_field(lua_State* L, Key&& key) {
field_getter<meta::Unqualified<Key>, global>{}.get(L, std::forward<Key>(key));
}
template <bool global = false, typename Key>
void get_field(lua_State* L, Key&& key, int tableindex) {
field_getter<meta::Unqualified<Key>, global>{}.get(L, std::forward<Key>(key), tableindex);
}
template <bool global = false, typename Key, typename Value>
void set_field(lua_State* L, Key&& key, Value&& value) {
field_setter<meta::Unqualified<Key>, global>{}.set(L, std::forward<Key>(key), std::forward<Value>(value));
}
template <bool global = false, typename Key, typename Value>
void set_field(lua_State* L, Key&& key, Value&& value, int tableindex) {
field_setter<meta::Unqualified<Key>, global>{}.set(L, std::forward<Key>(key), std::forward<Value>(value), tableindex);
}
} // stack
} // sol
#endif // SOL_STACK_CORE_HPP

138
sol/stack_field.hpp Normal file
View File

@ -0,0 +1,138 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_FIELD_HPP
#define SOL_STACK_FIELD_HPP
#include "stack_core.hpp"
#include "stack_push.hpp"
#include "stack_get.hpp"
#include "stack_check_get.hpp"
namespace sol {
namespace stack {
template <typename T, bool, typename>
struct field_getter {
template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = -2) {
push( L, std::forward<Key>( key ) );
lua_gettable( L, tableindex );
}
};
template <typename... Args, bool b, typename C>
struct field_getter<std::tuple<Args...>, b, C> {
template <std::size_t... I, typename Keys>
void apply(std::index_sequence<I...>, lua_State* L, Keys&& keys, int tableindex) {
tableindex = lua_absindex(L, tableindex);
void(detail::swallow{ (get_field<I < 1 && b>(L, detail::forward_get<I>(keys), tableindex), 0)... });
reference saved(L, -1);
lua_pop(L, static_cast<int>(sizeof...(I)));
saved.push();
}
template <typename Keys>
void get(lua_State* L, Keys&& keys, int tableindex = -2) {
apply(std::index_sequence_for<Args...>(), L, std::forward<Keys>(keys), tableindex);
}
};
template <typename A, typename B, bool b, typename C>
struct field_getter<std::pair<A, B>, b, C> {
template <typename Keys>
void get(lua_State* L, Keys&& keys, int tableindex = -2) {
tableindex = lua_absindex(L, tableindex);
get_field<b>(L, detail::forward_get<0>(keys), tableindex);
get_field<false>(L, detail::forward_get<1>(keys), tableindex + 1);
reference saved(L, -1);
lua_pop(L, static_cast<int>(2));
saved.push();
}
};
template <typename T>
struct field_getter<T, true, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key>
void get(lua_State* L, Key&& key, int = -1) {
lua_getglobal(L, &key[0]);
}
};
template <typename T>
struct field_getter<T, false, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = -1) {
lua_getfield(L, tableindex, &key[0]);
}
};
#if SOL_LUA_VERSION >= 503
template <typename T>
struct field_getter<T, false, std::enable_if_t<std::is_integral<T>::value>> {
template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = -1) {
lua_geti(L, tableindex, static_cast<lua_Integer>(key));
}
};
#endif // Lua 5.3.x
template <typename T, bool, typename>
struct field_setter {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -3) {
push(L, std::forward<Key>(key));
push(L, std::forward<Value>(value));
lua_settable(L, tableindex);
}
};
template <typename T>
struct field_setter<T, true, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int = -2) {
push(L, std::forward<Value>(value));
lua_setglobal(L, &key[0]);
}
};
template <typename T>
struct field_setter<T, false, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) {
push(L, std::forward<Value>(value));
lua_setfield(L, tableindex, &key[0]);
}
};
#if SOL_LUA_VERSION >= 503
template <typename T>
struct field_setter<T, false, std::enable_if_t<std::is_integral<T>::value>> {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) {
push(L, std::forward<Value>(value));
lua_seti(L, tableindex, static_cast<lua_Integer>(key));
}
};
#endif // Lua 5.3.x
} // stack
} // sol
#endif // SOL_STACK_FIELD_HPP

260
sol/stack_get.hpp Normal file
View File

@ -0,0 +1,260 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_GET_HPP
#define SOL_STACK_GET_HPP
#include "stack_core.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include "overload.hpp"
#include "error.hpp"
#include <memory>
#include <functional>
#include <utility>
namespace sol {
namespace stack {
template<typename T, typename>
struct getter {
static T& get(lua_State* L, int index = -1) {
return getter<T&>{}.get(L, index);
}
};
template<typename T>
struct getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
static T get(lua_State* L, int index = -1) {
return static_cast<T>(lua_tonumber(L, index));
}
};
template<typename T>
struct getter<T, std::enable_if_t<meta::And<std::is_integral<T>, std::is_signed<T>>::value>> {
static T get(lua_State* L, int index = -1) {
return static_cast<T>(lua_tointeger(L, index));
}
};
template<typename T>
struct getter<T, std::enable_if_t<meta::And<std::is_integral<T>, std::is_unsigned<T>>::value>> {
static T get(lua_State* L, int index = -1) {
return static_cast<T>(lua_tointeger(L, index));
}
};
template<typename T>
struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
static T get(lua_State* L, int index = -1) {
return T(L, index);
}
};
template<>
struct getter<userdata_value> {
static userdata_value get(lua_State* L, int index = -1) {
return userdata_value( lua_touserdata(L, index) );
}
};
template<>
struct getter<light_userdata_value> {
static light_userdata_value get(lua_State* L, int index = -1) {
return light_userdata_value( lua_touserdata(L, index) );
}
};
template<>
struct getter<type> {
static type get(lua_State *L, int index){
return static_cast<type>(lua_type(L, index));
}
};
template<>
struct getter<bool> {
static bool get(lua_State* L, int index) {
return lua_toboolean(L, index) != 0;
}
};
template<>
struct getter<std::string> {
static std::string get(lua_State* L, int index = -1) {
std::size_t len;
auto str = lua_tolstring(L, index, &len);
return { str, len };
}
};
template<>
struct getter<const char*> {
static const char* get(lua_State* L, int index = -1) {
return lua_tostring(L, index);
}
};
template<>
struct getter<nil_t> {
static nil_t get(lua_State*, int = -1) {
return nil_t{ };
}
};
template<>
struct getter<lua_CFunction> {
static lua_CFunction get(lua_State* L, int index = -1) {
return lua_tocfunction(L, index);
}
};
template<>
struct getter<c_closure> {
static c_closure get(lua_State* L, int index = -1) {
return c_closure(lua_tocfunction(L, index), -1);
}
};
template<>
struct getter<void*> {
static void* get(lua_State* L, int index = -1) {
return lua_touserdata(L, index);
}
};
template<typename T>
struct getter<T*> {
static T* get_no_nil(lua_State* L, int index = -1) {
void** pudata = static_cast<void**>(lua_touserdata(L, index));
void* udata = *pudata;
return get_no_nil_from(L, udata, index);
}
static T* get_no_nil_from(lua_State* L, void* udata, int index = -1) {
#ifndef SOL_NO_EXCEPTIONS
if (luaL_getmetafield(L, index, &detail::base_class_check_key()[0]) != 0) {
void* basecastdata = lua_touserdata(L, -1);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
// use the casting function to properly adjust the pointer for the desired T
udata = detail::catch_cast<T>(udata, basecast);
lua_pop(L, 1);
}
#elif !defined(SOL_NO_RTTI)
if (luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata;
// use the casting function to properly adjust the pointer for the desired T
udata = ic(udata, typeid(T));
lua_pop(L, 1);
}
#else
// Lol, you motherfucker
if (luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata;
// use the casting function to properly adjust the pointer for the desired T
udata = ic(udata, detail::id_for<T>::value);
lua_pop(L, 1);
}
#endif // No Runtime Type Information || Exceptions
T* obj = static_cast<T*>(udata);
return obj;
}
static T* get(lua_State* L, int index = -1) {
type t = type_of(L, index);
if (t == type::nil)
return nullptr;
return get_no_nil(L, index);
}
};
template<typename T, typename Real>
struct getter<unique_usertype<T, Real>> {
static Real& get(lua_State* L, int index = -1) {
T** pref = static_cast<T**>(lua_touserdata(L, index));
detail::special_destruct_func* fx = static_cast<detail::special_destruct_func*>(static_cast<void*>(pref + 1));
Real* mem = static_cast<Real*>(static_cast<void*>(fx + 1));
return *mem;
}
};
template<typename T>
struct getter<non_null<T*>> {
static T* get(lua_State* L, int index = -1) {
return getter<T*>::get_no_nil(L, index);
}
};
template<typename T>
struct getter<T&> {
static T& get(lua_State* L, int index = -1) {
return *getter<T*>::get_no_nil(L, index);
}
};
template<typename T>
struct getter<std::shared_ptr<T>> {
static std::shared_ptr<T>& get(lua_State* L, int index = -1) {
return getter<unique_usertype<T, std::shared_ptr<T>>>::get(L, index);
}
};
template<typename T, typename D>
struct getter<std::unique_ptr<T, D>> {
static std::unique_ptr<T, D>& get(lua_State* L, int index = -1) {
return getter<unique_usertype<T, std::unique_ptr<T, D>>>::get(L, index);
}
};
template<typename T>
struct getter<std::reference_wrapper<T>> {
static T& get(lua_State* L, int index = -1) {
return getter<T&>{}.get(L, index);
}
};
template<typename... Args>
struct getter<std::tuple<Args...>> {
template <std::size_t... I>
static decltype(auto) apply(std::index_sequence<I...>, lua_State* L, int index = -1) {
index = index < 0 ? lua_absindex(L, index) - ( sizeof...(I) - 1 ) : index;
return std::tuple<decltype(stack::get<Args>(L, index + I))...>(stack::get<Args>(L, index + I)...);
}
static decltype(auto) get(lua_State* L, int index = -1) {
return apply(std::index_sequence_for<Args...>(), L, index);
}
};
template<typename A, typename B>
struct getter<std::pair<A, B>> {
static decltype(auto) get(lua_State* L, int index = -1) {
index = index < 0 ? lua_absindex(L, index) - 1 : index;
return std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))>(stack::get<A>(L, index), stack::get<B>(L, index + 1));
}
};
} // stack
} // sol
#endif // SOL_STACK_GET_HPP

61
sol/stack_pop.hpp Normal file
View File

@ -0,0 +1,61 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_POP_HPP
#define SOL_STACK_POP_HPP
#include "stack_core.hpp"
#include "stack_get.hpp"
#include <utility>
#include <tuple>
namespace sol {
namespace stack {
template <typename T, typename>
struct popper {
inline static decltype(auto) pop(lua_State* L) {
decltype(auto) r = get<T>(L);
lua_pop(L, 1);
return r;
}
};
template <typename... Args>
struct popper<std::tuple<Args...>> {
inline static decltype(auto) pop(lua_State* L) {
decltype(auto) r = get<std::tuple<Args...>>(L);
lua_pop(L, static_cast<int>(sizeof...(Args)));
return r;
}
};
template <typename A, typename B>
struct popper<std::pair<A, B>> {
inline static decltype(auto) pop(lua_State* L) {
decltype(auto) r = get<std::pair<A, B>>(L);
lua_pop(L, 2);
return r;
}
};
} // stack
} // sol
#endif // SOL_STACK_POP_HPP

297
sol/stack_push.hpp Normal file
View File

@ -0,0 +1,297 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_PUSH_HPP
#define SOL_STACK_PUSH_HPP
#include "stack_core.hpp"
#include "raii.hpp"
#include <memory>
namespace sol {
namespace stack {
template<typename T, typename>
struct pusher {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
// Basically, we store all user-data like this:
// If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new
// data in the first sizeof(T*) bytes, and then however many bytes it takes to
// do the actual object. Things that are std::ref or plain T* are stored as
// just the sizeof(T*), and nothing else.
T** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
T*& referencereference = *pointerpointer;
T* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1);
referencereference = allocationtarget;
std::allocator<T> alloc{};
alloc.construct(allocationtarget, std::forward<Args>(args)...);
luaL_getmetatable(L, &usertype_traits<T>::metatable[0]);
lua_setmetatable(L, -2);
return 1;
}
};
template<typename T>
struct pusher<T*> {
static int push(lua_State* L, T* obj) {
if (obj == nullptr)
return stack::push(L, nil);
T** pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));
*pref = obj;
luaL_getmetatable(L, &usertype_traits<T*>::metatable[0]);
lua_setmetatable(L, -2);
return 1;
}
};
template<typename T, typename Real>
struct pusher<unique_usertype<T, Real>> {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
T** pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(detail::special_destruct_func) + sizeof(Real)));
detail::special_destruct_func* fx = static_cast<detail::special_destruct_func*>(static_cast<void*>(pref + 1));
Real* mem = static_cast<Real*>(static_cast<void*>(fx + 1));
*fx = detail::special_destruct<T, Real>;
detail::default_construct::construct(mem, std::forward<Args>(args)...);
*pref = std::addressof(detail::deref(*mem));
if (luaL_newmetatable(L, &usertype_traits<unique_usertype<T>>::metatable[0]) == 1) {
set_field(L, "__gc", detail::unique_destruct<T>);
}
lua_setmetatable(L, -2);
return 1;
}
};
template<typename T>
struct pusher<T, std::enable_if_t<is_unique_usertype<T>::value>> {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
typedef typename is_unique_usertype<T>::metatable_type meta_type;
return stack::push<unique_usertype<meta_type, T>>(L, std::forward<Args>(args)...);
}
};
template<typename T, typename D>
struct pusher<std::unique_ptr<T, D>> {
static int push(lua_State* L, std::unique_ptr<T, D> obj) {
if (obj == nullptr)
return stack::push(L, nil);
return stack::push<unique_usertype<T, std::unique_ptr<T, D>>>(L, std::move(obj));
}
};
template<typename T>
struct pusher<std::shared_ptr<T>> {
template <typename S>
static int push(lua_State* L, S&& s) {
if (s == nullptr)
return stack::push(L, nil);
return stack::push<unique_usertype<T, std::shared_ptr<T>>>(L, std::forward<S>(s));
}
};
template<typename T>
struct pusher<std::reference_wrapper<T>> {
static int push(lua_State* L, const std::reference_wrapper<T>& t) {
return stack::push(L, std::addressof(detail::deref(t.get())));
}
};
template<typename T>
struct pusher<T, std::enable_if_t<std::is_floating_point<T>::value>> {
static int push(lua_State* L, const T& value) {
lua_pushnumber(L, value);
return 1;
}
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::And<std::is_integral<T>, std::is_signed<T>>::value>> {
static int push(lua_State* L, const T& value) {
lua_pushinteger(L, static_cast<lua_Integer>(value));
return 1;
}
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::And<std::is_integral<T>, std::is_unsigned<T>>::value>> {
static int push(lua_State* L, const T& value) {
typedef std::make_signed_t<T> signed_int;
return stack::push(L, static_cast<signed_int>(value));
}
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::And<meta::has_begin_end<T>, meta::Not<meta::has_key_value_pair<T>>, meta::Not<std::is_base_of<reference, T>>>::value>> {
static int push(lua_State* L, const T& cont) {
lua_createtable(L, static_cast<int>(cont.size()), 0);
int tableindex = lua_gettop(L);
unsigned index = 1;
for(auto&& i : cont) {
set_field(L, index++, i, tableindex);
}
return 1;
}
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::And<meta::has_begin_end<T>, meta::has_key_value_pair<T>, meta::Not<std::is_base_of<reference, T>>>::value>> {
static int push(lua_State* L, const T& cont) {
lua_createtable(L, static_cast<int>(cont.size()), 0);
int tableindex = lua_gettop(L);
for(auto&& pair : cont) {
set_field(L, pair.first, pair.second, tableindex);
}
return 1;
}
};
template<typename T>
struct pusher<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
static int push(lua_State*, T& ref) {
return ref.push();
}
static int push(lua_State*, T&& ref) {
return ref.push();
}
};
template<>
struct pusher<bool> {
static int push(lua_State* L, bool b) {
lua_pushboolean(L, b);
return 1;
}
};
template<>
struct pusher<nil_t> {
static int push(lua_State* L, nil_t) {
lua_pushnil(L);
return 1;
}
};
template<>
struct pusher<std::remove_pointer_t<lua_CFunction>> {
static int push(lua_State* L, lua_CFunction func, int n = 0) {
lua_pushcclosure(L, func, n);
return 1;
}
};
template<>
struct pusher<lua_CFunction> {
static int push(lua_State* L, lua_CFunction func, int n = 0) {
lua_pushcclosure(L, func, n);
return 1;
}
};
template<>
struct pusher<c_closure> {
static int push(lua_State* L, c_closure closure) {
lua_pushcclosure(L, closure.c_function, closure.upvalues);
return 1;
}
};
template<>
struct pusher<void*> {
static int push(lua_State* L, void* userdata) {
lua_pushlightuserdata(L, userdata);
return 1;
}
};
template<>
struct pusher<light_userdata_value> {
static int push(lua_State* L, light_userdata_value userdata) {
lua_pushlightuserdata(L, userdata);
return 1;
}
};
template<>
struct pusher<userdata_value> {
static int push(lua_State* L, userdata_value data) {
void** ud = static_cast<void**>(lua_newuserdata(L, sizeof(void*)));
*ud = data.value;
return 1;
}
};
template<>
struct pusher<const char*> {
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 int push(lua_State* L, const char (&str)[N]) {
lua_pushlstring(L, str, N - 1);
return 1;
}
};
template<>
struct pusher<std::string> {
static int push(lua_State* L, const std::string& str) {
lua_pushlstring(L, str.c_str(), str.size());
return 1;
}
};
template<typename... Args>
struct pusher<std::tuple<Args...>> {
template <std::size_t... I, typename T>
static int push(std::index_sequence<I...>, lua_State* L, T&& t) {
int pushcount = 0;
(void)detail::swallow{ 0, (pushcount += stack::push(L,
detail::forward_get<I>(t)
), 0)... };
return pushcount;
}
template <typename T>
static int push(lua_State* L, T&& t) {
return push(std::index_sequence_for<Args...>(), L, std::forward<T>(t));
}
};
template<typename A, typename B>
struct pusher<std::pair<A, B>> {
template <typename T>
static int push(lua_State* L, T&& t) {
int pushcount = stack::push(L, detail::forward_get<0>(t));
pushcount += stack::push(L, detail::forward_get<1>(t));
return pushcount;
}
};
} // stack
} // sol
#endif // SOL_STACK_PUSH_HPP

View File

@ -255,6 +255,18 @@ public:
return *this;
}
template<typename... Args, typename R, typename C, typename Key>
state_view& set_function(Key&& key, R (C::*mem_ptr)(Args...)) {
global.set_function(std::forward<Key>(key), mem_ptr);
return *this;
}
template<typename Sig, typename C, typename Key>
state_view& set_function(Key&& key, Sig C::* mem_ptr) {
global.set_function(std::forward<Key>(key), mem_ptr);
return *this;
}
template<typename... Args, typename R, typename C, typename T, typename Key>
state_view& set_function(Key&& key, R (C::*mem_ptr)(Args...), T&& obj) {
global.set_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
@ -292,6 +304,11 @@ public:
return create_table(lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
}
template <typename... Args>
table create_table_with(Args&&... args) {
return create_table_with(lua_state(), std::forward<Args>(args)...);
}
static inline table create_table(lua_State* L, int narr = 0, int nrec = 0) {
return global_table::create(L, narr, nrec);
}
@ -300,6 +317,11 @@ public:
static inline table create_table(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
return global_table::create(L, narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
}
template <typename... Args>
static inline table create_table_with(lua_State* L, Args&&... args) {
return global_table::create_with(L, std::forward<Args>(args)...);
}
};
} // sol

View File

@ -62,13 +62,13 @@ class table_core : public reference {
}
}
template<typename... Ret, std::size_t... I, typename Keys>
auto tuple_get( types<Ret...>, std::index_sequence<I...>, Keys&& keys ) const
-> decltype(stack::pop<std::tuple<Ret...>>(nullptr)){
template<typename Ret0, typename Ret1, typename... Ret, std::size_t... I, typename Keys>
auto tuple_get( types<Ret0, Ret1, Ret...>, std::index_sequence<I...>, Keys&& keys ) const
-> decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)){
auto pp = stack::push_pop<is_global<meta::tuple_element_t<I, Keys>...>::value>(*this);
int tableindex = lua_gettop(lua_state());
void(detail::swallow{ ( stack::get_field<top_level>(lua_state(), detail::forward_get<I>(keys), tableindex), 0)... });
return stack::pop<std::tuple<Ret...>>( lua_state() );
return stack::pop<std::tuple<Ret0, Ret1, Ret...>>( lua_state() );
}
template<typename Ret, std::size_t I, typename Keys>
@ -241,6 +241,18 @@ public:
return *this;
}
template<typename... Args, typename R, typename C, typename Key>
table_core& set_function( Key&& key, R( C::*mem_ptr )( Args... ) ) {
set_resolved_function( std::forward<Key>( key ), mem_ptr );
return *this;
}
template<typename Sig, typename C, typename Key>
table_core& set_function( Key&& key, Sig C::* mem_ptr ) {
set_resolved_function( std::forward<Key>( key ), mem_ptr );
return *this;
}
template<typename... Sig, typename Fx, typename Key>
table_core& set_function( Key&& key, Fx&& fx ) {
set_fx( types<Sig...>( ), std::forward<Key>( key ), std::forward<Fx>( fx ) );
@ -271,6 +283,37 @@ private:
}
public:
static inline table create(lua_State* L, int narr = 0, int nrec = 0) {
lua_createtable(L, narr, nrec);
table result(L);
lua_pop(L, 1);
return result;
}
template <typename Key, typename Value, typename... Args>
static inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
lua_createtable(L, narr, nrec);
table result(L);
result.set(std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
lua_pop(L, 1);
return result;
}
template <typename... Args>
static inline table create_with(lua_State* L, Args&&... args) {
static const int narr = static_cast<int>(meta::count_if_2_pack<std::is_integral, Args...>::value);
return create(L, narr, static_cast<int>((sizeof...(Args) / 2) - narr), std::forward<Args>(args)...);
}
table create(int narr = 0, int nrec = 0) {
return create(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)...);
}
template <typename Name>
table create(Name&& name, int narr = 0, int nrec = 0) {
table x = create(lua_state(), narr, nrec);
@ -285,31 +328,9 @@ public:
return x;
}
table create(int narr = 0, int nrec = 0) {
return create(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)...);
}
static inline table create(lua_State* L, int narr = 0, int nrec = 0) {
lua_createtable(L, narr, nrec);
table result(L);
lua_pop(L, 1);
return result;
}
template <typename Key, typename Value, typename... Args>
static inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
if (narr == 0) narr = static_cast<int>(meta::count_if_pack<std::is_integral, Key, Value, Args...>::value);
if (nrec == 0) nrec = static_cast<int>(( sizeof...(Args) + 2 ) - narr);
lua_createtable(L, narr, nrec);
table result(L);
result.set(std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
lua_pop(L, 1);
return result;
template <typename... Args>
table create_with(Args&&... args) {
return create_with(lua_state(), std::forward<Args>(args)...);
}
};
} // sol

View File

@ -142,12 +142,25 @@ namespace meta_detail {
template<std::size_t I, template<typename...> class Pred, typename... Ts>
struct count_if_pack {};
template<std::size_t I, template<typename...> class Pred, typename T, typename... Ts>
struct count_if_pack<I, Pred, T, Ts...> : std::conditional_t<sizeof...(Ts) == 0, std::integral_constant<std::size_t, I>, count_if_pack<I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>> { };
struct count_if_pack<I, Pred, T, Ts...> : std::conditional_t<sizeof...(Ts) == 0,
std::integral_constant<std::size_t, I + static_cast<std::size_t>(Pred<T>::value)>,
count_if_pack<I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>
> { };
template<std::size_t I, template<typename...> class Pred, typename... Ts>
struct count_if_2_pack {};
template<std::size_t I, template<typename...> class Pred, typename T, typename U, typename... Ts>
struct count_if_2_pack<I, Pred, T, U, Ts...> : std::conditional_t<sizeof...(Ts) == 0,
std::integral_constant<std::size_t, I + static_cast<std::size_t>(Pred<T>::value)>,
count_if_2_pack<I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>
> { };
} // meta_detail
template<template<typename...> class Pred, typename... Ts>
struct count_if_pack : meta_detail::count_if_pack<0, Pred, Ts...> { };
template<template<typename...> class Pred, typename... Ts>
struct count_if_2_pack : meta_detail::count_if_2_pack<0, Pred, Ts...> { };
template<typename... Args>
struct return_type {
typedef std::tuple<Args...> type;

View File

@ -34,9 +34,9 @@ inline int static_trampoline (lua_State* L) {
return f(L);
}
template <typename Fx>
inline int trampoline(lua_State* L, Fx&& f) {
return f(L);
template <typename Fx, typename... Args>
inline int trampoline(lua_State* L, Fx&& f, Args&&... args) {
return f(L, std::forward<Args>(args)...);
}
inline int c_trampoline(lua_State* L, lua_CFunction f) {
@ -48,7 +48,7 @@ inline int static_trampoline (lua_State* L) {
try {
return f(L);
}
catch (const char *s) { // Catch and convert exceptions.
catch (const char *s) {
lua_pushstring(L, s);
}
catch (const std::exception& e) {
@ -60,12 +60,12 @@ inline int static_trampoline (lua_State* L) {
return lua_error(L);
}
template <typename Fx>
inline int trampoline(lua_State* L, Fx&& f) {
template <typename Fx, typename... Args>
inline int trampoline(lua_State* L, Fx&& f, Args&&... args) {
try {
return f(L);
return f(L, std::forward<Args>(args)...);
}
catch (const char *s) { // Catch and convert exceptions.
catch (const char *s) {
lua_pushstring(L, s);
}
catch (const std::exception& e) {
@ -232,9 +232,18 @@ 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<reference> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<object> : std::integral_constant<type, type::poly> {};
template <typename... Args>
struct lua_type_of<std::tuple<Args...>> : std::integral_constant<type, type::poly> {};
template <typename A, typename B>
struct lua_type_of<std::pair<A, B>> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<light_userdata_value> : std::integral_constant<type, type::lightuserdata> {};
@ -275,7 +284,18 @@ template <typename T>
struct lua_type_of<T, std::enable_if_t<std::is_enum<T>::value>> : std::integral_constant<type, type::number> {};
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> { };
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> { };
template <typename T>
struct is_lua_primitive<T*> : std::true_type {};
template <>
struct is_lua_primitive<userdata_value> : std::true_type {};
template <>
struct is_lua_primitive<light_userdata_value> : std::true_type {};
template <typename T>
struct is_lua_primitive<non_null<T>> : is_lua_primitive<T*> {};
template <typename T>
struct is_proxy_primitive : is_lua_primitive<T> { };

View File

@ -120,6 +120,21 @@ enum class stage {
uniquemeta,
};
template<bool releasemem = false, typename TCont>
inline int push_upvalues(lua_State* L, TCont&& cont) {
int n = 0;
for(auto& c : cont) {
if(releasemem) {
stack::push<light_userdata_value>(L, c.release());
}
else {
stack::push<light_userdata_value>(L, c.get());
}
++n;
}
return n;
}
template<typename T, stage metastage>
inline void push_metatable(lua_State* L, bool needsindexfunction, std::vector<std::unique_ptr<function_detail::base_function>>& funcs, std::vector<luaL_Reg>& functable, std::vector<luaL_Reg>& metafunctable, void* baseclasscheck, void* baseclasscast) {
static const auto& gcname = meta_function_names[static_cast<int>(meta_function::garbage_collect)];
@ -137,7 +152,7 @@ inline void push_metatable(lua_State* L, bool needsindexfunction, std::vector<st
return;
}
// Metamethods directly on the metatable itself
int metaup = stack::stack_detail::push_upvalues(L, funcs);
int metaup = push_upvalues(L, funcs);
switch (metastage) {
case stage::uniquemeta: {
if (gcname != metafunctable.back().name) {
@ -178,7 +193,7 @@ inline void push_metatable(lua_State* L, bool needsindexfunction, std::vector<st
// Otherwise, we use quick, fast table indexing for methods
// gives us performance boost in calling them
lua_createtable(L, 0, static_cast<int>(functable.size()));
int up = stack::stack_detail::push_upvalues(L, funcs);
int up = push_upvalues(L, funcs);
functable.push_back({nullptr, nullptr});
luaL_setfuncs(L, functable.data(), up);
functable.pop_back();
@ -192,7 +207,7 @@ inline void set_global_deleter(lua_State* L, lua_CFunction cleanup, Functions&&
// even if the user calls collectgarbage(), weirdly enough
lua_createtable(L, 0, 0); // global table that sits at toplevel
lua_createtable(L, 0, 1); // metatable for the global table
int up = stack::stack_detail::push_upvalues<true>(L, functions);
int up = push_upvalues<true>(L, functions);
stack::set_field(L, "__gc", c_closure(cleanup, up));
lua_setmetatable(L, -2);
// gctable name by default has ♻ part of it

View File

@ -372,13 +372,13 @@ TEST_CASE("simple/call-c++-function", "C++ function is called from lua") {
TEST_CASE("simple/call-lambda", "A C++ lambda is exposed to lua and called") {
sol::state lua;
int x = 0;
int a = 0;
lua.set_function("foo", [&x] { x = 1; });
lua.set_function("foo", [&a] { a = 1; });
lua.script("foo()");
REQUIRE(x == 1);
REQUIRE(a == 1);
}
TEST_CASE("advanced/get-and-call", "Checks for lambdas returning values after a get operation") {
@ -537,6 +537,17 @@ TEST_CASE("tables/create-local-named", "Check if creating a table is kosher") {
REQUIRE((testtable[3] == 4));
}
TEST_CASE("tables/create-with-local", "Check if creating a table is kosher") {
sol::state lua;
lua["testtable"] = lua.create_table_with("Woof", "Bark", 1, 2, 3, 4);
sol::object testobj = lua["testtable"];
REQUIRE(testobj.is<sol::table>());
sol::table testtable = testobj.as<sol::table>();
REQUIRE((testtable["Woof"] == std::string("Bark")));
REQUIRE((testtable[1] == 2));
REQUIRE((testtable[3] == 4));
}
TEST_CASE("tables/functions-variables", "Check if tables and function calls work as intended") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::os);