Fix up the API; prepare for release.

This commit is contained in:
ThePhD 2016-03-11 11:34:44 -05:00
parent 5d722af1b0
commit 1a9c7484b1
24 changed files with 655 additions and 317 deletions

View File

@ -39,6 +39,7 @@ cxx = os.environ.get('CXX', "g++")
parser = argparse.ArgumentParser()
parser.add_argument('--debug', action='store_true', help='compile with debug flags')
parser.add_argument('--cxx', metavar='<compiler>', help='compiler name to use (default: env.CXX=%s)' % cxx, default=cxx)
parser.add_argument('--cxx-flags', help='additional flags passed to the compiler', default='')
parser.add_argument('--ci', action='store_true', help=argparse.SUPPRESS)
parser.add_argument('--testing', action='store_true', help=argparse.SUPPRESS)
parser.add_argument('--lua-lib', help='lua library name (without the lib on *nix).', default='lua')
@ -55,6 +56,7 @@ args = parser.parse_args()
include = [ '.', './include' ]
depends = [os.path.join('Catch', 'include')]
cxxflags = [ '-Wall', '-Wextra', '-pedantic', '-pedantic-errors', '-std=c++14' ]
cxxflags.extend([p for p in re.split("( |\\\".*?\\\"|'.*?')", args.cxx_flags) if p.strip()])
ldflags = []
script_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
sol_dir = os.path.join(script_dir, 'sol')

View File

@ -24,6 +24,7 @@
#include "sol/state.hpp"
#include "sol/object.hpp"
#include "sol/userdata.hpp"
#include "sol/function.hpp"
#include "sol/coroutine.hpp"

View File

