call_0x.hpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // Copyright Daniel Wallin 2010. Use, modification and distribution is
  2. // subject to the Boost Software License, Version 1.0. (See accompanying
  3. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  4. #ifndef LUABIND_DETAIL_CALL_0X_100630_HPP
  5. # define LUABIND_DETAIL_CALL_0X_100630_HPP
  6. # include <luabind/config.hpp>
  7. # include <luabind/vector.hpp>
  8. # include <luabind/yield_policy.hpp>
  9. # include <luabind/detail/policy.hpp>
  10. # include <luabind/detail/index_tuple.hpp>
  11. # include <type_traits>
  12. namespace luabind { namespace detail {
  13. struct invoke_context;
  14. struct LUABIND_API function_object
  15. {
  16. function_object(lua_CFunction entry)
  17. : entry(entry)
  18. , next(0)
  19. {}
  20. virtual ~function_object()
  21. {}
  22. virtual int call(
  23. lua_State* L, invoke_context& ctx) const = 0;
  24. virtual void format_signature(lua_State* L, char const* function) const = 0;
  25. lua_CFunction entry;
  26. std::string name;
  27. function_object* next;
  28. object keepalive;
  29. };
  30. struct LUABIND_API invoke_context
  31. {
  32. invoke_context()
  33. : best_score((std::numeric_limits<int>::max)())
  34. , candidate_index(0)
  35. {}
  36. operator bool() const
  37. {
  38. return candidate_index == 1;
  39. }
  40. void format_error(lua_State* L, function_object const* overloads) const;
  41. int best_score;
  42. function_object const* candidates[10];
  43. int candidate_index;
  44. };
  45. template <class F, class... Args, class Policies>
  46. inline int invoke(
  47. lua_State* L, function_object const& self, invoke_context& ctx
  48. , F const& f, vector<Args...>, Policies const& policies)
  49. {
  50. return invoke_aux(
  51. L, self, ctx, f, policies, vector<Args...>()
  52. , typename make_index_tuple<sizeof...(Args) - 1>::type()
  53. );
  54. }
  55. template <int N, class T, class Policies>
  56. struct make_arg_converter
  57. {
  58. typedef typename find_conversion_policy<N + 1, Policies>::type generator;
  59. typedef typename mpl::apply_wrap2<generator, T, lua_to_cpp>::type type;
  60. };
  61. template <class R, class Policies>
  62. struct make_result_converter
  63. {
  64. typedef typename find_conversion_policy<0, Policies>::type generator;
  65. typedef typename mpl::apply_wrap2<generator, R, cpp_to_lua>::type type;
  66. };
  67. struct void_result
  68. {};
  69. template <class Policies>
  70. struct make_result_converter<void, Policies>
  71. {
  72. typedef void_result type;
  73. };
  74. template <class F, class Policies, class R, class... Args, int... Indices>
  75. inline int invoke_aux(
  76. lua_State* L, function_object const& self, invoke_context& ctx
  77. , F const& f, Policies const& policies
  78. , vector<R, Args...>, index_tuple<Indices...>)
  79. {
  80. typename make_result_converter<R, Policies>::type result_converter;
  81. return invoke_actual(
  82. L, self, ctx, f, policies
  83. , vector<R, Args...>(), index_tuple<Indices...>(), result_converter
  84. , typename make_arg_converter<Indices, Args, Policies>::type()...
  85. );
  86. }
  87. inline int sum_scores(int const* first, int const* last)
  88. {
  89. int result = 0;
  90. for (; first != last; ++first)
  91. {
  92. if (*first < 0)
  93. return *first;
  94. result += *first;
  95. }
  96. return result;
  97. }
  98. template <class T, class Converter>
  99. int compute_score(lua_State* L, Converter& converter, int index)
  100. {
  101. return converter.match(L, LUABIND_DECORATE_TYPE(T), index);
  102. }
  103. inline int compute_indices(int*, int base)
  104. {
  105. return base;
  106. }
  107. template <class Converter, class... Rest>
  108. int compute_indices(
  109. int* target, int base, Converter& converter, Rest&... rest)
  110. {
  111. *target = base;
  112. return compute_indices(target + 1, base + converter.consumed_args(), rest...);
  113. }
  114. template <class F, class ResultConverter, class... Args>
  115. void invoke_function(
  116. lua_State* L, F const& f, std::false_type, ResultConverter& result_converter
  117. , Args&&... args)
  118. {
  119. result_converter.apply(L, f(std::forward<Args>(args)...));
  120. }
  121. template <class F, class... Args>
  122. void invoke_function(
  123. lua_State* L, F const& f, std::false_type, void_result, Args&&... args)
  124. {
  125. f(std::forward<Args>(args)...);
  126. }
  127. template <class F, class ResultConverter, class This, class... Args>
  128. void invoke_function(
  129. lua_State* L, F const& f, std::true_type, ResultConverter& result_converter
  130. , This&& this_, Args&&... args)
  131. {
  132. result_converter.apply(L, (this_.*f)(std::forward<Args>(args)...));
  133. }
  134. template <class F, class This, class... Args>
  135. void invoke_function(
  136. lua_State* L, F const& f, std::true_type, void_result, This&& this_, Args&&... args)
  137. {
  138. (this_.*f)(std::forward<Args>(args)...);
  139. }
  140. inline int maybe_yield_aux(lua_State*, int results, mpl::false_)
  141. {
  142. return results;
  143. }
  144. inline int maybe_yield_aux(lua_State* L, int results, mpl::true_)
  145. {
  146. return lua_yield(L, results);
  147. }
  148. template <class Policies>
  149. int maybe_yield(lua_State* L, int results, Policies*)
  150. {
  151. return maybe_yield_aux(
  152. L, results, has_policy<Policies, yield_policy>());
  153. }
  154. // Helper that ignores everything passed to it. Used so that we can invoke
  155. // postcall on converters in a parameter pack expansion.
  156. template <class... T>
  157. void ignore(T&&...)
  158. {}
  159. template <
  160. class F, class Policies, class R, class... Args, int... Indices
  161. , class ResultConverter, class... Converters
  162. >
  163. inline int invoke_actual(
  164. lua_State* L, function_object const& self, invoke_context& ctx
  165. , F const& f, Policies const& policies
  166. , vector<R, Args...>, index_tuple<Indices...>
  167. , ResultConverter& result_converter, Converters&&... converters)
  168. {
  169. int indices[sizeof...(Args) + 1];
  170. int const arity = compute_indices(indices + 1, 1, converters...) - 1;
  171. int const arguments = lua_gettop(L);
  172. int score = -1;
  173. if (arity == arguments)
  174. {
  175. int const scores[] = {
  176. compute_score<Args>(L, converters, indices[Indices + 1])...
  177. };
  178. score = sum_scores(scores, scores + sizeof...(Args));
  179. }
  180. if (score >= 0 && score < ctx.best_score)
  181. {
  182. ctx.best_score = score;
  183. ctx.candidates[0] = &self;
  184. ctx.candidate_index = 1;
  185. }
  186. else if (score == ctx.best_score)
  187. {
  188. ctx.candidates[ctx.candidate_index++] = &self;
  189. }
  190. int results = 0;
  191. if (self.next)
  192. {
  193. results = self.next->call(L, ctx);
  194. }
  195. if (score == ctx.best_score && ctx.candidate_index == 1)
  196. {
  197. invoke_function(
  198. L, f, std::is_member_function_pointer<F>(), result_converter
  199. , converters.apply(L, LUABIND_DECORATE_TYPE(Args), indices[Indices + 1])...
  200. );
  201. ignore(
  202. (converters.converter_postcall(
  203. L, LUABIND_DECORATE_TYPE(Args), indices[Indices + 1]), 0)...
  204. );
  205. results = maybe_yield(L, lua_gettop(L) - arguments, (Policies*)0);
  206. indices[0] = arguments + results;
  207. policy_list_postcall<Policies>::apply(L, indices);
  208. }
  209. return results;
  210. }
  211. }} // namespace luabind::detail
  212. #endif // LUABIND_DETAIL_CALL_0X_100630_HPP