// 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 #include #include #include namespace sol { 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; struct constructor { static int construct(lua_State* L) { // First argument is now a table that represent the class to instantiate luaL_checktype(L, 1, LUA_TTABLE); lua_createtable(L, 0, 0); // Create table to represent instance // 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* userdata = lua_newuserdata(L, sizeof(T)); T* obj = static_cast(userdata); std::allocator alloc{}; alloc.construct(obj); 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 luserdata = stack::get(L, i); } userdata_t userdata = stack::get(L, 0); T* obj = static_cast(userdata.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(std::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 c, 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