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