usertypes.hpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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. * User type
  136. */
  137. template <typename U>
  138. struct Value<U*> {
  139. using T = internal::StripUserType<U>;
  140. /**
  141. * Reference a user type value on the stack.
  142. * \param state Lua state
  143. * \param n Stack index
  144. * \returns Pointer to the user type value.
  145. */
  146. static inline
  147. U* read(State* state, int n) {
  148. // T is unqualified, therefore conversion from T* to U* is allowed
  149. return internal::check_user_type<T>(state, n);
  150. }
  151. /**
  152. * Copy a value onto the stack. This function behaves exactly as if you would call
  153. * `Value<U&>::push(state, *ptr)`.
  154. * \param state Lua state
  155. * \param ptr Pointer to the user type value
  156. * \returns Number of values that have been pushed
  157. */
  158. static
  159. size_t push(State* state, const T* ptr) {
  160. return Value<T&>::push(state, *ptr);
  161. }
  162. };
  163. using MemberMap = std::map<std::string, CFunction>;
  164. /**
  165. * Register the metatable for user type `T`. This function allows you to register methods
  166. * which are shared across all instances of this type.
  167. *
  168. * By default a garbage-collector hook and string representation function are added as meta methods.
  169. * Both can be overwritten.
  170. *
  171. * \tparam U User type struct or class
  172. *
  173. * \param state Lua state
  174. * \param methods Map of methods
  175. * \param meta_methods Map of meta methods
  176. */
  177. template <typename U> static inline
  178. void registerUserType(
  179. State* state,
  180. const MemberMap& methods = MemberMap(),
  181. const MemberMap& meta_methods = MemberMap()
  182. ) {
  183. using T = internal::StripUserType<U>;
  184. // Setup an appropriate metatable name
  185. internal::new_user_type_metatable<T>(state);
  186. // Register methods
  187. if (methods.size() > 0 && meta_methods.count("__index") == 0) {
  188. push(state, "__index");
  189. lua_newtable(state);
  190. for (auto& method: methods) {
  191. setFields(state, -1, method.first, method.second);
  192. }
  193. lua_rawset(state, -3);
  194. }
  195. // Register garbage-collection hook
  196. if (meta_methods.count("__gc") == 0) {
  197. setFields(state, -1, "__gc", &internal::destruct_user_type<T>);
  198. }
  199. // Register string representation function
  200. if (meta_methods.count("__tostring") == 0) {
  201. setFields(state, -1, "__tostring", &internal::stringify_user_type<T>);
  202. }
  203. // Insert meta methods
  204. for (const auto& metamethod: meta_methods) {
  205. setFields(state, -1, metamethod.first, metamethod.second);
  206. }
  207. // Pop metatable off the stack
  208. lua_pop(state, -1);
  209. }
  210. namespace internal {
  211. template <typename T>
  212. struct UserTypeSignature {
  213. static_assert(
  214. sizeof(T) == -1,
  215. "Parameter to UserTypeSignature is not a valid signature"
  216. );
  217. };
  218. template <typename T, typename... A>
  219. struct UserTypeSignature<T (A...)> {
  220. using UserType = StripUserType<T>;
  221. static inline
  222. void registerConstructor(State* state, const std::string& name) {
  223. setGlobal(state, name, &construct_user_type<UserType, A...>);
  224. }
  225. };
  226. }
  227. /**
  228. * Same as the other `registerUserType` but registers the construtor as well. The template parameter
  229. * is a signature `U(A...)` where `U` is the user type and `A...` its constructor parameters.
  230. */
  231. template <typename T> static inline
  232. void registerUserType(
  233. State* state,
  234. const std::string& ctor_name,
  235. const MemberMap& methods = MemberMap(),
  236. const MemberMap& meta_methods = MemberMap()
  237. ) {
  238. using U = typename internal::UserTypeSignature<T>::UserType;
  239. registerUserType<U>(state, methods, meta_methods);
  240. internal::UserTypeSignature<T>::registerConstructor(state, ctor_name);
  241. }
  242. LUWRA_NS_END
  243. /**
  244. * Generate a `lua_CFunction` wrapper for a constructor.
  245. * \param type Type to instantiate
  246. * \param ... Constructor parameter types
  247. * \return Wrapped function as `lua_CFunction`
  248. */
  249. #define LUWRA_WRAP_CONSTRUCTOR(type, ...) \
  250. (&luwra::internal::construct_user_type<luwra::internal::StripUserType<type>, __VA_ARGS__>)
  251. #define LUWRA_FIELD(type, name) {__STRING(name), LUWRA_WRAP_FIELD(type::name)}
  252. #define LUWRA_METHOD(type, name) {__STRING(name), LUWRA_WRAP_METHOD(type::name)}
  253. #define LUWRA_FUNCTION(type, name) {__STRING(name), LUWRA_WRAP_FUNCTION(type::name)}
  254. #endif