stack.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. // sol2
  2. // The MIT License (MIT)
  3. // Copyright (c) 2013-2022 Rapptz, ThePhD and contributors
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy of
  5. // this software and associated documentation files (the "Software"), to deal in
  6. // the Software without restriction, including without limitation the rights to
  7. // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  8. // the Software, and to permit persons to whom the Software is furnished to do so,
  9. // subject to the following conditions:
  10. // The above copyright notice and this permission notice shall be included in all
  11. // copies or substantial portions of the Software.
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  14. // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  15. // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  16. // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  17. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. #ifndef SOL_STACK_HPP
  19. #define SOL_STACK_HPP
  20. #include <sol/trampoline.hpp>
  21. #include <sol/stack_core.hpp>
  22. #include <sol/stack_reference.hpp>
  23. #include <sol/stack_check.hpp>
  24. #include <sol/stack_get.hpp>
  25. #include <sol/stack_check_get.hpp>
  26. #include <sol/stack_push.hpp>
  27. #include <sol/stack_pop.hpp>
  28. #include <sol/stack_field.hpp>
  29. #include <sol/stack_probe.hpp>
  30. #include <sol/assert.hpp>
  31. #include <cstring>
  32. #include <array>
  33. namespace sol {
  34. namespace detail {
  35. using typical_chunk_name_t = char[SOL_ID_SIZE_I_];
  36. using typical_file_chunk_name_t = char[SOL_FILE_ID_SIZE_I_];
  37. inline const std::string& default_chunk_name() {
  38. static const std::string name = "";
  39. return name;
  40. }
  41. template <std::size_t N>
  42. const char* make_chunk_name(const string_view& code, const std::string& chunkname, char (&basechunkname)[N]) {
  43. if (chunkname.empty()) {
  44. auto it = code.cbegin();
  45. auto e = code.cend();
  46. std::size_t i = 0;
  47. static const std::size_t n = N - 4;
  48. for (i = 0; i < n && it != e; ++i, ++it) {
  49. basechunkname[i] = *it;
  50. }
  51. if (it != e) {
  52. for (std::size_t c = 0; c < 3; ++i, ++c) {
  53. basechunkname[i] = '.';
  54. }
  55. }
  56. basechunkname[i] = '\0';
  57. return &basechunkname[0];
  58. }
  59. else {
  60. return chunkname.c_str();
  61. }
  62. }
  63. inline void clear_entries(stack_reference r) {
  64. stack::push(r.lua_state(), lua_nil);
  65. while (lua_next(r.lua_state(), -2)) {
  66. absolute_index key(r.lua_state(), -2);
  67. auto pn = stack::pop_n(r.lua_state(), 1);
  68. stack::set_field<false, true>(r.lua_state(), key, lua_nil, r.stack_index());
  69. }
  70. }
  71. inline void clear_entries(const reference& registry_reference) {
  72. auto pp = stack::push_pop(registry_reference);
  73. stack_reference ref(registry_reference.lua_state(), -1);
  74. clear_entries(ref);
  75. }
  76. } // namespace detail
  77. namespace stack {
  78. namespace stack_detail {
  79. template <typename T>
  80. inline int push_as_upvalues(lua_State* L, T& item) {
  81. typedef std::decay_t<T> TValue;
  82. static const std::size_t itemsize = sizeof(TValue);
  83. static const std::size_t voidsize = sizeof(void*);
  84. static const std::size_t voidsizem1 = voidsize - 1;
  85. static const std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize;
  86. typedef std::array<void*, data_t_count> data_t;
  87. data_t data { {} };
  88. std::memcpy(&data[0], std::addressof(item), itemsize);
  89. int pushcount = 0;
  90. for (const auto& v : data) {
  91. lua_pushlightuserdata(L, v);
  92. pushcount += 1;
  93. }
  94. return pushcount;
  95. }
  96. template <typename T>
  97. inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 2) {
  98. static const std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*);
  99. typedef std::array<void*, data_t_count> data_t;
  100. data_t voiddata { {} };
  101. for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {
  102. voiddata[i] = lua_touserdata(L, upvalue_index(index++));
  103. }
  104. return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
  105. }
  106. template <typename T>
  107. inline std::pair<T, int> get_as_upvalues_using_function(lua_State* L, int function_index = -1) {
  108. static const std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*);
  109. typedef std::array<void*, data_t_count> data_t;
  110. function_index = lua_absindex(L, function_index);
  111. int index = 0;
  112. data_t voiddata { {} };
  113. for (std::size_t d = 0; d < sizeof(T); d += sizeof(void*)) {
  114. // first upvalue is nullptr to respect environment shenanigans
  115. // So +2 instead of +1
  116. const char* upvalue_name = lua_getupvalue(L, function_index, index + 2);
  117. if (upvalue_name == nullptr) {
  118. // We should freak out here...
  119. break;
  120. }
  121. voiddata[index] = lua_touserdata(L, -1);
  122. ++index;
  123. }
  124. lua_pop(L, index);
  125. return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
  126. }
  127. template <bool checked, typename Handler, typename Fx, typename... Args>
  128. static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, Handler&&, record&, Fx&& fx, Args&&... args) {
  129. return std::forward<Fx>(fx)(std::forward<Args>(args)...);
  130. }
  131. template <bool checked, typename Arg, typename... Args, std::size_t I, std::size_t... Is, typename Handler, typename Fx, typename... FxArgs>
  132. static decltype(auto) eval(types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L_, int start_index_, Handler&& handler_,
  133. record& tracking_, Fx&& fx_, FxArgs&&... fxargs_) {
  134. #if 0 && SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS)
  135. // NOTE: THIS IS TERMPORARILY TURNED OFF BECAUSE IT IMPACTS ACTUAL SEMANTICS W.R.T. THINGS LIKE LUAJIT,
  136. // SO IT MUST REMAIN OFF UNTIL WE CAN ESTABLISH SIMILAR BEHAVIOR IN MODES WHERE `checked == false`!
  137. // We can save performance/time by letting errors unwind produced arguments
  138. // rather than checking everything once, and then potentially re-doing work
  139. if constexpr (checked) {
  140. return eval<checked>(types<Args...>(),
  141. std::index_sequence<Is...>(),
  142. L_,
  143. start_index_,
  144. std::forward<Handler>(handler_),
  145. tracking_,
  146. std::forward<Fx>(fx_),
  147. std::forward<FxArgs>(fxargs_)...,
  148. *stack_detail::check_get_arg<Arg>(L_, start_index_ + tracking_.used, handler_, tracking_));
  149. }
  150. else
  151. #endif
  152. {
  153. return eval<checked>(types<Args...>(),
  154. std::index_sequence<Is...>(),
  155. L_,
  156. start_index_,
  157. std::forward<Handler>(handler_),
  158. tracking_,
  159. std::forward<Fx>(fx_),
  160. std::forward<FxArgs>(fxargs_)...,
  161. stack_detail::unchecked_get_arg<Arg>(L_, start_index_ + tracking_.used, tracking_));
  162. }
  163. }
  164. template <bool checkargs = detail::default_safe_function_calls, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs>
  165. inline decltype(auto) call(types<R>, types<Args...> argument_types_, std::index_sequence<I...> argument_indices_, lua_State* L_,
  166. int start_index_, Fx&& fx_, FxArgs&&... args_) {
  167. static_assert(meta::all_v<meta::is_not_move_only<Args>...>,
  168. "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take "
  169. "a reference and std::move it manually if this was your intention.");
  170. argument_handler<types<R, Args...>> handler {};
  171. record tracking {};
  172. #if SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS)
  173. if constexpr (checkargs) {
  174. multi_check<Args...>(L_, start_index_, handler);
  175. }
  176. #endif
  177. if constexpr (std::is_void_v<R>) {
  178. eval<checkargs>(
  179. argument_types_, argument_indices_, L_, start_index_, handler, tracking, std::forward<Fx>(fx_), std::forward<FxArgs>(args_)...);
  180. }
  181. else {
  182. return eval<checkargs>(
  183. argument_types_, argument_indices_, L_, start_index_, handler, tracking, std::forward<Fx>(fx_), std::forward<FxArgs>(args_)...);
  184. }
  185. }
  186. template <typename T>
  187. void raw_table_set(lua_State* L, T&& arg, int tableindex = -2) {
  188. int push_count = push(L, std::forward<T>(arg));
  189. SOL_ASSERT(push_count == 1);
  190. std::size_t unique_index = static_cast<std::size_t>(luaL_len(L, tableindex) + 1u);
  191. lua_rawseti(L, tableindex, static_cast<int>(unique_index));
  192. }
  193. } // namespace stack_detail
  194. template <typename T>
  195. int set_ref(lua_State* L, T&& arg, int tableindex = -2) {
  196. int push_count = push(L, std::forward<T>(arg));
  197. SOL_ASSERT(push_count == 1);
  198. return luaL_ref(L, tableindex);
  199. }
  200. template <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs>
  201. inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
  202. using args_indices = std::make_index_sequence<sizeof...(Args)>;
  203. if constexpr (std::is_void_v<R>) {
  204. stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
  205. }
  206. else {
  207. return stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
  208. }
  209. }
  210. template <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs>
  211. inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
  212. if constexpr (std::is_void_v<R>) {
  213. call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
  214. }
  215. else {
  216. return call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
  217. }
  218. }
  219. template <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs>
  220. inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
  221. using expected_count_t = meta::count_for_pack<lua_size, Args...>;
  222. if constexpr (std::is_void_v<R>) {
  223. call<check_args>(tr,
  224. ta,
  225. L,
  226. (std::max)(static_cast<int>(lua_gettop(L) - expected_count_t::value), static_cast<int>(0)),
  227. std::forward<Fx>(fx),
  228. std::forward<FxArgs>(args)...);
  229. }
  230. else {
  231. return call<check_args>(tr,
  232. ta,
  233. L,
  234. (std::max)(static_cast<int>(lua_gettop(L) - expected_count_t::value), static_cast<int>(0)),
  235. std::forward<Fx>(fx),
  236. std::forward<FxArgs>(args)...);
  237. }
  238. }
  239. template <bool check_args = detail::default_safe_function_calls, bool clean_stack = true, typename Ret0, typename... Ret, typename... Args,
  240. typename Fx, typename... FxArgs>
  241. inline int call_into_lua(types<Ret0, Ret...> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
  242. if constexpr (std::is_void_v<Ret0>) {
  243. call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
  244. if constexpr (clean_stack) {
  245. lua_settop(L, 0);
  246. }
  247. return 0;
  248. }
  249. else {
  250. (void)tr;
  251. decltype(auto) r
  252. = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
  253. using R = meta::unqualified_t<decltype(r)>;
  254. using is_stack = meta::any<is_stack_based<R>, std::is_same<R, absolute_index>, std::is_same<R, ref_index>, std::is_same<R, raw_index>>;
  255. if constexpr (clean_stack && !is_stack::value) {
  256. lua_settop(L, 0);
  257. }
  258. return push_reference(L, std::forward<decltype(r)>(r));
  259. }
  260. }
  261. template <bool check_args = detail::default_safe_function_calls, bool clean_stack = true, typename Fx, typename... FxArgs>
  262. inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
  263. using traits_type = lua_bind_traits<meta::unqualified_t<Fx>>;
  264. using args_list = typename traits_type::args_list;
  265. using returns_list = typename traits_type::returns_list;
  266. return call_into_lua<check_args, clean_stack>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
  267. }
  268. inline call_syntax get_call_syntax(lua_State* L, const string_view& key, int index) {
  269. if (lua_gettop(L) < 1) {
  270. return call_syntax::dot;
  271. }
  272. luaL_getmetatable(L, key.data());
  273. auto pn = pop_n(L, 1);
  274. if (lua_compare(L, -1, index, LUA_OPEQ) != 1) {
  275. return call_syntax::dot;
  276. }
  277. return call_syntax::colon;
  278. }
  279. inline void script(
  280. lua_State* L, lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
  281. detail::typical_chunk_name_t basechunkname = {};
  282. const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname);
  283. if (lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) {
  284. lua_error(L);
  285. }
  286. }
  287. inline void script(
  288. lua_State* L, const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
  289. detail::typical_chunk_name_t basechunkname = {};
  290. const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);
  291. if (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) {
  292. lua_error(L);
  293. }
  294. }
  295. inline void script_file(lua_State* L, const std::string& filename, load_mode mode = load_mode::any) {
  296. if (luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) {
  297. lua_error(L);
  298. }
  299. }
  300. inline void luajit_exception_handler(lua_State* L, int (*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) {
  301. #if SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE)
  302. if (L == nullptr) {
  303. return;
  304. }
  305. #if SOL_IS_ON(SOL_SAFE_STACK_CHECK)
  306. luaL_checkstack(L, 1, detail::not_enough_stack_space_generic);
  307. #endif // make sure stack doesn't overflow
  308. lua_pushlightuserdata(L, (void*)handler);
  309. auto pn = pop_n(L, 1);
  310. luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON);
  311. #else
  312. (void)L;
  313. (void)handler;
  314. #endif
  315. }
  316. inline void luajit_exception_off(lua_State* L) {
  317. #if SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE)
  318. if (L == nullptr) {
  319. return;
  320. }
  321. luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF);
  322. #else
  323. (void)L;
  324. #endif
  325. }
  326. } // namespace stack
  327. } // namespace sol
  328. #endif // SOL_STACK_HPP