// 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 "function_types.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; template struct constructor { template static void do_constructor(lua_State* L, T* obj, call_syntax syntax, int, types) { auto fx = [&obj] (Args&&... args) -> void { std::allocator alloc{}; alloc.construct(obj, std::forward(args)...); }; stack::get_call(L, 1 + static_cast(syntax), fx, types()); } static void match_constructor(lua_State*, T*, call_syntax, int) { throw sol_error("No matching constructor for the arguments provided"); } template static void match_constructor(lua_State* L, T* obj, call_syntax syntax, int argcount, types t, Args&&... args) { if (argcount == sizeof...(CArgs)) { do_constructor(L, obj, syntax, argcount, t); return; } match_constructor(L, obj, syntax, argcount, std::forward(args)...); } static int construct(lua_State* L) { call_syntax syntax = stack::get_call_syntax(L, meta); int argcount = lua_gettop(L); void* udata = lua_newuserdata(L, sizeof(T)); T* obj = static_cast(udata); match_constructor(L, obj, syntax, argcount - static_cast(syntax), typename std::common_type::type()...); luaL_getmetatable(L, meta.c_str()); lua_setmetatable(L, -2); return 1; } }; template struct destructor { static int destruct(lua_State* L) { userdata_t udata = stack::get(L, 1); T* obj = static_cast(udata.value); std::allocator alloc{}; alloc.destroy(obj); return 0; } }; 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(), &base_function::userdata::call }); build_function_tables(std::forward(args)...); } public: template userdata(Args&&... args) : userdata(classname, default_constructor, 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) + 2); functiontable.reserve(sizeof...(args) + 3); functions.reserve(sizeof...(args) + 2); build_function_tables<0>(std::forward(args)...); functionnames.push_back("new"); functiontable.push_back({ functionnames.back().c_str(), &constructor::construct }); functionnames.push_back("__gc"); functiontable.push_back({ functionnames.back().c_str(), &destructor::destruct }); functiontable.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