stack.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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 "internal.hpp"
  11. #include <cassert>
  12. #include <utility>
  13. #include <functional>
  14. #include <string>
  15. LUWRA_NS_BEGIN
  16. namespace internal {
  17. template <typename T>
  18. struct Layout {
  19. static_assert(
  20. sizeof(T) == -1,
  21. "Parameter to Layout is not a valid signature"
  22. );
  23. };
  24. template <typename R>
  25. struct Layout<R()> {
  26. using ReturnType = R;
  27. template <typename F, typename... A> static inline
  28. R direct(State*, int, F&& hook, A&&... args) {
  29. return hook(
  30. std::forward<A>(args)...
  31. );
  32. }
  33. };
  34. template <typename R, typename T>
  35. struct Layout<R(T)> {
  36. using ReturnType = R;
  37. template <typename F, typename... A> static inline
  38. R direct(State* state, int n, F&& hook, A&&... args) {
  39. return hook(
  40. std::forward<A>(args)...,
  41. Value<T>::read(state, n)
  42. );
  43. }
  44. };
  45. template <typename R, typename T1, typename... TR>
  46. struct Layout<R(T1, TR...)> {
  47. using ReturnType = R;
  48. template <typename F, typename... A> static inline
  49. R direct(State* state, int n, F&& hook, A&&... args) {
  50. return Layout<R(TR...)>::direct(
  51. state,
  52. n + 1,
  53. std::forward<F>(hook),
  54. std::forward<A>(args)...,
  55. Value<T1>::read(state, n)
  56. );
  57. }
  58. };
  59. }
  60. /**
  61. * Retrieve values from the stack and invoke a `Callable` with them.
  62. *
  63. * \tparam S Signature in the form of `R(A...)` where `A` is a sequence of types, which shall be
  64. * retrieved from the stack, and `R` the return type of `hook`
  65. * \tparam F An instance of `Callable` which accepts parameters `X..., A...` and returns `R`
  66. * (this parameter should be inferable and can be omitted)
  67. * \tparam X Extra argument types
  68. *
  69. * \param state Lua state instance
  70. * \param pos Index of the first value
  71. * \param hook Callable value
  72. * \param args Extra arguments which shall be be passed to `hook` before the stack values
  73. *
  74. * \returns Result of calling `hook`
  75. */
  76. template <typename S, typename F, typename... X> static inline
  77. typename internal::Layout<S>::ReturnType direct(State* state, int pos, F&& hook, X&&... args) {
  78. return internal::Layout<S>::direct(
  79. state,
  80. pos,
  81. std::forward<F>(hook),
  82. std::forward<X>(args)...
  83. );
  84. }
  85. /**
  86. * Same as `direct(state, 1, hook)`.
  87. */
  88. template <typename S, typename F, typename... A> static inline
  89. typename internal::Layout<S>::ReturnType direct(State* state, F&& hook, A&&... args) {
  90. return internal::Layout<S>::direct(
  91. state,
  92. 1,
  93. std::forward<F>(hook),
  94. std::forward<A>(args)...
  95. );
  96. }
  97. /**
  98. * A version of [direct](@ref direct) which tries to infer the stack layout from the given
  99. * `Callable`. It allows you to omit the template parameters since the compiler is able to infer the
  100. * parameter and return types.
  101. */
  102. template <typename T> static inline
  103. typename internal::CallableInfo<T>::ReturnType apply(State* state, int pos, T&& obj) {
  104. return internal::CallableInfo<T>::template RelaySignature<internal::Layout>::direct(
  105. state,
  106. pos,
  107. std::forward<T>(obj)
  108. );
  109. }
  110. /**
  111. * Same as `apply(state, 1, obj)`.
  112. */
  113. template <typename T> static inline
  114. typename internal::CallableInfo<T>::ReturnType apply(State* state, T&& obj) {
  115. return apply(state, 1, std::forward<T>(obj));
  116. }
  117. namespace internal {
  118. template <typename T>
  119. struct LayoutMapper {
  120. static_assert(
  121. sizeof(T) == -1,
  122. "Parameter to LayoutMapper is not a valid signature"
  123. );
  124. };
  125. template <typename... A>
  126. struct LayoutMapper<void(A...)> {
  127. template <typename F, typename... X> static inline
  128. size_t map(State* state, int n, F&& hook, X&&... args) {
  129. direct<void(A...)>(
  130. state,
  131. n,
  132. std::forward<F>(hook),
  133. std::forward<X>(args)...
  134. );
  135. return 0;
  136. }
  137. };
  138. template <typename R, typename... A>
  139. struct LayoutMapper<R(A...)> {
  140. template <typename F, typename... X> static inline
  141. size_t map(State* state, int n, F&& hook, X&&... args) {
  142. return push(
  143. state,
  144. direct<R(A...)>(
  145. state,
  146. n,
  147. std::forward<F>(hook),
  148. std::forward<X>(args)...
  149. )
  150. );
  151. }
  152. };
  153. }
  154. /**
  155. * Similiar to [direct](@ref direct) but pushes the result of the given `Callable` onto the stack.
  156. * \returns Number of values pushed
  157. */
  158. template <typename S, typename F, typename... A> static inline
  159. size_t map(State* state, int pos, F&& hook, A&&... args) {
  160. return internal::LayoutMapper<S>::map(
  161. state,
  162. pos,
  163. std::forward<F>(hook),
  164. std::forward<A>(args)...
  165. );
  166. }
  167. /**
  168. * Same as `map(state, 1, hook)`.
  169. */
  170. template <typename S, typename F, typename... A> static inline
  171. size_t map(State* state, F&& hook, A&&... args) {
  172. return internal::LayoutMapper<S>::map(
  173. state,
  174. 1,
  175. std::forward<F>(hook),
  176. std::forward<A>(args)...
  177. );
  178. }
  179. LUWRA_NS_END
  180. #endif