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