stack.hpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /* Luwra
  2. * Minimal-overhead Lua wrapper for C++
  3. *
  4. * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
  5. */
  6. #ifndef LUWRA_STACK_H_
  7. #define LUWRA_STACK_H_
  8. #include "common.hpp"
  9. #include "types.hpp"
  10. #include <cassert>
  11. #include <utility>
  12. #include <functional>
  13. #include <string>
  14. LUWRA_NS_BEGIN
  15. namespace internal {
  16. template <typename T>
  17. struct Layout {
  18. static_assert(
  19. sizeof(T) == -1,
  20. "Parameter to Layout is not a function signature"
  21. );
  22. };
  23. template <typename R>
  24. struct Layout<R()> {
  25. template <typename F, typename... A> static inline
  26. R direct(State*, int, F hook, A&&... args) {
  27. return hook(
  28. std::forward<A>(args)...
  29. );
  30. }
  31. };
  32. template <typename R, typename T>
  33. struct Layout<R(T)> {
  34. template <typename F, typename... A> static inline
  35. R direct(State* state, int n, F hook, A&&... args) {
  36. return hook(
  37. std::forward<A>(args)...,
  38. Value<T>::read(state, n)
  39. );
  40. }
  41. };
  42. template <typename R, typename T1, typename... TR>
  43. struct Layout<R(T1, TR...)> {
  44. template <typename F, typename... A> static inline
  45. R direct(State* state, int n, F hook, A&&... args) {
  46. return Layout<R(TR...)>::direct(
  47. state,
  48. n + 1,
  49. hook,
  50. std::forward<A>(args)...,
  51. Value<T1>::read(state, n)
  52. );
  53. }
  54. };
  55. template <typename K, typename V, typename... R>
  56. struct EntryPusher {
  57. static inline
  58. void push(State* state, int index, K&& key, V&& value, R&&... rest) {
  59. EntryPusher<K, V>::push(state, index, std::forward<K>(key), std::forward<V>(value));
  60. EntryPusher<R...>::push(state, index, std::forward<R>(rest)...);
  61. }
  62. };
  63. template <typename K, typename V>
  64. struct EntryPusher<K, V> {
  65. static inline
  66. void push(State* state, int index, K&& key, V&& value) {
  67. assert(1 == luwra::push(state, key));
  68. assert(1 == luwra::push(state, value));
  69. lua_rawset(state, index < 0 ? index - 2 : index);
  70. }
  71. };
  72. }
  73. /**
  74. * Assuming a stack layout as follows (where A = A0, A1 ... An):
  75. *
  76. * Position | Parameter
  77. * ----------+-----------
  78. * pos + n | An xn
  79. * ... | ...
  80. * pos + 1 | A1 x1
  81. * pos + 0 | A0 x0
  82. * ... | ...
  83. *
  84. * Given a function `R f(A0, A1, ... An)` you are able to map over
  85. * the values on the stack on the stack like so:
  86. *
  87. * R my_result = apply(lua_state, pos, f);
  88. *
  89. * which is equivalent to
  90. *
  91. * R my_result = f(x0, x1, ... xn);
  92. *
  93. * where x0, x1, ... xn are the values on the stack.
  94. */
  95. template <typename R, typename... A> static inline
  96. R apply(State* state, int pos, R (*function_pointer)(A...)) {
  97. return internal::Layout<R(A...)>::direct(state, pos, function_pointer);
  98. }
  99. /**
  100. * Same as `apply(state, 1, function_pointer)`.
  101. */
  102. template <typename R, typename... A> static inline
  103. R apply(State* state, R (*function_pointer)(A...)) {
  104. return apply(state, 1, function_pointer);
  105. }
  106. /**
  107. * Specialization of `apply` which works for `std::function`.
  108. */
  109. template <typename R, typename... A> static inline
  110. R apply(State* state, int pos, const std::function<R(A...)>& function_object) {
  111. return internal::Layout<R(A...)>::direct(state, pos, function_object);
  112. }
  113. /**
  114. * Same as `apply(state, 1, function_object)`.
  115. */
  116. template <typename R, typename... A> static inline
  117. R apply(State* state, const std::function<R(A...)>& function_object) {
  118. return apply(state, 1, function_object);
  119. }
  120. /**
  121. * Check if two values are equal.
  122. */
  123. static inline
  124. bool equal(State* state, int index1, int index2) {
  125. #if LUA_VERSION_NUM <= 501
  126. return lua_equal(state, index1, index2);
  127. #else
  128. return lua_compare(state, index1, index2, LUA_OPEQ);
  129. #endif
  130. }
  131. /**
  132. * Register a value as a global.
  133. */
  134. template <typename V> static inline
  135. void setGlobal(State* state, const std::string& name, V value) {
  136. assert(1 == push(state, value));
  137. lua_setglobal(state, name.c_str());
  138. }
  139. /**
  140. * Retrieve a global value.
  141. */
  142. template <typename V> static inline
  143. V getGlobal(State* state, const std::string& name) {
  144. lua_getglobal(state, name.c_str());
  145. V instance = read<V>(state, -1);
  146. lua_pop(state, 1);
  147. return instance;
  148. }
  149. /**
  150. * Set multiple fields at once. Allows you to provide multiple key-value pairs.
  151. */
  152. template <typename... R> static inline
  153. void setFields(State* state, int index, R&&... args) {
  154. static_assert(sizeof...(R) % 2 == 0, "Field parameters must appear in pairs");
  155. internal::EntryPusher<R...>::push(state, index, std::forward<R>(args)...);
  156. }
  157. /**
  158. * Create a new table and set its fields.
  159. */
  160. template <typename... R> static inline
  161. void newTable(State* state, R&&... args) {
  162. lua_newtable(state);
  163. setFields(state, lua_gettop(state), std::forward<R>(args)...);
  164. }
  165. LUWRA_NS_END
  166. #endif