From 43f215c27d8797bd328b17e8ab69f37484ea95c2 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Wed, 25 Dec 2019 13:24:21 -0500 Subject: [PATCH] Fix #913 --- include/sol/stack_push.hpp | 2267 ++++++++++++++++--------------- single/include/sol/forward.hpp | 4 +- single/include/sol/sol.hpp | 2271 ++++++++++++++++---------------- 3 files changed, 2270 insertions(+), 2272 deletions(-) diff --git a/include/sol/stack_push.hpp b/include/sol/stack_push.hpp index a895eab9..4ff80c00 100644 --- a/include/sol/stack_push.hpp +++ b/include/sol/stack_push.hpp @@ -44,1167 +44,1166 @@ #endif // Can use variant #endif // C++17 -namespace sol { - namespace stack { - namespace stack_detail { - template - inline bool integer_value_fits(const T& value) { - if constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed_v && sizeof(T) == sizeof(lua_Integer))) { - (void)value; - return true; - } - else { - auto u_min = static_cast((std::numeric_limits::min)()); - auto u_max = static_cast((std::numeric_limits::max)()); - auto t_min = static_cast((std::numeric_limits::min)()); - auto t_max = static_cast((std::numeric_limits::max)()); - return (u_min <= t_min || value >= static_cast(u_min)) && (u_max >= t_max || value <= static_cast(u_max)); - } +namespace sol { namespace stack { + namespace stack_detail { + template + inline bool integer_value_fits(const T& value) { + if constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed_v && sizeof(T) == sizeof(lua_Integer))) { + (void)value; + return true; } - - template - int msvc_is_ass_with_if_constexpr_push_enum(std::true_type, lua_State* L, const T& value) { - if constexpr (meta::any_same_v, char/*, char8_t*/, char16_t, char32_t>) { - if constexpr (std::is_signed_v) { - return stack::push(L, static_cast(value)); - } - else { - return stack::push(L, static_cast(value)); - } - } - else { - return stack::push(L, static_cast>(value)); - } - } - - template - int msvc_is_ass_with_if_constexpr_push_enum(std::false_type, lua_State*, const T&) { - return 0; + else { + auto u_min = static_cast((std::numeric_limits::min)()); + auto u_max = static_cast((std::numeric_limits::max)()); + auto t_min = static_cast((std::numeric_limits::min)()); + auto t_max = static_cast((std::numeric_limits::max)()); + return (u_min <= t_min || value >= static_cast(u_min)) && (u_max >= t_max || value <= static_cast(u_max)); } } - inline int push_environment_of(lua_State* L, int index = -1) { + template + int msvc_is_ass_with_if_constexpr_push_enum(std::true_type, lua_State* L, const T& value) { + if constexpr (meta::any_same_v, char /*, char8_t*/, char16_t, char32_t>) { + if constexpr (std::is_signed_v) { + return stack::push(L, static_cast(value)); + } + else { + return stack::push(L, static_cast(value)); + } + } + else { + return stack::push(L, static_cast>(value)); + } + } + + template + int msvc_is_ass_with_if_constexpr_push_enum(std::false_type, lua_State*, const T&) { + return 0; + } + } // namespace stack_detail + + inline int push_environment_of(lua_State* L, int index = -1) { #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_environment); + luaL_checkstack(L, 1, detail::not_enough_stack_space_environment); #endif // make sure stack doesn't overflow #if SOL_LUA_VERSION < 502 - // Use lua_getfenv - lua_getfenv(L, index); + // Use lua_getfenv + lua_getfenv(L, index); #else - // Use upvalues as explained in Lua 5.2 and beyond's manual - if (lua_getupvalue(L, index, 1) == nullptr) { - push(L, lua_nil); + // Use upvalues as explained in Lua 5.2 and beyond's manual + if (lua_getupvalue(L, index, 1) == nullptr) { + push(L, lua_nil); + return 1; + } +#endif + return 1; + } + + template + int push_environment_of(const T& target) { + target.push(); + return push_environment_of(target.lua_state(), -1) + 1; + } + + template + struct unqualified_pusher> { + template + static int push_fx(lua_State* L, F&& f, Args&&... args) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + // Basically, we store all user-data like this: + // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new + // data in the first sizeof(T*) bytes, and then however many bytes it takes to + // do the actual object. Things that are std::ref or plain T* are stored as + // just the sizeof(T*), and nothing else. + T* obj = detail::usertype_allocate(L); + f(); + std::allocator alloc{}; + std::allocator_traits>::construct(alloc, obj, std::forward(args)...); + return 1; + } + + template + static int push_keyed(lua_State* L, K&& k, Args&&... args) { + stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); + return push_fx(L, fx, std::forward(args)...); + } + + template + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_same_v, detail::with_function_tag>) { + (void)arg; + return push_fx(L, std::forward(args)...); + } + else { + return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); + } + } + + static int push(lua_State* L) { + return push_keyed(L, usertype_traits::metatable()); + } + }; + + template + struct unqualified_pusher> { + typedef meta::unqualified_t U; + + template + static int push_fx(lua_State* L, F&& f, T* obj) { + if (obj == nullptr) + return stack::push(L, lua_nil); +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + T** pref = detail::usertype_allocate_pointer(L); + f(); + *pref = obj; + return 1; + } + + template + static int push_keyed(lua_State* L, K&& k, T* obj) { + stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); + return push_fx(L, fx, obj); + } + + template + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_same_v, detail::with_function_tag>) { + (void)arg; + return push_fx(L, std::forward(args)...); + } + else { + return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); + } + } + }; + + template <> + struct unqualified_pusher { + template + static int push(lua_State* L, T&& obj) { + return stack::push(L, detail::ptr(obj)); + } + }; + + namespace stack_detail { + template + struct uu_pusher { + using u_traits = unique_usertype_traits; + using P = typename u_traits::type; + using Real = typename u_traits::actual_type; + + template + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_base_of_v>) { + if (u_traits::is_null(arg)) { + return stack::push(L, lua_nil); + } + return push_deep(L, std::forward(arg), std::forward(args)...); + } + else { + return push_deep(L, std::forward(arg), std::forward(args)...); + } + } + + template + static int push_deep(lua_State* L, Args&&... args) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + P** pref = nullptr; + detail::unique_destructor* fx = nullptr; + detail::unique_tag* id = nullptr; + Real* mem = detail::usertype_unique_allocate(L, pref, fx, id); + if (luaL_newmetatable(L, &usertype_traits>>::metatable()[0]) == 1) { + detail::lua_reg_table l{}; + int index = 0; + detail::indexed_insert insert_fx(l, index); + detail::insert_default_registrations

(insert_fx, detail::property_always_true); + l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor() }; + luaL_setfuncs(L, l, 0); + } + lua_setmetatable(L, -2); + *fx = detail::usertype_unique_alloc_destroy; + *id = &detail::inheritance

