2014-04-26 07:41:03 +08:00
|
|
|
// 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
|
|
|
|
|
2014-04-26 08:53:36 +08:00
|
|
|
#include "state.hpp"
|
2014-04-26 10:05:58 +08:00
|
|
|
#include "function_types.hpp"
|
2014-04-26 08:53:36 +08:00
|
|
|
#include "demangle.hpp"
|
2014-04-26 07:41:03 +08:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace sol {
|
2014-04-26 08:53:36 +08:00
|
|
|
namespace detail {
|
|
|
|
template<typename T, typename... Args>
|
|
|
|
inline std::unique_ptr<T> make_unique(Args&&... args) {
|
|
|
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
|
|
|
}
|
|
|
|
} // detail
|
2014-04-26 07:41:03 +08:00
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
template<typename T>
|
2014-04-26 07:41:03 +08:00
|
|
|
class userdata {
|
|
|
|
private:
|
|
|
|
friend table;
|
|
|
|
static const std::string classname;
|
|
|
|
static const std::string meta;
|
|
|
|
|
|
|
|
std::string luaname;
|
|
|
|
std::vector<std::string> functionnames;
|
2014-04-26 10:05:58 +08:00
|
|
|
std::vector<std::unique_ptr<base_function>> functions;
|
2014-04-26 07:41:03 +08:00
|
|
|
std::vector<luaL_Reg> functiontable;
|
2014-04-27 12:53:57 +08:00
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
template<typename... TTypes>
|
2014-04-26 07:41:03 +08:00
|
|
|
struct constructor {
|
2014-04-27 06:23:56 +08:00
|
|
|
template<typename... Args>
|
2014-04-27 12:53:57 +08:00
|
|
|
static void do_constructor(lua_State* L, T* obj, call_syntax syntax, int, types<Args...>) {
|
2014-04-27 06:23:56 +08:00
|
|
|
auto fx = [&obj] (Args&&... args) -> void {
|
2014-04-27 12:53:57 +08:00
|
|
|
std::allocator<T> alloc{};
|
2014-04-26 12:19:36 +08:00
|
|
|
alloc.construct(obj, std::forward<Args>(args)...);
|
|
|
|
};
|
2014-04-27 06:23:56 +08:00
|
|
|
stack::get_call(L, 1 + static_cast<int>(syntax), fx, types<Args...>());
|
|
|
|
}
|
2014-04-26 07:41:03 +08:00
|
|
|
|
2014-04-27 12:53:57 +08:00
|
|
|
static void match_constructor(lua_State*, T*, call_syntax, int) {
|
2014-04-27 06:23:56 +08:00
|
|
|
throw sol_error("No matching constructor for the arguments provided");
|
2014-04-26 12:19:36 +08:00
|
|
|
}
|
2014-04-27 12:53:57 +08:00
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
template<typename ...CArgs, typename... Args>
|
|
|
|
static void match_constructor(lua_State* L, T* obj, call_syntax syntax, int argcount, types<CArgs...> t, Args&&... args) {
|
2014-04-26 12:19:36 +08:00
|
|
|
if (argcount == sizeof...(CArgs)) {
|
2014-04-27 06:23:56 +08:00
|
|
|
do_constructor(L, obj, syntax, argcount, t);
|
2014-04-26 12:19:36 +08:00
|
|
|
return;
|
|
|
|
}
|
2014-04-27 06:23:56 +08:00
|
|
|
match_constructor(L, obj, syntax, argcount, std::forward<Args>(args)...);
|
2014-04-26 12:19:36 +08:00
|
|
|
}
|
2014-04-26 07:41:03 +08:00
|
|
|
|
2014-04-26 12:19:36 +08:00
|
|
|
static int construct(lua_State* L) {
|
2014-04-27 06:23:56 +08:00
|
|
|
call_syntax syntax = stack::get_call_syntax(L, meta);
|
2014-04-26 12:19:36 +08:00
|
|
|
int argcount = lua_gettop(L);
|
2014-04-27 12:53:57 +08:00
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
void* udata = lua_newuserdata(L, sizeof(T));
|
|
|
|
T* obj = static_cast<T*>(udata);
|
2014-04-27 12:53:57 +08:00
|
|
|
match_constructor(L, obj, syntax, argcount - static_cast<int>(syntax), typename std::common_type<TTypes>::type()...);
|
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
luaL_getmetatable(L, meta.c_str());
|
2014-04-26 07:41:03 +08:00
|
|
|
lua_setmetatable(L, -2);
|
2014-04-27 12:53:57 +08:00
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
return 1;
|
2014-04-26 07:41:03 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-04-26 08:53:36 +08:00
|
|
|
template<std::size_t n>
|
2014-04-26 07:41:03 +08:00
|
|
|
struct destructor {
|
|
|
|
static int destruct(lua_State* L) {
|
2014-04-27 06:23:56 +08:00
|
|
|
userdata_t udata = stack::get<userdata_t>(L, 1);
|
2014-04-26 12:19:36 +08:00
|
|
|
T* obj = static_cast<T*>(udata.value);
|
2014-04-26 07:41:03 +08:00
|
|
|
std::allocator<T> alloc{};
|
|
|
|
alloc.destroy(obj);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
template<std::size_t n>
|
2014-04-27 12:53:57 +08:00
|
|
|
void build_function_tables() {}
|
2014-04-26 07:41:03 +08:00
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
template<std::size_t n, typename... Args, typename Ret, typename... MArgs>
|
2014-04-26 07:41:03 +08:00
|
|
|
void build_function_tables(Ret(T::* func)(MArgs...), std::string name, Args&&... args) {
|
|
|
|
typedef typename std::decay<decltype(func)>::type fx_t;
|
|
|
|
functionnames.push_back(std::move(name));
|
2014-04-26 10:05:58 +08:00
|
|
|
functions.emplace_back(detail::make_unique<userdata_function<fx_t, T>>(std::move(func)));
|
2014-04-27 06:23:56 +08:00
|
|
|
functiontable.push_back({ functionnames.back().c_str(), &base_function::userdata<n>::call });
|
2014-04-26 07:41:03 +08:00
|
|
|
build_function_tables<n + 1>(std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2014-04-27 06:23:56 +08:00
|
|
|
template<typename... Args>
|
2014-04-27 13:29:37 +08:00
|
|
|
userdata(Args&&... args): userdata(classname, default_constructor, std::forward<Args>(args)...) {}
|
2014-04-26 07:41:03 +08:00
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
template<typename... Args, typename... CArgs>
|
2014-04-27 13:29:37 +08:00
|
|
|
userdata(constructors<CArgs...> c, Args&&... args): userdata(classname, std::move(c), std::forward<Args>(args)...) {}
|
2014-04-26 07:41:03 +08:00
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
template<typename... Args, typename... CArgs>
|
2014-04-27 13:29:37 +08:00
|
|
|
userdata(std::string name, constructors<CArgs...>, Args&&... args): luaname(std::move(name)) {
|
2014-04-27 06:23:56 +08:00
|
|
|
functionnames.reserve(sizeof...(args) + 2);
|
|
|
|
functiontable.reserve(sizeof...(args) + 3);
|
|
|
|
functions.reserve(sizeof...(args) + 2);
|
2014-04-26 07:41:03 +08:00
|
|
|
build_function_tables<0>(std::forward<Args>(args)...);
|
|
|
|
|
|
|
|
functionnames.push_back("new");
|
2014-04-26 12:19:36 +08:00
|
|
|
functiontable.push_back({ functionnames.back().c_str(), &constructor<CArgs...>::construct });
|
2014-04-27 06:23:56 +08:00
|
|
|
functionnames.push_back("__gc");
|
|
|
|
functiontable.push_back({ functionnames.back().c_str(), &destructor<sizeof...(Args) / 2>::destruct });
|
2014-04-27 12:53:57 +08:00
|
|
|
|
2014-04-26 07:41:03 +08:00
|
|
|
functiontable.push_back({ nullptr, nullptr });
|
|
|
|
}
|
|
|
|
|
2014-04-27 13:29:37 +08:00
|
|
|
template<typename... Args, typename... CArgs>
|
|
|
|
userdata(const char* name, constructors<CArgs...> c, Args&&... args) :
|
|
|
|
userdata(std::string(name), std::move(c), std::forward<Args>(args)...) {}
|
|
|
|
|
2014-04-27 12:53:57 +08:00
|
|
|
void register_into(const table& s) {}
|
2014-04-26 07:41:03 +08:00
|
|
|
};
|
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
template<typename T>
|
2014-04-26 07:41:03 +08:00
|
|
|
const std::string userdata<T>::classname = detail::demangle(typeid(T));
|
|
|
|
|
2014-04-27 06:23:56 +08:00
|
|
|
template<typename T>
|
2014-04-26 07:41:03 +08:00
|
|
|
const std::string userdata<T>::meta = std::string("sol.stateful.").append(classname);
|
|
|
|
|
2014-04-27 13:29:37 +08:00
|
|
|
} // sol
|
2014-04-26 07:41:03 +08:00
|
|
|
|
2014-04-26 08:42:38 +08:00
|
|
|
#endif // SOL_USERDATA_HPP
|