mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
all tests compile excepted related to test_table_return_two(), which uses contiguous container std::vector but has key-value pairs inside of it
c++ semantics dictate that it's accessed by index, but the tests seem to want to indicate that it should be accessed like a hashmap (or just using basic lua table semantics) i have no idea how to make this incompatibility work in the new system... i will ask repo master if he knows anything
This commit is contained in:
parent
6712ebe0bd
commit
423e44d6dc
|
@ -5,10 +5,10 @@
|
|||
|
||||
namespace sol {
|
||||
|
||||
template <typename Tc>
|
||||
template <typename Tc, typename = void>
|
||||
struct container {
|
||||
typedef typename std::conditional<std::is_lvalue_reference<Tc>::value, Tc, Decay<Tc>>::type T;
|
||||
typedef Decay<decltype(*(std::declval<T>().begin()))> value_type;
|
||||
typedef Unqualified<decltype(*(std::declval<T>().begin()))> value_type;
|
||||
T cont;
|
||||
|
||||
template <typename... Args>
|
||||
|
@ -20,26 +20,54 @@ struct container {
|
|||
return cont;
|
||||
}
|
||||
|
||||
void set( std::ptrdiff_t i, const value_type& value ) {
|
||||
void set(std::ptrdiff_t i, const value_type& value) {
|
||||
cont[ i ] = value;
|
||||
}
|
||||
|
||||
value_type& get( std::ptrdiff_t i ) {
|
||||
value_type& get(std::ptrdiff_t i) {
|
||||
return cont[ i ];
|
||||
}
|
||||
|
||||
std::size_t size( ) const {
|
||||
std::size_t size() const {
|
||||
return cont.size();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename Tc>
|
||||
struct container<Tc, typename std::enable_if<has_key_value_pair<Unqualified<Tc>>::value>::type> {
|
||||
typedef typename std::conditional<std::is_lvalue_reference<Tc>::value, Tc, Decay<Tc>>::type T;
|
||||
typedef Unqualified<decltype((*(std::declval<T>().begin())).first)> key_type;
|
||||
typedef Unqualified<decltype((*(std::declval<T>().begin())).second)> value_type;
|
||||
T cont;
|
||||
|
||||
template <typename... Args>
|
||||
container (Args&&... args) : cont(std::forward<Args>(args)...){
|
||||
|
||||
}
|
||||
|
||||
operator T& () const {
|
||||
return cont;
|
||||
}
|
||||
|
||||
void set(key_type i, const value_type& value) {
|
||||
cont[ i ] = value;
|
||||
}
|
||||
|
||||
value_type& get(key_type i) {
|
||||
return cont.at(i);
|
||||
}
|
||||
|
||||
std::size_t size() const {
|
||||
return cont.size();
|
||||
}
|
||||
};
|
||||
|
||||
namespace stack {
|
||||
template<typename T>
|
||||
struct pusher<T, typename std::enable_if<has_begin_end<T>::value>::type> {
|
||||
template<typename U = T, EnableIf<Not<has_key_value_pair<U>>> = 0>
|
||||
static void push(lua_State* L, const T& cont) {
|
||||
typedef container<U> container_t;
|
||||
typedef container<T> container_t;
|
||||
// todo: NEED to find a different way of handling this...
|
||||
static std::vector<std::shared_ptr<void>> classes{};
|
||||
userdata<container_t> classdata(default_constructor,
|
||||
|
@ -55,19 +83,22 @@ struct pusher<T, typename std::enable_if<has_begin_end<T>::value>::type> {
|
|||
std::allocator<container_t> alloc{};
|
||||
alloc.construct(c, cont);
|
||||
|
||||
auto&& meta = userdata_traits<T>::metatable;
|
||||
luaL_getmetatable(L, std::addressof(meta[0]));
|
||||
auto&& meta = userdata_traits<container_t>::metatable;
|
||||
if (luaL_newmetatable(L, std::addressof(meta[0])) == 1) {
|
||||
std::string err("metatable not defined for ");
|
||||
err += meta;
|
||||
throw error(err);
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename U = T, EnableIf<has_key_value_pair<U>> = 0>
|
||||
static void push(lua_State* L, const T& cont) {
|
||||
lua_createtable(L, cont.size(), 0);
|
||||
for(auto&& pair : cont) {
|
||||
pusher<Unqualified<decltype(pair.first)>>::push(L, pair.first);
|
||||
pusher<Unqualified<decltype(pair.second)>>::push(L, pair.second);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
template<typename T>
|
||||
struct getter<T, typename std::enable_if<has_begin_end<T>::value>::type> {
|
||||
static Unqualified<T>& get(lua_State* L, int index = -1) {
|
||||
typedef container<Unqualified<T>> container_t;
|
||||
container_t& data = stack::get<container_t>(L, index);
|
||||
return data.cont;
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
template<typename... Ret, typename... Args>
|
||||
typename return_type<Ret...>::type call(Args&&... args) const {
|
||||
push();
|
||||
stack::push(state(), std::forward<Args>(args)...);
|
||||
stack::push_args(state(), std::forward<Args>(args)...);
|
||||
return invoke(types<Ret...>(), sizeof...(Args));
|
||||
}
|
||||
};
|
||||
|
@ -166,7 +166,7 @@ struct pusher<function_t> {
|
|||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
stack::detail::push_userdata(L, userdata, metatablename);
|
||||
stack::detail::push_userdata<void*>(L, metatablename, userdata);
|
||||
stack::pusher<lua_CFunction>{}.push(L, freefunc, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -288,7 +288,7 @@ struct userdata_function : public base_function {
|
|||
|
||||
template<typename Return, typename Raw = Unqualified<Return>>
|
||||
typename std::enable_if<std::is_same<T, Raw>::value, void>::type push(lua_State* L, Return&& r) {
|
||||
if ( detail::get_ptr(r) == fx.item ) {
|
||||
if (detail::get_ptr(r) == fx.item) {
|
||||
// push nothing
|
||||
// note that pushing nothing with the ':'
|
||||
// syntax means we leave the instance of what
|
||||
|
@ -331,6 +331,8 @@ struct userdata_function : public base_function {
|
|||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
fx.item = detail::get_ptr(stack::get<Tp>(L, 1));
|
||||
if (fx.item == nullptr)
|
||||
throw error("userdata for function call is null: are you using wrong call syntax? (use item:function(...) synax)");
|
||||
return (*this)(tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -47,10 +47,11 @@ T* get_ptr(T* val) {
|
|||
|
||||
namespace stack {
|
||||
namespace detail {
|
||||
template<typename T, typename Key, typename U = Unqualified<T>>
|
||||
inline void push_userdata(lua_State* L, T&& userdata, Key&& metatablekey) {
|
||||
U* pdatum = static_cast<U*>(lua_newuserdata(L, sizeof(U)));
|
||||
new(pdatum)U(std::forward<T>(userdata));
|
||||
template<typename T, typename Key, typename... Args>
|
||||
inline void push_userdata(lua_State* L, Key&& metatablekey, Args&&... args) {
|
||||
T* pdatum = static_cast<T*>(lua_newuserdata(L, sizeof(T)));
|
||||
std::allocator<T> alloc{};
|
||||
alloc.construct(pdatum, std::forward<Args>(args)...);
|
||||
luaL_getmetatable(L, std::addressof(metatablekey[0]));
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
@ -193,16 +194,53 @@ struct pusher {
|
|||
pusher<T*>{}.push(L, std::addressof(t));
|
||||
}
|
||||
|
||||
template<typename U = T, EnableIf<Not<std::is_base_of<reference, U>>, Not<std::is_integral<U>>, Not<std::is_floating_point<U>>> = 0>
|
||||
template<typename U = Unqualified<T>, EnableIf<Not<std::is_base_of<reference, U>>, Not<std::is_integral<U>>, Not<std::is_floating_point<U>>> = 0>
|
||||
static void push(lua_State* L, T&& t) {
|
||||
detail::push_userdata(L, std::move(t), userdata_traits<T*>::metatable);
|
||||
detail::push_userdata<U>(L, userdata_traits<T*>::metatable, std::move(t));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct pusher<T*> {
|
||||
static void push(lua_State* L, T* obj) {
|
||||
detail::push_userdata(L, obj, userdata_traits<T*>::metatable);
|
||||
detail::push_userdata<T*>(L, userdata_traits<T*>::metatable, obj);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<table> {
|
||||
template<typename T, typename U = Unqualified<T>, EnableIf<std::is_base_of<reference, U>> = 0>
|
||||
static void push_as(lua_State *L, T&& ref) {
|
||||
ref.push();
|
||||
}
|
||||
|
||||
template<typename T, typename U = Unqualified<T>, EnableIf<has_begin_end<U>, Not<has_key_value_pair<U>>> = 0>
|
||||
static void push_as(lua_State* L, const T& cont) {
|
||||
lua_createtable(L, cont.size(), 0);
|
||||
unsigned index = 1;
|
||||
for(auto&& i : cont) {
|
||||
// push the index
|
||||
pusher<unsigned>{}.push(L, index++);
|
||||
// push the value
|
||||
pusher<Unqualified<decltype(i)>>{}.push(L, i);
|
||||
// set the table
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename U = Unqualified<T>, EnableIf<has_begin_end<U>, has_key_value_pair<U>> = 0>
|
||||
static void push_as(lua_State* L, const T& cont) {
|
||||
lua_createtable(L, cont.size(), 0);
|
||||
for(auto&& pair : cont) {
|
||||
pusher<Unqualified<decltype(pair.first)>>{}.push(L, pair.first);
|
||||
pusher<Unqualified<decltype(pair.second)>>{}.push(L, pair.second);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void push(lua_State *L, T&& table) {
|
||||
push_as(L, std::forward<T>(table));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -284,8 +322,17 @@ inline void push(lua_State*) {
|
|||
|
||||
template<typename T, typename... Args>
|
||||
inline void push(lua_State* L, T&& t, Args&&... args) {
|
||||
using swallow = char[];
|
||||
pusher<Unqualified<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline void push_args(lua_State*) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline void push_args(lua_State* L, T&& t, Args&&... args) {
|
||||
pusher<Unqualified<T>>{}.push(L, std::forward<T>(t));
|
||||
using swallow = char[];
|
||||
void(swallow{'\0', (pusher<Unqualified<Args>>{}.push(L, std::forward<Args>(args)), '\0')... });
|
||||
}
|
||||
|
||||
|
|
|
@ -232,7 +232,7 @@ private:
|
|||
}
|
||||
|
||||
push();
|
||||
stack::detail::push_userdata(state(), userdata, metatablename);
|
||||
stack::detail::push_userdata<void*>(state(), metatablename, userdata);
|
||||
luaL_setfuncs(state(), funcreg, 1);
|
||||
pop();
|
||||
return *this;
|
||||
|
|
106
sol/userdata.hpp
106
sol/userdata.hpp
|
@ -26,6 +26,8 @@
|
|||
#include "function_types.hpp"
|
||||
#include "userdata_traits.hpp"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
|
||||
namespace sol {
|
||||
namespace detail {
|
||||
|
@ -38,12 +40,17 @@ inline std::unique_ptr<T> make_unique(Args&&... args) {
|
|||
template<typename T>
|
||||
class userdata {
|
||||
private:
|
||||
const static std::array<std::string, 19> metafunctionnames;
|
||||
std::string luaname;
|
||||
std::vector<std::string> functionnames;
|
||||
std::vector<std::unique_ptr<base_function>> funcs;
|
||||
std::vector<std::unique_ptr<base_function>> ptrfuncs;
|
||||
std::vector<std::unique_ptr<base_function>> metafuncs;
|
||||
std::vector<std::unique_ptr<base_function>> ptrmetafuncs;
|
||||
std::vector<luaL_Reg> functiontable;
|
||||
std::vector<luaL_Reg> ptrfunctiontable;
|
||||
std::vector<luaL_Reg> metafunctiontable;
|
||||
std::vector<luaL_Reg> ptrmetafunctiontable;
|
||||
|
||||
template<typename... TTypes>
|
||||
struct constructor {
|
||||
|
@ -79,7 +86,7 @@ private:
|
|||
match_constructor(L, obj, syntax, argcount - static_cast<int>(syntax), typename std::common_type<TTypes>::type()...);
|
||||
|
||||
luaL_getmetatable(L, std::addressof(meta[0]));
|
||||
lua_setmetatable(L, -2);
|
||||
lua_setmetatable(L, -1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -100,14 +107,24 @@ private:
|
|||
void build_function_tables() {}
|
||||
|
||||
template<std::size_t N, typename... Args, typename TBase, typename Ret>
|
||||
void build_function_tables(std::string name, Ret TBase::* func, Args&&... args) {
|
||||
void build_function_tables(std::string funcname, Ret TBase::* func, Args&&... args) {
|
||||
static_assert(std::is_base_of<TBase, T>::value, "Any registered function must be part of the class");
|
||||
typedef typename std::decay<decltype(func)>::type function_type;
|
||||
functionnames.push_back(std::move(name));
|
||||
functionnames.push_back(std::move(funcname));
|
||||
std::string& name = functionnames.back();
|
||||
auto metamethod = std::find(metafunctionnames.begin(), metafunctionnames.end(), name);
|
||||
if (metamethod != metafunctionnames.end()) {
|
||||
metafuncs.emplace_back(detail::make_unique<userdata_function<function_type, T>>(std::move(func)));
|
||||
ptrmetafuncs.emplace_back(detail::make_unique<userdata_function<function_type, typename std::add_pointer<T>::type>>(std::move(func)));
|
||||
metafunctiontable.push_back({ name.c_str(), &base_function::userdata<N>::call });
|
||||
ptrmetafunctiontable.push_back({ name.c_str(), &base_function::userdata<N>::call });
|
||||
}
|
||||
else {
|
||||
funcs.emplace_back(detail::make_unique<userdata_function<function_type, T>>(std::move(func)));
|
||||
ptrfuncs.emplace_back(detail::make_unique<userdata_function<function_type, typename std::add_pointer<T>::type>>(std::move(func)));
|
||||
functiontable.push_back({ functionnames.back().c_str(), &base_function::userdata<N>::call });
|
||||
ptrfunctiontable.push_back({ functionnames.back().c_str(), &base_function::userdata<N>::call });
|
||||
functiontable.push_back({ name.c_str(), &base_function::userdata<N>::call });
|
||||
ptrfunctiontable.push_back({ name.c_str(), &base_function::userdata<N>::call });
|
||||
}
|
||||
build_function_tables<N + 1>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
@ -123,21 +140,27 @@ public:
|
|||
functionnames.reserve(sizeof...(args) + 2);
|
||||
functiontable.reserve(sizeof...(args) + 2);
|
||||
ptrfunctiontable.reserve(sizeof...(args) + 2);
|
||||
metafunctiontable.reserve(sizeof...(args) + 2);
|
||||
ptrmetafunctiontable.reserve(sizeof...(args) + 2);
|
||||
funcs.reserve(sizeof...(args) + 2);
|
||||
ptrfuncs.reserve(sizeof...(args) + 2);
|
||||
metafuncs.reserve(sizeof...(args) + 2);
|
||||
ptrmetafuncs.reserve(sizeof...(args) + 2);
|
||||
build_function_tables<0>(std::forward<Args>(args)...);
|
||||
|
||||
functionnames.push_back("new");
|
||||
functiontable.push_back({ functionnames.back().c_str(), &constructor<CArgs...>::construct });
|
||||
functionnames.push_back("__gc");
|
||||
functiontable.push_back({ functionnames.back().c_str(), &destructor<sizeof...(Args) / 2>::destruct });
|
||||
metafunctiontable.push_back({ functionnames.back().c_str(), &destructor<sizeof...(Args) / 2>::destruct });
|
||||
// ptr_functions does not participate in garbage collection/new,
|
||||
// as all pointered types are considered
|
||||
// to be references. This makes returns of
|
||||
// `std::vector<int>&` and `std::vector<int>*` work
|
||||
|
||||
functiontable.push_back({ nullptr, nullptr });
|
||||
metafunctiontable.push_back({ nullptr, nullptr });
|
||||
ptrfunctiontable.push_back({ nullptr, nullptr });
|
||||
ptrmetafunctiontable.push_back({ nullptr, nullptr });
|
||||
}
|
||||
|
||||
template<typename... Args, typename... CArgs>
|
||||
|
@ -156,6 +179,14 @@ public:
|
|||
return ptrfuncs;
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<base_function>>& meta_functions () const {
|
||||
return metafuncs;
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<base_function>>& meta_reference_functions () const {
|
||||
return ptrmetafuncs;
|
||||
}
|
||||
|
||||
const std::vector<luaL_Reg>& function_table () const {
|
||||
return functiontable;
|
||||
}
|
||||
|
@ -164,34 +195,65 @@ public:
|
|||
return ptrfunctiontable;
|
||||
}
|
||||
|
||||
const std::vector<luaL_Reg>& meta_function_table () const {
|
||||
return metafunctiontable;
|
||||
}
|
||||
|
||||
const std::vector<luaL_Reg>& meta_reference_function_table () const {
|
||||
return ptrmetafunctiontable;
|
||||
}
|
||||
|
||||
const std::string& name () const {
|
||||
return luaname;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const std::array<std::string, 19> userdata<T>::metafunctionnames = {
|
||||
"__index",
|
||||
"__newindex",
|
||||
"__mode",
|
||||
"__call",
|
||||
"__metatable",
|
||||
"__tostring",
|
||||
"__len",
|
||||
"__gc",
|
||||
"__unm",
|
||||
"__add",
|
||||
"__sub",
|
||||
"__mul",
|
||||
"__div",
|
||||
"__mod",
|
||||
"__pow",
|
||||
"__concat",
|
||||
"__eq",
|
||||
"__lt",
|
||||
"__le",
|
||||
};
|
||||
|
||||
namespace stack {
|
||||
template <typename T>
|
||||
struct pusher<userdata<T>> {
|
||||
static void push ( lua_State* L, userdata<T>& user ) {
|
||||
auto&& ptrmeta = userdata_traits<typename std::add_pointer<T>::type>::metatable;
|
||||
luaL_newmetatable(L, ptrmeta.c_str());
|
||||
for (std::size_t upvalues = 0; upvalues < user.reference_functions().size(); ++upvalues) {
|
||||
stack::push(L, static_cast<void*>(user.reference_functions()[ upvalues ].get()));
|
||||
}
|
||||
luaL_setfuncs(L, user.reference_function_table().data(), static_cast<uint32_t>(user.reference_functions().size()));
|
||||
|
||||
template <typename Meta, typename Funcs, typename FuncTable, typename MetaFuncs, typename MetaFuncTable>
|
||||
static void push_metatable(lua_State* L, Meta&& meta, Funcs&& funcs, FuncTable&& functable, MetaFuncs&& metafuncs, MetaFuncTable&& metafunctable) {
|
||||
luaL_newmetatable(L, std::addressof(meta[0]));
|
||||
// regular functions accessed through __index semantics
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -1, "__index");
|
||||
|
||||
auto&& meta = userdata_traits<T>::metatable;
|
||||
luaL_newmetatable(L, meta.c_str());
|
||||
for (std::size_t upvalues = 0; upvalues < user.functions().size(); ++upvalues) {
|
||||
stack::push(L, static_cast<void*>(user.functions()[ upvalues ].get()));
|
||||
for (std::size_t u = 0; u < funcs.size(); ++u) {
|
||||
stack::push<upvalue_t>(L, funcs[ u ].get());
|
||||
}
|
||||
luaL_setfuncs(L, functable.data(), static_cast<uint32_t>(funcs.size()));
|
||||
// meta functions
|
||||
for (std::size_t u = 0; u < metafuncs.size(); ++u) {
|
||||
stack::push<upvalue_t>(L, metafuncs[ u ].get());
|
||||
}
|
||||
luaL_setfuncs(L, metafunctable.data(), static_cast<uint32_t>(metafuncs.size()));
|
||||
}
|
||||
luaL_setfuncs(L, user.function_table().data(), static_cast<uint32_t>(user.functions().size()));
|
||||
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -1, "__index");
|
||||
static void push (lua_State* L, userdata<T>& user) {
|
||||
push_metatable(L, userdata_traits<T>::metatable, user.functions(), user.function_table(), user.meta_functions(), user.meta_function_table());
|
||||
push_metatable(L, userdata_traits<T*>::metatable, user.reference_functions(), user.reference_function_table(), user.meta_reference_functions(), user.meta_reference_function_table());
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
|
|
12
tests.cpp
12
tests.cpp
|
@ -14,14 +14,14 @@ void test_free_func2(std::function<int(int)> f, int arg1) {
|
|||
throw sol::error("failed function call!");
|
||||
}
|
||||
|
||||
std::function<int()> makefn () {
|
||||
std::function<int()> makefn() {
|
||||
auto fx = []() -> int {
|
||||
return 0x1456789;
|
||||
};
|
||||
return fx;
|
||||
}
|
||||
|
||||
void takefn ( std::function<int()> purr ) {
|
||||
void takefn(std::function<int()> purr) {
|
||||
if (purr() != 0x1456789)
|
||||
throw 0;
|
||||
}
|
||||
|
@ -404,11 +404,11 @@ TEST_CASE("functions/returning functions from C++ and getting in lua", "check to
|
|||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function( "makefn", makefn );
|
||||
lua.set_function( "takefn", takefn );
|
||||
lua.script( "afx = makefn()\n"
|
||||
lua.set_function("makefn", makefn);
|
||||
lua.set_function("takefn", takefn);
|
||||
lua.script("afx = makefn()\n"
|
||||
"print(afx())\n"
|
||||
"takefn(afx)\n" );
|
||||
"takefn(afx)\n");
|
||||
}
|
||||
|
||||
TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works properly") {
|
||||
|
|
Loading…
Reference in New Issue
Block a user