::template type_unique_cast; + detail::default_construct::construct(mem, std::forward(args)...); + *pref = unique_usertype_traits::get(*mem); return 1; } -#endif + }; + } // namespace stack_detail + + template + struct unqualified_pusher { + template + static int push(lua_State* L, Args&&... args) { + using Tu = meta::unqualified_t; + if constexpr (is_lua_reference_v) { + using int_arr = int[]; + int_arr p{ (std::forward(args).push(L))... }; + return p[0]; + } + else if constexpr (std::is_same_v) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushboolean(L, std::forward(args)...); + return 1; + } + else if constexpr (std::is_integral_v || std::is_same_v) { + const Tu& value(std::forward(args)...); +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_integral); +#endif // make sure stack doesn't overflow +#if SOL_LUA_VERSION >= 503 + if (stack_detail::integer_value_fits(value)) { + lua_pushinteger(L, static_cast(value)); + return 1; + } +#endif // Lua 5.3 and above +#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) + if (static_cast(llround(static_cast(value))) != value) { +#if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS + // Is this really worth it? + assert(false && "integer value will be misrepresented in lua"); + lua_pushinteger(L, static_cast(value)); + return 1; +#else + throw error(detail::direct_error, "integer value will be misrepresented in lua"); +#endif // No Exceptions + } +#endif // Safe Numerics and Number Precision Check + lua_pushnumber(L, static_cast(value)); + return 1; + } + else if constexpr (std::is_floating_point_v || std::is_same_v) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_floating); +#endif // make sure stack doesn't overflow + lua_pushnumber(L, std::forward(args)...); + return 1; + } + else if constexpr (std::is_enum_v) { + return stack_detail::msvc_is_ass_with_if_constexpr_push_enum(std::true_type(), L, std::forward(args)...); + } + else if constexpr (std::is_pointer_v) { + return stack::push>>(L, std::forward(args)...); + } + else if constexpr (is_unique_usertype_v) { + stack_detail::uu_pusher p; + (void)p; + return p.push(L, std::forward(args)...); + } + else { + return stack::push>(L, std::forward(args)...); + } + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const std::reference_wrapper& t) { + return stack::push(L, std::addressof(detail::deref(t.get()))); + } + }; + + template + struct unqualified_pusher> { + using has_kvp = meta::has_key_value_pair>>; + + static int push(lua_State* L, const T& tablecont) { + return push(has_kvp(), std::false_type(), L, tablecont); + } + + static int push(lua_State* L, const T& tablecont, nested_tag_t) { + return push(has_kvp(), std::true_type(), L, tablecont); + } + + static int push(std::true_type, lua_State* L, const T& tablecont) { + return push(has_kvp(), std::true_type(), L, tablecont); + } + + static int push(std::false_type, lua_State* L, const T& tablecont) { + return push(has_kvp(), std::false_type(), L, tablecont); + } + + template + static int push(std::true_type, std::integral_constant, lua_State* L, const T& tablecont) { + auto& cont = detail::deref(detail::unwrap(tablecont)); + lua_createtable(L, static_cast(cont.size()), 0); + int tableindex = lua_gettop(L); + for (const auto& pair : cont) { + if (is_nested) { + set_field(L, pair.first, as_nested_ref(pair.second), tableindex); + } + else { + set_field(L, pair.first, pair.second, tableindex); + } + } + return 1; + } + + template + static int push(std::false_type, std::integral_constant, lua_State* L, const T& tablecont) { + auto& cont = detail::deref(detail::unwrap(tablecont)); + lua_createtable(L, stack_detail::get_size_hint(cont), 0); + int tableindex = lua_gettop(L); + std::size_t index = 1; + for (const auto& i : cont) { +#if SOL_LUA_VERSION >= 503 + int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); + for (int pi = 0; pi < p; ++pi) { + lua_seti(L, tableindex, static_cast(index++)); + } +#else +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushinteger(L, static_cast(index)); + int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); + if (p == 1) { + ++index; + lua_settable(L, tableindex); + } + else { + int firstindex = tableindex + 1 + 1; + for (int pi = 0; pi < p; ++pi) { + stack::push(L, index); +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, firstindex); + lua_settable(L, tableindex); + ++index; + ++firstindex; + } + lua_pop(L, 1 + p); + } +#endif // Lua Version 5.3 and others + } + // TODO: figure out a better way to do this...? + // set_field(L, -1, cont.size()); + return 1; + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const T& v) { + using inner_t = std::remove_pointer_t>; + if constexpr (is_container_v) { + return stack::push>(L, v); + } + else { + return stack::push(L, v); + } + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const T& tablecont) { + using Tu = meta::unwrap_unqualified_t; + using inner_t = std::remove_pointer_t; + if constexpr (is_container_v) { + return stack::push>(L, tablecont, nested_tag); + } + else { + return stack::push(L, tablecont); + } + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const std::initializer_list& il) { + unqualified_pusher>> p{}; + // silence annoying VC++ warning + (void)p; + return p.push(L, il); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, lua_nil_t) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushnil(L); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State*, stack_count st) { + return st.count; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, metatable_key_t) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, "__mt", 4); + return 1; + } + }; + + template <> + struct unqualified_pusher> { + static int push(lua_State* L, lua_CFunction func, int n = 0) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, lua_CFunction func, int n = 0) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; + +#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE + template <> + struct unqualified_pusher> { + static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; +#endif // noexcept function type + + template <> + struct unqualified_pusher { + static int push(lua_State* L, c_closure cc) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, cc.c_function, cc.upvalues); + return 1; + } + }; + + template + struct unqualified_pusher> { + template + static int push(std::index_sequence, lua_State* L, T&& c) { + using f_tuple = decltype(std::forward(c).upvalues); + int pushcount = multi_push(L, std::get(std::forward(std::forward(c).upvalues))...); + return stack::push(L, c_closure(c.c_function, pushcount)); + } + + template + static int push(lua_State* L, T&& c) { + return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward(c)); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, void* userdata) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, userdata); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const void* userdata) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, const_cast(userdata)); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, lightuserdata_value userdata) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, userdata); + return 1; + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, light l) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, static_cast(l.value)); + return 1; + } + }; + + template + struct unqualified_pusher> { + template + static int push_with(lua_State* L, Key&& name, Args&&... args) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + // A dumb pusher + T* data = detail::user_allocate(L); + if (with_meta) { + // Make sure we have a plain GC set for this data +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + if (luaL_newmetatable(L, name) != 0) { + lua_CFunction cdel = detail::user_alloc_destruct; + lua_pushcclosure(L, cdel, 0); + lua_setfield(L, -2, "__gc"); + } + lua_setmetatable(L, -2); + } + std::allocator alloc{}; + std::allocator_traits>::construct(alloc, data, std::forward(args)...); + return 1; + } + + template + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_same_v, metatable_key_t>) { + const auto name = &arg[0]; + return push_with(L, name, std::forward(args)...); + } + else if constexpr (std::is_same_v, no_metatable_t>) { + (void)arg; + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, std::forward(args)...); + } + else { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, std::forward(arg), std::forward(args)...); + } + } + + static int push(lua_State* L, const user& u) { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, u.value); + } + + static int push(lua_State* L, user&& u) { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, std::move(u.value)); + } + + static int push(lua_State* L, no_metatable_t, const user& u) { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, u.value); + } + + static int push(lua_State* L, no_metatable_t, user&& u) { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, std::move(u.value)); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, userdata_value data) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + void** ud = detail::usertype_allocate_pointer(L); + *ud = data.value; + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push_sized(lua_State* L, const char* str, std::size_t len) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, len); + return 1; + } + + static int push(lua_State* L, const char* str) { + if (str == nullptr) + return stack::push(L, lua_nil); + return push_sized(L, str, std::char_traits::length(str)); + } + + static int push(lua_State* L, const char* strb, const char* stre) { + return push_sized(L, strb, stre - strb); + } + + static int push(lua_State* L, const char* str, std::size_t len) { + return push_sized(L, str, len); + } + }; + + template <> + struct unqualified_pusher { + static int push_sized(lua_State* L, const char* str, std::size_t len) { + unqualified_pusher p{}; + (void)p; + return p.push_sized(L, str, len); + } + + static int push(lua_State* L, const char* str) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char* strb, const char* stre) { + unqualified_pusher p{}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char* str, std::size_t len) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str, len); + } + }; + + template + struct unqualified_pusher { + static int push(lua_State* L, const char (&str)[N]) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, std::char_traits::length(str)); + return 1; + } + + static int push(lua_State* L, const char (&str)[N], std::size_t sz) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, sz); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, char c) { + const char str[2] = { c, '\0' }; + return stack::push(L, str, 1); + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const std::basic_string& str) { + if constexpr (!std::is_same_v) { + return stack::push(L, str.data(), str.size()); + } + else { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str.c_str(), str.size()); + return 1; + } + } + + static int push(lua_State* L, const std::basic_string& str, std::size_t sz) { + if constexpr (!std::is_same_v) { + return stack::push(L, str.data(), sz); + } + else { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str.c_str(), sz); + return 1; + } + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const basic_string_view& sv) { + return stack::push(L, sv.data(), sv.length()); + } + + static int push(lua_State* L, const basic_string_view& sv, std::size_t n) { + return stack::push(L, sv.data(), n); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, meta_function m) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_meta_function_name); +#endif // make sure stack doesn't overflow + const std::string& str = to_string(m); + lua_pushlstring(L, str.c_str(), str.size()); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, absolute_index ai) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, ai); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, raw_index ri) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, ri); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, ref_index ri) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_rawgeti(L, LUA_REGISTRYINDEX, ri); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const wchar_t* wstr) { + return push(L, wstr, std::char_traits::length(wstr)); + } + + static int push(lua_State* L, const wchar_t* wstr, std::size_t sz) { + return push(L, wstr, wstr + sz); + } + + static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { + if constexpr (sizeof(wchar_t) == 2) { + const char16_t* sb = reinterpret_cast(strb); + const char16_t* se = reinterpret_cast(stre); + return stack::push(L, sb, se); + } + else { + const char32_t* sb = reinterpret_cast(strb); + const char32_t* se = reinterpret_cast(stre); + return stack::push(L, sb, se); + } + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const wchar_t* str) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { + unqualified_pusher p{}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const wchar_t* str, std::size_t len) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str, len); + } + }; + + template <> + struct unqualified_pusher { + static int convert_into(lua_State* L, char* start, std::size_t, const char16_t* strb, const char16_t* stre) { + char* target = start; + char32_t cp = 0; + for (const char16_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf16_to_code_point(strtarget, stre); + if (dr.error != unicode::error_code::ok) { + cp = unicode::unicode_detail::replacement; + } + else { + cp = dr.codepoint; + } + auto er = unicode::code_point_to_utf8(cp); + const char* utf8data = er.code_units.data(); + std::memcpy(target, utf8data, er.code_units_size); + target += er.code_units_size; + strtarget = dr.next; + } + + return stack::push(L, start, target); + } + + static int push(lua_State* L, const char16_t* u16str) { + return push(L, u16str, std::char_traits::length(u16str)); + } + + static int push(lua_State* L, const char16_t* u16str, std::size_t sz) { + return push(L, u16str, u16str + sz); + } + + static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { + char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; + // if our max string space is small enough, use SBO + // right off the bat + std::size_t max_possible_code_units = (stre - strb) * 4; + if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { + return convert_into(L, sbo, max_possible_code_units, strb, stre); + } + // otherwise, we must manually count/check size + std::size_t needed_size = 0; + for (const char16_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf16_to_code_point(strtarget, stre); + auto er = unicode::code_point_to_utf8(dr.codepoint); + needed_size += er.code_units_size; + strtarget = dr.next; + } + if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { + return convert_into(L, sbo, needed_size, strb, stre); + } + std::string u8str("", 0); + u8str.resize(needed_size); + char* target = &u8str[0]; + return convert_into(L, target, needed_size, strb, stre); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const char16_t* str) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { + unqualified_pusher p{}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char16_t* str, std::size_t len) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str, len); + } + }; + + template <> + struct unqualified_pusher { + static int convert_into(lua_State* L, char* start, std::size_t, const char32_t* strb, const char32_t* stre) { + char* target = start; + char32_t cp = 0; + for (const char32_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf32_to_code_point(strtarget, stre); + if (dr.error != unicode::error_code::ok) { + cp = unicode::unicode_detail::replacement; + } + else { + cp = dr.codepoint; + } + auto er = unicode::code_point_to_utf8(cp); + const char* data = er.code_units.data(); + std::memcpy(target, data, er.code_units_size); + target += er.code_units_size; + strtarget = dr.next; + } + return stack::push(L, start, target); + } + + static int push(lua_State* L, const char32_t* u32str) { + return push(L, u32str, u32str + std::char_traits::length(u32str)); + } + + static int push(lua_State* L, const char32_t* u32str, std::size_t sz) { + return push(L, u32str, u32str + sz); + } + + static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { + char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; + // if our max string space is small enough, use SBO + // right off the bat + std::size_t max_possible_code_units = (stre - strb) * 4; + if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { + return convert_into(L, sbo, max_possible_code_units, strb, stre); + } + // otherwise, we must manually count/check size + std::size_t needed_size = 0; + for (const char32_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf32_to_code_point(strtarget, stre); + auto er = unicode::code_point_to_utf8(dr.codepoint); + needed_size += er.code_units_size; + strtarget = dr.next; + } + if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { + return convert_into(L, sbo, needed_size, strb, stre); + } + std::string u8str("", 0); + u8str.resize(needed_size); + char* target = &u8str[0]; + return convert_into(L, target, needed_size, strb, stre); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const char32_t* str) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { + unqualified_pusher p{}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char32_t* str, std::size_t len) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str, len); + } + }; + + template + struct unqualified_pusher { + static int push(lua_State* L, const wchar_t (&str)[N]) { + return push(L, str, std::char_traits::length(str)); + } + + static int push(lua_State* L, const wchar_t (&str)[N], std::size_t sz) { + return stack::push(L, str, str + sz); + } + }; + + template + struct unqualified_pusher { + static int push(lua_State* L, const char16_t (&str)[N]) { + return push(L, str, std::char_traits::length(str)); + } + + static int push(lua_State* L, const char16_t (&str)[N], std::size_t sz) { + return stack::push(L, str, str + sz); + } + }; + + template + struct unqualified_pusher { + static int push(lua_State* L, const char32_t (&str)[N]) { + return push(L, str, std::char_traits::length(str)); + } + + static int push(lua_State* L, const char32_t (&str)[N], std::size_t sz) { + return stack::push(L, str, str + sz); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, wchar_t c) { + const wchar_t str[2] = { c, '\0' }; + return stack::push(L, &str[0], 1); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, char16_t c) { + const char16_t str[2] = { c, '\0' }; + return stack::push(L, &str[0], 1); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, char32_t c) { + const char32_t str[2] = { c, '\0' }; + return stack::push(L, &str[0], 1); + } + }; + + template + struct unqualified_pusher> { + template + static int push(std::index_sequence, lua_State* L, T&& t) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, static_cast(sizeof...(I)), detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + int pushcount = 0; + (void)detail::swallow{ 0, (pushcount += stack::push(L, std::get(std::forward(t))), 0)... }; + return pushcount; + } + + template + static int push(lua_State* L, T&& t) { + return push(std::index_sequence_for(), L, std::forward(t)); + } + }; + + template + struct unqualified_pusher> { + template + static int push(lua_State* L, T&& t) { + int pushcount = stack::push(L, std::get<0>(std::forward(t))); + pushcount += stack::push(L, std::get<1>(std::forward(t))); + return pushcount; + } + }; + + template + struct unqualified_pusher> { + template + static int push(lua_State* L, T&& t) { + if (t == nullopt) { + return stack::push(L, nullopt); + } + return stack::push(L, static_cast::value, O&, O&&>>(t.value())); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, nullopt_t) { + return stack::push(L, lua_nil); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, std::nullptr_t) { + return stack::push(L, lua_nil); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State*, const this_state&) { + return 0; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State*, const this_main_state&) { + return 0; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const new_table& nt) { + lua_createtable(L, nt.sequence_hint, nt.map_hint); + return 1; + } + }; + + template + struct unqualified_pusher> { + template + static int push(lua_State* L, T&& bc, const char* bytecode_name) { + const auto first = bc.data(); + const auto bcsize = bc.size(); + // pushes either the function, or an error + // if it errors, shit goes south, and people can test that upstream + (void)luaL_loadbuffer( + L, reinterpret_cast(first), static_cast(bcsize * (sizeof(*first) / sizeof(const char))), bytecode_name); return 1; } template - int push_environment_of(const T& target) { - target.push(); - return push_environment_of(target.lua_state(), -1) + 1; + static int push(lua_State* L, T&& bc) { + return push(L, std::forward(bc), "bytecode"); } - - template - struct unqualified_pusher> { - template - static int push_fx(lua_State* L, F&& f, Args&&... args) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); -#endif // make sure stack doesn't overflow - // Basically, we store all user-data like this: - // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new - // data in the first sizeof(T*) bytes, and then however many bytes it takes to - // do the actual object. Things that are std::ref or plain T* are stored as - // just the sizeof(T*), and nothing else. - T* obj = detail::usertype_allocate(L); - f(); - std::allocator alloc{}; - std::allocator_traits>::construct(alloc, obj, std::forward(args)...); - return 1; - } - - template - static int push_keyed(lua_State* L, K&& k, Args&&... args) { - stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); - return push_fx(L, fx, std::forward(args)...); - } - - template - static int push(lua_State* L, Arg&& arg, Args&&... args) { - if constexpr (std::is_same_v, detail::with_function_tag>) { - (void)arg; - return push_fx(L, std::forward(args)...); - } - else { - return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); - } - } - - static int push(lua_State* L) { - return push_keyed(L, usertype_traits::metatable()); - } - }; - - template - struct unqualified_pusher> { - typedef meta::unqualified_t U; - - template - static int push_fx(lua_State* L, F&& f, T* obj) { - if (obj == nullptr) - return stack::push(L, lua_nil); -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); -#endif // make sure stack doesn't overflow - T** pref = detail::usertype_allocate_pointer(L); - f(); - *pref = obj; - return 1; - } - - template - static int push_keyed(lua_State* L, K&& k, T* obj) { - stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); - return push_fx(L, fx, obj); - } - - template - static int push(lua_State* L, Arg&& arg, Args&&... args) { - if constexpr (std::is_same_v, detail::with_function_tag>) { - (void)arg; - return push_fx(L, std::forward(args)...); - } - else { - return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); - } - } - }; - - template <> - struct unqualified_pusher { - template - static int push(lua_State* L, T&& obj) { - return stack::push(L, detail::ptr(obj)); - } - }; - - namespace stack_detail { - template - struct uu_pusher { - using u_traits = unique_usertype_traits; - using P = typename u_traits::type; - using Real = typename u_traits::actual_type; - - template - static int push(lua_State* L, Arg&& arg, Args&&... args) { - if constexpr (std::is_base_of_v>) { - if (u_traits::is_null(arg)) { - return stack::push(L, lua_nil); - } - return push_deep(L, std::forward(arg), std::forward(args)...); - } - else { - return push_deep(L, std::forward(arg), std::forward(args)...); - } - } - - template - static int push_deep(lua_State* L, Args&&... args) { - #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); - #endif // make sure stack doesn't overflow - P** pref = nullptr; - detail::unique_destructor* fx = nullptr; - detail::unique_tag* id = nullptr; - Real* mem = detail::usertype_unique_allocate(L, pref, fx, id); - if (luaL_newmetatable(L, &usertype_traits>>::metatable()[0]) == 1) { - detail::lua_reg_table l{}; - int index = 0; - detail::indexed_insert insert_fx(l, index); - detail::insert_default_registrations

