types.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. /* Luwra
  2. * Minimal-overhead Lua wrapper for C++
  3. *
  4. * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
  5. */
  6. #ifndef LUWRA_TYPES_H_
  7. #define LUWRA_TYPES_H_
  8. #include "common.hpp"
  9. #include <utility>
  10. #include <tuple>
  11. #include <string>
  12. #include <type_traits>
  13. #include <limits>
  14. LUWRA_NS_BEGIN
  15. /* Lua types */
  16. using Integer = lua_Integer;
  17. using Number = lua_Number;
  18. using State = lua_State;
  19. using CFunction = lua_CFunction;
  20. /**
  21. * Wrapper for a stack value
  22. * \note This generic version should not be used since it does not implement anything.
  23. * It is not always obvious whether you have used this generic instance or not. Therefore this
  24. * class produces an error message when it is being used. Look for `Parameter to Value is not
  25. * supported` in your compiler output.
  26. */
  27. template <typename T>
  28. struct Value {
  29. static_assert(
  30. sizeof(T) == -1,
  31. "Parameter to Value is not supported"
  32. );
  33. /**
  34. * Retrieve a value from the stack.
  35. * \param state Lua state
  36. * \param index Position of the value
  37. */
  38. static
  39. T read(State* state, int index);
  40. /**
  41. * Push a value onto the stack.
  42. * \param state Lua state
  43. * \param value The value you want to push
  44. * \returns Number of values pushed
  45. */
  46. static
  47. size_t push(State* state, T value);
  48. };
  49. // Nil
  50. template <>
  51. struct Value<std::nullptr_t> {
  52. static inline
  53. std::nullptr_t read(State* state, int n) {
  54. luaL_checktype(state, n, LUA_TNIL);
  55. return nullptr;
  56. }
  57. static inline
  58. size_t push(State* state, std::nullptr_t) {
  59. lua_pushnil(state);
  60. return 1;
  61. }
  62. };
  63. /**
  64. * This does nothing.
  65. */
  66. static inline
  67. size_t push(State*) {
  68. return 0;
  69. }
  70. /**
  71. * Convenient wrapped for [Value<T>::push](@ref Value<T>::push).
  72. */
  73. template <typename T> static inline
  74. size_t push(State* state, T value) {
  75. return Value<T>::push(state, value);
  76. }
  77. /**
  78. * Allows you to push multiple values at once.
  79. */
  80. template <typename T1, typename T2, typename... TR>
  81. size_t push(State* state, T1 value, T2&& head, TR&&... rest) {
  82. return push(state, value) + push(state, std::forward<T2>(head), std::forward<TR>(rest)...);
  83. }
  84. /**
  85. * Convenient wrapper for [Value<T>::read](@ref Value<T>::read).
  86. */
  87. template <typename T> static inline
  88. T read(State* state, int index) {
  89. return Value<T>::read(state, index);
  90. }
  91. /**
  92. * Define a template specialization of `Value` for `type` with a `retrf(State*, int)` which
  93. * extracts it from the stack and a `pushf(State*, type)` which pushes the value on the stack again.
  94. * This assumes that only one value will be pushed onto the stack.
  95. */
  96. #define LUWRA_DEF_VALUE(type, retrf, pushf) \
  97. template <> \
  98. struct Value<type> { \
  99. static inline \
  100. type read(State* state, int n) { \
  101. return retrf(state, n); \
  102. } \
  103. \
  104. static inline \
  105. size_t push(State* state, type value) { \
  106. pushf(state, value); \
  107. return 1; \
  108. } \
  109. }
  110. #ifndef luaL_checkboolean
  111. /**
  112. * Check if the value at index `n` is a boolean and retrieve its value.
  113. */
  114. #define luaL_checkboolean(state, n) \
  115. (luaL_checktype(state, n, LUA_TBOOLEAN), lua_toboolean(state, n))
  116. #endif
  117. #ifndef luaL_checkcfunction
  118. /**
  119. * Check if the value at index `n` is a C function and retrieve it.
  120. */
  121. #define luaL_checkcfunction(state, n) \
  122. (luaL_checktype(state, n, LUA_TCFUNCTION), lua_tocfunction(state, n))
  123. #endif
  124. #ifndef luaL_pushstdstring
  125. /**
  126. * push a `std::string` as string onto the stack.
  127. */
  128. #define luaL_pushstdstring(state, stdstring) \
  129. (lua_pushstring(state, (stdstring).c_str()))
  130. #endif
  131. namespace internal {
  132. template <typename T>
  133. struct NumericTransportValue {
  134. static_assert(
  135. sizeof(T) == -1,
  136. "Parameter to NumericTransportValue is not a numeric base type"
  137. );
  138. };
  139. // Transport unit `Integer`
  140. template <>
  141. struct NumericTransportValue<Integer> {
  142. static inline
  143. Integer read(State* state, int index) {
  144. return luaL_checkinteger(state, index);
  145. }
  146. static inline
  147. size_t push(State* state, Integer value) {
  148. lua_pushinteger(state, value);
  149. return 1;
  150. }
  151. };
  152. // Transport unit `Number`
  153. template <>
  154. struct NumericTransportValue<Number> {
  155. static inline
  156. Number read(State* state, int index) {
  157. return luaL_checknumber(state, index);
  158. }
  159. static inline
  160. size_t push(State* state, Number value) {
  161. lua_pushnumber(state, value);
  162. return 1;
  163. }
  164. };
  165. // Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is smaller
  166. // than `B`.
  167. template <typename I, typename B>
  168. struct NumericContainedValueBase {
  169. static constexpr
  170. bool qualifies =
  171. // TODO: Remove warning about comparsion between signed and unsigned integers
  172. std::numeric_limits<I>::max() <= std::numeric_limits<B>::max()
  173. && std::numeric_limits<I>::lowest() >= std::numeric_limits<B>::lowest();
  174. static inline
  175. I read(State* state, int index) {
  176. return
  177. static_cast<I>(NumericTransportValue<B>::read(state, index));
  178. }
  179. static inline
  180. size_t push(State* state, I value) {
  181. NumericTransportValue<B>::push(state, static_cast<B>(value));
  182. return 1;
  183. }
  184. };
  185. // Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is bigger
  186. // than `B`.
  187. template <typename I, typename B>
  188. struct NumericTruncatingValueBase {
  189. static inline
  190. I read(State* state, int index) {
  191. return static_cast<I>(NumericTransportValue<B>::read(state, index));
  192. }
  193. static inline
  194. size_t push(State*, I) {
  195. static_assert(
  196. sizeof(I) == -1,
  197. "You must not use 'Value<I>::push' specializations which inherit from NumericTruncatingValueBase"
  198. );
  199. return -1;
  200. }
  201. };
  202. // Base for `Value<I>` specializations which uses `B` as transport unit
  203. template <typename I, typename B>
  204. using NumericValueBase =
  205. typename std::conditional<
  206. std::is_same<I, B>::value,
  207. NumericTransportValue<B>,
  208. typename std::conditional<
  209. NumericContainedValueBase<I, B>::qualifies,
  210. NumericContainedValueBase<I, B>,
  211. NumericTruncatingValueBase<I, B>
  212. >::type
  213. >::type;
  214. }
  215. /**
  216. * Define an integral type which will be transported via `base`.
  217. */
  218. #define LUWRA_DEF_NUMERIC(base, type) \
  219. template <> \
  220. struct Value<type>: internal::NumericValueBase<type, base> {};
  221. // Lua-dependent types
  222. LUWRA_DEF_NUMERIC(Number, float)
  223. LUWRA_DEF_NUMERIC(Number, double)
  224. LUWRA_DEF_NUMERIC(Number, long double)
  225. // Integral types
  226. LUWRA_DEF_NUMERIC(Integer, signed char)
  227. LUWRA_DEF_NUMERIC(Integer, unsigned char)
  228. LUWRA_DEF_NUMERIC(Integer, signed short)
  229. LUWRA_DEF_NUMERIC(Integer, unsigned short)
  230. LUWRA_DEF_NUMERIC(Integer, signed int)
  231. LUWRA_DEF_NUMERIC(Integer, unsigned int)
  232. LUWRA_DEF_NUMERIC(Integer, signed long int)
  233. LUWRA_DEF_NUMERIC(Integer, unsigned long int)
  234. LUWRA_DEF_NUMERIC(Integer, signed long long int)
  235. LUWRA_DEF_NUMERIC(Integer, unsigned long long int)
  236. // C/C++ types
  237. LUWRA_DEF_VALUE(bool, luaL_checkboolean, lua_pushboolean);
  238. LUWRA_DEF_VALUE(const char*, luaL_checkstring, lua_pushstring);
  239. LUWRA_DEF_VALUE(std::string, luaL_checkstring, luaL_pushstdstring);
  240. // Do not export these macros
  241. #undef LUWRA_DEF_VALUE
  242. #undef LUWRA_DEF_NUMERIC
  243. // Alias for string literals
  244. template <size_t n>
  245. struct Value<char[n]>: Value<const char*> {};
  246. // Alias for const string literals
  247. template <size_t n>
  248. struct Value<const char[n]>: Value<const char*> {};
  249. /**
  250. * C Functions may be pushed aswell.
  251. */
  252. template <>
  253. struct Value<CFunction> {
  254. static inline
  255. size_t push(State* state, CFunction fun) {
  256. lua_pushcfunction(state, fun);
  257. return 1;
  258. }
  259. };
  260. /**
  261. * An arbitrary value on an execution stack.
  262. * Note: this value is only available as long as it exists on its originating stack.
  263. */
  264. struct Arbitrary {
  265. State* state;
  266. int index;
  267. };
  268. template <>
  269. struct Value<Arbitrary> {
  270. static inline
  271. Arbitrary read(State* state, int index) {
  272. if (index < 0)
  273. index = lua_gettop(state) + (index + 1);
  274. return Arbitrary {state, index};
  275. }
  276. static inline
  277. size_t push(State* state, const Arbitrary& value) {
  278. lua_pushvalue(value.state, value.index);
  279. if (value.state != state)
  280. lua_xmove(value.state, state, 1);
  281. return 1;
  282. }
  283. };
  284. namespace internal {
  285. template <typename>
  286. struct StackPusher;
  287. template <size_t I>
  288. struct StackPusher<std::index_sequence<I>> {
  289. template <typename... T> static inline
  290. size_t push(State* state, const std::tuple<T...>& package) {
  291. using R = typename std::tuple_element<I, std::tuple<T...>>::type;
  292. return Value<R>::push(state, std::get<I>(package));
  293. }
  294. };
  295. template <size_t I, size_t... Is>
  296. struct StackPusher<std::index_sequence<I, Is...>> {
  297. template <typename... T> static inline
  298. size_t push(State* state, const std::tuple<T...>& package) {
  299. return
  300. StackPusher<std::index_sequence<I>>::push(state, package)
  301. + StackPusher<std::index_sequence<Is...>>::push(state, package);
  302. }
  303. };
  304. }
  305. /**
  306. * Allows you to use multiple return values.
  307. */
  308. template <typename... A>
  309. struct Value<std::tuple<A...>> {
  310. static inline
  311. size_t push(State* state, const std::tuple<A...>& value) {
  312. return internal::StackPusher<std::make_index_sequence<sizeof...(A)>>::push(state, value);
  313. }
  314. };
  315. /**
  316. * Fix specialization for const types.
  317. */
  318. template <typename T>
  319. struct Value<const T>: Value<T> {};
  320. /**
  321. * Fix specialization for volatile types.
  322. */
  323. template <typename T>
  324. struct Value<volatile T>: Value<T> {};
  325. namespace internal {
  326. /**
  327. *
  328. */
  329. struct PushableI {
  330. virtual
  331. size_t push(State* state) const = 0;
  332. virtual
  333. PushableI* copy() const = 0;
  334. virtual
  335. ~PushableI() {}
  336. };
  337. /**
  338. *
  339. */
  340. template <typename T>
  341. struct PushableT: virtual PushableI {
  342. T value;
  343. inline
  344. PushableT(T value): value(value) {}
  345. virtual
  346. size_t push(State* state) const {
  347. return Value<T>::push(state, value);
  348. }
  349. virtual
  350. PushableI* copy() const {
  351. return new PushableT<T>(value);
  352. }
  353. };
  354. }
  355. /**
  356. *
  357. */
  358. struct Pushable: virtual internal::PushableI {
  359. internal::PushableI* interface;
  360. template <typename T> inline
  361. Pushable(T value): interface(new internal::PushableT<T>(value)) {}
  362. inline
  363. Pushable(Pushable&& other): interface(other.interface) {
  364. other.interface = nullptr;
  365. }
  366. Pushable(const Pushable& other): interface(other.interface->copy()) {}
  367. virtual
  368. size_t push(State* state) const {
  369. return interface->push(state);
  370. }
  371. virtual
  372. internal::PushableI* copy() const {
  373. return new Pushable(*this);
  374. }
  375. virtual
  376. ~Pushable() {
  377. if (interface)
  378. delete interface;
  379. }
  380. };
  381. template <>
  382. struct Value<Pushable> {
  383. static inline
  384. size_t push(State* state, const Pushable& value) {
  385. return value.push(state);
  386. }
  387. };
  388. LUWRA_NS_END
  389. #endif