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_CORE_HPP
23 #define SOL_STACK_CORE_HPP
24 
25 #include "types.hpp"
26 #include "reference.hpp"
27 #include "stack_reference.hpp"
28 #include "userdata.hpp"
29 #include "tuple.hpp"
30 #include "traits.hpp"
31 #include "tie.hpp"
32 #include "stack_guard.hpp"
33 #include <vector>
34 #include <string>
35 
36 namespace sol {
37 	namespace detail {
38 		struct as_reference_tag {};
39 		template <typename T>
40 		struct as_pointer_tag {};
41 		template <typename T>
42 		struct as_value_tag {};
43 
44 		using special_destruct_func = void(*)(void*);
45 
46 		template <typename T, typename Real>
special_destruct(void * memory)47 		inline void special_destruct(void* memory) {
48 			T** pointerpointer = static_cast<T**>(memory);
49 			special_destruct_func* dx = static_cast<special_destruct_func*>(static_cast<void*>(pointerpointer + 1));
50 			Real* target = static_cast<Real*>(static_cast<void*>(dx + 1));
51 			target->~Real();
52 		}
53 
54 		template <typename T>
unique_destruct(lua_State * L)55 		inline int unique_destruct(lua_State* L) {
56 			void* memory = lua_touserdata(L, 1);
57 			T** pointerpointer = static_cast<T**>(memory);
58 			special_destruct_func& dx = *static_cast<special_destruct_func*>(static_cast<void*>(pointerpointer + 1));
59 			(dx)(memory);
60 			return 0;
61 		}
62 
63 		template <typename T>
user_alloc_destroy(lua_State * L)64 		inline int user_alloc_destroy(lua_State* L) {
65 			void* rawdata = lua_touserdata(L, 1);
66 			T* data = static_cast<T*>(rawdata);
67 			std::allocator<T> alloc;
68 			alloc.destroy(data);
69 			return 0;
70 		}
71 
72 		template <typename T>
usertype_alloc_destroy(lua_State * L)73 		inline int usertype_alloc_destroy(lua_State* L) {
74 			void* rawdata = lua_touserdata(L, 1);
75 			T** pdata = static_cast<T**>(rawdata);
76 			T* data = *pdata;
77 			std::allocator<T> alloc{};
78 			alloc.destroy(data);
79 			return 0;
80 		}
81 
82 		template <typename T>
reserve(T &,std::size_t)83 		void reserve(T&, std::size_t) {}
84 
85 		template <typename T, typename Al>
reserve(std::vector<T,Al> & arr,std::size_t hint)86 		void reserve(std::vector<T, Al>& arr, std::size_t hint) {
87 			arr.reserve(hint);
88 		}
89 
90 		template <typename T, typename Tr, typename Al>
reserve(std::basic_string<T,Tr,Al> & arr,std::size_t hint)91 		void reserve(std::basic_string<T, Tr, Al>& arr, std::size_t hint) {
92 			arr.reserve(hint);
93 		}
94 	} // detail
95 
96 	namespace stack {
97 
98 		template<typename T, bool global = false, bool raw = false, typename = void>
99 		struct field_getter;
100 		template <typename T, bool global = false, bool raw = false, typename = void>
101 		struct probe_field_getter;
102 		template<typename T, bool global = false, bool raw = false, typename = void>
103 		struct field_setter;
104 		template<typename T, typename = void>
105 		struct getter;
106 		template<typename T, typename = void>
107 		struct popper;
108 		template<typename T, typename = void>
109 		struct pusher;
110 		template<typename T, type = lua_type_of<T>::value, typename = void>
111 		struct checker;
112 		template<typename T, typename = void>
113 		struct check_getter;
114 
115 		struct probe {
116 			bool success;
117 			int levels;
118 
probesol::stack::probe119 			probe(bool s, int l) : success(s), levels(l) {}
120 
operator boolsol::stack::probe121 			operator bool() const { return success; };
122 		};
123 
124 		struct record {
125 			int last;
126 			int used;
127 
recordsol::stack::record128 			record() : last(), used() {}
usesol::stack::record129 			void use(int count) {
130 				last = count;
131 				used += count;
132 			}
133 		};
134 
135 		namespace stack_detail {
136 			template <typename T>
137 			struct strip {
138 				typedef T type;
139 			};
140 			template <typename T>
141 			struct strip<std::reference_wrapper<T>> {
142 				typedef T& type;
143 			};
144 			template <typename T>
145 			struct strip<user<T>> {
146 				typedef T& type;
147 			};
148 			template <typename T>
149 			struct strip<non_null<T>> {
150 				typedef T type;
151 			};
152 			template <typename T>
153 			using strip_t = typename strip<T>::type;
154 			const bool default_check_arguments =
155 #ifdef SOL_CHECK_ARGUMENTS
156 				true;
157 #else
158 				false;
159 #endif
160 			template<typename T>
unchecked_get(lua_State * L,int index,record & tracking)161 			inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) {
162 				return getter<meta::unqualified_t<T>>{}.get(L, index, tracking);
163 			}
164 		} // stack_detail
165 
maybe_indexable(lua_State * L,int index=-1)166 		inline bool maybe_indexable(lua_State* L, int index = -1) {
167 			type t = type_of(L, index);
168 			return t == type::userdata || t == type::table;
169 		}
170 
171 		template<typename T, typename... Args>
push(lua_State * L,T && t,Args &&...args)172 		inline int push(lua_State* L, T&& t, Args&&... args) {
173 			return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
174 		}
175 
176 		// allow a pusher of a specific type, but pass in any kind of args
177 		template<typename T, typename Arg, typename... Args>
push_specific(lua_State * L,Arg && arg,Args &&...args)178 		inline int push_specific(lua_State* L, Arg&& arg, Args&&... args) {
179 			return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
180 		}
181 
182 		template<typename T, typename... Args>
push_reference(lua_State * L,T && t,Args &&...args)183 		inline int push_reference(lua_State* L, T&& t, Args&&... args) {
184 			typedef meta::all<
185 				std::is_lvalue_reference<T>,
186 				meta::neg<std::is_const<T>>,
187 				meta::neg<is_lua_primitive<meta::unqualified_t<T>>>,
188 				meta::neg<is_unique_usertype<meta::unqualified_t<T>>>
189 			> use_reference_tag;
190 			return pusher<std::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
191 		}
192 
multi_push(lua_State *)193 		inline int multi_push(lua_State*) {
194 			// do nothing
195 			return 0;
196 		}
197 
198 		template<typename T, typename... Args>
multi_push(lua_State * L,T && t,Args &&...args)199 		inline int multi_push(lua_State* L, T&& t, Args&&... args) {
200 			int pushcount = push(L, std::forward<T>(t));
201 			void(sol::detail::swallow{ (pushcount += sol::stack::push(L, std::forward<Args>(args)), 0)... });
202 			return pushcount;
203 		}
204 
multi_push_reference(lua_State *)205 		inline int multi_push_reference(lua_State*) {
206 			// do nothing
207 			return 0;
208 		}
209 
210 		template<typename T, typename... Args>
multi_push_reference(lua_State * L,T && t,Args &&...args)211 		inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) {
212 			int pushcount = push_reference(L, std::forward<T>(t));
213 			void(sol::detail::swallow{ (pushcount += sol::stack::push_reference(L, std::forward<Args>(args)), 0)... });
214 			return pushcount;
215 		}
216 
217 		template <typename T, typename Handler>
check(lua_State * L,int index,Handler && handler,record & tracking)218 		bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
219 			typedef meta::unqualified_t<T> Tu;
220 			checker<Tu> c;
221 			// VC++ has a bad warning here: shut it up
222 			(void)c;
223 			return c.check(L, index, std::forward<Handler>(handler), tracking);
224 		}
225 
226 		template <typename T, typename Handler>
check(lua_State * L,int index,Handler && handler)227 		bool check(lua_State* L, int index, Handler&& handler) {
228 			record tracking{};
229 			return check<T>(L, index, std::forward<Handler>(handler), tracking);
230 		}
231 
232 		template <typename T>
check(lua_State * L,int index=-lua_size<meta::unqualified_t<T>>::value)233 		bool check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
234 			auto handler = no_panic;
235 			return check<T>(L, index, handler);
236 		}
237 
238 		template<typename T, typename Handler>
check_get(lua_State * L,int index,Handler && handler,record & tracking)239 		inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
240 			return check_getter<meta::unqualified_t<T>>{}.get(L, index, std::forward<Handler>(handler), tracking);
241 		}
242 
243 		template<typename T, typename Handler>
check_get(lua_State * L,int index,Handler && handler)244 		inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler) {
245 			record tracking{};
246 			return check_get<T>(L, index, handler, tracking);
247 		}
248 
249 		template<typename T>
check_get(lua_State * L,int index=-lua_size<meta::unqualified_t<T>>::value)250 		inline decltype(auto) check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
251 			auto handler = no_panic;
252 			return check_get<T>(L, index, handler);
253 		}
254 
255 		namespace stack_detail {
256 
257 #ifdef SOL_CHECK_ARGUMENTS
258 			template <typename T>
tagged_get(types<T>,lua_State * L,int index,record & tracking)259 			inline auto tagged_get(types<T>, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {
260 				auto op = check_get<T>(L, index, type_panic, tracking);
261 				return *std::move(op);
262 			}
263 #else
264 			template <typename T>
265 			inline decltype(auto) tagged_get(types<T>, lua_State* L, int index, record& tracking) {
266 				return stack_detail::unchecked_get<T>(L, index, tracking);
267 			}
268 #endif
269 
270 			template <typename T>
tagged_get(types<optional<T>>,lua_State * L,int index,record & tracking)271 			inline decltype(auto) tagged_get(types<optional<T>>, lua_State* L, int index, record& tracking) {
272 				return stack_detail::unchecked_get<optional<T>>(L, index, tracking);
273 			}
274 
275 			template <bool b>
276 			struct check_types {
277 				template <typename T, typename... Args, typename Handler>
checksol::stack::stack_detail::check_types278 				static bool check(types<T, Args...>, lua_State* L, int firstargument, Handler&& handler, record& tracking) {
279 					if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking))
280 						return false;
281 					return check(types<Args...>(), L, firstargument, std::forward<Handler>(handler), tracking);
282 				}
283 
284 				template <typename Handler>
checksol::stack::stack_detail::check_types285 				static bool check(types<>, lua_State*, int, Handler&&, record&) {
286 					return true;
287 				}
288 			};
289 
290 			template <>
291 			struct check_types<false> {
292 				template <typename... Args, typename Handler>
checksol::stack::stack_detail::check_types293 				static bool check(types<Args...>, lua_State*, int, Handler&&, record&) {
294 					return true;
295 				}
296 			};
297 
298 		} // stack_detail
299 
300 		template <bool b, typename... Args, typename Handler>
multi_check(lua_State * L,int index,Handler && handler,record & tracking)301 		bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) {
302 			return stack_detail::check_types<b>{}.check(types<meta::unqualified_t<Args>...>(), L, index, std::forward<Handler>(handler), tracking);
303 		}
304 
305 		template <bool b, typename... Args, typename Handler>
multi_check(lua_State * L,int index,Handler && handler)306 		bool multi_check(lua_State* L, int index, Handler&& handler) {
307 			record tracking{};
308 			return multi_check<b, Args...>(L, index, std::forward<Handler>(handler), tracking);
309 		}
310 
311 		template <bool b, typename... Args>
multi_check(lua_State * L,int index)312 		bool multi_check(lua_State* L, int index) {
313 			auto handler = no_panic;
314 			return multi_check<b, Args...>(L, index, handler);
315 		}
316 
317 		template <typename... Args, typename Handler>
multi_check(lua_State * L,int index,Handler && handler,record & tracking)318 		bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) {
319 			return multi_check<true, Args...>(L, index, std::forward<Handler>(handler), tracking);
320 		}
321 
322 		template <typename... Args, typename Handler>
multi_check(lua_State * L,int index,Handler && handler)323 		bool multi_check(lua_State* L, int index, Handler&& handler) {
324 			return multi_check<true, Args...>(L, index, std::forward<Handler>(handler));
325 		}
326 
327 		template <typename... Args>
multi_check(lua_State * L,int index)328 		bool multi_check(lua_State* L, int index) {
329 			return multi_check<true, Args...>(L, index);
330 		}
331 
332 		template<typename T>
get(lua_State * L,int index,record & tracking)333 		inline decltype(auto) get(lua_State* L, int index, record& tracking) {
334 			return stack_detail::tagged_get(types<T>(), L, index, tracking);
335 		}
336 
337 		template<typename T>
get(lua_State * L,int index=-lua_size<meta::unqualified_t<T>>::value)338 		inline decltype(auto) get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
339 			record tracking{};
340 			return get<T>(L, index, tracking);
341 		}
342 
343 		template<typename T>
pop(lua_State * L)344 		inline decltype(auto) pop(lua_State* L) {
345 			return popper<meta::unqualified_t<T>>{}.pop(L);
346 		}
347 
348 		template <bool global = false, bool raw = false, typename Key>
get_field(lua_State * L,Key && key)349 		void get_field(lua_State* L, Key&& key) {
350 			field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key));
351 		}
352 
353 		template <bool global = false, bool raw = false, typename Key>
get_field(lua_State * L,Key && key,int tableindex)354 		void get_field(lua_State* L, Key&& key, int tableindex) {
355 			field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key), tableindex);
356 		}
357 
358 		template <bool global = false, typename Key>
raw_get_field(lua_State * L,Key && key)359 		void raw_get_field(lua_State* L, Key&& key) {
360 			get_field<global, true>(L, std::forward<Key>(key));
361 		}
362 
363 		template <bool global = false, typename Key>
raw_get_field(lua_State * L,Key && key,int tableindex)364 		void raw_get_field(lua_State* L, Key&& key, int tableindex) {
365 			get_field<global, true>(L, std::forward<Key>(key), tableindex);
366 		}
367 
368 		template <bool global = false, bool raw = false, typename Key>
probe_get_field(lua_State * L,Key && key)369 		probe probe_get_field(lua_State* L, Key&& key) {
370 			return probe_field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key));
371 		}
372 
373 		template <bool global = false, bool raw = false, typename Key>
probe_get_field(lua_State * L,Key && key,int tableindex)374 		probe probe_get_field(lua_State* L, Key&& key, int tableindex) {
375 			return probe_field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key), tableindex);
376 		}
377 
378 		template <bool global = false, typename Key>
probe_raw_get_field(lua_State * L,Key && key)379 		probe probe_raw_get_field(lua_State* L, Key&& key) {
380 			return probe_get_field<global, true>(L, std::forward<Key>(key));
381 		}
382 
383 		template <bool global = false, typename Key>
probe_raw_get_field(lua_State * L,Key && key,int tableindex)384 		probe probe_raw_get_field(lua_State* L, Key&& key, int tableindex) {
385 			return probe_get_field<global, true>(L, std::forward<Key>(key), tableindex);
386 		}
387 
388 		template <bool global = false, bool raw = false, typename Key, typename Value>
set_field(lua_State * L,Key && key,Value && value)389 		void set_field(lua_State* L, Key&& key, Value&& value) {
390 			field_setter<meta::unqualified_t<Key>, global, raw>{}.set(L, std::forward<Key>(key), std::forward<Value>(value));
391 		}
392 
393 		template <bool global = false, bool raw = false, typename Key, typename Value>
set_field(lua_State * L,Key && key,Value && value,int tableindex)394 		void set_field(lua_State* L, Key&& key, Value&& value, int tableindex) {
395 			field_setter<meta::unqualified_t<Key>, global, raw>{}.set(L, std::forward<Key>(key), std::forward<Value>(value), tableindex);
396 		}
397 
398 		template <bool global = false, typename Key, typename Value>
raw_set_field(lua_State * L,Key && key,Value && value)399 		void raw_set_field(lua_State* L, Key&& key, Value&& value) {
400 			set_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value));
401 		}
402 
403 		template <bool global = false, typename Key, typename Value>
raw_set_field(lua_State * L,Key && key,Value && value,int tableindex)404 		void raw_set_field(lua_State* L, Key&& key, Value&& value, int tableindex) {
405 			set_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value), tableindex);
406 		}
407 	} // stack
408 } // sol
409 
410 #endif // SOL_STACK_CORE_HPP
411