(insert_fx, detail::property_always_true); - l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor() }; - luaL_setfuncs(L, l, 0); - } - lua_setmetatable(L, -2); - *fx = detail::usertype_unique_alloc_destroy; - *id = &detail::inheritance

::template type_unique_cast; - detail::default_construct::construct(mem, std::forward(args)...); - *pref = unique_usertype_traits::get(*mem); - return 1; - } - }; - } // namespace stack_detail - - template - struct unqualified_pusher { - template - static int push(lua_State* L, Args&&... args) { - using Tu = meta::unqualified_t; - if constexpr (is_lua_reference_v) { - using int_arr = int[]; - int_arr p{ (std::forward(args).push(L))... }; - return p[0]; - } - else if constexpr (std::is_same_v) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushboolean(L, std::forward(args)...); - return 1; - } - else if constexpr (std::is_integral_v || std::is_same_v) { - const Tu& value(std::forward(args)...); -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_integral); -#endif // make sure stack doesn't overflow -#if SOL_LUA_VERSION >= 503 - if (stack_detail::integer_value_fits(value)) { - lua_pushinteger(L, static_cast(value)); - return 1; - } -#endif // Lua 5.3 and above -#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) - if (static_cast(llround(static_cast(value))) != value) { -#if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS - // Is this really worth it? - assert(false && "integer value will be misrepresented in lua"); - lua_pushnumber(L, static_cast(std::forward(args)...)); - return 1; -#else - throw error(detail::direct_error, "integer value will be misrepresented in lua"); -#endif // No Exceptions - } -#endif // Safe Numerics and Number Precision Check - lua_pushnumber(L, static_cast(value)); - return 1; - } - else if constexpr (std::is_floating_point_v || std::is_same_v) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_floating); -#endif // make sure stack doesn't overflow - lua_pushnumber(L, std::forward(args)...); - return 1; - } - else if constexpr (std::is_enum_v) { - return stack_detail::msvc_is_ass_with_if_constexpr_push_enum(std::true_type(), L, std::forward(args)...); - } - else if constexpr (std::is_pointer_v) { - return stack::push>>(L, std::forward(args)...); - } - else if constexpr (is_unique_usertype_v) { - stack_detail::uu_pusher p; - (void)p; - return p.push(L, std::forward(args)...); - } - else { - return stack::push>(L, std::forward(args)...); - } - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const std::reference_wrapper& t) { - return stack::push(L, std::addressof(detail::deref(t.get()))); - } - }; - - template - struct unqualified_pusher> { - using has_kvp = meta::has_key_value_pair>>; - - static int push(lua_State* L, const T& tablecont) { - return push(has_kvp(), std::false_type(), L, tablecont); - } - - static int push(lua_State* L, const T& tablecont, nested_tag_t) { - return push(has_kvp(), std::true_type(), L, tablecont); - } - - static int push(std::true_type, lua_State* L, const T& tablecont) { - return push(has_kvp(), std::true_type(), L, tablecont); - } - - static int push(std::false_type, lua_State* L, const T& tablecont) { - return push(has_kvp(), std::false_type(), L, tablecont); - } - - template - static int push(std::true_type, std::integral_constant, lua_State* L, const T& tablecont) { - auto& cont = detail::deref(detail::unwrap(tablecont)); - lua_createtable(L, static_cast(cont.size()), 0); - int tableindex = lua_gettop(L); - for (const auto& pair : cont) { - if (is_nested) { - set_field(L, pair.first, as_nested_ref(pair.second), tableindex); - } - else { - set_field(L, pair.first, pair.second, tableindex); - } - } - return 1; - } - - template - static int push(std::false_type, std::integral_constant, lua_State* L, const T& tablecont) { - auto& cont = detail::deref(detail::unwrap(tablecont)); - lua_createtable(L, stack_detail::get_size_hint(cont), 0); - int tableindex = lua_gettop(L); - std::size_t index = 1; - for (const auto& i : cont) { -#if SOL_LUA_VERSION >= 503 - int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); - for (int pi = 0; pi < p; ++pi) { - lua_seti(L, tableindex, static_cast(index++)); - } -#else -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushinteger(L, static_cast(index)); - int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); - if (p == 1) { - ++index; - lua_settable(L, tableindex); - } - else { - int firstindex = tableindex + 1 + 1; - for (int pi = 0; pi < p; ++pi) { - stack::push(L, index); -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushvalue(L, firstindex); - lua_settable(L, tableindex); - ++index; - ++firstindex; - } - lua_pop(L, 1 + p); - } -#endif // Lua Version 5.3 and others - } - // TODO: figure out a better way to do this...? - // set_field(L, -1, cont.size()); - return 1; - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const T& v) { - using inner_t = std::remove_pointer_t>; - if constexpr (is_container_v) { - return stack::push>(L, v); - } - else { - return stack::push(L, v); - } - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const T& tablecont) { - using Tu = meta::unwrap_unqualified_t; - using inner_t = std::remove_pointer_t; - if constexpr (is_container_v) { - return stack::push>(L, tablecont, nested_tag); - } - else { - return stack::push(L, tablecont); - } - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const std::initializer_list& il) { - unqualified_pusher>> p{}; - // silence annoying VC++ warning - (void)p; - return p.push(L, il); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, lua_nil_t) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushnil(L); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State*, stack_count st) { - return st.count; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, metatable_key_t) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, "__mt", 4); - return 1; - } - }; - - template <> - struct unqualified_pusher> { - static int push(lua_State* L, lua_CFunction func, int n = 0) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushcclosure(L, func, n); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, lua_CFunction func, int n = 0) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushcclosure(L, func, n); - return 1; - } - }; - -#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE - template <> - struct unqualified_pusher> { - static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushcclosure(L, func, n); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushcclosure(L, func, n); - return 1; - } - }; -#endif // noexcept function type - - template <> - struct unqualified_pusher { - static int push(lua_State* L, c_closure cc) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushcclosure(L, cc.c_function, cc.upvalues); - return 1; - } - }; - - template - struct unqualified_pusher> { - template - static int push(std::index_sequence, lua_State* L, T&& c) { - using f_tuple = decltype(std::forward(c).upvalues); - int pushcount = multi_push(L, std::get(std::forward(std::forward(c).upvalues))...); - return stack::push(L, c_closure(c.c_function, pushcount)); - } - - template - static int push(lua_State* L, T&& c) { - return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward(c)); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, void* userdata) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushlightuserdata(L, userdata); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const void* userdata) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushlightuserdata(L, const_cast(userdata)); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, lightuserdata_value userdata) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushlightuserdata(L, userdata); - return 1; - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, light l) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushlightuserdata(L, static_cast(l.value)); - return 1; - } - }; - - template - struct unqualified_pusher> { - template - static int push_with(lua_State* L, Key&& name, Args&&... args) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); -#endif // make sure stack doesn't overflow - // A dumb pusher - T* data = detail::user_allocate(L); - if (with_meta) { - // Make sure we have a plain GC set for this data -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - if (luaL_newmetatable(L, name) != 0) { - lua_CFunction cdel = detail::user_alloc_destruct; - lua_pushcclosure(L, cdel, 0); - lua_setfield(L, -2, "__gc"); - } - lua_setmetatable(L, -2); - } - std::allocator alloc{}; - std::allocator_traits>::construct(alloc, data, std::forward(args)...); - return 1; - } - - template - static int push(lua_State* L, Arg&& arg, Args&&... args) { - if constexpr (std::is_same_v, metatable_key_t>) { - const auto name = &arg[0]; - return push_with(L, name, std::forward(args)...); - } - else if constexpr (std::is_same_v, no_metatable_t>) { - (void)arg; - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::forward(args)...); - } - else { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::forward(arg), std::forward(args)...); - } - } - - static int push(lua_State* L, const user& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, u.value); - } - - static int push(lua_State* L, user&& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::move(u.value)); - } - - static int push(lua_State* L, no_metatable_t, const user& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, u.value); - } - - static int push(lua_State* L, no_metatable_t, user&& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::move(u.value)); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, userdata_value data) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); -#endif // make sure stack doesn't overflow - void** ud = detail::usertype_allocate_pointer(L); - *ud = data.value; - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push_sized(lua_State* L, const char* str, std::size_t len) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, str, len); - return 1; - } - - static int push(lua_State* L, const char* str) { - if (str == nullptr) - return stack::push(L, lua_nil); - return push_sized(L, str, std::char_traits::length(str)); - } - - static int push(lua_State* L, const char* strb, const char* stre) { - return push_sized(L, strb, stre - strb); - } - - static int push(lua_State* L, const char* str, std::size_t len) { - return push_sized(L, str, len); - } - }; - - template <> - struct unqualified_pusher { - static int push_sized(lua_State* L, const char* str, std::size_t len) { - unqualified_pusher p{}; - (void)p; - return p.push_sized(L, str, len); - } - - static int push(lua_State* L, const char* str) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str); - } - - static int push(lua_State* L, const char* strb, const char* stre) { - unqualified_pusher p{}; - (void)p; - return p.push(L, strb, stre); - } - - static int push(lua_State* L, const char* str, std::size_t len) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str, len); - } - }; - - template - struct unqualified_pusher { - static int push(lua_State* L, const char (&str)[N]) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, str, std::char_traits::length(str)); - return 1; - } - - static int push(lua_State* L, const char (&str)[N], std::size_t sz) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, str, sz); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, char c) { - const char str[2] = { c, '\0' }; - return stack::push(L, str, 1); - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const std::basic_string& str) { - if constexpr (!std::is_same_v) { - return stack::push(L, str.data(), str.size()); - } - else { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, str.c_str(), str.size()); - return 1; - } - } - - static int push(lua_State* L, const std::basic_string& str, std::size_t sz) { - if constexpr (!std::is_same_v) { - return stack::push(L, str.data(), sz); - } - else { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, str.c_str(), sz); - return 1; - } - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const basic_string_view& sv) { - return stack::push(L, sv.data(), sv.length()); - } - - static int push(lua_State* L, const basic_string_view& sv, std::size_t n) { - return stack::push(L, sv.data(), n); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, meta_function m) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_meta_function_name); -#endif // make sure stack doesn't overflow - const std::string& str = to_string(m); - lua_pushlstring(L, str.c_str(), str.size()); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, absolute_index ai) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushvalue(L, ai); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, raw_index ri) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushvalue(L, ri); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, ref_index ri) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_rawgeti(L, LUA_REGISTRYINDEX, ri); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const wchar_t* wstr) { - return push(L, wstr, std::char_traits::length(wstr)); - } - - static int push(lua_State* L, const wchar_t* wstr, std::size_t sz) { - return push(L, wstr, wstr + sz); - } - - static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { - if constexpr (sizeof(wchar_t) == 2) { - const char16_t* sb = reinterpret_cast(strb); - const char16_t* se = reinterpret_cast(stre); - return stack::push(L, sb, se); - } - else { - const char32_t* sb = reinterpret_cast(strb); - const char32_t* se = reinterpret_cast(stre); - return stack::push(L, sb, se); - } - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const wchar_t* str) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str); - } - - static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { - unqualified_pusher p{}; - (void)p; - return p.push(L, strb, stre); - } - - static int push(lua_State* L, const wchar_t* str, std::size_t len) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str, len); - } - }; - - template <> - struct unqualified_pusher { - static int convert_into(lua_State* L, char* start, std::size_t, const char16_t* strb, const char16_t* stre) { - char* target = start; - char32_t cp = 0; - for (const char16_t* strtarget = strb; strtarget < stre;) { - auto dr = unicode::utf16_to_code_point(strtarget, stre); - if (dr.error != unicode::error_code::ok) { - cp = unicode::unicode_detail::replacement; - } - else { - cp = dr.codepoint; - } - auto er = unicode::code_point_to_utf8(cp); - const char* utf8data = er.code_units.data(); - std::memcpy(target, utf8data, er.code_units_size); - target += er.code_units_size; - strtarget = dr.next; - } - - return stack::push(L, start, target); - } - - static int push(lua_State* L, const char16_t* u16str) { - return push(L, u16str, std::char_traits::length(u16str)); - } - - static int push(lua_State* L, const char16_t* u16str, std::size_t sz) { - return push(L, u16str, u16str + sz); - } - - static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { - char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; - // if our max string space is small enough, use SBO - // right off the bat - std::size_t max_possible_code_units = (stre - strb) * 4; - if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { - return convert_into(L, sbo, max_possible_code_units, strb, stre); - } - // otherwise, we must manually count/check size - std::size_t needed_size = 0; - for (const char16_t* strtarget = strb; strtarget < stre;) { - auto dr = unicode::utf16_to_code_point(strtarget, stre); - auto er = unicode::code_point_to_utf8(dr.codepoint); - needed_size += er.code_units_size; - strtarget = dr.next; - } - if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { - return convert_into(L, sbo, needed_size, strb, stre); - } - std::string u8str("", 0); - u8str.resize(needed_size); - char* target = &u8str[0]; - return convert_into(L, target, needed_size, strb, stre); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const char16_t* str) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str); - } - - static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { - unqualified_pusher p{}; - (void)p; - return p.push(L, strb, stre); - } - - static int push(lua_State* L, const char16_t* str, std::size_t len) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str, len); - } - }; - - template <> - struct unqualified_pusher { - static int convert_into(lua_State* L, char* start, std::size_t, const char32_t* strb, const char32_t* stre) { - char* target = start; - char32_t cp = 0; - for (const char32_t* strtarget = strb; strtarget < stre;) { - auto dr = unicode::utf32_to_code_point(strtarget, stre); - if (dr.error != unicode::error_code::ok) { - cp = unicode::unicode_detail::replacement; - } - else { - cp = dr.codepoint; - } - auto er = unicode::code_point_to_utf8(cp); - const char* data = er.code_units.data(); - std::memcpy(target, data, er.code_units_size); - target += er.code_units_size; - strtarget = dr.next; - } - return stack::push(L, start, target); - } - - static int push(lua_State* L, const char32_t* u32str) { - return push(L, u32str, u32str + std::char_traits::length(u32str)); - } - - static int push(lua_State* L, const char32_t* u32str, std::size_t sz) { - return push(L, u32str, u32str + sz); - } - - static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { - char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; - // if our max string space is small enough, use SBO - // right off the bat - std::size_t max_possible_code_units = (stre - strb) * 4; - if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { - return convert_into(L, sbo, max_possible_code_units, strb, stre); - } - // otherwise, we must manually count/check size - std::size_t needed_size = 0; - for (const char32_t* strtarget = strb; strtarget < stre;) { - auto dr = unicode::utf32_to_code_point(strtarget, stre); - auto er = unicode::code_point_to_utf8(dr.codepoint); - needed_size += er.code_units_size; - strtarget = dr.next; - } - if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { - return convert_into(L, sbo, needed_size, strb, stre); - } - std::string u8str("", 0); - u8str.resize(needed_size); - char* target = &u8str[0]; - return convert_into(L, target, needed_size, strb, stre); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const char32_t* str) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str); - } - - static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { - unqualified_pusher p{}; - (void)p; - return p.push(L, strb, stre); - } - - static int push(lua_State* L, const char32_t* str, std::size_t len) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str, len); - } - }; - - template - struct unqualified_pusher { - static int push(lua_State* L, const wchar_t (&str)[N]) { - return push(L, str, std::char_traits::length(str)); - } - - static int push(lua_State* L, const wchar_t (&str)[N], std::size_t sz) { - return stack::push(L, str, str + sz); - } - }; - - template - struct unqualified_pusher { - static int push(lua_State* L, const char16_t (&str)[N]) { - return push(L, str, std::char_traits::length(str)); - } - - static int push(lua_State* L, const char16_t (&str)[N], std::size_t sz) { - return stack::push(L, str, str + sz); - } - }; - - template - struct unqualified_pusher { - static int push(lua_State* L, const char32_t (&str)[N]) { - return push(L, str, std::char_traits::length(str)); - } - - static int push(lua_State* L, const char32_t (&str)[N], std::size_t sz) { - return stack::push(L, str, str + sz); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, wchar_t c) { - const wchar_t str[2] = { c, '\0' }; - return stack::push(L, &str[0], 1); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, char16_t c) { - const char16_t str[2] = { c, '\0' }; - return stack::push(L, &str[0], 1); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, char32_t c) { - const char32_t str[2] = { c, '\0' }; - return stack::push(L, &str[0], 1); - } - }; - - template - struct unqualified_pusher> { - template - static int push(std::index_sequence, lua_State* L, T&& t) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, static_cast(sizeof...(I)), detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - int pushcount = 0; - (void)detail::swallow{ 0, (pushcount += stack::push(L, std::get(std::forward(t))), 0)... }; - return pushcount; - } - - template - static int push(lua_State* L, T&& t) { - return push(std::index_sequence_for(), L, std::forward(t)); - } - }; - - template - struct unqualified_pusher> { - template - static int push(lua_State* L, T&& t) { - int pushcount = stack::push(L, std::get<0>(std::forward(t))); - pushcount += stack::push(L, std::get<1>(std::forward(t))); - return pushcount; - } - }; - - template - struct unqualified_pusher> { - template - static int push(lua_State* L, T&& t) { - if (t == nullopt) { - return stack::push(L, nullopt); - } - return stack::push(L, static_cast::value, O&, O&&>>(t.value())); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, nullopt_t) { - return stack::push(L, lua_nil); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, std::nullptr_t) { - return stack::push(L, lua_nil); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State*, const this_state&) { - return 0; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State*, const this_main_state&) { - return 0; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const new_table& nt) { - lua_createtable(L, nt.sequence_hint, nt.map_hint); - return 1; - } - }; - - template - struct unqualified_pusher> { - template - static int push(lua_State* L, T&& bc, const char* bytecode_name) { - const auto first = bc.data(); - const auto bcsize = bc.size(); - // pushes either the function, or an error - // if it errors, shit goes south, and people can test that upstream - (void)luaL_loadbuffer(L, reinterpret_cast(first), static_cast(bcsize * (sizeof(*first) / sizeof(const char))), bytecode_name); - return 1; - } - - template - static int push(lua_State* L, T&& bc) { - return push(L, std::forward(bc), "bytecode"); - } - }; + }; #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES - template - struct unqualified_pusher> { - template - static int push(lua_State* L, T&& t) { - if (t == std::nullopt) { - return stack::push(L, nullopt); - } - return stack::push(L, static_cast::value, O&, O&&>>(t.value())); + template + struct unqualified_pusher> { + template + static int push(lua_State* L, T&& t) { + if (t == std::nullopt) { + return stack::push(L, nullopt); } - }; + return stack::push(L, static_cast::value, O&, O&&>>(t.value())); + } + }; #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT - namespace stack_detail { + namespace stack_detail { - struct push_function { - lua_State* L; + struct push_function { + lua_State* L; - push_function(lua_State* L) : L(L) { - } - - template - int operator()(T&& value) const { - return stack::push(L, std::forward(value)); - } - }; - - } // namespace stack_detail - - template - struct unqualified_pusher> { - static int push(lua_State* L, const std::variant& v) { - return std::visit(stack_detail::push_function(L), v); + push_function(lua_State* L) : L(L) { } - static int push(lua_State* L, std::variant&& v) { - return std::visit(stack_detail::push_function(L), std::move(v)); + template + int operator()(T&& value) const { + return stack::push(L, std::forward(value)); } }; + + } // namespace stack_detail + + template + struct unqualified_pusher> { + static int push(lua_State* L, const std::variant& v) { + return std::visit(stack_detail::push_function(L), v); + } + + static int push(lua_State* L, std::variant&& v) { + return std::visit(stack_detail::push_function(L), std::move(v)); + } + }; #endif // Variant because Clang is terrible #endif // C++17 Support - } -} // namespace sol::stack +}} // namespace sol::stack #endif // SOL_STACK_PUSH_HPP diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index 875d6ff5..bc35c701 100644 --- a/single/include/sol/forward.hpp +++ b/single/include/sol/forward.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-12-23 14:09:10.625316 UTC -// This header was generated with sol v3.2.0 (revision 1f27149) +// Generated 2019-12-25 18:24:10.892183 UTC +// This header was generated with sol v3.2.0 (revision 36972a9) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP diff --git a/single/include/sol/sol.hpp b/single/include/sol/sol.hpp index 67d82074..8b82c0b0 100644 --- a/single/include/sol/sol.hpp +++ b/single/include/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-12-23 14:09:10.057090 UTC -// This header was generated with sol v3.2.0 (revision 1f27149) +// Generated 2019-12-25 18:24:10.331683 UTC +// This header was generated with sol v3.2.0 (revision 36972a9) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -13085,1168 +13085,1167 @@ namespace sol { namespace stack { #endif // Can use variant #endif // C++17 -namespace sol { - namespace stack { - namespace stack_detail { - template - inline bool integer_value_fits(const T& value) { - if constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed_v && sizeof(T) == sizeof(lua_Integer))) { - (void)value; - return true; - } - else { - auto u_min = static_cast((std::numeric_limits::min)()); - auto u_max = static_cast((std::numeric_limits::max)()); - auto t_min = static_cast((std::numeric_limits::min)()); - auto t_max = static_cast((std::numeric_limits::max)()); - return (u_min <= t_min || value >= static_cast(u_min)) && (u_max >= t_max || value <= static_cast(u_max)); - } +namespace sol { namespace stack { + namespace stack_detail { + template + inline bool integer_value_fits(const T& value) { + if constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed_v && sizeof(T) == sizeof(lua_Integer))) { + (void)value; + return true; } - - template - int msvc_is_ass_with_if_constexpr_push_enum(std::true_type, lua_State* L, const T& value) { - if constexpr (meta::any_same_v, char/*, char8_t*/, char16_t, char32_t>) { - if constexpr (std::is_signed_v) { - return stack::push(L, static_cast(value)); - } - else { - return stack::push(L, static_cast(value)); - } - } - else { - return stack::push(L, static_cast>(value)); - } - } - - template - int msvc_is_ass_with_if_constexpr_push_enum(std::false_type, lua_State*, const T&) { - return 0; + else { + auto u_min = static_cast((std::numeric_limits::min)()); + auto u_max = static_cast((std::numeric_limits::max)()); + auto t_min = static_cast((std::numeric_limits::min)()); + auto t_max = static_cast((std::numeric_limits::max)()); + return (u_min <= t_min || value >= static_cast(u_min)) && (u_max >= t_max || value <= static_cast(u_max)); } } - inline int push_environment_of(lua_State* L, int index = -1) { + template + int msvc_is_ass_with_if_constexpr_push_enum(std::true_type, lua_State* L, const T& value) { + if constexpr (meta::any_same_v, char /*, char8_t*/, char16_t, char32_t>) { + if constexpr (std::is_signed_v) { + return stack::push(L, static_cast(value)); + } + else { + return stack::push(L, static_cast(value)); + } + } + else { + return stack::push(L, static_cast>(value)); + } + } + + template + int msvc_is_ass_with_if_constexpr_push_enum(std::false_type, lua_State*, const T&) { + return 0; + } + } // namespace stack_detail + + inline int push_environment_of(lua_State* L, int index = -1) { #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_environment); + luaL_checkstack(L, 1, detail::not_enough_stack_space_environment); #endif // make sure stack doesn't overflow #if SOL_LUA_VERSION < 502 - // Use lua_getfenv - lua_getfenv(L, index); + // Use lua_getfenv + lua_getfenv(L, index); #else - // Use upvalues as explained in Lua 5.2 and beyond's manual - if (lua_getupvalue(L, index, 1) == nullptr) { - push(L, lua_nil); + // Use upvalues as explained in Lua 5.2 and beyond's manual + if (lua_getupvalue(L, index, 1) == nullptr) { + push(L, lua_nil); + return 1; + } +#endif + return 1; + } + + template + int push_environment_of(const T& target) { + target.push(); + return push_environment_of(target.lua_state(), -1) + 1; + } + + template + struct unqualified_pusher> { + template + static int push_fx(lua_State* L, F&& f, Args&&... args) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + // Basically, we store all user-data like this: + // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new + // data in the first sizeof(T*) bytes, and then however many bytes it takes to + // do the actual object. Things that are std::ref or plain T* are stored as + // just the sizeof(T*), and nothing else. + T* obj = detail::usertype_allocate(L); + f(); + std::allocator alloc{}; + std::allocator_traits>::construct(alloc, obj, std::forward(args)...); + return 1; + } + + template + static int push_keyed(lua_State* L, K&& k, Args&&... args) { + stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); + return push_fx(L, fx, std::forward(args)...); + } + + template + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_same_v, detail::with_function_tag>) { + (void)arg; + return push_fx(L, std::forward(args)...); + } + else { + return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); + } + } + + static int push(lua_State* L) { + return push_keyed(L, usertype_traits::metatable()); + } + }; + + template + struct unqualified_pusher> { + typedef meta::unqualified_t U; + + template + static int push_fx(lua_State* L, F&& f, T* obj) { + if (obj == nullptr) + return stack::push(L, lua_nil); +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + T** pref = detail::usertype_allocate_pointer(L); + f(); + *pref = obj; + return 1; + } + + template + static int push_keyed(lua_State* L, K&& k, T* obj) { + stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); + return push_fx(L, fx, obj); + } + + template + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_same_v, detail::with_function_tag>) { + (void)arg; + return push_fx(L, std::forward(args)...); + } + else { + return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); + } + } + }; + + template <> + struct unqualified_pusher { + template + static int push(lua_State* L, T&& obj) { + return stack::push(L, detail::ptr(obj)); + } + }; + + namespace stack_detail { + template + struct uu_pusher { + using u_traits = unique_usertype_traits; + using P = typename u_traits::type; + using Real = typename u_traits::actual_type; + + template + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_base_of_v>) { + if (u_traits::is_null(arg)) { + return stack::push(L, lua_nil); + } + return push_deep(L, std::forward(arg), std::forward(args)...); + } + else { + return push_deep(L, std::forward(arg), std::forward(args)...); + } + } + + template + static int push_deep(lua_State* L, Args&&... args) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + P** pref = nullptr; + detail::unique_destructor* fx = nullptr; + detail::unique_tag* id = nullptr; + Real* mem = detail::usertype_unique_allocate(L, pref, fx, id); + if (luaL_newmetatable(L, &usertype_traits>>::metatable()[0]) == 1) { + detail::lua_reg_table l{}; + int index = 0; + detail::indexed_insert insert_fx(l, index); + detail::insert_default_registrations

