usertypes.hpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /* Luwra
  2. * Minimal-overhead Lua wrapper for C++
  3. *
  4. * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
  5. */
  6. #ifndef LUWRA_USERTYPES_H_
  7. #define LUWRA_USERTYPES_H_
  8. #include "common.hpp"
  9. #include "types.hpp"
  10. #include "stack.hpp"
  11. #include <map>
  12. #include <string>
  13. LUWRA_NS_BEGIN
  14. namespace internal {
  15. template <typename T>
  16. using StripUserType = typename std::remove_cv<T>::type;
  17. /**
  18. * User type registry identifiers
  19. */
  20. template <typename T>
  21. struct UserTypeReg {
  22. /**
  23. * Dummy field which is used because it has a seperate address for each instance of T
  24. */
  25. static
  26. const int id;
  27. /**
  28. * Registry name for a metatable which is associated with a user type
  29. */
  30. static
  31. const std::string name;
  32. };
  33. template <typename T>
  34. const int UserTypeReg<T>::id = INT_MAX;
  35. template <typename T>
  36. const std::string UserTypeReg<T>::name = "UD#" + std::to_string(uintptr_t(&id));
  37. /**
  38. * Register a new metatable for a user type T.
  39. */
  40. template <typename U> static inline
  41. void new_user_type_metatable(State* state) {
  42. using T = StripUserType<U>;
  43. luaL_newmetatable(state, UserTypeReg<T>::name.c_str());
  44. }
  45. /**
  46. * Check if the value at the given index if a user type T.
  47. */
  48. template <typename U> static inline
  49. StripUserType<U>* check_user_type(State* state, int index) {
  50. using T = StripUserType<U>;
  51. return static_cast<T*>(luaL_checkudata(state, index, UserTypeReg<T>::name.c_str()));
  52. }
  53. /**
  54. * Apply U's metatable for the value at the top of the stack.
  55. */
  56. template <typename U> static inline
  57. void apply_user_type_meta_table(State* state) {
  58. setMetatable(state, UserTypeReg<StripUserType<U>>::name.c_str());
  59. }
  60. /**
  61. * Lua C function to construct a user type T with parameters A
  62. */
  63. template <typename U, typename... A> static inline
  64. int construct_user_type(State* state) {
  65. return direct<size_t (A...)>(
  66. state,
  67. &Value<StripUserType<U>&>::template push<A...>,
  68. state
  69. );
  70. }
  71. /**
  72. * Lua C function to destruct a user type T
  73. */
  74. template <typename U> static inline
  75. int destruct_user_type(State* state) {
  76. using T = StripUserType<U>;
  77. read<T&>(state, 1).~T();
  78. return 0;
  79. }
  80. /**
  81. * Create a string representation for user type T.
  82. */
  83. template <typename U> static
  84. int stringify_user_type(State* state) {
  85. using T = StripUserType<U>;
  86. return push(
  87. state,
  88. internal::UserTypeReg<T>::name
  89. + "@"
  90. + std::to_string(uintptr_t(Value<T*>::read(state, 1)))
  91. );
  92. }
  93. }
  94. /**
  95. * User type
  96. */
  97. template <typename U>
  98. struct Value<U&> {
  99. using T = internal::StripUserType<U>;
  100. /**
  101. * Reference a user type value on the stack.
  102. * \param state Lua state
  103. * \param n Stack index
  104. * \returns Reference to the user type value
  105. */
  106. static inline
  107. U& read(State* state, int n) {
  108. // T is unqualified, therefore conversion from T& to U& is allowed
  109. return *internal::check_user_type<T>(state, n);
  110. }
  111. /**
  112. * Construct a user type value on the stack.
  113. * \note Instances created using this specialization are allocated and constructed as full user
  114. * data types in Lua. The default garbage-collecting hook will destruct the user type,
  115. * once it has been marked.
  116. * \param state Lua state
  117. * \param args Constructor arguments
  118. * \returns Number of values that have been pushed onto the stack
  119. */
  120. template <typename... A> static inline
  121. size_t push(State* state, A&&... args) {
  122. void* mem = lua_newuserdata(state, sizeof(T));
  123. if (!mem) {
  124. luaL_error(state, "Failed to allocate user type");
  125. return -1;
  126. }
  127. // Construct
  128. new (mem) T {std::forward<A>(args)...};
  129. // Apply metatable for unqualified type T
  130. internal::apply_user_type_meta_table<T>(state);
  131. return 1;
  132. }
  133. };
  134. /**
  135. * Construct a user type value on the stack.
  136. * \note Instances created using this specialization are allocated and constructed as full user
  137. * data types in Lua. The default garbage-collecting hook will destruct the user type,
  138. * once it has been marked.
  139. * \param state Lua state
  140. * \param args Constructor arguments
  141. * \returns Reference to the constructed value
  142. */
  143. template <typename U, typename... A> static inline
  144. internal::StripUserType<U>& construct(State* state, A&&... args) {
  145. using T = internal::StripUserType<U>;
  146. void* mem = lua_newuserdata(state, sizeof(T));
  147. if (!mem) {
  148. luaL_error(state, "Failed to allocate user type");
  149. // 'luaL_error' will not return
  150. }
  151. // Construct
  152. T* value = new (mem) T {std::forward<A>(args)...};
  153. // Apply metatable for unqualified type T
  154. internal::apply_user_type_meta_table<T>(state);
  155. return *value;
  156. }
  157. /**
  158. * User type
  159. */
  160. template <typename U>
  161. struct Value<U*> {
  162. using T = internal::StripUserType<U>;
  163. /**
  164. * Reference a user type value on the stack.
  165. * \param state Lua state
  166. * \param n Stack index
  167. * \returns Pointer to the user type value.
  168. */
  169. static inline
  170. U* read(State* state, int n) {
  171. // T is unqualified, therefore conversion from T* to U* is allowed
  172. return internal::check_user_type<T>(state, n);
  173. }
  174. /**
  175. * Copy a value onto the stack. This function behaves exactly as if you would call
  176. * `Value<U&>::push(state, *ptr)`.
  177. * \param state Lua state
  178. * \param ptr Pointer to the user type value
  179. * \returns Number of values that have been pushed
  180. */
  181. static inline
  182. size_t push(State* state, const T* ptr) {
  183. return Value<T&>::push(state, *ptr);
  184. }
  185. };
  186. using MemberMap = std::map<std::string, CFunction>;
  187. /**
  188. * Register the metatable for user type `T`. This function allows you to register methods
  189. * which are shared across all instances of this type.
  190. *
  191. * By default a garbage-collector hook and string representation function are added as meta methods.
  192. * Both can be overwritten.
  193. *
  194. * \tparam U User type struct or class
  195. *
  196. * \param state Lua state
  197. * \param methods Map of methods
  198. * \param meta_methods Map of meta methods
  199. */
  200. template <typename U> static inline
  201. void registerUserType(
  202. State* state,
  203. const MemberMap& methods = MemberMap(),
  204. const MemberMap& meta_methods = MemberMap()
  205. ) {
  206. using T = internal::StripUserType<U>;
  207. // Setup an appropriate metatable name
  208. internal::new_user_type_metatable<T>(state);
  209. // Register methods
  210. if (methods.size() > 0 && meta_methods.count("__index") == 0) {
  211. push(state, "__index");
  212. lua_newtable(state);
  213. for (auto& method: methods) {
  214. setFields(state, -1, method.first, method.second);
  215. }
  216. lua_rawset(state, -3);
  217. }
  218. // Register garbage-collection hook
  219. if (meta_methods.count("__gc") == 0) {
  220. setFields(state, -1, "__gc", &internal::destruct_user_type<T>);
  221. }
  222. // Register string representation function
  223. if (meta_methods.count("__tostring") == 0) {
  224. setFields(state, -1, "__tostring", &internal::stringify_user_type<T>);
  225. }
  226. // Insert meta methods
  227. for (const auto& metamethod: meta_methods) {
  228. setFields(state, -1, metamethod.first, metamethod.second);
  229. }
  230. // Pop metatable off the stack
  231. lua_pop(state, -1);
  232. }
  233. namespace internal {
  234. template <typename T>
  235. struct UserTypeSignature {
  236. static_assert(
  237. sizeof(T) == -1,
  238. "Parameter to UserTypeSignature is not a valid signature"
  239. );
  240. };
  241. template <typename T, typename... A>
  242. struct UserTypeSignature<T (A...)> {
  243. using UserType = StripUserType<T>;
  244. static inline
  245. void registerConstructor(State* state, const std::string& name) {
  246. setGlobal(state, name, &construct_user_type<UserType, A...>);
  247. }
  248. };
  249. }
  250. /**
  251. * Same as the other `registerUserType` but registers the construtor as well. The template parameter
  252. * is a signature `U(A...)` where `U` is the user type and `A...` its constructor parameters.
  253. */
  254. template <typename T> static inline
  255. void registerUserType(
  256. State* state,
  257. const std::string& ctor_name,
  258. const MemberMap& methods = MemberMap(),
  259. const MemberMap& meta_methods = MemberMap()
  260. ) {
  261. using U = typename internal::UserTypeSignature<T>::UserType;
  262. registerUserType<U>(state, methods, meta_methods);
  263. internal::UserTypeSignature<T>::registerConstructor(state, ctor_name);
  264. }
  265. LUWRA_NS_END
  266. /**
  267. * Generate a `lua_CFunction` wrapper for a constructor.
  268. * \param type Type to instantiate
  269. * \param ... Constructor parameter types
  270. * \return Wrapped function as `lua_CFunction`
  271. */
  272. #define LUWRA_WRAP_CONSTRUCTOR(type, ...) \
  273. (&luwra::internal::construct_user_type<luwra::internal::StripUserType<type>, __VA_ARGS__>)
  274. #define LUWRA_FIELD(type, name) {__STRING(name), LUWRA_WRAP_FIELD(type::name)}
  275. #define LUWRA_METHOD(type, name) {__STRING(name), LUWRA_WRAP_METHOD(type::name)}
  276. #define LUWRA_FUNCTION(type, name) {__STRING(name), LUWRA_WRAP_FUNCTION(type::name)}
  277. #endif