// The MIT License (MIT) // Copyright (c) 2013 Danny Y., Rapptz // 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_USERDATA_HPP #define SOL_USERDATA_HPP #include "state.hpp" #include "lua_function.hpp" #include "demangle.hpp" #include namespace sol { namespace detail { template inline std::unique_ptr make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } } // detail template class userdata { private: friend table; static const std::string classname; static const std::string meta; std::string luaname; std::vector functionnames; std::vector> functions; std::vector functiontable; std::vector metatable; template struct constructor { template static void do_constructor(lua_State* L, T* obj, int argcount, types t) { auto fx = [&obj] ( Args&&... args ) -> void { std::allocator alloc{}; alloc.construct(obj, std::forward(args)...); }; stack::pop_call(L, fx, t); } static void match_constructor(lua_State* L, T* obj, int argcount) { if (argcount != 0) throw sol_error("No matching constructor for the arguments provided"); } template static void match_constructor(lua_State* L, T* obj, int argcount, types t, Args&&... args) { if (argcount == sizeof...(CArgs)) { do_constructor( L, obj, argcount, t ); return; } match_constructor( L, obj, argcount, std::forward(args)...); } static int construct(lua_State* L) { int argcount = lua_gettop(L); // First argument is now a table that represent the class to instantiate luaL_checktype( L, 1, LUA_TTABLE ); // Table represents the instance lua_createtable(L, 0, 0); // Set first argument of new to metatable of instance lua_pushvalue(L, 1); lua_setmetatable(L, -2); // Do function lookups in metatable lua_pushvalue(L, 1); lua_setfield(L, 1, "__index"); void* udata = lua_newuserdata( L, sizeof( T ) ); T* obj = static_cast( udata ); match_constructor( L, obj, argcount - 1, std::common_type::type( )... ); //match_constructor( L, obj, argcount - 1, types( ) ); luaL_getmetatable(L, meta.c_str()); lua_setmetatable(L, -2); lua_setfield(L, -2, "__self"); return 1; } }; template struct destructor { static int destruct(lua_State* L) { for(std::size_t i = 0; i < n; ++i) { lightuserdata_t ludata = stack::get(L, i); lua_func* func = static_cast(ludata.value); std::default_delete dx{}; dx(func); } userdata_t udata = stack::get(L, 0); T* obj = static_cast(udata.value); std::allocator alloc{}; alloc.destroy(obj); return 0; } }; template struct class_func { static int call(lua_State* L) { // Zero-based template parameter, but upvalues start at 1 void* inheritancedata = stack::get(L, i + 1); if (inheritancedata == nullptr) throw sol_error("call from Lua to C++ function has null data"); lua_func* pfx = static_cast(inheritancedata); lua_func& fx = *pfx; int r = fx(L); return r; } }; template void build_function_tables() { } template void build_function_tables(Ret(T::* func)(MArgs...), std::string name, Args&&... args) { typedef typename std::decay::type fx_t; functionnames.push_back(std::move(name)); functions.emplace_back(detail::make_unique>(std::move(func))); functiontable.push_back({ functionnames.back().c_str(), &class_func::call }); build_function_tables(std::forward(args)...); } public: template userdata(Args&&... args) : userdata(classname, std::forward(args)...) {} template userdata(std::string name, Args&&... args) : userdata(name, constructors>(), std::forward(args)...) {} template userdata(constructors c, Args&&... args) : userdata(classname, std::move(c), std::forward(args)...) {} template userdata(std::string name, constructors, Args&&... args) : luaname(std::move(name)) { functionnames.reserve(sizeof...(args)); functiontable.reserve(sizeof...(args)); functions.reserve(sizeof...(args)); metatable.reserve(sizeof...(args)); build_function_tables<0>(std::forward(args)...); functionnames.push_back("new"); functiontable.push_back({ functionnames.back().c_str(), &constructor::construct }); functiontable.push_back({ nullptr, nullptr }); metatable.push_back({ "__gc", &destructor::destruct }); metatable.push_back({ nullptr, nullptr }); } void register_into(const table& s) { } }; template const std::string userdata::classname = detail::demangle(typeid(T)); template const std::string userdata::meta = std::string("sol.stateful.").append(classname); } #endif // SOL_USERDATA_HPP