(insert_fx, detail::property_always_true); + l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor() }; + luaL_setfuncs(L, l, 0); + } + lua_setmetatable(L, -2); + *fx = detail::usertype_unique_alloc_destroy; + *id = &detail::inheritance

::template type_unique_cast; + detail::default_construct::construct(mem, std::forward(args)...); + *pref = unique_usertype_traits::get(*mem); return 1; } -#endif + }; + } // namespace stack_detail + + template + struct unqualified_pusher { + template + static int push(lua_State* L, Args&&... args) { + using Tu = meta::unqualified_t; + if constexpr (is_lua_reference_v) { + using int_arr = int[]; + int_arr p{ (std::forward(args).push(L))... }; + return p[0]; + } + else if constexpr (std::is_same_v) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushboolean(L, std::forward(args)...); + return 1; + } + else if constexpr (std::is_integral_v || std::is_same_v) { + const Tu& value(std::forward(args)...); +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_integral); +#endif // make sure stack doesn't overflow +#if SOL_LUA_VERSION >= 503 + if (stack_detail::integer_value_fits(value)) { + lua_pushinteger(L, static_cast(value)); + return 1; + } +#endif // Lua 5.3 and above +#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) + if (static_cast(llround(static_cast(value))) != value) { +#if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS + // Is this really worth it? + assert(false && "integer value will be misrepresented in lua"); + lua_pushinteger(L, static_cast(value)); + return 1; +#else + throw error(detail::direct_error, "integer value will be misrepresented in lua"); +#endif // No Exceptions + } +#endif // Safe Numerics and Number Precision Check + lua_pushnumber(L, static_cast(value)); + return 1; + } + else if constexpr (std::is_floating_point_v || std::is_same_v) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_floating); +#endif // make sure stack doesn't overflow + lua_pushnumber(L, std::forward(args)...); + return 1; + } + else if constexpr (std::is_enum_v) { + return stack_detail::msvc_is_ass_with_if_constexpr_push_enum(std::true_type(), L, std::forward(args)...); + } + else if constexpr (std::is_pointer_v) { + return stack::push>>(L, std::forward(args)...); + } + else if constexpr (is_unique_usertype_v) { + stack_detail::uu_pusher p; + (void)p; + return p.push(L, std::forward(args)...); + } + else { + return stack::push>(L, std::forward(args)...); + } + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const std::reference_wrapper& t) { + return stack::push(L, std::addressof(detail::deref(t.get()))); + } + }; + + template + struct unqualified_pusher> { + using has_kvp = meta::has_key_value_pair>>; + + static int push(lua_State* L, const T& tablecont) { + return push(has_kvp(), std::false_type(), L, tablecont); + } + + static int push(lua_State* L, const T& tablecont, nested_tag_t) { + return push(has_kvp(), std::true_type(), L, tablecont); + } + + static int push(std::true_type, lua_State* L, const T& tablecont) { + return push(has_kvp(), std::true_type(), L, tablecont); + } + + static int push(std::false_type, lua_State* L, const T& tablecont) { + return push(has_kvp(), std::false_type(), L, tablecont); + } + + template + static int push(std::true_type, std::integral_constant, lua_State* L, const T& tablecont) { + auto& cont = detail::deref(detail::unwrap(tablecont)); + lua_createtable(L, static_cast(cont.size()), 0); + int tableindex = lua_gettop(L); + for (const auto& pair : cont) { + if (is_nested) { + set_field(L, pair.first, as_nested_ref(pair.second), tableindex); + } + else { + set_field(L, pair.first, pair.second, tableindex); + } + } + return 1; + } + + template + static int push(std::false_type, std::integral_constant, lua_State* L, const T& tablecont) { + auto& cont = detail::deref(detail::unwrap(tablecont)); + lua_createtable(L, stack_detail::get_size_hint(cont), 0); + int tableindex = lua_gettop(L); + std::size_t index = 1; + for (const auto& i : cont) { +#if SOL_LUA_VERSION >= 503 + int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); + for (int pi = 0; pi < p; ++pi) { + lua_seti(L, tableindex, static_cast(index++)); + } +#else +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushinteger(L, static_cast(index)); + int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); + if (p == 1) { + ++index; + lua_settable(L, tableindex); + } + else { + int firstindex = tableindex + 1 + 1; + for (int pi = 0; pi < p; ++pi) { + stack::push(L, index); +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, firstindex); + lua_settable(L, tableindex); + ++index; + ++firstindex; + } + lua_pop(L, 1 + p); + } +#endif // Lua Version 5.3 and others + } + // TODO: figure out a better way to do this...? + // set_field(L, -1, cont.size()); + return 1; + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const T& v) { + using inner_t = std::remove_pointer_t>; + if constexpr (is_container_v) { + return stack::push>(L, v); + } + else { + return stack::push(L, v); + } + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const T& tablecont) { + using Tu = meta::unwrap_unqualified_t; + using inner_t = std::remove_pointer_t; + if constexpr (is_container_v) { + return stack::push>(L, tablecont, nested_tag); + } + else { + return stack::push(L, tablecont); + } + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const std::initializer_list& il) { + unqualified_pusher>> p{}; + // silence annoying VC++ warning + (void)p; + return p.push(L, il); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, lua_nil_t) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushnil(L); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State*, stack_count st) { + return st.count; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, metatable_key_t) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, "__mt", 4); + return 1; + } + }; + + template <> + struct unqualified_pusher> { + static int push(lua_State* L, lua_CFunction func, int n = 0) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, lua_CFunction func, int n = 0) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; + +#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE + template <> + struct unqualified_pusher> { + static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; +#endif // noexcept function type + + template <> + struct unqualified_pusher { + static int push(lua_State* L, c_closure cc) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, cc.c_function, cc.upvalues); + return 1; + } + }; + + template + struct unqualified_pusher> { + template + static int push(std::index_sequence, lua_State* L, T&& c) { + using f_tuple = decltype(std::forward(c).upvalues); + int pushcount = multi_push(L, std::get(std::forward(std::forward(c).upvalues))...); + return stack::push(L, c_closure(c.c_function, pushcount)); + } + + template + static int push(lua_State* L, T&& c) { + return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward(c)); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, void* userdata) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, userdata); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const void* userdata) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, const_cast(userdata)); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, lightuserdata_value userdata) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, userdata); + return 1; + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, light l) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, static_cast(l.value)); + return 1; + } + }; + + template + struct unqualified_pusher> { + template + static int push_with(lua_State* L, Key&& name, Args&&... args) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + // A dumb pusher + T* data = detail::user_allocate(L); + if (with_meta) { + // Make sure we have a plain GC set for this data +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + if (luaL_newmetatable(L, name) != 0) { + lua_CFunction cdel = detail::user_alloc_destruct; + lua_pushcclosure(L, cdel, 0); + lua_setfield(L, -2, "__gc"); + } + lua_setmetatable(L, -2); + } + std::allocator alloc{}; + std::allocator_traits>::construct(alloc, data, std::forward(args)...); + return 1; + } + + template + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_same_v, metatable_key_t>) { + const auto name = &arg[0]; + return push_with(L, name, std::forward(args)...); + } + else if constexpr (std::is_same_v, no_metatable_t>) { + (void)arg; + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, std::forward(args)...); + } + else { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, std::forward(arg), std::forward(args)...); + } + } + + static int push(lua_State* L, const user& u) { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, u.value); + } + + static int push(lua_State* L, user&& u) { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, std::move(u.value)); + } + + static int push(lua_State* L, no_metatable_t, const user& u) { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, u.value); + } + + static int push(lua_State* L, no_metatable_t, user&& u) { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, std::move(u.value)); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, userdata_value data) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + void** ud = detail::usertype_allocate_pointer(L); + *ud = data.value; + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push_sized(lua_State* L, const char* str, std::size_t len) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, len); + return 1; + } + + static int push(lua_State* L, const char* str) { + if (str == nullptr) + return stack::push(L, lua_nil); + return push_sized(L, str, std::char_traits::length(str)); + } + + static int push(lua_State* L, const char* strb, const char* stre) { + return push_sized(L, strb, stre - strb); + } + + static int push(lua_State* L, const char* str, std::size_t len) { + return push_sized(L, str, len); + } + }; + + template <> + struct unqualified_pusher { + static int push_sized(lua_State* L, const char* str, std::size_t len) { + unqualified_pusher p{}; + (void)p; + return p.push_sized(L, str, len); + } + + static int push(lua_State* L, const char* str) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char* strb, const char* stre) { + unqualified_pusher p{}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char* str, std::size_t len) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str, len); + } + }; + + template + struct unqualified_pusher { + static int push(lua_State* L, const char (&str)[N]) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, std::char_traits::length(str)); + return 1; + } + + static int push(lua_State* L, const char (&str)[N], std::size_t sz) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, sz); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, char c) { + const char str[2] = { c, '\0' }; + return stack::push(L, str, 1); + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const std::basic_string& str) { + if constexpr (!std::is_same_v) { + return stack::push(L, str.data(), str.size()); + } + else { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str.c_str(), str.size()); + return 1; + } + } + + static int push(lua_State* L, const std::basic_string& str, std::size_t sz) { + if constexpr (!std::is_same_v) { + return stack::push(L, str.data(), sz); + } + else { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str.c_str(), sz); + return 1; + } + } + }; + + template + struct unqualified_pusher> { + static int push(lua_State* L, const basic_string_view& sv) { + return stack::push(L, sv.data(), sv.length()); + } + + static int push(lua_State* L, const basic_string_view& sv, std::size_t n) { + return stack::push(L, sv.data(), n); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, meta_function m) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_meta_function_name); +#endif // make sure stack doesn't overflow + const std::string& str = to_string(m); + lua_pushlstring(L, str.c_str(), str.size()); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, absolute_index ai) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, ai); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, raw_index ri) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, ri); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, ref_index ri) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_rawgeti(L, LUA_REGISTRYINDEX, ri); + return 1; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const wchar_t* wstr) { + return push(L, wstr, std::char_traits::length(wstr)); + } + + static int push(lua_State* L, const wchar_t* wstr, std::size_t sz) { + return push(L, wstr, wstr + sz); + } + + static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { + if constexpr (sizeof(wchar_t) == 2) { + const char16_t* sb = reinterpret_cast(strb); + const char16_t* se = reinterpret_cast(stre); + return stack::push(L, sb, se); + } + else { + const char32_t* sb = reinterpret_cast(strb); + const char32_t* se = reinterpret_cast(stre); + return stack::push(L, sb, se); + } + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const wchar_t* str) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { + unqualified_pusher p{}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const wchar_t* str, std::size_t len) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str, len); + } + }; + + template <> + struct unqualified_pusher { + static int convert_into(lua_State* L, char* start, std::size_t, const char16_t* strb, const char16_t* stre) { + char* target = start; + char32_t cp = 0; + for (const char16_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf16_to_code_point(strtarget, stre); + if (dr.error != unicode::error_code::ok) { + cp = unicode::unicode_detail::replacement; + } + else { + cp = dr.codepoint; + } + auto er = unicode::code_point_to_utf8(cp); + const char* utf8data = er.code_units.data(); + std::memcpy(target, utf8data, er.code_units_size); + target += er.code_units_size; + strtarget = dr.next; + } + + return stack::push(L, start, target); + } + + static int push(lua_State* L, const char16_t* u16str) { + return push(L, u16str, std::char_traits::length(u16str)); + } + + static int push(lua_State* L, const char16_t* u16str, std::size_t sz) { + return push(L, u16str, u16str + sz); + } + + static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { + char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; + // if our max string space is small enough, use SBO + // right off the bat + std::size_t max_possible_code_units = (stre - strb) * 4; + if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { + return convert_into(L, sbo, max_possible_code_units, strb, stre); + } + // otherwise, we must manually count/check size + std::size_t needed_size = 0; + for (const char16_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf16_to_code_point(strtarget, stre); + auto er = unicode::code_point_to_utf8(dr.codepoint); + needed_size += er.code_units_size; + strtarget = dr.next; + } + if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { + return convert_into(L, sbo, needed_size, strb, stre); + } + std::string u8str("", 0); + u8str.resize(needed_size); + char* target = &u8str[0]; + return convert_into(L, target, needed_size, strb, stre); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const char16_t* str) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { + unqualified_pusher p{}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char16_t* str, std::size_t len) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str, len); + } + }; + + template <> + struct unqualified_pusher { + static int convert_into(lua_State* L, char* start, std::size_t, const char32_t* strb, const char32_t* stre) { + char* target = start; + char32_t cp = 0; + for (const char32_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf32_to_code_point(strtarget, stre); + if (dr.error != unicode::error_code::ok) { + cp = unicode::unicode_detail::replacement; + } + else { + cp = dr.codepoint; + } + auto er = unicode::code_point_to_utf8(cp); + const char* data = er.code_units.data(); + std::memcpy(target, data, er.code_units_size); + target += er.code_units_size; + strtarget = dr.next; + } + return stack::push(L, start, target); + } + + static int push(lua_State* L, const char32_t* u32str) { + return push(L, u32str, u32str + std::char_traits::length(u32str)); + } + + static int push(lua_State* L, const char32_t* u32str, std::size_t sz) { + return push(L, u32str, u32str + sz); + } + + static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { + char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; + // if our max string space is small enough, use SBO + // right off the bat + std::size_t max_possible_code_units = (stre - strb) * 4; + if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { + return convert_into(L, sbo, max_possible_code_units, strb, stre); + } + // otherwise, we must manually count/check size + std::size_t needed_size = 0; + for (const char32_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf32_to_code_point(strtarget, stre); + auto er = unicode::code_point_to_utf8(dr.codepoint); + needed_size += er.code_units_size; + strtarget = dr.next; + } + if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { + return convert_into(L, sbo, needed_size, strb, stre); + } + std::string u8str("", 0); + u8str.resize(needed_size); + char* target = &u8str[0]; + return convert_into(L, target, needed_size, strb, stre); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const char32_t* str) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { + unqualified_pusher p{}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char32_t* str, std::size_t len) { + unqualified_pusher p{}; + (void)p; + return p.push(L, str, len); + } + }; + + template + struct unqualified_pusher { + static int push(lua_State* L, const wchar_t (&str)[N]) { + return push(L, str, std::char_traits::length(str)); + } + + static int push(lua_State* L, const wchar_t (&str)[N], std::size_t sz) { + return stack::push(L, str, str + sz); + } + }; + + template + struct unqualified_pusher { + static int push(lua_State* L, const char16_t (&str)[N]) { + return push(L, str, std::char_traits::length(str)); + } + + static int push(lua_State* L, const char16_t (&str)[N], std::size_t sz) { + return stack::push(L, str, str + sz); + } + }; + + template + struct unqualified_pusher { + static int push(lua_State* L, const char32_t (&str)[N]) { + return push(L, str, std::char_traits::length(str)); + } + + static int push(lua_State* L, const char32_t (&str)[N], std::size_t sz) { + return stack::push(L, str, str + sz); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, wchar_t c) { + const wchar_t str[2] = { c, '\0' }; + return stack::push(L, &str[0], 1); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, char16_t c) { + const char16_t str[2] = { c, '\0' }; + return stack::push(L, &str[0], 1); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, char32_t c) { + const char32_t str[2] = { c, '\0' }; + return stack::push(L, &str[0], 1); + } + }; + + template + struct unqualified_pusher> { + template + static int push(std::index_sequence, lua_State* L, T&& t) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, static_cast(sizeof...(I)), detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + int pushcount = 0; + (void)detail::swallow{ 0, (pushcount += stack::push(L, std::get(std::forward(t))), 0)... }; + return pushcount; + } + + template + static int push(lua_State* L, T&& t) { + return push(std::index_sequence_for(), L, std::forward(t)); + } + }; + + template + struct unqualified_pusher> { + template + static int push(lua_State* L, T&& t) { + int pushcount = stack::push(L, std::get<0>(std::forward(t))); + pushcount += stack::push(L, std::get<1>(std::forward(t))); + return pushcount; + } + }; + + template + struct unqualified_pusher> { + template + static int push(lua_State* L, T&& t) { + if (t == nullopt) { + return stack::push(L, nullopt); + } + return stack::push(L, static_cast::value, O&, O&&>>(t.value())); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, nullopt_t) { + return stack::push(L, lua_nil); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, std::nullptr_t) { + return stack::push(L, lua_nil); + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State*, const this_state&) { + return 0; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State*, const this_main_state&) { + return 0; + } + }; + + template <> + struct unqualified_pusher { + static int push(lua_State* L, const new_table& nt) { + lua_createtable(L, nt.sequence_hint, nt.map_hint); + return 1; + } + }; + + template + struct unqualified_pusher> { + template + static int push(lua_State* L, T&& bc, const char* bytecode_name) { + const auto first = bc.data(); + const auto bcsize = bc.size(); + // pushes either the function, or an error + // if it errors, shit goes south, and people can test that upstream + (void)luaL_loadbuffer( + L, reinterpret_cast(first), static_cast(bcsize * (sizeof(*first) / sizeof(const char))), bytecode_name); return 1; } template - int push_environment_of(const T& target) { - target.push(); - return push_environment_of(target.lua_state(), -1) + 1; + static int push(lua_State* L, T&& bc) { + return push(L, std::forward(bc), "bytecode"); } - - template - struct unqualified_pusher> { - template - static int push_fx(lua_State* L, F&& f, Args&&... args) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); -#endif // make sure stack doesn't overflow - // Basically, we store all user-data like this: - // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new - // data in the first sizeof(T*) bytes, and then however many bytes it takes to - // do the actual object. Things that are std::ref or plain T* are stored as - // just the sizeof(T*), and nothing else. - T* obj = detail::usertype_allocate(L); - f(); - std::allocator alloc{}; - std::allocator_traits>::construct(alloc, obj, std::forward(args)...); - return 1; - } - - template - static int push_keyed(lua_State* L, K&& k, Args&&... args) { - stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); - return push_fx(L, fx, std::forward(args)...); - } - - template - static int push(lua_State* L, Arg&& arg, Args&&... args) { - if constexpr (std::is_same_v, detail::with_function_tag>) { - (void)arg; - return push_fx(L, std::forward(args)...); - } - else { - return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); - } - } - - static int push(lua_State* L) { - return push_keyed(L, usertype_traits::metatable()); - } - }; - - template - struct unqualified_pusher> { - typedef meta::unqualified_t U; - - template - static int push_fx(lua_State* L, F&& f, T* obj) { - if (obj == nullptr) - return stack::push(L, lua_nil); -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); -#endif // make sure stack doesn't overflow - T** pref = detail::usertype_allocate_pointer(L); - f(); - *pref = obj; - return 1; - } - - template - static int push_keyed(lua_State* L, K&& k, T* obj) { - stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); - return push_fx(L, fx, obj); - } - - template - static int push(lua_State* L, Arg&& arg, Args&&... args) { - if constexpr (std::is_same_v, detail::with_function_tag>) { - (void)arg; - return push_fx(L, std::forward(args)...); - } - else { - return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); - } - } - }; - - template <> - struct unqualified_pusher { - template - static int push(lua_State* L, T&& obj) { - return stack::push(L, detail::ptr(obj)); - } - }; - - namespace stack_detail { - template - struct uu_pusher { - using u_traits = unique_usertype_traits; - using P = typename u_traits::type; - using Real = typename u_traits::actual_type; - - template - static int push(lua_State* L, Arg&& arg, Args&&... args) { - if constexpr (std::is_base_of_v>) { - if (u_traits::is_null(arg)) { - return stack::push(L, lua_nil); - } - return push_deep(L, std::forward(arg), std::forward(args)...); - } - else { - return push_deep(L, std::forward(arg), std::forward(args)...); - } - } - - template - static int push_deep(lua_State* L, Args&&... args) { - #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); - #endif // make sure stack doesn't overflow - P** pref = nullptr; - detail::unique_destructor* fx = nullptr; - detail::unique_tag* id = nullptr; - Real* mem = detail::usertype_unique_allocate(L, pref, fx, id); - if (luaL_newmetatable(L, &usertype_traits>>::metatable()[0]) == 1) { - detail::lua_reg_table l{}; - int index = 0; - detail::indexed_insert insert_fx(l, index); - detail::insert_default_registrations

