stack.hpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. LUWRA_NS_BEGIN
  14. namespace internal {
  15. template <typename T>
  16. struct Layout {
  17. static_assert(
  18. sizeof(T) == -1,
  19. "Parameter to Layout is not a function signature"
  20. );
  21. };
  22. template <typename R, typename T>
  23. struct Layout<R(T)> {
  24. template <typename F, typename... A> static inline
  25. R direct(State* state, int n, F hook, A&&... args) {
  26. return hook(
  27. std::forward<A>(args)...,
  28. Value<T>::read(state, n)
  29. );
  30. }
  31. };
  32. template <typename R, typename T1, typename... TR>
  33. struct Layout<R(T1, TR...)> {
  34. template <typename F, typename... A> static inline
  35. R direct(State* state, int n, F hook, A&&... args) {
  36. return Layout<R(TR...)>::direct(
  37. state,
  38. n + 1,
  39. hook,
  40. std::forward<A>(args)...,
  41. Value<T1>::read(state, n)
  42. );
  43. }
  44. };
  45. template <typename K, typename V, typename... R>
  46. struct EntryPusher {
  47. static inline
  48. void push(State* state, int index, K&& key, V&& value, R&&... rest) {
  49. EntryPusher<K, V>::push(state, index, std::forward<K>(key), std::forward<V>(value));
  50. EntryPusher<R...>::push(state, index, std::forward<R>(rest)...);
  51. }
  52. };
  53. template <typename K, typename V>
  54. struct EntryPusher<K, V> {
  55. static inline
  56. void push(State* state, int index, K&& key, V&& value) {
  57. assert(1 == luwra::push(state, key));
  58. assert(1 == luwra::push(state, value));
  59. lua_rawset(state, index < 0 ? index - 2 : index);
  60. }
  61. };
  62. }
  63. /**
  64. * Assuming a stack layout as follows (where A = A0, A1 ... An):
  65. *
  66. * Position | Parameter
  67. * ----------+-----------
  68. * pos + n | An xn
  69. * ... | ...
  70. * pos + 1 | A1 x1
  71. * pos + 0 | A0 x0
  72. * ... | ...
  73. *
  74. * Given a function `R f(A0, A1, ... An)` you are able to map over
  75. * the values on the stack on the stack like so:
  76. *
  77. * R my_result = apply(lua_state, pos, f);
  78. *
  79. * which is equivalent to
  80. *
  81. * R my_result = f(x0, x1, ... xn);
  82. *
  83. * where x0, x1, ... xn are the values on the stack.
  84. */
  85. template <typename R, typename... A> static inline
  86. R apply(State* state, int pos, R (*function_pointer)(A...)) {
  87. return internal::Layout<R(A...)>::direct(state, pos, function_pointer);
  88. }
  89. /**
  90. * Same as `apply(state, 1, function_pointer)`.
  91. */
  92. template <typename R, typename... A> static inline
  93. R apply(State* state, R (*function_pointer)(A...)) {
  94. return apply(state, 1, function_pointer);
  95. }
  96. /**
  97. * Specialization of `apply` which works for `std::function`.
  98. */
  99. template <typename R, typename... A> static inline
  100. R apply(State* state, int pos, const std::function<R(A...)>& function_object) {
  101. return internal::Layout<R(A...)>::direct(state, pos, function_object);
  102. }
  103. /**
  104. * Same as `apply(state, 1, function_object)`.
  105. */
  106. template <typename R, typename... A> static inline
  107. R apply(State* state, const std::function<R(A...)>& function_object) {
  108. return apply(state, 1, function_object);
  109. }
  110. /**
  111. * Check if two values are equal.
  112. */
  113. static inline
  114. bool equal(State* state, int index1, int index2) {
  115. #if LUA_VERSION_NUM <= 501
  116. return lua_equal(state, index1, index2);
  117. #else
  118. return lua_compare(state, index1, index2, LUA_OPEQ);
  119. #endif
  120. }
  121. /**
  122. * Register a value as a global.
  123. */
  124. template <typename T> static inline
  125. void register_global(State* state, const char* name, T value) {
  126. assert(1 == push(state, value));
  127. lua_setglobal(state, name);
  128. }
  129. /**
  130. * Set multiple fields at once. Allows you to provide multiple key-value pairs.
  131. */
  132. template <typename... R> static inline
  133. void set_fields(State* state, int index, R&&... args) {
  134. static_assert(sizeof...(R) % 2 == 0, "Field parameters must appear in pairs");
  135. internal::EntryPusher<R...>::push(state, index, std::forward<R>(args)...);
  136. }
  137. /**
  138. * Create a new table and set its fields.
  139. */
  140. template <typename... R> static inline
  141. void new_table(State* state, R&&... args) {
  142. lua_newtable(state);
  143. set_fields(state, lua_gettop(state), std::forward<R>(args)...);
  144. }
  145. LUWRA_NS_END
  146. #endif