1 // sol2 2 3 // The MIT License (MIT) 4 5 // Copyright (c) 2013-2018 Rapptz, ThePhD and contributors 6 7 // Permission is hereby granted, free of charge, to any person obtaining a copy of 8 // this software and associated documentation files (the "Software"), to deal in 9 // the Software without restriction, including without limitation the rights to 10 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 // the Software, and to permit persons to whom the Software is furnished to do so, 12 // subject to the following conditions: 13 14 // The above copyright notice and this permission notice shall be included in all 15 // copies or substantial portions of the Software. 16 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 #ifndef SOL_STACK_PUSH_HPP 25 #define SOL_STACK_PUSH_HPP 26 27 #include "stack_core.hpp" 28 #include "raii.hpp" 29 #include "optional.hpp" 30 #include "usertype_traits.hpp" 31 #include "filters.hpp" 32 #include "unicode.hpp" 33 34 #include <memory> 35 #include <type_traits> 36 #include <cassert> 37 #include <limits> 38 #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES 39 #include <string_view> 40 #include <optional> 41 #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT 42 #include <variant> 43 #endif // Can use variant 44 #endif // C++17 45 46 namespace sol { 47 namespace stack { push_environment_of(lua_State * L,int index=-1)48 inline int push_environment_of(lua_State* L, int index = -1) { 49 #if SOL_LUA_VERSION < 502 50 // Use lua_getfenv 51 lua_getfenv(L, index); 52 return 1; 53 #else 54 // Use upvalues as explained in Lua 5.2 and beyond's manual 55 if (lua_getupvalue(L, index, 1) == nullptr) { 56 push(L, lua_nil); 57 return 1; 58 } 59 #endif 60 return 1; 61 } 62 63 template <typename T> push_environment_of(const T & target)64 int push_environment_of(const T& target) { 65 target.push(); 66 return push_environment_of(target.lua_state(), -1) + 1; 67 } 68 69 template <typename T> 70 struct pusher<detail::as_value_tag<T>> { 71 template <typename F, typename... Args> push_fxsol::stack::pusher72 static int push_fx(lua_State* L, F&& f, Args&&... args) { 73 // Basically, we store all user-data like this: 74 // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new 75 // data in the first sizeof(T*) bytes, and then however many bytes it takes to 76 // do the actual object. Things that are std::ref or plain T* are stored as 77 // just the sizeof(T*), and nothing else. 78 T* obj = detail::usertype_allocate<T>(L); 79 std::allocator<T> alloc{}; 80 std::allocator_traits<std::allocator<T>>::construct(alloc, obj, std::forward<Args>(args)...); 81 f(); 82 return 1; 83 } 84 85 template <typename K, typename... Args> push_keyedsol::stack::pusher86 static int push_keyed(lua_State* L, K&& k, Args&&... args) { 87 stack_detail::undefined_metatable<T> fx(L, &k[0]); 88 return push_fx(L, fx, std::forward<Args>(args)...); 89 } 90 91 template <typename... Args> pushsol::stack::pusher92 static int push(lua_State* L, Args&&... args) { 93 return push_keyed(L, usertype_traits<T>::metatable(), std::forward<Args>(args)...); 94 } 95 }; 96 97 template <typename T> 98 struct pusher<detail::as_pointer_tag<T>> { 99 typedef meta::unqualified_t<T> U; 100 101 template <typename F> push_fxsol::stack::pusher102 static int push_fx(lua_State* L, F&& f, T* obj) { 103 if (obj == nullptr) 104 return stack::push(L, lua_nil); 105 T** pref = detail::usertype_allocate_pointer<T>(L); 106 *pref = obj; 107 f(); 108 return 1; 109 } 110 111 template <typename K> push_keyedsol::stack::pusher112 static int push_keyed(lua_State* L, K&& k, T* obj) { 113 stack_detail::undefined_metatable<U*> fx(L, &k[0]); 114 return push_fx(L, fx, obj); 115 } 116 pushsol::stack::pusher117 static int push(lua_State* L, T* obj) { 118 return push_keyed(L, usertype_traits<U*>::metatable(), obj); 119 } 120 }; 121 122 template <> 123 struct pusher<detail::as_reference_tag> { 124 template <typename T> pushsol::stack::pusher125 static int push(lua_State* L, T&& obj) { 126 return stack::push(L, detail::ptr(obj)); 127 } 128 }; 129 130 template <typename T, typename> 131 struct pusher { 132 template <typename... Args> pushsol::stack::pusher133 static int push(lua_State* L, Args&&... args) { 134 return pusher<detail::as_value_tag<T>>{}.push(L, std::forward<Args>(args)...); 135 } 136 }; 137 138 template <typename T> 139 struct pusher<T*, meta::disable_if_t<meta::any<is_container<meta::unqualified_t<T>>, std::is_function<meta::unqualified_t<T>>, is_lua_reference<meta::unqualified_t<T>>>::value>> { 140 template <typename... Args> pushsol::stack::pusher141 static int push(lua_State* L, Args&&... args) { 142 return pusher<detail::as_pointer_tag<T>>{}.push(L, std::forward<Args>(args)...); 143 } 144 }; 145 146 template <typename T> 147 struct pusher<T, std::enable_if_t<is_unique_usertype<T>::value>> { 148 typedef typename unique_usertype_traits<T>::type P; 149 typedef typename unique_usertype_traits<T>::actual_type Real; 150 151 template <typename Arg, meta::enable<std::is_base_of<Real, meta::unqualified_t<Arg>>> = meta::enabler> pushsol::stack::pusher152 static int push(lua_State* L, Arg&& arg) { 153 if (unique_usertype_traits<T>::is_null(arg)) { 154 return stack::push(L, lua_nil); 155 } 156 return push_deep(L, std::forward<Arg>(arg)); 157 } 158 159 template <typename Arg0, typename Arg1, typename... Args> pushsol::stack::pusher160 static int push(lua_State* L, Arg0&& arg0, Arg0&& arg1, Args&&... args) { 161 return push_deep(L, std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...); 162 } 163 164 template <typename... Args> push_deepsol::stack::pusher165 static int push_deep(lua_State* L, Args&&... args) { 166 P** pref = nullptr; 167 detail::unique_destructor* fx = nullptr; 168 detail::unique_tag* id = nullptr; 169 Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id); 170 *fx = detail::usertype_unique_alloc_destroy<P, Real>; 171 #if 0 172 *id = &detail::inheritance<P>::type_unique_cast_bases<Real>; 173 #else 174 *id = &usertype_traits<Real>::qualified_name()[0]; 175 #endif 176 detail::default_construct::construct(mem, std::forward<Args>(args)...); 177 *pref = unique_usertype_traits<T>::get(*mem); 178 if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) { 179 luaL_Reg l[32]{}; 180 int index = 0; 181 auto prop_fx = [](meta_function) { return true; }; 182 usertype_detail::insert_default_registrations<P>(l, index, prop_fx); 183 usertype_detail::make_destructor<T>(l, index); 184 luaL_setfuncs(L, l, 0); 185 } 186 lua_setmetatable(L, -2); 187 return 1; 188 } 189 }; 190 191 template <typename T> 192 struct pusher<std::reference_wrapper<T>> { pushsol::stack::pusher193 static int push(lua_State* L, const std::reference_wrapper<T>& t) { 194 return stack::push(L, std::addressof(detail::deref(t.get()))); 195 } 196 }; 197 198 template <typename T> 199 struct pusher<T, std::enable_if_t<std::is_floating_point<T>::value>> { pushsol::stack::pusher200 static int push(lua_State* L, const T& value) { 201 lua_pushnumber(L, value); 202 return 1; 203 } 204 }; 205 206 template <typename T> 207 struct pusher<T, std::enable_if_t<std::is_integral<T>::value>> { pushsol::stack::pusher208 static int push(lua_State* L, const T& value) { 209 #if SOL_LUA_VERSION >= 503 210 static auto integer_value_fits = [](T const& value) { 211 if (sizeof(T) < sizeof(lua_Integer) || (std::is_signed<T>::value && sizeof(T) == sizeof(lua_Integer))) { 212 return true; 213 } 214 auto u_min = static_cast<std::intmax_t>((std::numeric_limits<lua_Integer>::min)()); 215 auto u_max = static_cast<std::uintmax_t>((std::numeric_limits<lua_Integer>::max)()); 216 auto t_min = static_cast<std::intmax_t>((std::numeric_limits<T>::min)()); 217 auto t_max = static_cast<std::uintmax_t>((std::numeric_limits<T>::max)()); 218 return (u_min <= t_min || value >= static_cast<T>(u_min)) && (u_max >= t_max || value <= static_cast<T>(u_max)); 219 }; 220 if (integer_value_fits(value)) { 221 lua_pushinteger(L, static_cast<lua_Integer>(value)); 222 return 1; 223 } 224 #endif // Lua 5.3 and above 225 #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) 226 if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) { 227 #if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS 228 // Is this really worth it? 229 assert(false && "integer value will be misrepresented in lua"); 230 lua_pushnumber(L, static_cast<lua_Number>(value)); 231 return 1; 232 #else 233 throw error(detail::direct_error, "integer value will be misrepresented in lua"); 234 #endif // No Exceptions 235 } 236 #endif // Safe Numerics and Number Precision Check 237 lua_pushnumber(L, static_cast<lua_Number>(value)); 238 return 1; 239 } 240 }; 241 242 template <typename T> 243 struct pusher<T, std::enable_if_t<std::is_enum<T>::value>> { pushsol::stack::pusher244 static int push(lua_State* L, const T& value) { 245 if (std::is_same<char, std::underlying_type_t<T>>::value) { 246 return stack::push(L, static_cast<int>(value)); 247 } 248 return stack::push(L, static_cast<std::underlying_type_t<T>>(value)); 249 } 250 }; 251 252 template <typename T> 253 struct pusher<detail::as_table_tag<T>> { pushsol::stack::pusher254 static int push(lua_State* L, const T& tablecont) { 255 typedef meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>> has_kvp; 256 return push(has_kvp(), std::false_type(), L, tablecont); 257 } 258 pushsol::stack::pusher259 static int push(std::true_type, lua_State* L, const T& tablecont) { 260 typedef meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>> has_kvp; 261 return push(has_kvp(), std::true_type(), L, tablecont); 262 } 263 pushsol::stack::pusher264 static int push(std::false_type, lua_State* L, const T& tablecont) { 265 typedef meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>> has_kvp; 266 return push(has_kvp(), std::false_type(), L, tablecont); 267 } 268 269 template <bool is_nested> pushsol::stack::pusher270 static int push(std::true_type, std::integral_constant<bool, is_nested>, lua_State* L, const T& tablecont) { 271 auto& cont = detail::deref(detail::unwrap(tablecont)); 272 lua_createtable(L, static_cast<int>(cont.size()), 0); 273 int tableindex = lua_gettop(L); 274 for (const auto& pair : cont) { 275 if (is_nested) { 276 set_field(L, pair.first, as_nested_ref(pair.second), tableindex); 277 } 278 else { 279 set_field(L, pair.first, pair.second, tableindex); 280 } 281 } 282 return 1; 283 } 284 285 template <bool is_nested> pushsol::stack::pusher286 static int push(std::false_type, std::integral_constant<bool, is_nested>, lua_State* L, const T& tablecont) { 287 auto& cont = detail::deref(detail::unwrap(tablecont)); 288 lua_createtable(L, stack_detail::get_size_hint(cont), 0); 289 int tableindex = lua_gettop(L); 290 std::size_t index = 1; 291 for (const auto& i : cont) { 292 #if SOL_LUA_VERSION >= 503 293 int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); 294 for (int pi = 0; pi < p; ++pi) { 295 lua_seti(L, tableindex, static_cast<lua_Integer>(index++)); 296 } 297 #else 298 lua_pushinteger(L, static_cast<lua_Integer>(index)); 299 int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); 300 if (p == 1) { 301 ++index; 302 lua_settable(L, tableindex); 303 } 304 else { 305 int firstindex = tableindex + 1 + 1; 306 for (int pi = 0; pi < p; ++pi) { 307 stack::push(L, index); 308 lua_pushvalue(L, firstindex); 309 lua_settable(L, tableindex); 310 ++index; 311 ++firstindex; 312 } 313 lua_pop(L, 1 + p); 314 } 315 #endif // Lua Version 5.3 and others 316 } 317 // TODO: figure out a better way to do this...? 318 //set_field(L, -1, cont.size()); 319 return 1; 320 } 321 }; 322 323 template <typename T> 324 struct pusher<as_table_t<T>, std::enable_if_t<is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { pushsol::stack::pusher325 static int push(lua_State* L, const T& tablecont) { 326 return stack::push<detail::as_table_tag<T>>(L, tablecont); 327 } 328 }; 329 330 template <typename T> 331 struct pusher<as_table_t<T>, std::enable_if_t<!is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { pushsol::stack::pusher332 static int push(lua_State* L, const T& v) { 333 return stack::push(L, v); 334 } 335 }; 336 337 template <typename T> 338 struct pusher<nested<T>, std::enable_if_t<is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { pushsol::stack::pusher339 static int push(lua_State* L, const T& tablecont) { 340 pusher<detail::as_table_tag<T>> p{}; 341 // silence annoying VC++ warning 342 (void)p; 343 return p.push(std::true_type(), L, tablecont); 344 } 345 }; 346 347 template <typename T> 348 struct pusher<nested<T>, std::enable_if_t<!is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { pushsol::stack::pusher349 static int push(lua_State* L, const T& tablecont) { 350 pusher<meta::unqualified_t<T>> p{}; 351 // silence annoying VC++ warning 352 (void)p; 353 return p.push(L, tablecont); 354 } 355 }; 356 357 template <typename T> 358 struct pusher<std::initializer_list<T>> { pushsol::stack::pusher359 static int push(lua_State* L, const std::initializer_list<T>& il) { 360 pusher<detail::as_table_tag<std::initializer_list<T>>> p{}; 361 // silence annoying VC++ warning 362 (void)p; 363 return p.push(L, il); 364 } 365 }; 366 367 template <typename T> 368 struct pusher<T, std::enable_if_t<is_lua_reference<T>::value>> { pushsol::stack::pusher369 static int push(lua_State* L, const T& ref) { 370 return ref.push(L); 371 } 372 pushsol::stack::pusher373 static int push(lua_State* L, T&& ref) { 374 return ref.push(L); 375 } 376 }; 377 378 template <> 379 struct pusher<bool> { pushsol::stack::pusher380 static int push(lua_State* L, bool b) { 381 lua_pushboolean(L, b); 382 return 1; 383 } 384 }; 385 386 template <> 387 struct pusher<lua_nil_t> { pushsol::stack::pusher388 static int push(lua_State* L, lua_nil_t) { 389 lua_pushnil(L); 390 return 1; 391 } 392 }; 393 394 template <> 395 struct pusher<stack_count> { pushsol::stack::pusher396 static int push(lua_State*, stack_count st) { 397 return st.count; 398 } 399 }; 400 401 template <> 402 struct pusher<metatable_t> { pushsol::stack::pusher403 static int push(lua_State* L, metatable_t) { 404 lua_pushlstring(L, "__mt", 4); 405 return 1; 406 } 407 }; 408 409 template <> 410 struct pusher<std::remove_pointer_t<lua_CFunction>> { pushsol::stack::pusher411 static int push(lua_State* L, lua_CFunction func, int n = 0) { 412 lua_pushcclosure(L, func, n); 413 return 1; 414 } 415 }; 416 417 template <> 418 struct pusher<lua_CFunction> { pushsol::stack::pusher419 static int push(lua_State* L, lua_CFunction func, int n = 0) { 420 lua_pushcclosure(L, func, n); 421 return 1; 422 } 423 }; 424 425 #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE 426 template <> 427 struct pusher<std::remove_pointer_t<detail::lua_CFunction_noexcept>> { pushsol::stack::pusher428 static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { 429 lua_pushcclosure(L, func, n); 430 return 1; 431 } 432 }; 433 434 template <> 435 struct pusher<detail::lua_CFunction_noexcept> { pushsol::stack::pusher436 static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { 437 lua_pushcclosure(L, func, n); 438 return 1; 439 } 440 }; 441 #endif // noexcept function type 442 443 template <> 444 struct pusher<c_closure> { pushsol::stack::pusher445 static int push(lua_State* L, c_closure cc) { 446 lua_pushcclosure(L, cc.c_function, cc.upvalues); 447 return 1; 448 } 449 }; 450 451 template <typename Arg, typename... Args> 452 struct pusher<closure<Arg, Args...>> { 453 template <std::size_t... I, typename T> pushsol::stack::pusher454 static int push(std::index_sequence<I...>, lua_State* L, T&& c) { 455 int pushcount = multi_push(L, detail::forward_get<I>(c.upvalues)...); 456 return stack::push(L, c_closure(c.c_function, pushcount)); 457 } 458 459 template <typename T> pushsol::stack::pusher460 static int push(lua_State* L, T&& c) { 461 return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward<T>(c)); 462 } 463 }; 464 465 template <> 466 struct pusher<void*> { pushsol::stack::pusher467 static int push(lua_State* L, void* userdata) { 468 lua_pushlightuserdata(L, userdata); 469 return 1; 470 } 471 }; 472 473 template <> 474 struct pusher<const void*> { pushsol::stack::pusher475 static int push(lua_State* L, const void* userdata) { 476 lua_pushlightuserdata(L, const_cast<void*>(userdata)); 477 return 1; 478 } 479 }; 480 481 template <> 482 struct pusher<lightuserdata_value> { pushsol::stack::pusher483 static int push(lua_State* L, lightuserdata_value userdata) { 484 lua_pushlightuserdata(L, userdata); 485 return 1; 486 } 487 }; 488 489 template <typename T> 490 struct pusher<light<T>> { pushsol::stack::pusher491 static int push(lua_State* L, light<T> l) { 492 lua_pushlightuserdata(L, static_cast<void*>(l.value)); 493 return 1; 494 } 495 }; 496 497 template <typename T> 498 struct pusher<user<T>> { 499 template <bool with_meta = true, typename Key, typename... Args> push_withsol::stack::pusher500 static int push_with(lua_State* L, Key&& name, Args&&... args) { 501 // A dumb pusher 502 T* data = detail::user_allocate<T>(L); 503 std::allocator<T> alloc{}; 504 std::allocator_traits<std::allocator<T>>::construct(alloc, data, std::forward<Args>(args)...); 505 if (with_meta) { 506 // Make sure we have a plain GC set for this data 507 if (luaL_newmetatable(L, name) != 0) { 508 lua_CFunction cdel = detail::user_alloc_destruct<T>; 509 lua_pushcclosure(L, cdel, 0); 510 lua_setfield(L, -2, "__gc"); 511 } 512 lua_setmetatable(L, -2); 513 } 514 return 1; 515 } 516 517 template <typename Arg, typename... Args, meta::disable<meta::any_same<meta::unqualified_t<Arg>, no_metatable_t, metatable_t>> = meta::enabler> pushsol::stack::pusher518 static int push(lua_State* L, Arg&& arg, Args&&... args) { 519 const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; 520 return push_with(L, name, std::forward<Arg>(arg), std::forward<Args>(args)...); 521 } 522 523 template <typename... Args> pushsol::stack::pusher524 static int push(lua_State* L, no_metatable_t, Args&&... args) { 525 const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; 526 return push_with<false>(L, name, std::forward<Args>(args)...); 527 } 528 529 template <typename Key, typename... Args> pushsol::stack::pusher530 static int push(lua_State* L, metatable_t, Key&& key, Args&&... args) { 531 const auto name = &key[0]; 532 return push_with<true>(L, name, std::forward<Args>(args)...); 533 } 534 pushsol::stack::pusher535 static int push(lua_State* L, const user<T>& u) { 536 const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; 537 return push_with(L, name, u.value); 538 } 539 pushsol::stack::pusher540 static int push(lua_State* L, user<T>&& u) { 541 const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; 542 return push_with(L, name, std::move(u.value)); 543 } 544 pushsol::stack::pusher545 static int push(lua_State* L, no_metatable_t, const user<T>& u) { 546 const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; 547 return push_with<false>(L, name, u.value); 548 } 549 pushsol::stack::pusher550 static int push(lua_State* L, no_metatable_t, user<T>&& u) { 551 const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; 552 return push_with<false>(L, name, std::move(u.value)); 553 } 554 }; 555 556 template <> 557 struct pusher<userdata_value> { pushsol::stack::pusher558 static int push(lua_State* L, userdata_value data) { 559 void** ud = detail::usertype_allocate_pointer<void>(L); 560 *ud = data.value; 561 return 1; 562 } 563 }; 564 565 template <> 566 struct pusher<const char*> { push_sizedsol::stack::pusher567 static int push_sized(lua_State* L, const char* str, std::size_t len) { 568 lua_pushlstring(L, str, len); 569 return 1; 570 } 571 pushsol::stack::pusher572 static int push(lua_State* L, const char* str) { 573 if (str == nullptr) 574 return stack::push(L, lua_nil); 575 return push_sized(L, str, std::char_traits<char>::length(str)); 576 } 577 pushsol::stack::pusher578 static int push(lua_State* L, const char* strb, const char* stre) { 579 return push_sized(L, strb, stre - strb); 580 } 581 pushsol::stack::pusher582 static int push(lua_State* L, const char* str, std::size_t len) { 583 return push_sized(L, str, len); 584 } 585 }; 586 587 template <> 588 struct pusher<char*> { push_sizedsol::stack::pusher589 static int push_sized(lua_State* L, const char* str, std::size_t len) { 590 pusher<const char*> p{}; 591 (void)p; 592 return p.push_sized(L, str, len); 593 } 594 pushsol::stack::pusher595 static int push(lua_State* L, const char* str) { 596 pusher<const char*> p{}; 597 (void)p; 598 return p.push(L, str); 599 } 600 pushsol::stack::pusher601 static int push(lua_State* L, const char* strb, const char* stre) { 602 pusher<const char*> p{}; 603 (void)p; 604 return p.push(L, strb, stre); 605 } 606 pushsol::stack::pusher607 static int push(lua_State* L, const char* str, std::size_t len) { 608 pusher<const char*> p{}; 609 (void)p; 610 return p.push(L, str, len); 611 } 612 }; 613 614 template <size_t N> 615 struct pusher<char[N]> { pushsol::stack::pusher616 static int push(lua_State* L, const char (&str)[N]) { 617 lua_pushlstring(L, str, std::char_traits<char>::length(str)); 618 return 1; 619 } 620 pushsol::stack::pusher621 static int push(lua_State* L, const char (&str)[N], std::size_t sz) { 622 lua_pushlstring(L, str, sz); 623 return 1; 624 } 625 }; 626 627 template <> 628 struct pusher<char> { pushsol::stack::pusher629 static int push(lua_State* L, char c) { 630 const char str[2] = { c, '\0' }; 631 return stack::push(L, str, 1); 632 } 633 }; 634 635 template <typename Traits, typename Al> 636 struct pusher<std::basic_string<char, Traits, Al>> { pushsol::stack::pusher637 static int push(lua_State* L, const std::basic_string<char, Traits, Al>& str) { 638 lua_pushlstring(L, str.c_str(), str.size()); 639 return 1; 640 } 641 pushsol::stack::pusher642 static int push(lua_State* L, const std::basic_string<char, Traits, Al>& str, std::size_t sz) { 643 lua_pushlstring(L, str.c_str(), sz); 644 return 1; 645 } 646 }; 647 648 template <typename Ch, typename Traits> 649 struct pusher<basic_string_view<Ch, Traits>> { pushsol::stack::pusher650 static int push(lua_State* L, const basic_string_view<Ch, Traits>& sv) { 651 return stack::push(L, sv.data(), sv.length()); 652 } 653 pushsol::stack::pusher654 static int push(lua_State* L, const basic_string_view<Ch, Traits>& sv, std::size_t n) { 655 return stack::push(L, sv.data(), n); 656 } 657 }; 658 659 template <> 660 struct pusher<meta_function> { pushsol::stack::pusher661 static int push(lua_State* L, meta_function m) { 662 const std::string& str = to_string(m); 663 lua_pushlstring(L, str.c_str(), str.size()); 664 return 1; 665 } 666 }; 667 668 template <> 669 struct pusher<absolute_index> { pushsol::stack::pusher670 static int push(lua_State* L, absolute_index ai) { 671 lua_pushvalue(L, ai); 672 return 1; 673 } 674 }; 675 676 template <> 677 struct pusher<raw_index> { pushsol::stack::pusher678 static int push(lua_State* L, raw_index ri) { 679 lua_pushvalue(L, ri); 680 return 1; 681 } 682 }; 683 684 template <> 685 struct pusher<ref_index> { pushsol::stack::pusher686 static int push(lua_State* L, ref_index ri) { 687 lua_rawgeti(L, LUA_REGISTRYINDEX, ri); 688 return 1; 689 } 690 }; 691 692 template <> 693 struct pusher<const wchar_t*> { pushsol::stack::pusher694 static int push(lua_State* L, const wchar_t* wstr) { 695 return push(L, wstr, std::char_traits<wchar_t>::length(wstr)); 696 } 697 pushsol::stack::pusher698 static int push(lua_State* L, const wchar_t* wstr, std::size_t sz) { 699 return push(L, wstr, wstr + sz); 700 } 701 pushsol::stack::pusher702 static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { 703 if (sizeof(wchar_t) == 2) { 704 const char16_t* sb = reinterpret_cast<const char16_t*>(strb); 705 const char16_t* se = reinterpret_cast<const char16_t*>(stre); 706 return stack::push(L, sb, se); 707 } 708 const char32_t* sb = reinterpret_cast<const char32_t*>(strb); 709 const char32_t* se = reinterpret_cast<const char32_t*>(stre); 710 return stack::push(L, sb, se); 711 } 712 }; 713 714 template <> 715 struct pusher<wchar_t*> { pushsol::stack::pusher716 static int push(lua_State* L, const wchar_t* str) { 717 pusher<const wchar_t*> p{}; 718 (void)p; 719 return p.push(L, str); 720 } 721 pushsol::stack::pusher722 static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { 723 pusher<const wchar_t*> p{}; 724 (void)p; 725 return p.push(L, strb, stre); 726 } 727 pushsol::stack::pusher728 static int push(lua_State* L, const wchar_t* str, std::size_t len) { 729 pusher<const wchar_t*> p{}; 730 (void)p; 731 return p.push(L, str, len); 732 } 733 }; 734 735 template <> 736 struct pusher<const char16_t*> { convert_intosol::stack::pusher737 static int convert_into(lua_State* L, char* start, std::size_t, const char16_t* strb, const char16_t* stre) { 738 char* target = start; 739 char32_t cp = 0; 740 for (const char16_t* strtarget = strb; strtarget < stre;) { 741 auto dr = unicode::utf16_to_code_point(strtarget, stre); 742 if (dr.error != unicode::error_code::ok) { 743 cp = unicode::unicode_detail::replacement; 744 } 745 else { 746 cp = dr.codepoint; 747 } 748 auto er = unicode::code_point_to_utf8(cp); 749 const char* utf8data = er.code_units.data(); 750 std::memcpy(target, utf8data, er.code_units_size); 751 target += er.code_units_size; 752 strtarget = dr.next; 753 } 754 755 return stack::push(L, start, target); 756 } 757 pushsol::stack::pusher758 static int push(lua_State* L, const char16_t* u16str) { 759 return push(L, u16str, std::char_traits<char16_t>::length(u16str)); 760 } 761 pushsol::stack::pusher762 static int push(lua_State* L, const char16_t* u16str, std::size_t sz) { 763 return push(L, u16str, u16str + sz); 764 } 765 pushsol::stack::pusher766 static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { 767 // TODO: use new unicode methods 768 // TODO: use new unicode methods 769 char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; 770 // if our max string space is small enough, use SBO 771 // right off the bat 772 std::size_t max_possible_code_units = (stre - strb) * 4; 773 if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { 774 return convert_into(L, sbo, max_possible_code_units, strb, stre); 775 } 776 // otherwise, we must manually count/check size 777 std::size_t needed_size = 0; 778 for (const char16_t* strtarget = strb; strtarget < stre;) { 779 auto dr = unicode::utf16_to_code_point(strtarget, stre); 780 auto er = unicode::code_point_to_utf8(dr.codepoint); 781 needed_size += er.code_units_size; 782 strtarget = dr.next; 783 } 784 if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { 785 return convert_into(L, sbo, needed_size, strb, stre); 786 } 787 std::string u8str("", 0); 788 u8str.resize(needed_size); 789 char* target = &u8str[0]; 790 return convert_into(L, target, needed_size, strb, stre); 791 } 792 }; 793 794 template <> 795 struct pusher<char16_t*> { pushsol::stack::pusher796 static int push(lua_State* L, const char16_t* str) { 797 pusher<const char16_t*> p{}; 798 (void)p; 799 return p.push(L, str); 800 } 801 pushsol::stack::pusher802 static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { 803 pusher<const char16_t*> p{}; 804 (void)p; 805 return p.push(L, strb, stre); 806 } 807 pushsol::stack::pusher808 static int push(lua_State* L, const char16_t* str, std::size_t len) { 809 pusher<const char16_t*> p{}; 810 (void)p; 811 return p.push(L, str, len); 812 } 813 }; 814 815 template <> 816 struct pusher<const char32_t*> { convert_intosol::stack::pusher817 static int convert_into(lua_State* L, char* start, std::size_t, const char32_t* strb, const char32_t* stre) { 818 char* target = start; 819 char32_t cp = 0; 820 for (const char32_t* strtarget = strb; strtarget < stre;) { 821 auto dr = unicode::utf32_to_code_point(strtarget, stre); 822 if (dr.error != unicode::error_code::ok) { 823 cp = unicode::unicode_detail::replacement; 824 } 825 else { 826 cp = dr.codepoint; 827 } 828 auto er = unicode::code_point_to_utf8(cp); 829 const char* data = er.code_units.data(); 830 std::memcpy(target, data, er.code_units_size); 831 target += er.code_units_size; 832 strtarget = dr.next; 833 } 834 return stack::push(L, start, target); 835 } 836 pushsol::stack::pusher837 static int push(lua_State* L, const char32_t* u32str) { 838 return push(L, u32str, u32str + std::char_traits<char32_t>::length(u32str)); 839 } 840 pushsol::stack::pusher841 static int push(lua_State* L, const char32_t* u32str, std::size_t sz) { 842 return push(L, u32str, u32str + sz); 843 } 844 pushsol::stack::pusher845 static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { 846 // TODO: use new unicode methods 847 char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; 848 // if our max string space is small enough, use SBO 849 // right off the bat 850 std::size_t max_possible_code_units = (stre - strb) * 4; 851 if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { 852 return convert_into(L, sbo, max_possible_code_units, strb, stre); 853 } 854 // otherwise, we must manually count/check size 855 std::size_t needed_size = 0; 856 for (const char32_t* strtarget = strb; strtarget < stre;) { 857 auto dr = unicode::utf32_to_code_point(strtarget, stre); 858 auto er = unicode::code_point_to_utf8(dr.codepoint); 859 needed_size += er.code_units_size; 860 strtarget = dr.next; 861 } 862 if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { 863 return convert_into(L, sbo, needed_size, strb, stre); 864 } 865 std::string u8str("", 0); 866 u8str.resize(needed_size); 867 char* target = &u8str[0]; 868 return convert_into(L, target, needed_size, strb, stre); 869 } 870 }; 871 872 template <> 873 struct pusher<char32_t*> { pushsol::stack::pusher874 static int push(lua_State* L, const char32_t* str) { 875 pusher<const char32_t*> p{}; 876 (void)p; 877 return p.push(L, str); 878 } 879 pushsol::stack::pusher880 static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { 881 pusher<const char32_t*> p{}; 882 (void)p; 883 return p.push(L, strb, stre); 884 } 885 pushsol::stack::pusher886 static int push(lua_State* L, const char32_t* str, std::size_t len) { 887 pusher<const char32_t*> p{}; 888 (void)p; 889 return p.push(L, str, len); 890 } 891 }; 892 893 template <size_t N> 894 struct pusher<wchar_t[N]> { pushsol::stack::pusher895 static int push(lua_State* L, const wchar_t (&str)[N]) { 896 return push(L, str, std::char_traits<wchar_t>::length(str)); 897 } 898 pushsol::stack::pusher899 static int push(lua_State* L, const wchar_t (&str)[N], std::size_t sz) { 900 return stack::push<const wchar_t*>(L, str, str + sz); 901 } 902 }; 903 904 template <size_t N> 905 struct pusher<char16_t[N]> { pushsol::stack::pusher906 static int push(lua_State* L, const char16_t (&str)[N]) { 907 return push(L, str, std::char_traits<char16_t>::length(str)); 908 } 909 pushsol::stack::pusher910 static int push(lua_State* L, const char16_t (&str)[N], std::size_t sz) { 911 return stack::push<const char16_t*>(L, str, str + sz); 912 } 913 }; 914 915 template <size_t N> 916 struct pusher<char32_t[N]> { pushsol::stack::pusher917 static int push(lua_State* L, const char32_t (&str)[N]) { 918 return push(L, str, std::char_traits<char32_t>::length(str)); 919 } 920 pushsol::stack::pusher921 static int push(lua_State* L, const char32_t (&str)[N], std::size_t sz) { 922 return stack::push<const char32_t*>(L, str, str + sz); 923 } 924 }; 925 926 template <> 927 struct pusher<wchar_t> { pushsol::stack::pusher928 static int push(lua_State* L, wchar_t c) { 929 const wchar_t str[2] = { c, '\0' }; 930 return stack::push(L, &str[0], 1); 931 } 932 }; 933 934 template <> 935 struct pusher<char16_t> { pushsol::stack::pusher936 static int push(lua_State* L, char16_t c) { 937 const char16_t str[2] = { c, '\0' }; 938 return stack::push(L, &str[0], 1); 939 } 940 }; 941 942 template <> 943 struct pusher<char32_t> { pushsol::stack::pusher944 static int push(lua_State* L, char32_t c) { 945 const char32_t str[2] = { c, '\0' }; 946 return stack::push(L, &str[0], 1); 947 } 948 }; 949 950 template <typename Ch, typename Traits, typename Al> 951 struct pusher<std::basic_string<Ch, Traits, Al>, std::enable_if_t<!std::is_same<Ch, char>::value>> { pushsol::stack::pusher952 static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& wstr) { 953 return push(L, wstr, wstr.size()); 954 } 955 pushsol::stack::pusher956 static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& wstr, std::size_t sz) { 957 return stack::push(L, wstr.data(), wstr.data() + sz); 958 } 959 }; 960 961 template <typename... Args> 962 struct pusher<std::tuple<Args...>> { 963 template <std::size_t... I, typename T> pushsol::stack::pusher964 static int push(std::index_sequence<I...>, lua_State* L, T&& t) { 965 int pushcount = 0; 966 (void)detail::swallow{ 0, (pushcount += stack::push(L, detail::forward_get<I>(t)), 0)... }; 967 return pushcount; 968 } 969 970 template <typename T> pushsol::stack::pusher971 static int push(lua_State* L, T&& t) { 972 return push(std::index_sequence_for<Args...>(), L, std::forward<T>(t)); 973 } 974 }; 975 976 template <typename A, typename B> 977 struct pusher<std::pair<A, B>> { 978 template <typename T> pushsol::stack::pusher979 static int push(lua_State* L, T&& t) { 980 int pushcount = stack::push(L, detail::forward_get<0>(t)); 981 pushcount += stack::push(L, detail::forward_get<1>(t)); 982 return pushcount; 983 } 984 }; 985 986 template <typename O> 987 struct pusher<optional<O>> { 988 template <typename T> pushsol::stack::pusher989 static int push(lua_State* L, T&& t) { 990 if (t == nullopt) { 991 return stack::push(L, nullopt); 992 } 993 return stack::push(L, static_cast<std::conditional_t<std::is_lvalue_reference<T>::value, O&, O&&>>(t.value())); 994 } 995 }; 996 997 template <> 998 struct pusher<nullopt_t> { pushsol::stack::pusher999 static int push(lua_State* L, nullopt_t) { 1000 return stack::push(L, lua_nil); 1001 } 1002 }; 1003 1004 template <> 1005 struct pusher<std::nullptr_t> { pushsol::stack::pusher1006 static int push(lua_State* L, std::nullptr_t) { 1007 return stack::push(L, lua_nil); 1008 } 1009 }; 1010 1011 template <> 1012 struct pusher<this_state> { pushsol::stack::pusher1013 static int push(lua_State*, const this_state&) { 1014 return 0; 1015 } 1016 }; 1017 1018 template <> 1019 struct pusher<this_main_state> { pushsol::stack::pusher1020 static int push(lua_State*, const this_main_state&) { 1021 return 0; 1022 } 1023 }; 1024 1025 template <> 1026 struct pusher<new_table> { pushsol::stack::pusher1027 static int push(lua_State* L, const new_table& nt) { 1028 lua_createtable(L, nt.sequence_hint, nt.map_hint); 1029 return 1; 1030 } 1031 }; 1032 1033 #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES 1034 template <typename O> 1035 struct pusher<std::optional<O>> { 1036 template <typename T> pushsol::stack::pusher1037 static int push(lua_State* L, T&& t) { 1038 if (t == std::nullopt) { 1039 return stack::push(L, nullopt); 1040 } 1041 return stack::push(L, static_cast<std::conditional_t<std::is_lvalue_reference<T>::value, O&, O&&>>(t.value())); 1042 } 1043 }; 1044 1045 #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT 1046 namespace stack_detail { 1047 1048 struct push_function { 1049 lua_State* L; 1050 push_functionsol::stack::stack_detail::push_function1051 push_function(lua_State* L) 1052 : L(L) { 1053 } 1054 1055 template <typename T> operator ()sol::stack::stack_detail::push_function1056 int operator()(T&& value) const { 1057 return stack::push<T>(L, std::forward<T>(value)); 1058 } 1059 }; 1060 1061 } // namespace stack_detail 1062 1063 template <typename... Tn> 1064 struct pusher<std::variant<Tn...>> { pushsol::stack::pusher1065 static int push(lua_State* L, const std::variant<Tn...>& v) { 1066 return std::visit(stack_detail::push_function(L), v); 1067 } 1068 pushsol::stack::pusher1069 static int push(lua_State* L, std::variant<Tn...>&& v) { 1070 return std::visit(stack_detail::push_function(L), std::move(v)); 1071 } 1072 }; 1073 #endif // Variant because Clang is terrible 1074 #endif // C++17 Support 1075 } 1076 } // namespace sol::stack 1077 1078 #endif // SOL_STACK_PUSH_HPP 1079