@ -71,26 +71,26 @@ private:
}
public:
coroutine(lua_State* L, int index = -1) : reference(L, index) {}
coroutine() = default;
coroutine(const coroutine&) = default;
coroutine& operator=(const coroutine&) = default;
coroutine(lua_State* L, int index = -1) noexcept : reference(L, index) {}
coroutine() noexcept = default;
coroutine(const coroutine&) noexcept = default;
coroutine& operator=(const coroutine&) noexcept = default;
call_status status() const {
call_status status() const noexcept {
return stats;
}
bool error() const {
bool error() const noexcept {
call_status cs = status();
return cs != call_status::ok && cs != call_status::yielded;
}
bool runnable () const {
bool runnable () const noexcept {
return valid()
&& (status() == call_status::yielded);
}
explicit operator bool() const {
explicit operator bool() const noexcept {
return runnable();
}
@ -107,7 +107,7 @@ public:
template<typename... Ret, typename... Args>
decltype(auto) call( Args&&... args ) {
push();
int pushcount = stack::push_args( lua_state(), std::forward<Args>( args )... );
int pushcount = stack::multi_push( lua_state(), std::forward<Args>( args )... );
return invoke( types<Ret...>( ), std::index_sequence_for<Ret...>(), pushcount );
}
};

View File

@ -32,6 +32,7 @@
namespace sol {
namespace detail {
#ifndef SOL_NO_RTTI
#ifdef _MSC_VER
inline std::string get_type_name(const std::type_info& id) {
return id.name();
@ -49,9 +50,66 @@ inline std::string get_type_name(const std::type_info& id) {
#else
#error Compiler not supported for demangling
#endif // compilers
#else
#ifdef _MSC_VER
template <typename T>
inline std::string get_type_name() {
std::string name = __FUNCSIG__;
std::size_t start = name.find_last_of('<');
std::size_t end = name.find_last_of('>');
if (end == std::string::npos)
end = name.size();
if (start == std::string::npos)
start = 0;
if (start < name.size() - 1)
start += 1;
name = name.substr(start, end - start);
return name;
}
inline std::string demangle(const std::type_info& id) {
std::string realname = get_type_name(id);
#elif defined(__GNUC__)
template <typename T>
inline std::string get_type_name() {
std::string name = __PRETTY_FUNCTION__;
std::size_t start = name.find_first_of('=');
std::size_t end = name.find_last_of(';');
if (end == std::string::npos)
end = name.size();
if (start == std::string::npos)
start = 0;
if (start < name.size() - 1)
start += 2;
name = name.substr(start, end - start);
return name;
}
#elif defined(__clang__)
template <typename T>
inline std::string get_type_name() {
std::string name = __PRETTY_FUNCTION__;
std::size_t start = name.find_last_of('[');
start = name.find_first_of('=', start);
std::size_t end = name.find_last_of(']');
if (end == std::string::npos)
end = name.size();
if (start == std::string::npos)
start = 0;
if (start < name.size() - 1)
start += 1;
name = name.substr(start, end - start);
return name;
}
#else
#error Compiler not supported for demangling
#endif // compilers
#endif // No Runtime Type information
template <typename T>
inline std::string demangle() {
#ifndef SOL_NO_RTTI
std::string realname = get_type_name(typeid(T));
#else
std::string realname = get_type_name<T>();
#endif // No Runtime Type Information
const static std::array<std::string, 2> removals = {{ "struct ", "class " }};
const static std::array<std::string, 2> replacements = {{ "::", "_" }};
for(std::size_t r = 0; r < removals.size(); ++r) {

View File

@ -92,7 +92,7 @@ public:
template<typename... Ret, typename... Args>
decltype(auto) call( Args&&... args ) const {
push( );
int pushcount = stack::push_args( lua_state( ), std::forward<Args>( args )... );
int pushcount = stack::multi_push( lua_state( ), std::forward<Args>( args )... );
return invoke( types<Ret...>( ), std::index_sequence_for<Ret...>(), pushcount );
}
};

View File

@ -41,10 +41,10 @@ struct constructor_match {
constructor_match(T* obj) : obj(obj) {}
template <bool b, typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(meta::Bool<b>, types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
default_construct func{};
return stack::call_into_lua<b ? false : stack::stack_detail::default_check_arguments>(r, a, func, L, start, obj);
return stack::call_into_lua<false>(r, a, func, L, start, obj);
}
};
} // detail
@ -86,11 +86,7 @@ inline int construct(lua_State* L) {
template <typename T>
inline int destruct(lua_State* L) {
userdata udata = stack::get<userdata>(L, 1);
// The first sizeof(T*) bytes are the reference: the rest is
// the actual data itself (if there is a reference at all)
T** pobj = reinterpret_cast<T**>(udata.value);
T*& obj = *pobj;
T* obj = stack::get<non_null<T*>>(L, 1);
std::allocator<T> alloc{};
alloc.destroy(obj);
return 0;
@ -109,8 +105,8 @@ struct usertype_constructor_function : base_function {
usertype_constructor_function(Functions... fxs) : overloads(fxs...) {}
template <bool b, typename Fx, std::size_t I, typename... R, typename... Args>
int call(meta::Bool<b>, types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int call(types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
static const auto& meta = usertype_traits<T>::metatable;
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
T*& referencepointer = *pointerpointer;
@ -120,7 +116,7 @@ struct usertype_constructor_function : base_function {
userdataref.pop();
auto& func = std::get<I>(overloads);
stack::call_into_lua<b ? false : stack::stack_detail::default_check_arguments>(r, a, func, L, start, function_detail::implicit_wrapper<T>(obj));
stack::call_into_lua<false>(r, a, func, L, start, function_detail::implicit_wrapper<T>(obj));
userdataref.push();
luaL_getmetatable(L, &meta[0]);

View File

@ -205,10 +205,10 @@ static void func_gc(std::true_type, lua_State*) {
template <std::size_t limit>
static void func_gc(std::false_type, lua_State* L) {
for (std::size_t i = 0; i < limit; ++i) {
upvalue up = stack::get<upvalue>(L, static_cast<int>(i + 1));
if (up.value == nullptr)
void* value = stack::get<light_userdata_value>(L, up_value_index(static_cast<int>(i + 1)));
if (value == nullptr)
continue;
base_function* obj = static_cast<base_function*>(up.value);
base_function* obj = static_cast<base_function*>(value);
std::allocator<base_function> alloc{};
alloc.destroy(obj);
alloc.deallocate(obj, 1);
@ -216,19 +216,21 @@ static void func_gc(std::false_type, lua_State* L) {
}
inline int call(lua_State* L) {
void** pinheritancedata = static_cast<void**>(stack::get<upvalue>(L, 1).value);
void* ludata = stack::get<light_userdata_value>(L, up_value_index(1));
void** pinheritancedata = static_cast<void**>(ludata);
return base_call(L, *pinheritancedata);
}
inline int gc(lua_State* L) {
void** pudata = static_cast<void**>(stack::get<userdata>(L, 1).value);
void* udata = stack::get<userdata_value>(L, 1);
void** pudata = static_cast<void**>(udata);
return base_gc(L, *pudata);
}
template<std::size_t I>
inline int usertype_call(lua_State* L) {
// Zero-based template parameter, but upvalues start at 1
return base_call(L, stack::get<upvalue>(L, I + 1));
return base_call(L, stack::get<light_userdata_value>(L, up_value_index(static_cast<int>(I + 1))));
}
template<std::size_t I>

View File

@ -57,10 +57,10 @@ inline int overload_match_arity(types<Fx, Fxs...>, std::index_sequence<I, In...>
if (traits::arity != fxarity) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (sizeof...(Fxs) != 0 && !function_detail::check_types(args_type(), args_indices(), L, start)) {
if (!function_detail::check_types(args_type(), args_indices(), L, start)) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
return matchfx(meta::Bool<sizeof...(Fxs) != 0>(), types<Fx>(), Index<I>(), return_types(), args_type(), L, fxarity, start, std::forward<Args>(args)...);
return matchfx(types<Fx>(), Index<I>(), return_types(), args_type(), L, fxarity, start, std::forward<Args>(args)...);
}
} // internals
@ -93,10 +93,10 @@ struct overloaded_function : base_function {
}
template <bool b, typename Fx, std::size_t I, typename... R, typename... Args>
int call(meta::Bool<b>, types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int call(types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
auto& func = std::get<I>(overloads);
return stack::call_into_lua<b ? false : stack::stack_detail::default_check_arguments>(r, a, func, L, start);
return stack::call_into_lua<false>(r, a, func, L, start);
}
virtual int operator()(lua_State* L) override {
@ -113,11 +113,11 @@ struct usertype_overloaded_function : base_function {
usertype_overloaded_function(std::tuple<Functions...> set) : overloads(std::move(set)) {}
template <bool b,typename Fx, std::size_t I, typename... R, typename... Args>
int call(meta::Bool<b>, types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int call(types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
auto& func = std::get<I>(overloads);
func.item = detail::ptr(stack::get<T>(L, 1));
return stack::call_into_lua<b ? false : stack::stack_detail::default_check_arguments>(r, a, func, L, start);
return stack::call_into_lua<false>(r, a, func, L, start);
}
virtual int operator()(lua_State* L) override {

View File

@ -151,7 +151,7 @@ struct usertype_indexing_function : base_function {
if (functionpair != functions.end()) {
std::pair<bool, base_function*>& target = functionpair->second;
if (target.first) {
stack::push<upvalue>(L, target.second);
stack::push<light_userdata_value>(L, target.second);
stack::push(L, c_closure(usertype_call<0>, 1));
return 1;
}

View File

@ -23,6 +23,9 @@
#define SOL_INHERITANCE_HPP
#include "types.hpp"
#if defined(SOL_NO_RTTI) && defined(SOL_NO_EXCEPTIONS)
#include <atomic>
#endif // No Runtime Type Information and No Exceptions
namespace sol {
template <typename... Args>
@ -30,53 +33,69 @@ struct base_list { };
template <typename... Args>
using bases = base_list<Args...>;
const auto base_classes = bases<>();
typedef bases<> base_classes_tag;
const auto base_classes = base_classes_tag();
namespace detail {
#if defined(SOL_NO_RTTI) && defined(SOL_NO_EXCEPTIONS)
inline std::size_t unique_id () {
static std::atomic<std::size_t> x(0);
return ++x;
}
template <typename T>
struct id_for {
static const std::size_t value;
};
template <typename T>
const std::size_t id_for<T>::value = unique_id();
#endif // No Runtime Type Information / No Exceptions
const auto& base_class_check_key = u8"♡o。.(✿ฺ。 ✿ฺ)";
const auto& base_class_cast_key = u8"(◕‿◕✿)";
#ifndef SOL_NO_EXCEPTIONS
template <typename T>
void throw_as(void* p) {
throw static_cast<T*>(p);
template <typename T>
void throw_as(void* p) {
throw static_cast<T*>(p);
}
using throw_cast = decltype(&throw_as<void>);
template <typename T>
inline T* catch_cast(void* p, throw_cast f) {
try {
f(static_cast<void*>(p));
}
using throw_cast = decltype(&throw_as<void>);
template <typename T>
T* catch_cast(void* p, throw_cast f) {
try {
f(static_cast<void*>(p));
}
catch (T* ptr) {
return ptr;
}
catch (...) {
return static_cast<T*>(p);
}
catch (T* ptr) {
return ptr;
}
catch (...) {
return static_cast<T*>(p);
}
return static_cast<T*>(p);
}
template <typename T>
bool catch_check(throw_cast f) {
try {
f( nullptr );
}
catch (T*) {
return true;
}
catch (...) {
return false;
}
template <typename T>
inline bool catch_check(throw_cast f) {
try {
f( nullptr );
}
catch (T*) {
return true;
}
catch (...) {
return false;
}
return false;
}
#elif !defined(SOL_NO_RTTI)
template <typename T, typename... Bases>
struct inheritance {
static bool type_check(types<>, const std::type_info& typeinfo) {
static bool type_check(types<>, const std::type_info&) {
return false;
}
@ -89,26 +108,61 @@ struct inheritance {
return ti != typeid(T) || type_check(types<Bases...>(), ti);
}
static void* type_cast(types<>, T*, const std::type_info& typeinfo) {
static void* type_cast(types<>, T*, const std::type_info& ti) {
return nullptr;
}
template <typename Base, typename... Args>
static void* type_cast(types<Base, Args...>, T* data, const std::type_info& ti) {
// Make sure to convert to T first, and then dynamic cast to the proper type
return ti != typeid(Base) ? type_check(types<Bases...>(), ti) : dynamic_cast<Base*>(static_cast<T*>(data));
return ti != typeid(Base) ? type_cast(types<Bases...>(), data, ti) : static_cast<void*>(dynamic_cast<Base*>(static_cast<T*>(data)));
}
static void* cast(void* data, const std::type_info& ti) {
return ti != typeid(T) ? type_check(types<Bases...>(), ti) : static_cast<T*>(data);
static void* cast(void* voiddata, const std::type_info& ti) {
T* data = static_cast<T*>(voiddata);
return static_cast<void*>(ti != typeid(T) ? type_cast(types<Bases...>(), data, ti) : data);
}
};
using inheritance_check_function = decltype(&inheritance<void>::check);
using inheritance_cast_function = decltype(&inheritance<void>::cast);
#endif // No Runtime Type Information
#else
template <typename T, typename... Bases>
struct inheritance {
static bool type_check(types<>, std::size_t) {
return false;
}
} // usertype_detail
template <typename Base, typename... Args>
static bool type_check(types<Base, Args...>, std::size_t ti) {
return ti != id_for<Base>::value || type_check(types<Bases...>(), ti);
}
static bool check(std::size_t ti) {
return ti != id_for<T>::value || type_check(types<Bases...>(), ti);
}
static void* type_cast(types<>, T*, std::size_t) {
return nullptr;
}
template <typename Base, typename... Args>
static void* type_cast(types<Base, Args...>, T* data, std::size_t ti) {
// Make sure to convert to T first, and then dynamic cast to the proper type
return ti != id_for<Base>::value ? type_cast(types<Bases...>(), data, ti) : static_cast<void*>(static_cast<Base*>(data));
}
static void* cast(void* voiddata, std::size_t ti) {
T* data = static_cast<T*>(voiddata);
return static_cast<void*>(ti != id_for<T>::value ? type_cast(types<Bases...>(), data, ti) : data);
}
};
using inheritance_check_function = decltype(&inheritance<void>::check);
using inheritance_cast_function = decltype(&inheritance<void>::cast);
#endif // No Exceptions and/or No Runtime Type Information
} // detail
} // sol
#endif // SOL_INHERITANCE_HPP

View File

@ -30,8 +30,7 @@
namespace sol {
class object : public reference {
public:
object(lua_State* L, int index = -1): reference(L, index) {}
object() = default;
using reference::reference;
template<typename T>
decltype(auto) as() const {
@ -41,21 +40,10 @@ public:
template<typename T>
bool is() const {
if (!reference::valid())
if (!valid())
return false;
auto expected = type_of<T>();
auto actual = get_type();
return (expected == actual) || (expected == type::poly);
}
bool valid() const {
if (!reference::valid())
return false;
return !this->is<nil_t>();
}
explicit operator bool() {
return valid();
auto pp = stack::push_pop(*this);
return stack::check<T>(lua_state(), -1, no_panic);
}
};

View File

@ -93,17 +93,17 @@ private:
int returncount = 0;
call_status code = call_status::ok;
#ifndef SOL_NO_EXCEPTIONS
auto onexcept = [&](const char* error) {
auto onexcept = [&](const char* error) {
h.stackindex = 0;
if (h.target.valid()) {
h.target.push();
stack::push(lua_state(), error);
lua_call(lua_state(), 1, 1);
}
else {
else {
stack::push(lua_state(), error);
}
};
}
};
try {
#endif // No Exceptions
code = static_cast<call_status>(luacall(n, LUA_MULTRET, h));
@ -132,7 +132,7 @@ private:
}
public:
sol::reference error_handler;
reference error_handler;
protected_function() = default;
protected_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) {
@ -157,7 +157,7 @@ public:
decltype(auto) call(Args&&... args) const {
handler h(error_handler);
push();
int pushcount = stack::push_args(lua_state(), std::forward<Args>(args)...);
int pushcount = stack::multi_push(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::index_sequence_for<Ret...>(), pushcount, h);
}
};

View File

@ -34,16 +34,16 @@ private:
int index;
int returncount;
int popcount;
call_status error;
call_status err;
public:
protected_function_result() = default;
protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status error = call_status::ok): L(L), index(index), returncount(returncount), popcount(popcount), error(error) {
protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status error = call_status::ok): L(L), index(index), returncount(returncount), popcount(popcount), err(error) {
}
protected_function_result(const protected_function_result&) = default;
protected_function_result& operator=(const protected_function_result&) = default;
protected_function_result(protected_function_result&& o) : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), error(o.error) {
protected_function_result(protected_function_result&& o) : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) {
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
@ -51,14 +51,14 @@ public:
o.index = 0;
o.returncount = 0;
o.popcount = 0;
o.error = call_status::runtime;
o.err = call_status::runtime;
}
protected_function_result& operator=(protected_function_result&& o) {
L = o.L;
index = o.index;
returncount = o.returncount;
popcount = o.popcount;
error = o.error;
err = o.err;
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
@ -66,12 +66,16 @@ public:
o.index = 0;
o.returncount = 0;
o.popcount = 0;
o.error = call_status::runtime;
o.err = call_status::runtime;
return *this;
}
call_status error() const {
return err;
}
bool valid() const {
return error == call_status::ok;
return error() == call_status::ok;
}
template<typename T>
@ -83,6 +87,28 @@ public:
stack::remove(L, index, popcount);
}
};
struct protected_result {
private:
protected_function_result result;
public:
template <typename... Args>
protected_result( Args&&... args ) : result(std::forward<Args>(args)...) {
}
bool valid() const {
return result.valid();
}
explicit operator bool () const {
return valid();
}
protected_function_result& operator* () {
return result;
}
};
} // sol
#endif // SOL_FUNCTION_RESULT_HPP

View File

@ -50,7 +50,7 @@ struct constructor_wrapper : std::tuple<Functions...> {
};
template <typename... Functions>
constructor_wrapper<Functions...> constructor(Functions&&... functions) {
constructor_wrapper<Functions...> initializers(Functions&&... functions) {
return constructor_wrapper<Functions...>(std::forward<Functions>(functions)...);
}

View File

@ -52,7 +52,7 @@ private:
lua_State* L = nullptr; // non-owning
int ref = LUA_NOREF;
int copy() const {
int copy() const noexcept {
if (ref == LUA_NOREF)
return LUA_NOREF;
push();
@ -60,7 +60,7 @@ private:
}
protected:
reference(lua_State* L, detail::global_tag) : L(L) {
reference(lua_State* L, detail::global_tag) noexcept : L(L) {
lua_pushglobaltable(L);
ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
@ -68,12 +68,12 @@ protected:
public:
reference() noexcept = default;
reference(lua_State* L, int index = -1): L(L) {
reference(lua_State* L, int index = -1) noexcept : L(L) {
lua_pushvalue(L, index);
ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
virtual ~reference() {
virtual ~reference() noexcept {
luaL_unref(L, LUA_REGISTRYINDEX, ref);
}
@ -115,19 +115,19 @@ public:
lua_pop(lua_state( ), n);
}
int get_index() const {
int registry_index() const noexcept {
return ref;
}
bool valid () const {
return !(ref == LUA_NOREF);
bool valid () const noexcept {
return !(ref == LUA_NOREF || ref == LUA_REFNIL);
}
explicit operator bool () const {
explicit operator bool () const noexcept {
return valid();
}
type get_type() const {
type get_type() const noexcept {
push();
int result = lua_type(L, -1);
lua_pop(L, 1);

View File

@ -24,6 +24,7 @@
#include "error.hpp"
#include "reference.hpp"
#include "userdata.hpp"
#include "tuple.hpp"
#include "traits.hpp"
#include "usertype_traits.hpp"
@ -60,13 +61,13 @@ 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 push_args(lua_State*) {
inline int multi_push(lua_State*) {
// do nothing
return 0;
}
template<typename T, typename... Args>
inline int push_args(lua_State* L, T&& t, Args&&... 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;
@ -92,8 +93,8 @@ bool check(lua_State* L, int index, Handler&& handler) {
}
template <typename T>
bool check(lua_State* L, int index) {
auto handler = type_panic;
bool check(lua_State* L, int index = -1) {
auto handler = no_panic;
return check<T>(L, index, handler);
}
@ -130,10 +131,10 @@ static int push_upvalues(lua_State* L, TCont&& cont) {
int n = 0;
for(auto& c : cont) {
if(releasemem) {
stack::push<upvalue>(L, c.release());
stack::push<light_userdata_value>(L, c.release());
}
else {
stack::push<upvalue>(L, c.get());
stack::push<light_userdata_value>(L, c.get());
}
++n;
}
@ -144,7 +145,7 @@ template <typename T>
struct userdata_pusher {
template <typename Key, typename... Args>
static void push (lua_State* L, Key&& metatablekey, Args&&... args) {
// Basically, we store all user0data like this:
// 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
@ -255,26 +256,19 @@ struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
};
template<>
struct getter<userdata> {
static userdata get(lua_State* L, int index = -1) {
struct getter<userdata_value> {
static userdata_value get(lua_State* L, int index = -1) {
return{ lua_touserdata(L, index) };
}
};
template<>
struct getter<light_userdata> {
static light_userdata get(lua_State* L, int index = -1) {
struct getter<light_userdata_value> {
static light_userdata_value get(lua_State* L, int index = -1) {
return{ lua_touserdata(L, index) };
}
};
template<>
struct getter<upvalue> {
static upvalue get(lua_State* L, int index = 1) {
return{ lua_touserdata(L, lua_upvalueindex(index)) };
}
};
template<>
struct getter<void*> {
static void* get(lua_State* L, int index = -1) {
@ -286,24 +280,36 @@ 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;
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, -1, &detail::base_class_check_key[0]) != 0) {
void* basecastdata = stack::get<light_userdata>(L);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
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);
}
udata = detail::catch_cast<T>(udata, basecast);
lua_pop(L, 1);
}
#elif !defined(SOL_NO_RTTI)
if (luaL_getmetafield(L, -1, &detail::base_class_check_key[0]) != 0) {
detail::inheritance_cast_function ic = (detail::inheritance_cast_function)stack::get<light_userdata>(L);
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);
}
lua_pop(L, 1);
}
#else
// Lol, inheritance could never work like this
// 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;
@ -313,7 +319,14 @@ struct getter<T*> {
type t = type_of(L, index);
if (t == type::nil)
return nullptr;
return get_no_nil(L, index);
return get_no_nil(L, index);
}
};
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);
}
};
@ -421,7 +434,7 @@ struct checker<T*, type::userdata, C> {
}
};
template <typename T,typename C>
template <typename T, typename C>
struct checker<T, type::userdata, C> {
template <typename Handler>
static bool check (lua_State* L, type indextype, int index, const Handler& handler) {
@ -429,6 +442,8 @@ struct checker<T, type::userdata, C> {
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;
@ -442,20 +457,34 @@ struct checker<T, type::userdata, C> {
}
bool success = lua_rawequal(L, -1, -2) == 1;
#ifndef SOL_NO_EXCEPTIONS
if (!success) {
if (!success) {
lua_getfield(L, -2, &detail::base_class_check_key[0]);
void* basecastdata = stack::get<light_userdata>(L);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
success |= detail::catch_check<T>(basecast);
lua_pop(L, 1);
}
void* basecastdata = stack::get<light_userdata_value>(L);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
success |= detail::catch_check<T>(basecast);
lua_pop(L, 1);
}
#elif !defined(SOL_NO_RTTI)
if (!success) {
if (!success) {
lua_getfield(L, -2, &detail::base_class_check_key[0]);
detail::inheritance_check_function ic = (detail::inheritance_check_function)stack::get<light_userdata>(L);
success |= ic(typeid(T));
lua_pop(L, 1);
}
if (stack::get<type>(L) != type::nil) {
void* basecastdata = stack::get<light_userdata_value>(L);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
success |= ic(typeid(T));
}
lua_pop(L, 1);
}
#else
// Topkek
if (!success) {
lua_getfield(L, -2, &detail::base_class_check_key[0]);
if (stack::get<type>(L) != type::nil) {
void* basecastdata = stack::get<light_userdata_value>(L);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
success |= ic(detail::id_for<T>::value);
}
lua_pop(L, 1);
}
#endif // No Runtime Type Information || Exceptions
lua_pop(L, 2);
return success;
@ -522,30 +551,25 @@ struct pusher<T, std::enable_if_t<meta::And<std::is_integral<T>, std::is_unsigne
};
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>>>::value>> {
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) {
// push the index
pusher<unsigned>{}.push(L, index++);
// push the value
pusher<meta::Unqualified<decltype(i)>>{}.push(L, i);
// set the table
lua_settable(L, -3);
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>>::value>> {
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) {
pusher<meta::Unqualified<decltype(pair.first)>>{}.push(L, pair.first);
pusher<meta::Unqualified<decltype(pair.second)>>{}.push(L, pair.second);
lua_settable(L, -3);
set_field(L, pair.first, pair.second, tableindex);
}
return 1;
}
@ -556,6 +580,10 @@ 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<typename T>
@ -621,24 +649,16 @@ struct pusher<void*> {
};
template<>
struct pusher<upvalue> {
static int push(lua_State* L, upvalue upv) {
lua_pushlightuserdata(L, upv);
return 1;
}
};
template<>
struct pusher<light_userdata> {
static int push(lua_State* L, light_userdata userdata) {
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> {
static int push(lua_State* L, userdata data) {
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;
@ -782,7 +802,7 @@ inline int push_as_upvalues(lua_State* L, T& item) {
std::memcpy(&data[0], std::addressof(item), itemsize);
int pushcount = 0;
for(auto&& v : data) {
pushcount += push(L, upvalue(v));
pushcount += push(L, light_userdata_value(v));
}
return pushcount;
}
@ -793,7 +813,7 @@ inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) {
typedef std::array<void*, data_t_count> data_t;
data_t voiddata{ {} };
for(std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {
voiddata[i] = get<upvalue>(L, index++);
voiddata[i] = get<light_userdata_value>(L, up_value_index(index++));
}
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
}

View File

@ -32,7 +32,7 @@ public:
state(lua_CFunction panic = detail::atpanic) : unique_base(luaL_newstate(), lua_close),
state_view(unique_base::get()) {
set_panic(panic);
stack::luajit_exception_handler(unique_base::get());
stack::luajit_exception_handler(unique_base::get());
}
using state_view::get;

View File

@ -31,6 +31,7 @@ namespace detail {
inline int atpanic(lua_State* L) {
#ifdef SOL_NO_EXCEPTIONS
(void)L;
return -1;
#else
const char* message = lua_tostring(L, -1);
std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic";
@ -57,12 +58,12 @@ class state_view {
private:
lua_State* L;
table reg;
global_table globals;
global_table global;
public:
state_view(lua_State* L):
L(L),
reg(L, LUA_REGISTRYINDEX),
globals(L, detail::global_) {
global(L, detail::global_) {
}
@ -142,81 +143,30 @@ public:
}
}
void open_file(const std::string& filename) {
void script_file(const std::string& filename) {
if(luaL_dofile(L, filename.c_str())) {
lua_error(L);
}
}
template<typename... Args, typename... Keys>
decltype(auto) get(Keys&&... keys) const {
return globals.get<Args...>(std::forward<Keys>(keys)...);
table_iterator begin () const {
return global.begin();
}
template<typename... Args>
state_view& set(Args&&... args) {
globals.set(std::forward<Args>(args)...);
return *this;
table_iterator end() const {
return global.end();
}
template<typename T, typename... Keys>
decltype(auto) traverse_get(Keys&&... keys) const {
return globals.traverse_get<T>(std::forward<Keys>(keys)...);
table_iterator cbegin() const {
return global.cbegin();
}
template<typename... Args>
state_view& traverse_set(Args&&... args) {
globals.traverse_set(std::forward<Args>(args)...);
return *this;
table_iterator cend() const {
return global.cend();
}
template<typename T>
state_view& set_usertype(usertype<T>& user) {
return set_usertype(usertype_traits<T>::name, user);
}
template<typename Key, typename T>
state_view& set_usertype(Key&& key, usertype<T>& user) {
globals.set_usertype(std::forward<Key>(key), user);
return *this;
}
template<typename Class, typename... Args>
state_view& new_usertype(const std::string& name, Args&&... args) {
usertype<Class> utype(std::forward<Args>(args)...);
set_usertype(name, utype);
return *this;
}
template<typename Class, typename CTor0, typename... CTor, typename... Args>
state_view& new_usertype(const std::string& name, Args&&... args) {
constructors<types<CTor0, CTor...>> ctor{};
return new_usertype<Class>(name, ctor, std::forward<Args>(args)...);
}
template<typename Class, typename... CArgs, typename... Args>
state_view& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
usertype<Class> utype(ctor, std::forward<Args>(args)...);
set_usertype(name, utype);
return *this;
}
template <typename Fx>
void for_each(Fx&& fx) {
globals.for_each(std::forward<Fx>(fx));
}
template<typename T>
table create_table(T&& key, int narr = 0, int nrec = 0) {
lua_createtable(L, narr, nrec);
table result(L);
lua_pop(L, 1);
globals.set(std::forward<T>(key), result);
return result;
}
global_table global() const {
return globals;
global_table globals() const {
return global;
}
table registry() const {
@ -227,45 +177,110 @@ public:
lua_atpanic(L, panic);
}
template<typename T>
proxy<global_table&, T> operator[](T&& key) {
return globals[std::forward<T>(key)];
template<typename... Args, typename... Keys>
decltype(auto) get(Keys&&... keys) const {
return global.get<Args...>(std::forward<Keys>(keys)...);
}
template<typename... Args>
state_view& set(Args&&... args) {
global.set(std::forward<Args>(args)...);
return *this;
}
template<typename T, typename... Keys>
decltype(auto) traverse_get(Keys&&... keys) const {
return global.traverse_get<T>(std::forward<Keys>(keys)...);
}
template<typename... Args>
state_view& traverse_set(Args&&... args) {
global.traverse_set(std::forward<Args>(args)...);
return *this;
}
template<typename T>
proxy<const global_table, T> operator[](T&& key) const {
return globals[std::forward<T>(key)];
state_view& set_usertype(usertype<T>& user) {
return set_usertype(usertype_traits<T>::name, user);
}
template<typename Key, typename T>
state_view& set_usertype(Key&& key, usertype<T>& user) {
global.set_usertype(std::forward<Key>(key), user);
return *this;
}
template<typename Class, typename... Args>
state_view& new_usertype(const std::string& name, Args&&... args) {
global.new_usertype<Class>(name, std::forward<Args>(args)...);
return *this;
}
template<typename Class, typename CTor0, typename... CTor, typename... Args>
state_view& new_usertype(const std::string& name, Args&&... args) {
global.new_usertype<Class, CTor0, CTor...>(name, std::forward<Args>(args)...);
return *this;
}
template<typename Class, typename... CArgs, typename... Args>
state_view& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
global.new_usertype<Class>(name, ctor, std::forward<Args>(args)...);
return *this;
}
template <typename Fx>
void for_each(Fx&& fx) {
global.for_each(std::forward<Fx>(fx));
}
template<typename T>
proxy<global_table&, T> operator[](T&& key) {
return global[std::forward<T>(key)];
}
template<typename T>
proxy<const global_table&, T> operator[](T&& key) const {
return global[std::forward<T>(key)];
}
template<typename... Args, typename R, typename Key>
state_view& set_function(Key&& key, R fun_ptr(Args...)){
globals.set_function(std::forward<Key>(key), fun_ptr);
global.set_function(std::forward<Key>(key), fun_ptr);
return *this;
}
template<typename Sig, typename Key>
state_view& set_function(Key&& key, Sig* fun_ptr){
globals.set_function(std::forward<Key>(key), fun_ptr);
global.set_function(std::forward<Key>(key), fun_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) {
globals.set_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
global.set_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
return *this;
}
template<typename Sig, typename C, typename T, typename Key>
state_view& set_function(Key&& key, Sig C::* mem_ptr, T&& obj) {
globals.set_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
global.set_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
return *this;
}
template<typename... Sig, typename Fx, typename Key>
state_view& set_function(Key&& key, Fx&& fx) {
globals.set_function<Sig...>(std::forward<Key>(key), std::forward<Fx>(fx));
global.set_function<Sig...>(std::forward<Key>(key), std::forward<Fx>(fx));
return *this;
}
static inline table create_table(lua_State* L, int narr = 0, int nrec = 0) {
return global_table::create(L, narr, nrec);
}
template <typename Key, typename Value, typename... Args>
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)...);
}
};
} // sol

View File

@ -26,6 +26,7 @@
#include "stack.hpp"
#include "function_types.hpp"
#include "usertype.hpp"
#include "table_iterator.hpp"
namespace sol {
template <bool top_level>
@ -36,6 +37,31 @@ class table_core : public reference {
template <typename... Args>
using is_global = meta::And<meta::Bool<top_level>, meta::is_c_str<Args>...>;
template<typename Fx>
void for_each(std::true_type, Fx&& fx) const {
auto pp = stack::push_pop( *this );
stack::push( lua_state( ), nil );
while ( lua_next( this->lua_state( ), -2 ) ) {
sol::object key( lua_state( ), -2 );
sol::object value( lua_state( ), -1 );
std::pair<sol::object&, sol::object&> keyvalue(key, value);
fx( keyvalue );
lua_pop( lua_state( ), 1 );
}
}
template<typename Fx>
void for_each(std::false_type, Fx&& fx) const {
auto pp = stack::push_pop( *this );
stack::push( lua_state( ), nil );
while ( lua_next( this->lua_state( ), -2 ) ) {
sol::object key( lua_state( ), -2 );
sol::object value( lua_state( ), -1 );
fx( key, value );
lua_pop( lua_state( ), 1 );
}
}
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)){
@ -85,11 +111,27 @@ class table_core : public reference {
public:
table_core( ) noexcept : reference( ) { }
table_core( const table_core<true>& global ) : reference( global ) { }
table_core( const table_core<true>& global ) noexcept : reference( global ) { }
table_core( lua_State* L, int index = -1 ) : reference( L, index ) {
type_assert( L, index, type::table );
}
table_iterator begin () const {
return table_iterator(*this);
}
table_iterator end() const {
return table_iterator();
}
table_iterator cbegin() const {
return begin();
}
table_iterator cend() const {
return end();
}
template<typename... Ret, typename... Keys>
decltype(auto) get( Keys&&... keys ) const {
return tuple_get( types<Ret...>( ), std::index_sequence_for<Ret...>( ), std::forward_as_tuple(std::forward<Keys>(keys)...));
@ -126,16 +168,30 @@ public:
return set(std::forward<Key>(key), user);
}
template<typename Class, typename... Args>
table_core& new_usertype(const std::string& name, Args&&... args) {
usertype<Class> utype(std::forward<Args>(args)...);
set_usertype(name, utype);
return *this;
}
template<typename Class, typename CTor0, typename... CTor, typename... Args>
table_core& new_usertype(const std::string& name, Args&&... args) {
constructors<types<CTor0, CTor...>> ctor{};
return new_usertype<Class>(name, ctor, std::forward<Args>(args)...);
}
template<typename Class, typename... CArgs, typename... Args>
table_core& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
usertype<Class> utype(ctor, std::forward<Args>(args)...);
set_usertype(name, utype);
return *this;
}
template<typename Fx>
void for_each( Fx&& fx ) const {
auto pp = stack::push_pop( *this );
stack::push( lua_state( ), nil );
while ( lua_next( this->lua_state( ), -2 ) ) {
sol::object key( lua_state( ), -2 );
sol::object value( lua_state( ), -1 );
fx( key, value );
lua_pop( lua_state( ), 1 );
}
typedef meta::is_callable<Fx( std::pair<sol::object, sol::object> )> is_paired;
for_each(is_paired(), std::forward<Fx>(fx));
}
size_t size( ) const {
@ -221,6 +277,8 @@ public:
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)...);

View File

@ -135,6 +135,16 @@ using at_in_pack_t = typename at_in_pack<I, Args...>::type;
template<std::size_t I, typename Arg, typename... Args>
struct at_in_pack<I, Arg, Args...> : std::conditional<I == 0, Arg, at_in_pack_t<I - 1, Args...>> {};
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...>> { };
} // meta_detail
template<template<typename...> class Pred, typename... Ts>
struct count_if_pack : meta_detail::count_if_pack<0, Pred, Ts...> { };
template<typename... Args>
struct return_type {
typedef std::tuple<Args...> type;
@ -153,7 +163,22 @@ struct return_type<> {
template <typename... Args>
using return_type_t = typename return_type<Args...>::type;
namespace detail {
namespace meta_detail {
template <typename> struct always_true : std::true_type {};
struct is_callable_tester {
template <typename Fun, typename... Args>
always_true<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
template <typename...>
std::false_type static test(...);
};
} // meta_detail
template <typename T>
struct is_callable;
template <typename Fun, typename... Args>
struct is_callable<Fun(Args...)> : decltype(meta_detail::is_callable_tester::test<Fun, Args...>(0)) {};
namespace meta_detail {
template<typename T, bool isclass = std::is_class<Unqualified<T>>::value>
struct is_function_impl : std::is_function<std::remove_pointer_t<T>> {};
@ -186,15 +211,15 @@ struct check_deducible_signature {
using type = std::is_void<decltype(test<F>(0))>;
};
} // detail
} // meta_detail
template<class F>
struct has_deducible_signature : detail::check_deducible_signature<F>::type { };
struct has_deducible_signature : meta_detail::check_deducible_signature<F>::type { };
template<typename T>
struct Function : Bool<detail::is_function_impl<T>::value> {};
struct Function : Bool<meta_detail::is_function_impl<T>::value> {};
namespace detail {
namespace meta_detail {
template<typename Signature, bool b = has_deducible_signature<Signature>::value>
struct fx_traits;
@ -263,10 +288,10 @@ struct fx_traits<R(*)(Args...), false> {
using arg = std::tuple_element_t<i, args_tuple_type>;
};
} // detail
} // meta_detail
template<typename Signature>
struct function_traits : detail::fx_traits<std::decay_t<Signature>> {};
struct function_traits : meta_detail::fx_traits<std::decay_t<Signature>> {};
template<typename Signature>
using function_args_t = typename function_traits<Signature>::args_type;
@ -277,7 +302,7 @@ using function_signature_t = typename function_traits<Signature>::signature_type
template<typename Signature>
using function_return_t = typename function_traits<Signature>::return_type;
namespace detail {
namespace meta_detail {
template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
struct callable_traits : function_traits<Signature> {
@ -299,10 +324,10 @@ struct callable_traits<Signature, true> {
template<std::size_t i>
using arg = std::tuple_element_t<i, args_tuple_type>;
};
} // detail
} // meta_detail
template<typename Signature>
struct callable_traits : detail::callable_traits<std::remove_volatile_t<Signature>> {
struct callable_traits : meta_detail::callable_traits<std::remove_volatile_t<Signature>> {
};
@ -339,7 +364,7 @@ using is_string_constructible = Or<std::is_same<Unqualified<T>, const char*>, st
template <typename T>
using is_c_str = Or<std::is_same<std::decay_t<Unqualified<T>>, char*>, std::is_same<Unqualified<T>, std::string>>;
namespace detail {
namespace meta_detail {
template <typename T, meta::DisableIf<meta::is_specialization_of<meta::Unqualified<T>, std::tuple>> = 0>
decltype(auto) force_tuple(T&& x) {
return std::forward_as_tuple(x);
@ -349,11 +374,11 @@ template <typename T, meta::EnableIf<meta::is_specialization_of<meta::Unqualifie
decltype(auto) force_tuple(T&& x) {
return std::forward<T>(x);
}
} // detail
} // meta_detail
template <typename... X>
decltype(auto) tuplefy(X&&... x ) {
return std::tuple_cat(detail::force_tuple(x)...);
return std::tuple_cat(meta_detail::force_tuple(x)...);
}
} // meta
namespace detail {
@ -411,7 +436,7 @@ template<typename T>
inline T* ptr(T* val) {
return val;
}
} // detail
} // meta_detail
} // sol
#endif // SOL_TRAITS_HPP

View File

@ -87,27 +87,27 @@ const nil_t nil {};
inline bool operator==(nil_t, nil_t) { return true; }
inline bool operator!=(nil_t, nil_t) { return false; }
struct void_type : types<void> {}; // This is important because it allows myobject.call( Void, ... ) to work
const void_type Void {};
template <typename T>
struct non_null {};
template<typename... Args>
struct function_sig {};
struct upvalue {
struct up_value_index {
int index;
up_value_index(int idx) : index(lua_upvalueindex(idx)) {}
operator int() const { return index; }
};
struct light_userdata_value {
void* value;
upvalue(void* data) : value(data) {}
light_userdata_value(void* data) : value(data) {}
operator void*() const { return value; }
};
struct light_userdata {
struct userdata_value {
void* value;
light_userdata(void* data) : value(data) {}
operator void*() const { return value; }
};
struct userdata {
void* value;
userdata(void* data) : value(data) {}
userdata_value(void* data) : value(data) {}
operator void*() const { return value; }
};
@ -161,7 +161,7 @@ inline int type_panic(lua_State* L, int index, type expected, type actual) {
}
// Specify this function as the handler for lua::check if you know there's nothing wrong
inline int no_panic(lua_State*, int, type, type) {
inline int no_panic(lua_State*, int, type, type) noexcept {
return 0;
}
@ -202,6 +202,8 @@ class protected_function;
class coroutine;
class thread;
class object;
class userdata;
class light_userdata;
template <typename T, typename = void>
struct lua_type_of : std::integral_constant<type, type::userdata> {};
@ -230,9 +232,18 @@ struct lua_type_of<global_table> : std::integral_constant<type, type::table> { }
template <>
struct lua_type_of<object> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<light_userdata_value> : std::integral_constant<type, type::lightuserdata> {};
template <>
struct lua_type_of<userdata_value> : std::integral_constant<type, type::userdata> {};
template <>
struct lua_type_of<light_userdata> : std::integral_constant<type, type::lightuserdata> {};
template <>
struct lua_type_of<userdata> : std::integral_constant<type, type::userdata> {};
template <>
struct lua_type_of<lua_CFunction> : std::integral_constant<type, type::function> {};

View File

@ -121,12 +121,12 @@ inline void push_metatable(lua_State* L, bool needsindexfunction, Funcs&& funcs,
int metatableindex = lua_gettop(L);
#if !defined(SOL_NO_EXCEPTIONS) || !defined(SOL_NO_RTTI)
if (baseclasscheck != nullptr) {
stack::push(L, light_userdata(baseclasscheck));
lua_setfield(L, metatableindex, &detail::base_class_check_key[0]);
stack::push(L, light_userdata_value(baseclasscheck));
lua_setfield(L, metatableindex, &detail::base_class_check_key[0]);
}
if (baseclasscast != nullptr) {
stack::push(L, light_userdata(baseclasscast));
lua_setfield(L, metatableindex, &detail::base_class_cast_key[0]);
stack::push(L, light_userdata_value(baseclasscast));
lua_setfield(L, metatableindex, &detail::base_class_cast_key[0]);
}
#endif // No Exceptions || RTTI
if (funcs.size() < 1 && metafunctable.size() < 2) {
@ -342,17 +342,24 @@ private:
}
template<std::size_t N, typename... Bases, typename... Args>
void build_function_tables(bases<>, bases<Bases...>, Args&&... args) {
void build_function_tables(base_classes_tag, bases<Bases...>, Args&&... args) {
build_function_tables<N>(std::forward<Args>(args)...);
if (sizeof...(Bases) < 1)
return;
#ifndef SOL_NO_EXCEPTIONS
static_assert(sizeof(void*) <= sizeof(detail::throw_cast), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
baseclasscast = (void*)&detail::throw_as<T>;
static_assert(sizeof(void*) <= sizeof(detail::throw_cast), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
baseclasscast = (void*)&detail::throw_as<T>;
#elif !defined(SOL_NO_RTTI)
static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
baseclasscheck = (void*)&detail::userdata_check<T, Bases...>::check;
baseclasscast = (void*)&detail::userdata_check<T, Bases...>::cast;
static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
baseclasscheck = (void*)&detail::inheritance<T, Bases...>::check;
baseclasscast = (void*)&detail::inheritance<T, Bases...>::cast;
#else
static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
baseclasscheck = (void*)&detail::inheritance<T, Bases...>::check;
baseclasscast = (void*)&detail::inheritance<T, Bases...>::cast;
#endif // No Runtime Type Information vs. Throw-Style Inheritance
build_function_tables<N>(std::forward<Args>(args)...);
}
template<std::size_t N>

View File

@ -35,16 +35,16 @@ struct usertype_traits {
};
template<typename T>
const std::string usertype_traits<T>::name = detail::demangle(typeid(T));
const std::string usertype_traits<T>::name = detail::demangle<T>();
template<typename T>
const std::string usertype_traits<T>::metatable = std::string("sol.").append(detail::demangle(typeid(T)));
const std::string usertype_traits<T>::metatable = std::string("sol.").append(detail::demangle<T>());
template<typename T>
const std::string usertype_traits<T>::variable_metatable = std::string("sol.").append(detail::demangle(typeid(T))).append(".variables");
const std::string usertype_traits<T>::variable_metatable = std::string("sol.").append(detail::demangle<T>()).append(".variables");
template<typename T>
const std::string usertype_traits<T>::gc_table = std::string("sol.").append(detail::demangle(typeid(T))).append(".\xE2\x99\xBB");
const std::string usertype_traits<T>::gc_table = std::string("sol.").append(detail::demangle<T>().append(".\xE2\x99\xBB"));
}

View File

@ -1,5 +1,6 @@
#define CATCH_CONFIG_MAIN
#define SOL_CHECK_ARGUMENTS
#include <catch.hpp>
#include <sol.hpp>
#include <vector>
@ -546,6 +547,17 @@ TEST_CASE("tables/variables", "Check if tables and variables work as intended")
REQUIRE_NOTHROW(lua.script("assert(os.name == \"windows\")"));
}
TEST_CASE("tables/create", "Check if creating a table is kosher") {
sol::state lua;
lua["testtable"] = sol::table::create(lua.lua_state(), 0, 0, "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);
@ -754,7 +766,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
REQUIRE(b == 20.4);
};
REQUIRE_NOTHROW(assert1(lua.global()));
REQUIRE_NOTHROW(assert1(lua.globals()));
}
TEST_CASE("tables/usertype", "Show that we can create classes from usertype and use them") {
@ -771,7 +783,7 @@ TEST_CASE("tables/usertype", "Show that we can create classes from usertype and
sol::object a = lua.get<sol::object>("a");
sol::object b = lua.get<sol::object>("b");
sol::object c = lua.get<sol::object>("c");
REQUIRE((a.is<sol::userdata>()));
REQUIRE((a.is<sol::userdata_value>()));
auto atype = a.get_type();
auto btype = b.get_type();
auto ctype = c.get_type();
@ -839,7 +851,7 @@ TEST_CASE("tables/usertype-utility", "Show internal management of classes regist
sol::object a = lua.get<sol::object>("a");
sol::object b = lua.get<sol::object>("b");
sol::object c = lua.get<sol::object>("c");
REQUIRE((a.is<sol::userdata>()));
REQUIRE((a.is<sol::userdata_value>()));
auto atype = a.get_type();
auto btype = b.get_type();
auto ctype = c.get_type();
@ -941,8 +953,7 @@ TEST_CASE("tables/for-each", "Testing the use of for_each to get values from a l
sol::table tbl = lua[ "arr" ];
std::size_t tablesize = 4;
std::size_t iterations = 0;
tbl.for_each(
[&iterations](sol::object key, sol::object value) {
auto fx = [&iterations](sol::object key, sol::object value) {
++iterations;
sol::type keytype = key.get_type();
switch (keytype) {
@ -973,8 +984,72 @@ TEST_CASE("tables/for-each", "Testing the use of for_each to get values from a l
default:
break;
}
}
);
};
auto fxpair = [&fx](std::pair<sol::object, sol::object> kvp) { fx(kvp.first, kvp.second); };
tbl.for_each( fx );
REQUIRE(iterations == tablesize);
iterations = 0;
tbl.for_each( fxpair );
REQUIRE(iterations == tablesize);
}
TEST_CASE("tables/iterators", "Testing the use of iteratrs to get values from a lua table") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.script("arr = {\n"
"[0] = \"Hi\",\n"
"[1] = 123.45,\n"
"[2] = \"String value\",\n"
// Does nothing
//"[3] = nil,\n"
//"[nil] = 3,\n"
"[\"WOOF\"] = 123,\n"
"}");
sol::table tbl = lua[ "arr" ];
std::size_t tablesize = 4;
std::size_t iterations = 0;
int begintop = 0;
int endtop = 0;
{
stack_guard s(lua.lua_state(), begintop, endtop);
for (auto& kvp : tbl) {
[&iterations](sol::object key, sol::object value) {
++iterations;
sol::type keytype = key.get_type();
switch (keytype) {
case sol::type::number:
switch (key.as<int>()) {
case 0:
REQUIRE((value.as<std::string>() == "Hi"));
break;
case 1:
REQUIRE((value.as<double>() == 123.45));
break;
case 2:
REQUIRE((value.as<std::string>() == "String value"));
break;
case 3:
REQUIRE((value.is<sol::nil_t>()));
break;
}
break;
case sol::type::string:
if (key.as<std::string>() == "WOOF") {
REQUIRE((value.as<double>() == 123));
}
break;
case sol::type::nil:
REQUIRE((value.as<double>() == 3));
break;
default:
break;
}
}(kvp.first, kvp.second);
}
} REQUIRE(begintop == endtop);
REQUIRE(iterations == tablesize);
}
@ -1365,7 +1440,7 @@ TEST_CASE("usertype/private-constructible", "Check to make sure special snowflak
lua.open_libraries(sol::lib::base);
lua.new_usertype<factory_test>("factory_test",
"new", sol::constructor(factory_test::save),
"new", sol::initializers(factory_test::save),
"__gc", sol::destructor(factory_test::kill),
"a", &factory_test::a
);
@ -1470,7 +1545,7 @@ end
lua.script(script);
sol::thread runner = sol::thread::create(lua.lua_state());
sol::state_view runnerstate = runner.state();
sol::coroutine cr = lua["loop"];
sol::coroutine cr = runnerstate["loop"];
int counter;
for (counter = 20; counter < 31 && cr; ++counter) {