1 // The MIT License (MIT) 2 3 // Copyright (c) 2013-2016 Rapptz, ThePhD and contributors 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 // this software and associated documentation files (the "Software"), to deal in 7 // the Software without restriction, including without limitation the rights to 8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 // the Software, and to permit persons to whom the Software is furnished to do so, 10 // subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22 #ifndef SOL_STACK_HPP 23 #define SOL_STACK_HPP 24 25 #include "stack_core.hpp" 26 #include "stack_reference.hpp" 27 #include "stack_check.hpp" 28 #include "stack_get.hpp" 29 #include "stack_check_get.hpp" 30 #include "stack_push.hpp" 31 #include "stack_pop.hpp" 32 #include "stack_field.hpp" 33 #include "stack_probe.hpp" 34 #include <cstring> 35 #include <array> 36 37 namespace sol { 38 namespace stack { 39 namespace stack_detail { 40 template<typename T> push_as_upvalues(lua_State * L,T & item)41 inline int push_as_upvalues(lua_State* L, T& item) { 42 typedef std::decay_t<T> TValue; 43 const static std::size_t itemsize = sizeof(TValue); 44 const static std::size_t voidsize = sizeof(void*); 45 const static std::size_t voidsizem1 = voidsize - 1; 46 const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; 47 typedef std::array<void*, data_t_count> data_t; 48 49 data_t data{ {} }; 50 std::memcpy(&data[0], std::addressof(item), itemsize); 51 int pushcount = 0; 52 for (auto&& v : data) { 53 pushcount += push(L, lightuserdata_value(v)); 54 } 55 return pushcount; 56 } 57 58 template<typename T> get_as_upvalues(lua_State * L,int index=1)59 inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) { 60 const static std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); 61 typedef std::array<void*, data_t_count> data_t; 62 data_t voiddata{ {} }; 63 for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { 64 voiddata[i] = get<lightuserdata_value>(L, upvalue_index(index++)); 65 } 66 return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index); 67 } 68 69 struct evaluator { 70 template <typename Fx, typename... Args> evalsol::stack::stack_detail::evaluator71 static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, record&, Fx&& fx, Args&&... args) { 72 return std::forward<Fx>(fx)(std::forward<Args>(args)...); 73 } 74 75 template <typename Fx, typename Arg, typename... Args, std::size_t I, std::size_t... Is, typename... FxArgs> evalsol::stack::stack_detail::evaluator76 static decltype(auto) eval(types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L, int start, record& tracking, Fx&& fx, FxArgs&&... fxargs) { 77 return eval(types<Args...>(), std::index_sequence<Is...>(), L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)..., stack_detail::unchecked_get<Arg>(L, start + tracking.used, tracking)); 78 } 79 }; 80 81 template <bool checkargs = default_check_arguments, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>> call(types<R>,types<Args...> ta,std::index_sequence<I...> tai,lua_State * L,int start,Fx && fx,FxArgs &&...args)82 inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { 83 #ifndef _MSC_VER 84 static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "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 a reference and std::move it manually if this was your intention."); 85 #endif // This compiler make me so fucking sad 86 multi_check<checkargs, Args...>(L, start, type_panic); 87 record tracking{}; 88 return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); 89 } 90 91 template <bool checkargs = default_check_arguments, std::size_t... I, typename... Args, typename Fx, typename... FxArgs> call(types<void>,types<Args...> ta,std::index_sequence<I...> tai,lua_State * L,int start,Fx && fx,FxArgs &&...args)92 inline void call(types<void>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { 93 #ifndef _MSC_VER 94 static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "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 a reference and std::move it manually if this was your intention."); 95 #endif // This compiler make me so fucking sad 96 multi_check<checkargs, Args...>(L, start, type_panic); 97 record tracking{}; 98 evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); 99 } 100 } // stack_detail 101 102 template <typename T> set_ref(lua_State * L,T && arg,int tableindex=-2)103 int set_ref(lua_State* L, T&& arg, int tableindex = -2) { 104 push(L, std::forward<T>(arg)); 105 return luaL_ref(L, tableindex); 106 } 107 remove(lua_State * L,int index,int count)108 inline void remove(lua_State* L, int index, int count) { 109 if (count < 1) 110 return; 111 int top = lua_gettop(L); 112 if (index == -1 || top == index) { 113 // Slice them right off the top 114 lua_pop(L, static_cast<int>(count)); 115 return; 116 } 117 118 // Remove each item one at a time using stack operations 119 // Probably slower, maybe, haven't benchmarked, 120 // but necessary 121 if (index < 0) { 122 index = lua_gettop(L) + (index + 1); 123 } 124 int last = index + count; 125 for (int i = index; i < last; ++i) { 126 lua_remove(L, index); 127 } 128 } 129 130 template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>> call(types<R> tr,types<Args...> ta,lua_State * L,int start,Fx && fx,FxArgs &&...args)131 inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { 132 typedef std::make_index_sequence<sizeof...(Args)> args_indices; 133 return stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); 134 } 135 136 template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>> call(types<R> tr,types<Args...> ta,lua_State * L,Fx && fx,FxArgs &&...args)137 inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { 138 return call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); 139 } 140 141 template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs> call(types<void> tr,types<Args...> ta,lua_State * L,int start,Fx && fx,FxArgs &&...args)142 inline void call(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { 143 typedef std::make_index_sequence<sizeof...(Args)> args_indices; 144 stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); 145 } 146 147 template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs> call(types<void> tr,types<Args...> ta,lua_State * L,Fx && fx,FxArgs &&...args)148 inline void call(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { 149 call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); 150 } 151 152 template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>> call_from_top(types<R> tr,types<Args...> ta,lua_State * L,Fx && fx,FxArgs &&...args)153 inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { 154 return call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...); 155 } 156 157 template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs> call_from_top(types<void> tr,types<Args...> ta,lua_State * L,Fx && fx,FxArgs &&...args)158 inline void call_from_top(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { 159 call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...); 160 } 161 162 template<bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs> call_into_lua(types<void> tr,types<Args...> ta,lua_State * L,int start,Fx && fx,FxArgs &&...fxargs)163 inline int call_into_lua(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { 164 call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); 165 lua_settop(L, 0); 166 return 0; 167 } 168 169 template<bool check_args = stack_detail::default_check_arguments, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::neg<std::is_void<Ret0>>::value>> call_into_lua(types<Ret0,Ret...>,types<Args...> ta,lua_State * L,int start,Fx && fx,FxArgs &&...fxargs)170 inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { 171 decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); 172 lua_settop(L, 0); 173 return push_reference(L, std::forward<decltype(r)>(r)); 174 } 175 176 template<bool check_args = stack_detail::default_check_arguments, typename Fx, typename... FxArgs> call_lua(lua_State * L,int start,Fx && fx,FxArgs &&...fxargs)177 inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { 178 typedef lua_bind_traits<meta::unqualified_t<Fx>> traits_type; 179 typedef typename traits_type::args_list args_list; 180 typedef typename traits_type::returns_list returns_list; 181 return call_into_lua(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); 182 } 183 get_call_syntax(lua_State * L,const std::string & key,int index)184 inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) { 185 if (lua_gettop(L) == 0) { 186 return call_syntax::dot; 187 } 188 luaL_getmetatable(L, key.c_str()); 189 auto pn = pop_n(L, 1); 190 if (lua_compare(L, -1, index, LUA_OPEQ) != 1) { 191 return call_syntax::dot; 192 } 193 return call_syntax::colon; 194 } 195 script(lua_State * L,const std::string & code)196 inline void script(lua_State* L, const std::string& code) { 197 if (luaL_dostring(L, code.c_str())) { 198 lua_error(L); 199 } 200 } 201 script_file(lua_State * L,const std::string & filename)202 inline void script_file(lua_State* L, const std::string& filename) { 203 if (luaL_dofile(L, filename.c_str())) { 204 lua_error(L); 205 } 206 } 207 luajit_exception_handler(lua_State * L,int (* handler)(lua_State *,lua_CFunction)=detail::c_trampoline)208 inline void luajit_exception_handler(lua_State* L, int(*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) { 209 #ifdef SOL_LUAJIT 210 lua_pushlightuserdata(L, (void*)handler); 211 auto pn = pop_n(L, 1); 212 luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); 213 #else 214 (void)L; 215 (void)handler; 216 #endif 217 } 218 luajit_exception_off(lua_State * L)219 inline void luajit_exception_off(lua_State* L) { 220 #ifdef SOL_LUAJIT 221 luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF); 222 #else 223 (void)L; 224 #endif 225 } 226 } // stack 227 } // sol 228 229 #endif // SOL_STACK_HPP 230