(insert_fx, detail::property_always_true); - l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor() }; - luaL_setfuncs(L, l, 0); - } - lua_setmetatable(L, -2); - *fx = detail::usertype_unique_alloc_destroy; - *id = &detail::inheritance

::template type_unique_cast; - detail::default_construct::construct(mem, std::forward(args)...); - *pref = unique_usertype_traits::get(*mem); - return 1; - } - }; - } // namespace stack_detail - - template - struct unqualified_pusher { - template - static int push(lua_State* L, Args&&... args) { - using Tu = meta::unqualified_t; - if constexpr (is_lua_reference_v) { - using int_arr = int[]; - int_arr p{ (std::forward(args).push(L))... }; - return p[0]; - } - else if constexpr (std::is_same_v) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushboolean(L, std::forward(args)...); - return 1; - } - else if constexpr (std::is_integral_v || std::is_same_v) { - const Tu& value(std::forward(args)...); -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_integral); -#endif // make sure stack doesn't overflow -#if SOL_LUA_VERSION >= 503 - if (stack_detail::integer_value_fits(value)) { - lua_pushinteger(L, static_cast(value)); - return 1; - } -#endif // Lua 5.3 and above -#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) - if (static_cast(llround(static_cast(value))) != value) { -#if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS - // Is this really worth it? - assert(false && "integer value will be misrepresented in lua"); - lua_pushnumber(L, static_cast(std::forward(args)...)); - return 1; -#else - throw error(detail::direct_error, "integer value will be misrepresented in lua"); -#endif // No Exceptions - } -#endif // Safe Numerics and Number Precision Check - lua_pushnumber(L, static_cast(value)); - return 1; - } - else if constexpr (std::is_floating_point_v || std::is_same_v) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_floating); -#endif // make sure stack doesn't overflow - lua_pushnumber(L, std::forward(args)...); - return 1; - } - else if constexpr (std::is_enum_v) { - return stack_detail::msvc_is_ass_with_if_constexpr_push_enum(std::true_type(), L, std::forward(args)...); - } - else if constexpr (std::is_pointer_v) { - return stack::push>>(L, std::forward(args)...); - } - else if constexpr (is_unique_usertype_v) { - stack_detail::uu_pusher p; - (void)p; - return p.push(L, std::forward(args)...); - } - else { - return stack::push>(L, std::forward(args)...); - } - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const std::reference_wrapper& t) { - return stack::push(L, std::addressof(detail::deref(t.get()))); - } - }; - - template - struct unqualified_pusher> { - using has_kvp = meta::has_key_value_pair>>; - - static int push(lua_State* L, const T& tablecont) { - return push(has_kvp(), std::false_type(), L, tablecont); - } - - static int push(lua_State* L, const T& tablecont, nested_tag_t) { - return push(has_kvp(), std::true_type(), L, tablecont); - } - - static int push(std::true_type, lua_State* L, const T& tablecont) { - return push(has_kvp(), std::true_type(), L, tablecont); - } - - static int push(std::false_type, lua_State* L, const T& tablecont) { - return push(has_kvp(), std::false_type(), L, tablecont); - } - - template - static int push(std::true_type, std::integral_constant, lua_State* L, const T& tablecont) { - auto& cont = detail::deref(detail::unwrap(tablecont)); - lua_createtable(L, static_cast(cont.size()), 0); - int tableindex = lua_gettop(L); - for (const auto& pair : cont) { - if (is_nested) { - set_field(L, pair.first, as_nested_ref(pair.second), tableindex); - } - else { - set_field(L, pair.first, pair.second, tableindex); - } - } - return 1; - } - - template - static int push(std::false_type, std::integral_constant, lua_State* L, const T& tablecont) { - auto& cont = detail::deref(detail::unwrap(tablecont)); - lua_createtable(L, stack_detail::get_size_hint(cont), 0); - int tableindex = lua_gettop(L); - std::size_t index = 1; - for (const auto& i : cont) { -#if SOL_LUA_VERSION >= 503 - int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); - for (int pi = 0; pi < p; ++pi) { - lua_seti(L, tableindex, static_cast(index++)); - } -#else -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushinteger(L, static_cast(index)); - int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); - if (p == 1) { - ++index; - lua_settable(L, tableindex); - } - else { - int firstindex = tableindex + 1 + 1; - for (int pi = 0; pi < p; ++pi) { - stack::push(L, index); -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushvalue(L, firstindex); - lua_settable(L, tableindex); - ++index; - ++firstindex; - } - lua_pop(L, 1 + p); - } -#endif // Lua Version 5.3 and others - } - // TODO: figure out a better way to do this...? - // set_field(L, -1, cont.size()); - return 1; - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const T& v) { - using inner_t = std::remove_pointer_t>; - if constexpr (is_container_v) { - return stack::push>(L, v); - } - else { - return stack::push(L, v); - } - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const T& tablecont) { - using Tu = meta::unwrap_unqualified_t; - using inner_t = std::remove_pointer_t; - if constexpr (is_container_v) { - return stack::push>(L, tablecont, nested_tag); - } - else { - return stack::push(L, tablecont); - } - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const std::initializer_list& il) { - unqualified_pusher>> p{}; - // silence annoying VC++ warning - (void)p; - return p.push(L, il); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, lua_nil_t) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushnil(L); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State*, stack_count st) { - return st.count; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, metatable_key_t) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, "__mt", 4); - return 1; - } - }; - - template <> - struct unqualified_pusher> { - static int push(lua_State* L, lua_CFunction func, int n = 0) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushcclosure(L, func, n); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, lua_CFunction func, int n = 0) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushcclosure(L, func, n); - return 1; - } - }; - -#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE - template <> - struct unqualified_pusher> { - static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushcclosure(L, func, n); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushcclosure(L, func, n); - return 1; - } - }; -#endif // noexcept function type - - template <> - struct unqualified_pusher { - static int push(lua_State* L, c_closure cc) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushcclosure(L, cc.c_function, cc.upvalues); - return 1; - } - }; - - template - struct unqualified_pusher> { - template - static int push(std::index_sequence, lua_State* L, T&& c) { - using f_tuple = decltype(std::forward(c).upvalues); - int pushcount = multi_push(L, std::get(std::forward(std::forward(c).upvalues))...); - return stack::push(L, c_closure(c.c_function, pushcount)); - } - - template - static int push(lua_State* L, T&& c) { - return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward(c)); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, void* userdata) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushlightuserdata(L, userdata); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const void* userdata) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushlightuserdata(L, const_cast(userdata)); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, lightuserdata_value userdata) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushlightuserdata(L, userdata); - return 1; - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, light l) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushlightuserdata(L, static_cast(l.value)); - return 1; - } - }; - - template - struct unqualified_pusher> { - template - static int push_with(lua_State* L, Key&& name, Args&&... args) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); -#endif // make sure stack doesn't overflow - // A dumb pusher - T* data = detail::user_allocate(L); - if (with_meta) { - // Make sure we have a plain GC set for this data -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - if (luaL_newmetatable(L, name) != 0) { - lua_CFunction cdel = detail::user_alloc_destruct; - lua_pushcclosure(L, cdel, 0); - lua_setfield(L, -2, "__gc"); - } - lua_setmetatable(L, -2); - } - std::allocator alloc{}; - std::allocator_traits>::construct(alloc, data, std::forward(args)...); - return 1; - } - - template - static int push(lua_State* L, Arg&& arg, Args&&... args) { - if constexpr (std::is_same_v, metatable_key_t>) { - const auto name = &arg[0]; - return push_with(L, name, std::forward(args)...); - } - else if constexpr (std::is_same_v, no_metatable_t>) { - (void)arg; - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::forward(args)...); - } - else { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::forward(arg), std::forward(args)...); - } - } - - static int push(lua_State* L, const user& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, u.value); - } - - static int push(lua_State* L, user&& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::move(u.value)); - } - - static int push(lua_State* L, no_metatable_t, const user& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, u.value); - } - - static int push(lua_State* L, no_metatable_t, user&& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::move(u.value)); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, userdata_value data) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); -#endif // make sure stack doesn't overflow - void** ud = detail::usertype_allocate_pointer(L); - *ud = data.value; - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push_sized(lua_State* L, const char* str, std::size_t len) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, str, len); - return 1; - } - - static int push(lua_State* L, const char* str) { - if (str == nullptr) - return stack::push(L, lua_nil); - return push_sized(L, str, std::char_traits::length(str)); - } - - static int push(lua_State* L, const char* strb, const char* stre) { - return push_sized(L, strb, stre - strb); - } - - static int push(lua_State* L, const char* str, std::size_t len) { - return push_sized(L, str, len); - } - }; - - template <> - struct unqualified_pusher { - static int push_sized(lua_State* L, const char* str, std::size_t len) { - unqualified_pusher p{}; - (void)p; - return p.push_sized(L, str, len); - } - - static int push(lua_State* L, const char* str) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str); - } - - static int push(lua_State* L, const char* strb, const char* stre) { - unqualified_pusher p{}; - (void)p; - return p.push(L, strb, stre); - } - - static int push(lua_State* L, const char* str, std::size_t len) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str, len); - } - }; - - template - struct unqualified_pusher { - static int push(lua_State* L, const char (&str)[N]) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, str, std::char_traits::length(str)); - return 1; - } - - static int push(lua_State* L, const char (&str)[N], std::size_t sz) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, str, sz); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, char c) { - const char str[2] = { c, '\0' }; - return stack::push(L, str, 1); - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const std::basic_string& str) { - if constexpr (!std::is_same_v) { - return stack::push(L, str.data(), str.size()); - } - else { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, str.c_str(), str.size()); - return 1; - } - } - - static int push(lua_State* L, const std::basic_string& str, std::size_t sz) { - if constexpr (!std::is_same_v) { - return stack::push(L, str.data(), sz); - } - else { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); -#endif // make sure stack doesn't overflow - lua_pushlstring(L, str.c_str(), sz); - return 1; - } - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, const basic_string_view& sv) { - return stack::push(L, sv.data(), sv.length()); - } - - static int push(lua_State* L, const basic_string_view& sv, std::size_t n) { - return stack::push(L, sv.data(), n); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, meta_function m) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_meta_function_name); -#endif // make sure stack doesn't overflow - const std::string& str = to_string(m); - lua_pushlstring(L, str.c_str(), str.size()); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, absolute_index ai) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushvalue(L, ai); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, raw_index ri) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushvalue(L, ri); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, ref_index ri) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_rawgeti(L, LUA_REGISTRYINDEX, ri); - return 1; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const wchar_t* wstr) { - return push(L, wstr, std::char_traits::length(wstr)); - } - - static int push(lua_State* L, const wchar_t* wstr, std::size_t sz) { - return push(L, wstr, wstr + sz); - } - - static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { - if constexpr (sizeof(wchar_t) == 2) { - const char16_t* sb = reinterpret_cast(strb); - const char16_t* se = reinterpret_cast(stre); - return stack::push(L, sb, se); - } - else { - const char32_t* sb = reinterpret_cast(strb); - const char32_t* se = reinterpret_cast(stre); - return stack::push(L, sb, se); - } - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const wchar_t* str) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str); - } - - static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { - unqualified_pusher p{}; - (void)p; - return p.push(L, strb, stre); - } - - static int push(lua_State* L, const wchar_t* str, std::size_t len) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str, len); - } - }; - - template <> - struct unqualified_pusher { - static int convert_into(lua_State* L, char* start, std::size_t, const char16_t* strb, const char16_t* stre) { - char* target = start; - char32_t cp = 0; - for (const char16_t* strtarget = strb; strtarget < stre;) { - auto dr = unicode::utf16_to_code_point(strtarget, stre); - if (dr.error != unicode::error_code::ok) { - cp = unicode::unicode_detail::replacement; - } - else { - cp = dr.codepoint; - } - auto er = unicode::code_point_to_utf8(cp); - const char* utf8data = er.code_units.data(); - std::memcpy(target, utf8data, er.code_units_size); - target += er.code_units_size; - strtarget = dr.next; - } - - return stack::push(L, start, target); - } - - static int push(lua_State* L, const char16_t* u16str) { - return push(L, u16str, std::char_traits::length(u16str)); - } - - static int push(lua_State* L, const char16_t* u16str, std::size_t sz) { - return push(L, u16str, u16str + sz); - } - - static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { - char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; - // if our max string space is small enough, use SBO - // right off the bat - std::size_t max_possible_code_units = (stre - strb) * 4; - if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { - return convert_into(L, sbo, max_possible_code_units, strb, stre); - } - // otherwise, we must manually count/check size - std::size_t needed_size = 0; - for (const char16_t* strtarget = strb; strtarget < stre;) { - auto dr = unicode::utf16_to_code_point(strtarget, stre); - auto er = unicode::code_point_to_utf8(dr.codepoint); - needed_size += er.code_units_size; - strtarget = dr.next; - } - if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { - return convert_into(L, sbo, needed_size, strb, stre); - } - std::string u8str("", 0); - u8str.resize(needed_size); - char* target = &u8str[0]; - return convert_into(L, target, needed_size, strb, stre); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const char16_t* str) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str); - } - - static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { - unqualified_pusher p{}; - (void)p; - return p.push(L, strb, stre); - } - - static int push(lua_State* L, const char16_t* str, std::size_t len) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str, len); - } - }; - - template <> - struct unqualified_pusher { - static int convert_into(lua_State* L, char* start, std::size_t, const char32_t* strb, const char32_t* stre) { - char* target = start; - char32_t cp = 0; - for (const char32_t* strtarget = strb; strtarget < stre;) { - auto dr = unicode::utf32_to_code_point(strtarget, stre); - if (dr.error != unicode::error_code::ok) { - cp = unicode::unicode_detail::replacement; - } - else { - cp = dr.codepoint; - } - auto er = unicode::code_point_to_utf8(cp); - const char* data = er.code_units.data(); - std::memcpy(target, data, er.code_units_size); - target += er.code_units_size; - strtarget = dr.next; - } - return stack::push(L, start, target); - } - - static int push(lua_State* L, const char32_t* u32str) { - return push(L, u32str, u32str + std::char_traits::length(u32str)); - } - - static int push(lua_State* L, const char32_t* u32str, std::size_t sz) { - return push(L, u32str, u32str + sz); - } - - static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { - char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; - // if our max string space is small enough, use SBO - // right off the bat - std::size_t max_possible_code_units = (stre - strb) * 4; - if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { - return convert_into(L, sbo, max_possible_code_units, strb, stre); - } - // otherwise, we must manually count/check size - std::size_t needed_size = 0; - for (const char32_t* strtarget = strb; strtarget < stre;) { - auto dr = unicode::utf32_to_code_point(strtarget, stre); - auto er = unicode::code_point_to_utf8(dr.codepoint); - needed_size += er.code_units_size; - strtarget = dr.next; - } - if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { - return convert_into(L, sbo, needed_size, strb, stre); - } - std::string u8str("", 0); - u8str.resize(needed_size); - char* target = &u8str[0]; - return convert_into(L, target, needed_size, strb, stre); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const char32_t* str) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str); - } - - static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { - unqualified_pusher p{}; - (void)p; - return p.push(L, strb, stre); - } - - static int push(lua_State* L, const char32_t* str, std::size_t len) { - unqualified_pusher p{}; - (void)p; - return p.push(L, str, len); - } - }; - - template - struct unqualified_pusher { - static int push(lua_State* L, const wchar_t (&str)[N]) { - return push(L, str, std::char_traits::length(str)); - } - - static int push(lua_State* L, const wchar_t (&str)[N], std::size_t sz) { - return stack::push(L, str, str + sz); - } - }; - - template - struct unqualified_pusher { - static int push(lua_State* L, const char16_t (&str)[N]) { - return push(L, str, std::char_traits::length(str)); - } - - static int push(lua_State* L, const char16_t (&str)[N], std::size_t sz) { - return stack::push(L, str, str + sz); - } - }; - - template - struct unqualified_pusher { - static int push(lua_State* L, const char32_t (&str)[N]) { - return push(L, str, std::char_traits::length(str)); - } - - static int push(lua_State* L, const char32_t (&str)[N], std::size_t sz) { - return stack::push(L, str, str + sz); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, wchar_t c) { - const wchar_t str[2] = { c, '\0' }; - return stack::push(L, &str[0], 1); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, char16_t c) { - const char16_t str[2] = { c, '\0' }; - return stack::push(L, &str[0], 1); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, char32_t c) { - const char32_t str[2] = { c, '\0' }; - return stack::push(L, &str[0], 1); - } - }; - - template - struct unqualified_pusher> { - template - static int push(std::index_sequence, lua_State* L, T&& t) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, static_cast(sizeof...(I)), detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - int pushcount = 0; - (void)detail::swallow{ 0, (pushcount += stack::push(L, std::get(std::forward(t))), 0)... }; - return pushcount; - } - - template - static int push(lua_State* L, T&& t) { - return push(std::index_sequence_for(), L, std::forward(t)); - } - }; - - template - struct unqualified_pusher> { - template - static int push(lua_State* L, T&& t) { - int pushcount = stack::push(L, std::get<0>(std::forward(t))); - pushcount += stack::push(L, std::get<1>(std::forward(t))); - return pushcount; - } - }; - - template - struct unqualified_pusher> { - template - static int push(lua_State* L, T&& t) { - if (t == nullopt) { - return stack::push(L, nullopt); - } - return stack::push(L, static_cast::value, O&, O&&>>(t.value())); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, nullopt_t) { - return stack::push(L, lua_nil); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, std::nullptr_t) { - return stack::push(L, lua_nil); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State*, const this_state&) { - return 0; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State*, const this_main_state&) { - return 0; - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, const new_table& nt) { - lua_createtable(L, nt.sequence_hint, nt.map_hint); - return 1; - } - }; - - template - struct unqualified_pusher> { - template - static int push(lua_State* L, T&& bc, const char* bytecode_name) { - const auto first = bc.data(); - const auto bcsize = bc.size(); - // pushes either the function, or an error - // if it errors, shit goes south, and people can test that upstream - (void)luaL_loadbuffer(L, reinterpret_cast(first), static_cast(bcsize * (sizeof(*first) / sizeof(const char))), bytecode_name); - return 1; - } - - template - static int push(lua_State* L, T&& bc) { - return push(L, std::forward(bc), "bytecode"); - } - }; + }; #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES - template - struct unqualified_pusher> { - template - static int push(lua_State* L, T&& t) { - if (t == std::nullopt) { - return stack::push(L, nullopt); - } - return stack::push(L, static_cast::value, O&, O&&>>(t.value())); + template + struct unqualified_pusher> { + template + static int push(lua_State* L, T&& t) { + if (t == std::nullopt) { + return stack::push(L, nullopt); } - }; + return stack::push(L, static_cast::value, O&, O&&>>(t.value())); + } + }; #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT - namespace stack_detail { + namespace stack_detail { - struct push_function { - lua_State* L; + struct push_function { + lua_State* L; - push_function(lua_State* L) : L(L) { - } - - template - int operator()(T&& value) const { - return stack::push(L, std::forward(value)); - } - }; - - } // namespace stack_detail - - template - struct unqualified_pusher> { - static int push(lua_State* L, const std::variant& v) { - return std::visit(stack_detail::push_function(L), v); + push_function(lua_State* L) : L(L) { } - static int push(lua_State* L, std::variant&& v) { - return std::visit(stack_detail::push_function(L), std::move(v)); + template + int operator()(T&& value) const { + return stack::push(L, std::forward(value)); } }; + + } // namespace stack_detail + + template + struct unqualified_pusher> { + static int push(lua_State* L, const std::variant& v) { + return std::visit(stack_detail::push_function(L), v); + } + + static int push(lua_State* L, std::variant&& v) { + return std::visit(stack_detail::push_function(L), std::move(v)); + } + }; #endif // Variant because Clang is terrible #endif // C++17 Support - } -} // namespace sol::stack +}} // namespace sol::stack // end of sol/stack_push.hpp