diff --git a/sol2/sol.hpp b/sol2/sol.hpp index 3917c55..92da27f 100644 --- a/sol2/sol.hpp +++ b/sol2/sol.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors +// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in @@ -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 2017-11-21 19:35:19.155726 UTC -// This header was generated with sol v2.18.7 (revision a0de11a) +// Generated 2018-02-23 21:59:31.750406 UTC +// This header was generated with sol v2.19.4 (revision b60132e) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -64,41 +64,28 @@ // beginning of sol/feature_test.hpp -#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402))) +#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L)))) #ifndef SOL_CXX17_FEATURES #define SOL_CXX17_FEATURES 1 #endif // C++17 features macro #endif // C++17 features check -#if defined(__cpp_noexcept_function_type) +#ifdef SOL_CXX17_FEATURES +#if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && (defined(_MSVC_LANG) && ((_MSVC_LANG >= 201403L)))) #ifndef SOL_NOEXCEPT_FUNCTION_TYPE #define SOL_NOEXCEPT_FUNCTION_TYPE 1 #endif // noexcept is part of a function's type -#endif - -#if defined(_WIN32) || defined(_MSC_VER) -#ifndef SOL_CODECVT_SUPPORT -#define SOL_CODECVT_SUPPORT 1 -#endif // sol codecvt support -#elif defined(__GNUC__) -#if __GNUC__ >= 5 -#ifndef SOL_CODECVT_SUPPORT -#define SOL_CODECVT_SUPPORT 1 -#endif // codecvt support -#endif // g++ 5.x.x (MinGW too) -#else -#endif // Windows/VC++ vs. g++ vs Others +#endif // compiler-specific checks +#endif // C++17 only #ifdef _MSC_VER -#ifdef _DEBUG -#ifndef NDEBUG -#ifndef SOL_CHECK_ARGUMENTS -#endif // Check Arguments -#ifndef SOL_SAFE_USERTYPE -#define SOL_SAFE_USERTYPE 1 -#endif // Safe Usertypes -#endif // NDEBUG -#endif // Debug +#if defined(_DEBUG) && !defined(NDEBUG) + +#ifndef SOL_IN_DEBUG_DETECTED +#define SOL_IN_DEBUG_DETECTED 1 +#endif + +#endif // VC++ Debug macros #ifndef _CPPUNWIND #ifndef SOL_NO_EXCEPTIONS @@ -113,15 +100,13 @@ #endif // Automatic RTTI #elif defined(__GNUC__) || defined(__clang__) -#ifndef NDEBUG -#ifndef __OPTIMIZE__ -#ifndef SOL_CHECK_ARGUMENTS -#endif // Check Arguments -#ifndef SOL_SAFE_USERTYPE -#define SOL_SAFE_USERTYPE 1 -#endif // Safe Usertypes -#endif // g++ optimizer flag -#endif // Not Debug +#if !defined(NDEBUG) && !defined(__OPTIMIZE__) + +#ifndef SOL_IN_DEBUG_DETECTED +#define SOL_IN_DEBUG_DETECTED 1 +#endif + +#endif // Not Debug && g++ optimizer flag #ifndef __EXCEPTIONS #ifndef SOL_NO_EXCEPTIONS @@ -137,18 +122,70 @@ #endif // vc++ || clang++/g++ -#ifndef SOL_SAFE_USERTYPE -#ifdef SOL_CHECK_ARGUMENTS +#if defined(SOL_CHECK_ARGUMENTS) + +#if !defined(SOL_SAFE_GETTER) +#define SOL_SAFE_GETTER 1 +#endif + +#if !defined(SOL_SAFE_USERTYPE) #define SOL_SAFE_USERTYPE 1 -#endif // Turn on Safety for all -#endif // Safe Usertypes +#endif + +#if !defined(SOL_SAFE_REFERENCES) +#define SOL_SAFE_REFERENCES 1 +#endif + +#if !defined(SOL_SAFE_FUNCTION) +#define SOL_SAFE_FUNCTION 1 +#endif + +#if !defined(SOL_SAFE_FUNCTION_CALLS) +#define SOL_SAFE_FUNCTION_CALLS 1 +#endif + +#if !defined(SOL_SAFE_PROXIES) +#define SOL_SAFE_PROXIES 1 +#endif + +#if !defined(SOL_SAFE_NUMERICS) +#define SOL_SAFE_NUMERICS 1 +#endif + +#endif // Turn on Safety for all if top-level macro is defined + +#ifdef SOL_IN_DEBUG_DETECTED + +#if !defined(SOL_SAFE_REFERENCES) +#define SOL_SAFE_REFERENCES 1 +#endif + +#if !defined(SOL_SAFE_USERTYPE) +#define SOL_SAFE_USERTYPE 1 +#endif + +#if !defined(SOL_SAFE_FUNCTION_CALLS) +#define SOL_SAFE_FUNCTION_CALLS 1 +#endif + +#endif // Turn on all debug safety features for VC++ / g++ / clang++ and similar #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil) -#ifndef SOL_NO_NIL +#if !defined(SOL_NO_NIL) #define SOL_NO_NIL 1 #endif #endif // avoiding nil defines / keywords +#ifdef SOL_USE_BOOST +#ifndef SOL_UNORDERED_MAP_COMPATIBLE_HASH +#define SOL_UNORDERED_MAP_COMPATIBLE_HASH +#endif // SOL_UNORDERED_MAP_COMPATIBLE_HASH +#endif // Boost has unordered_map with Compatible Key and CompatibleHash + +#ifndef SOL_STACK_STRING_OPTIMIZATION_SIZE +#define SOL_STACK_STRING_OPTIMIZATION_SIZE 1024 +#endif // Optimized conversion routines using a KB or so off the stack + // end of sol/feature_test.hpp namespace sol { @@ -210,13 +247,12 @@ namespace sol { using function = protected_function; using main_function = main_protected_function; using stack_function = stack_protected_function; - using stack_aligned_function = stack_aligned_safe_function; #else using function = unsafe_function; using main_function = main_unsafe_function; using stack_function = stack_unsafe_function; - using stack_aligned_function = stack_aligned_unsafe_function; #endif + using stack_aligned_function = stack_aligned_unsafe_function; using stack_aligned_stack_handler_function = basic_protected_function; struct unsafe_function_result; @@ -393,10 +429,10 @@ namespace sol { }; template - using tuple_element = std::tuple_element>; + using tuple_element = std::tuple_element>; template - using tuple_element_t = std::tuple_element_t>; + using tuple_element_t = std::tuple_element_t>; template using unqualified_tuple_element = unqualified>; @@ -760,34 +796,36 @@ namespace meta { #ifdef SOL_NOEXCEPT_FUNCTION_TYPE template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(__stdcall* function_pointer_type)(Args...) noexcept; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(__stdcall* function_pointer_type)(Args...) noexcept; }; - template - struct fx_traits : basic_traits { + /* __stdcall cannot be applied to functions with varargs*/ + /*template + struct fx_traits<__stdcall R(Args..., ...) noexcept, false> : basic_traits { typedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept; - }; + };*/ template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args...) noexcept; }; - template + /* __stdcall does not work with varargs */ + /*template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) noexcept; - }; + };*/ /* Const Volatile */ template @@ -795,80 +833,88 @@ namespace meta { typedef R (__stdcall T::*function_pointer_type)(Args...) const noexcept; }; - template + /* __stdcall does not work with varargs */ + /*template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const noexcept; - }; + };*/ template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile noexcept; }; - template + /* __stdcall does not work with varargs */ + /*template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile noexcept; - }; + };*/ template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args...) & noexcept; }; - template + /* __stdcall does not work with varargs */ + /*template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) & noexcept; - }; + };*/ template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args...) const& noexcept; }; - template + /* __stdcall does not work with varargs */ + /*template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const& noexcept; - }; + };*/ template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile& noexcept; }; - template + /* __stdcall does not work with varargs */ + /*template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile& noexcept; - }; + };*/ template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args...) && noexcept; }; - template + /* __stdcall does not work with varargs */ + /*template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) && noexcept; - }; + };*/ template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args...) const&& noexcept; }; - template + /* __stdcall does not work with varargs */ + /*template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const&& noexcept; - }; + };*/ template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&& noexcept; }; - template + /* __stdcall does not work with varargs */ + /*template struct fx_traits : basic_traits { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile&& noexcept; - }; + };*/ #endif // noexcept is part of a function's type #endif // __stdcall x86 VC++ bug @@ -918,15 +964,163 @@ namespace meta { // end of sol/bind_traits.hpp +// beginning of sol/string_view.hpp + +#ifdef SOL_CXX17_FEATURES +#include +#endif // C++17 features +#include +#ifdef SOL_USE_BOOST +#include +#endif + +namespace sol { +#ifdef SOL_CXX17_FEATURES + template > + using basic_string_view = std::basic_string_view; + typedef std::string_view string_view; + typedef std::wstring_view wstring_view; + typedef std::u16string_view u16string_view; + typedef std::u32string_view u32string_view; + typedef std::hash string_view_hash; +#else + template > + struct basic_string_view { + std::size_t s; + const Char* p; + + basic_string_view(const std::string& r) + : basic_string_view(r.data(), r.size()) { + } + basic_string_view(const Char* ptr) + : basic_string_view(ptr, Traits::length(ptr)) { + } + basic_string_view(const Char* ptr, std::size_t sz) + : s(sz), p(ptr) { + } + + static int compare(const Char* lhs_p, std::size_t lhs_sz, const Char* rhs_p, std::size_t rhs_sz) { + int result = Traits::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz); + if (result != 0) + return result; + if (lhs_sz < rhs_sz) + return -1; + if (lhs_sz > rhs_sz) + return 1; + return 0; + } + + const Char* begin() const { + return p; + } + + const Char* end() const { + return p + s; + } + + const Char* cbegin() const { + return p; + } + + const Char* cend() const { + return p + s; + } + + const Char* data() const { + return p; + } + + std::size_t size() const { + return s; + } + + std::size_t length() const { + return size(); + } + + operator std::basic_string() const { + return std::basic_string(data(), size()); + } + + bool operator==(const basic_string_view& r) const { + return compare(p, s, r.data(), r.size()) == 0; + } + + bool operator==(const Char* r) const { + return compare(r, Traits::length(r), p, s) == 0; + } + + bool operator==(const std::basic_string& r) const { + return compare(r.data(), r.size(), p, s) == 0; + } + + bool operator!=(const basic_string_view& r) const { + return !(*this == r); + } + + bool operator!=(const char* r) const { + return !(*this == r); + } + + bool operator!=(const std::basic_string& r) const { + return !(*this == r); + } + }; + + template > + struct basic_string_view_hash { + typedef basic_string_view argument_type; + typedef std::size_t result_type; + + template + result_type operator()(const std::basic_string& r) const { + return (*this)(argument_type(r.c_str(), r.size())); + } + + result_type operator()(const argument_type& r) const { +#ifdef SOL_USE_BOOST + return boost::hash_range(r.begin(), r.end()); +#else + // Modified, from libstdc++ + // An implementation attempt at Fowler No Voll, 1a. + // Supposedly, used in MSVC, + // GCC (libstdc++) uses MurmurHash of some sort for 64-bit though...? + // But, well. Can't win them all, right? + // This should normally only apply when NOT using boost, + // so this should almost never be tapped into... + std::size_t hash = 0; + const unsigned char* cptr = reinterpret_cast(r.data()); + for (std::size_t sz = r.size(); sz != 0; --sz) { + hash ^= static_cast(*cptr++); + hash *= static_cast(1099511628211ULL); + } + return hash; +#endif + } + }; +} // namespace sol + +namespace std { + template + struct hash< ::sol::basic_string_view > : ::sol::basic_string_view_hash {}; +} // namespace std + +namespace sol { + using string_view = basic_string_view; + using wstring_view = basic_string_view; + using u16string_view = basic_string_view; + using u32string_view = basic_string_view; + using string_view_hash = std::hash; +#endif // C++17 Support +} // namespace sol + +// end of sol/string_view.hpp + #include #include #include -#include #include #include -#ifdef SOL_CXX17_FEATURES -#include -#endif namespace sol { template @@ -1138,9 +1332,9 @@ namespace sol { struct always_true : std::true_type {}; struct is_invokable_tester { template - always_true()(std::declval()...))> static test(int); + static always_true()(std::declval()...))> test(int); template - std::false_type static test(...); + static std::false_type test(...); }; } // namespace meta_detail @@ -1369,6 +1563,11 @@ namespace sol { std::true_type supports_adl_to_string(const T&); std::false_type supports_adl_to_string(...); #endif + + template + struct is_matched_lookup_impl : std::false_type {}; + template + struct is_matched_lookup_impl : std::is_same {}; } // namespace meta_detail #if defined(_MSC_VER) && _MSC_VER <= 1910 @@ -1436,12 +1635,23 @@ namespace sol { template struct is_lookup : meta::all, has_value_type> {}; + template + struct is_matched_lookup : meta_detail::is_matched_lookup_impl::value> {}; + + template + using is_string_like = any< + is_specialization_of>, + is_specialization_of>, + meta::all>, meta::any_same>>, char, char16_t, char32_t, wchar_t>> + >; + template using is_string_constructible = any< - std::is_same, const char*>, std::is_same, char>, std::is_same, std::string>, std::is_same, std::initializer_list> + meta::all>, std::is_same>>, char>>, + std::is_same, const char*>, + std::is_same, char>, std::is_same, std::string>, std::is_same, std::initializer_list> #ifdef SOL_CXX17_FEATURES - , - std::is_same, std::string_view> + , std::is_same, std::string_view> #endif >; @@ -1539,6 +1749,16 @@ namespace sol { return *std::forward(item); } + template >, meta::neg>>> = meta::enabler> + auto deref_non_pointer(T&& item) -> decltype(std::forward(item)) { + return std::forward(item); + } + + template >, meta::neg>>> = meta::enabler> + inline auto deref_non_pointer(T&& item) -> decltype(*std::forward(item)) { + return *std::forward(item); + } + template inline T* ptr(T& val) { return std::addressof(val); @@ -1572,14 +1792,14 @@ namespace sol { // beginning of sol/compatibility/version.hpp -#ifdef SOL_USING_CXX_LUA +#if defined(SOL_USING_CXX_LUA) #include #include #include #ifdef SOL_USING_CXX_LUAJIT #include #endif // C++ LuaJIT ... whatever that means -#ifndef SOL_EXCEPTIONS_SAFE_PROPAGATION +#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_EXCEPTIONS_ALWAYS_UNSAFE) #define SOL_EXCEPTIONS_SAFE_PROPAGATION #endif // Exceptions can be propagated safely using C++-compiled Lua #else @@ -3048,38 +3268,38 @@ namespace sol { // workaround for missing traits in GCC and CLANG template struct is_nothrow_move_constructible { - constexpr static bool value = ::std::is_nothrow_constructible::value; + static constexprbool value = ::std::is_nothrow_constructible::value; }; template struct is_assignable { template - constexpr static bool has_assign(...) { + static constexprbool has_assign(...) { return false; } template () = ::std::declval(), true))> // the comma operator is necessary for the cases where operator= returns void - constexpr static bool has_assign(bool) { + static constexprbool has_assign(bool) { return true; } - constexpr static bool value = has_assign(true); + static constexprbool value = has_assign(true); }; template struct is_nothrow_move_assignable { template struct has_nothrow_move_assign { - constexpr static bool value = false; + static constexprbool value = false; }; template struct has_nothrow_move_assign { - constexpr static bool value = noexcept(::std::declval() = ::std::declval()); + static constexprbool value = noexcept(::std::declval() = ::std::declval()); }; - constexpr static bool value = has_nothrow_move_assign::value>::value; + static constexprbool value = has_nothrow_move_assign::value>::value; }; // end workaround @@ -3122,16 +3342,16 @@ namespace sol { template struct has_overloaded_addressof { template - constexpr static bool has_overload(...) { + static constexpr bool has_overload(...) { return false; } template ().operator&())> - constexpr static bool has_overload(bool) { + static constexpr bool has_overload(bool) { return true; } - constexpr static bool value = has_overload(true); + static constexpr bool value = has_overload(true); }; template )> @@ -3506,7 +3726,7 @@ namespace sol { #ifdef SOL_NO_EXCEPTIONS // we can't abort here // because there's no constexpr abort - : *(T*)nullptr; + : *static_cast(nullptr); #else : (throw bad_optional_access("bad optional access"), contained_val()); #endif @@ -3515,7 +3735,7 @@ namespace sol { OPTIONAL_MUTABLE_CONSTEXPR T& value() & { return initialized() ? contained_val() #ifdef SOL_NO_EXCEPTIONS - : *(T*)nullptr; + : *static_cast(nullptr); #else : (throw bad_optional_access("bad optional access"), contained_val()); #endif @@ -3526,7 +3746,7 @@ namespace sol { #ifdef SOL_NO_EXCEPTIONS // we can't abort here // because there's no constexpr abort - : std::move(*(T*)nullptr); + : std::move(*static_cast(nullptr)); #else : (throw bad_optional_access("bad optional access"), contained_val()); #endif @@ -3553,7 +3773,7 @@ namespace sol { #ifdef SOL_NO_EXCEPTIONS // we can't abort here // because there's no constexpr abort - : *(T*)nullptr; + : *static_cast(nullptr); #else : (throw bad_optional_access("bad optional access"), contained_val()); #endif @@ -3564,7 +3784,7 @@ namespace sol { #ifdef SOL_NO_EXCEPTIONS // we can abort here // but the others are constexpr, so we can't... - : (std::abort(), *(T*)nullptr); + : (std::abort(), *static_cast(nullptr)); #else : (throw bad_optional_access("bad optional access"), contained_val()); #endif @@ -4061,6 +4281,15 @@ namespace sol { // beginning of sol/forward_detail.hpp namespace sol { + namespace detail { + const bool default_safe_function_calls = +#ifdef SOL_SAFE_FUNCTION_CALLS + true; +#else + false; +#endif + } // namespace detail + namespace meta { namespace meta_detail { } @@ -4086,106 +4315,6 @@ namespace sol { // end of sol/forward_detail.hpp -// beginning of sol/string_view.hpp - -#ifdef SOL_CXX17_FEATURES -#endif // C++17 features - -namespace sol { -#ifdef SOL_CXX17_FEATURES - typedef std::string_view string_view; - typedef std::wstring_view wstring_view; - typedef std::u16string_view u16string_view; - typedef std::u32string_view u32string_view; -#else - template > - struct basic_string_view { - std::size_t s; - const Char* p; - - basic_string_view(const std::string& r) - : basic_string_view(r.data(), r.size()) { - } - basic_string_view(const Char* ptr) - : basic_string_view(ptr, Traits::length(ptr)) { - } - basic_string_view(const Char* ptr, std::size_t sz) - : s(sz), p(ptr) { - } - - static int compare(const Char* lhs_p, std::size_t lhs_sz, const Char* rhs_p, std::size_t rhs_sz) { - int result = Traits::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz); - if (result != 0) - return result; - if (lhs_sz < rhs_sz) - return -1; - if (lhs_sz > rhs_sz) - return 1; - return 0; - } - - const Char* begin() const { - return p; - } - - const Char* end() const { - return p + s; - } - - const Char* cbegin() const { - return p; - } - - const Char* cend() const { - return p + s; - } - - const Char* data() const { - return p; - } - - std::size_t size() const { - return s; - } - - std::size_t length() const { - return size(); - } - - bool operator==(const basic_string_view& r) const { - return compare(p, s, r.data(), r.size()) == 0; - } - - bool operator==(const Char* r) const { - return compare(r, std::char_traits::length(r), p, s) == 0; - } - - bool operator==(const std::basic_string& r) const { - return compare(r.data(), r.size(), p, s) == 0; - } - - bool operator!=(const basic_string_view& r) const { - return !(*this == r); - } - - bool operator!=(const char* r) const { - return !(*this == r); - } - - bool operator!=(const std::basic_string& r) const { - return !(*this == r); - } - }; - - using string_view = basic_string_view; - using wstring_view = basic_string_view; - using u16string_view = basic_string_view; - using u32string_view = basic_string_view; -#endif // C++17 Support -} // namespace sol - -// end of sol/string_view.hpp - // beginning of sol/raii.hpp namespace sol { @@ -4193,8 +4322,9 @@ namespace sol { struct default_construct { template static void construct(T&& obj, Args&&... args) { - std::allocator> alloc{}; - alloc.construct(obj, std::forward(args)...); + typedef meta::unqualified_t Tu; + std::allocator alloc{}; + std::allocator_traits>::construct(alloc, obj, std::forward(args)...); } template @@ -4223,6 +4353,12 @@ namespace sol { } }; + struct state_deleter { + void operator()(lua_State* L) const { + lua_close(L); + } + }; + template inline std::unique_ptr make_unique_deleter(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); @@ -4377,6 +4513,8 @@ namespace sol { namespace detail { #ifdef SOL_NOEXCEPT_FUNCTION_TYPE typedef int (*lua_CFunction_noexcept)(lua_State* L) noexcept; +#else + typedef int(*lua_CFunction_noexcept)(lua_State* L); #endif // noexcept function type for lua_CFunction #ifdef SOL_NO_EXCEPTIONS @@ -4390,6 +4528,11 @@ namespace sol { int static_trampoline_noexcept(lua_State* L) noexcept { return f(L); } +#else + template + int static_trampoline_noexcept(lua_State* L) noexcept { + return f(L); + } #endif template @@ -4524,6 +4667,9 @@ namespace sol { struct unchecked_t {}; const unchecked_t unchecked = unchecked_t{}; + + struct yield_tag_t {}; + const yield_tag_t yield_tag = yield_tag_t{}; } // namespace detail struct lua_nil_t {}; @@ -4548,6 +4694,30 @@ namespace sol { struct no_metatable_t {}; const no_metatable_t no_metatable = {}; + template + struct yielding_t { + T func; + + yielding_t() = default; + yielding_t(const yielding_t&) = default; + yielding_t(yielding_t&&) = default; + yielding_t& operator=(const yielding_t&) = default; + yielding_t& operator=(yielding_t&&) = default; + template , yielding_t>>, meta::neg>>> = meta::enabler> + yielding_t(Arg&& arg) + : func(std::forward(arg)) { + } + template + yielding_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) + : func(std::forward(arg0), std::forward(arg1), std::forward(args)...) { + } + }; + + template + inline yielding_t> yielding(F&& f) { + return yielding_t>(std::forward(f)); + } + typedef std::remove_pointer_t lua_CFunction_ref; template @@ -4832,15 +5002,25 @@ namespace sol { }; template - as_table_t as_table(T&& container) { + as_table_t as_table_ref(T&& container) { return as_table_t(std::forward(container)); } template - nested as_nested(T&& container) { + as_table_t> as_table(T&& container) { + return as_table_t>(std::forward(container)); + } + + template + nested as_nested_ref(T&& container) { return nested(std::forward(container)); } + template + nested> as_nested(T&& container) { + return nested>(std::forward(container)); + } + struct this_state { lua_State* L; @@ -4954,7 +5134,7 @@ namespace sol { }; inline const std::string& to_string(call_status c) { - static const std::array names{ { + static const std::array names{ { "ok", "yielded", "runtime", @@ -4963,6 +5143,8 @@ namespace sol { "gc", "syntax", "file", + "CRITICAL_EXCEPTION_FAILURE", + "CRITICAL_INDETERMINATE_STATE_FAILURE" } }; switch (c) { case call_status::ok: @@ -4982,16 +5164,37 @@ namespace sol { case call_status::file: return names[7]; } - return names[0]; + if (static_cast(c) == -1) { + // One of the many cases where a critical exception error has occurred + return names[8]; + } + return names[9]; + } + + inline bool is_indeterminate_call_failure(call_status c) { + switch (c) { + case call_status::ok: + case call_status::yielded: + case call_status::runtime: + case call_status::memory: + case call_status::handler: + case call_status::gc: + case call_status::syntax: + case call_status::file: + return false; + } + return true; } inline const std::string& to_string(load_status c) { - static const std::array names{ { + static const std::array names{ { "ok", "memory", "gc", "syntax", "file", + "CRITICAL_EXCEPTION_FAILURE", + "CRITICAL_INDETERMINATE_STATE_FAILURE" } }; switch (c) { case load_status::ok: @@ -5005,7 +5208,11 @@ namespace sol { case load_status::file: return names[4]; } - return names[0]; + if (static_cast(c) == -1) { + // One of the many cases where a critical exception error has occurred + return names[5]; + } + return names[6]; } inline const std::string& to_string(load_mode c) { @@ -5119,35 +5326,17 @@ namespace sol { template struct is_container> : std::false_type {}; - template <> - struct is_container : std::false_type {}; + template + struct is_container> : std::false_type {}; - template <> - struct is_container : std::false_type {}; - - template <> - struct is_container : std::false_type {}; - - template <> - struct is_container : std::false_type {}; - -#ifdef SOL_CXX17_FEATURES - template <> - struct is_container : std::false_type {}; - - template <> - struct is_container : std::false_type {}; - - template <> - struct is_container : std::false_type {}; - - template <> - struct is_container : std::false_type {}; -#endif // C++ 17 + template + struct is_container> : std::false_type {}; template - struct is_container>::value && !is_initializer_list>::value>> : std::true_type {}; + struct is_container>::value + && !is_initializer_list>::value + && !meta::is_string_like>::value + >> : std::true_type {}; template struct is_container>::value && !meta::any_same>, char, wchar_t, char16_t, char32_t>::value>> : std::true_type {}; @@ -5163,17 +5352,11 @@ namespace sol { template struct lua_type_of : std::integral_constant {}; - template <> - struct lua_type_of : std::integral_constant {}; + template + struct lua_type_of> : std::integral_constant {}; - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; + template + struct lua_type_of> : std::integral_constant {}; template struct lua_type_of : std::integral_constant {}; @@ -5337,18 +5520,6 @@ namespace sol { template <> struct lua_type_of : std::integral_constant {}; - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - #ifdef SOL_CXX17_FEATURES template struct lua_type_of> : std::integral_constant {}; @@ -5527,6 +5698,9 @@ namespace sol { template struct is_environment : std::integral_constant::value || is_table::value> {}; + template + struct is_automagical : std::true_type {}; + template inline type type_of() { return lua_type_of>::value; @@ -5596,7 +5770,7 @@ namespace detail { inline std::string ctti_get_type_name() { // cardinal sins from MINGW using namespace std; - const static std::array removals = {{"{anonymous}", "(anonymous namespace)"}}; + static const std::array removals = {{"{anonymous}", "(anonymous namespace)"}}; std::string name = __PRETTY_FUNCTION__; std::size_t start = name.find_first_of('['); start = name.find_first_of('=', start); @@ -5630,7 +5804,7 @@ namespace detail { #elif defined(_MSC_VER) template inline std::string ctti_get_type_name() { - const static std::array removals = {{"public:", "private:", "protected:", "struct ", "class ", "`anonymous-namespace'", "`anonymous namespace'"}}; + static const std::array removals = {{"public:", "private:", "protected:", "struct ", "class ", "`anonymous-namespace'", "`anonymous namespace'"}}; std::string name = __FUNCSIG__; std::size_t start = name.find("get_type_name"); if (start == std::string::npos) @@ -5992,6 +6166,9 @@ namespace sol { if (count < 1) return; int top = lua_gettop(L); + if (top < 1) { + return; + } if (rawindex == -count || top == rawindex) { // Slice them right off the top lua_pop(L, static_cast(count)); @@ -6148,6 +6325,7 @@ namespace sol { return; } if (r.ref == LUA_NOREF) { + luastate = r.luastate; ref = LUA_NOREF; return; } @@ -6171,6 +6349,7 @@ namespace sol { return; } if (r.ref == LUA_NOREF) { + luastate = r.luastate; ref = LUA_NOREF; return; } @@ -6329,6 +6508,15 @@ namespace sol { return *this; } + basic_reference& operator=(const lua_nil_t&) noexcept { + if (valid()) { + deref(); + } + luastate = nullptr; + ref = LUA_NOREF; + return *this; + } + template basic_reference& operator=(proxy_base&& r); @@ -6889,7 +7077,7 @@ namespace sol { T** pdata = static_cast(memory); T* data = *pdata; std::allocator alloc{}; - alloc.destroy(data); + std::allocator_traits>::destroy(alloc, data); return 0; } @@ -6909,7 +7097,7 @@ namespace sol { memory = align_user(memory); T* data = static_cast(memory); std::allocator alloc; - alloc.destroy(data); + std::allocator_traits>::destroy(alloc, data); return 0; } @@ -6918,7 +7106,7 @@ namespace sol { memory = align_usertype_unique(memory); Real* target = static_cast(memory); std::allocator alloc; - alloc.destroy(target); + std::allocator_traits>::destroy(alloc, target); } template @@ -7022,13 +7210,6 @@ namespace sol { template using strip_extensible_t = typename strip_extensible::type; - const bool default_check_arguments = -#ifdef SOL_CHECK_ARGUMENTS - true; -#else - false; -#endif - template static int get_size_hint(const C& c) { return static_cast(c.size()); @@ -7057,6 +7238,20 @@ namespace sol { use_reference_tag; return pusher>>{}.push(L, std::forward(arg), std::forward(args)...); } + + template + bool check_usertype(std::false_type, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { + typedef meta::unqualified_t Tu; + typedef detail::as_value_tag detail_t; + return checker{}.check(types>(), L, index, indextype, std::forward(handler), tracking); + } + + template + bool check_usertype(std::true_type, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { + typedef meta::unqualified_t>> Tu; + typedef detail::as_pointer_tag detail_t; + return checker{}.check(L, index, indextype, std::forward(handler), tracking); + } } // namespace stack_detail inline bool maybe_indexable(lua_State* L, int index = -1) { @@ -7156,6 +7351,24 @@ namespace sol { return check(L, index, handler); } + template + bool check_usertype(lua_State* L, int index, Handler&& handler, record& tracking) { + type indextype = type_of(L, index); + return stack_detail::check_usertype(std::is_pointer(), L, index, indextype, std::forward(handler), tracking); + } + + template + bool check_usertype(lua_State* L, int index, Handler&& handler) { + record tracking{}; + return check_usertype(L, index, std::forward(handler), tracking); + } + + template + bool check_usertype(lua_State* L, int index = -lua_size>::value) { + auto handler = no_panic; + return check_usertype(L, index, handler); + } + template inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) { typedef meta::unqualified_t Tu; @@ -7178,12 +7391,17 @@ namespace sol { namespace stack_detail { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_GETTER template inline auto tagged_get(types, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get(L, index, tracking)) { auto op = check_get(L, index, type_panic_c_str, tracking); return *std::move(op); } + + template + inline decltype(auto) tagged_get(types>, lua_State* L, int index, record& tracking) { + return stack_detail::unchecked_get>(L, index, tracking); + } #else template inline decltype(auto) tagged_get(types, lua_State* L, int index, record& tracking) { @@ -7191,11 +7409,6 @@ namespace sol { } #endif - template - inline decltype(auto) tagged_get(types>, lua_State* L, int index, record& tracking) { - return stack_detail::unchecked_get>(L, index, tracking); - } - template struct check_types { template @@ -7253,6 +7466,21 @@ namespace sol { return multi_check(L, index); } + template + inline decltype(auto) get_usertype(lua_State* L, int index, record& tracking) { +#ifdef SOL_SAFE_GETTER + return stack_detail::tagged_get(types::value, detail::as_pointer_tag>, detail::as_value_tag>>(), L, index, tracking); +#else + return stack_detail::unchecked_get::value, detail::as_pointer_tag>, detail::as_value_tag>>(L, index, tracking); +#endif + } + + template + inline decltype(auto) get_usertype(lua_State* L, int index = -lua_size>::value) { + record tracking{}; + return get_usertype(L, index, tracking); + } + template inline decltype(auto) get(lua_State* L, int index, record& tracking) { return stack_detail::tagged_get(types(), L, index, tracking); @@ -7373,8 +7601,6 @@ namespace sol { // beginning of sol/inheritance.hpp -#include - namespace sol { template struct base_list {}; @@ -7394,19 +7620,6 @@ namespace sol { template bool has_derived::value = false; - inline std::size_t unique_id() { - static std::atomic x(0); - return ++x; - } - - template - struct id_for { - static const std::size_t value; - }; - - template - const std::size_t id_for::value = unique_id(); - inline decltype(auto) base_class_check_key() { static const auto& key = "class_check"; return key; @@ -7429,32 +7642,32 @@ namespace sol { template struct inheritance { - static bool type_check_bases(types<>, std::size_t) { + static bool type_check_bases(types<>, const std::string&) { return false; } template - static bool type_check_bases(types, std::size_t ti) { - return ti == id_for::value || type_check_bases(types(), ti); + static bool type_check_bases(types, const std::string& ti) { + return ti == usertype_traits::qualified_name() || type_check_bases(types(), ti); } - static bool type_check(std::size_t ti) { - return ti == id_for::value || type_check_bases(types(), ti); + static bool type_check(const std::string& ti) { + return ti == usertype_traits::qualified_name() || type_check_bases(types(), ti); } - static void* type_cast_bases(types<>, T*, std::size_t) { + static void* type_cast_bases(types<>, T*, const std::string&) { return nullptr; } template - static void* type_cast_bases(types, T* data, std::size_t ti) { + static void* type_cast_bases(types, T* data, const std::string& ti) { // Make sure to convert to T first, and then dynamic cast to the proper type - return ti != id_for::value ? type_cast_bases(types(), data, ti) : static_cast(static_cast(data)); + return ti != usertype_traits::qualified_name() ? type_cast_bases(types(), data, ti) : static_cast(static_cast(data)); } - static void* type_cast(void* voiddata, std::size_t ti) { + static void* type_cast(void* voiddata, const std::string& ti) { T* data = static_cast(voiddata); - return static_cast(ti != id_for::value ? type_cast_bases(types(), data, ti) : data); + return static_cast(ti != usertype_traits::qualified_name() ? type_cast_bases(types(), data, ti) : data); } }; @@ -7536,17 +7749,21 @@ namespace stack { int isnum = 0; lua_tointegerx(L, index, &isnum); const bool success = isnum != 0; + if (!success) { + // expected type, actual type + handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); + } #else // this check is precise, does not convert if (lua_isinteger(L, index) == 1) { return true; } const bool success = false; -#endif // If numbers are enabled, use the imprecise check if (!success) { // expected type, actual type handler(L, index, type::number, type_of(L, index), "not a numeric type"); } +#endif // If numbers are enabled, use the imprecise check return success; #else #ifndef SOL_STRINGS_ARE_NUMBERS @@ -7845,6 +8062,12 @@ namespace stack { template struct checker, type::userdata, C> { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + const type indextype = type_of(L, index); + return check(types(), L, index, indextype, handler, tracking); + } + template static bool check(types, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { #ifdef SOL_ENABLE_INTEROP @@ -7880,8 +8103,8 @@ namespace stack { lua_rawget(L, metatableindex); if (type_of(L, -1) != type::lua_nil) { void* basecastdata = lua_touserdata(L, -1); - detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; - success = ic(detail::id_for::value); + detail::inheritance_check_function ic = reinterpret_cast(basecastdata); + success = ic(usertype_traits::qualified_name()); } } if (!success) { @@ -7895,11 +8118,28 @@ namespace stack { }; template - struct checker { + struct checker, type::userdata, C> { + template + static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { + if (indextype == type::lua_nil) { + tracking.use(1); + return true; + } + return stack_detail::check_usertype(std::false_type(), L, index, indextype, std::forward(handler), tracking); + } + template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { const type indextype = type_of(L, index); - return checker, type::userdata, C>{}.check(types(), L, index, indextype, std::forward(handler), tracking); + return check(L, index, handler, indextype, tracking); + } + }; + + template + struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + return check_usertype(L, index, std::forward(handler), tracking); } }; @@ -7907,13 +8147,7 @@ namespace stack { struct checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - const type indextype = type_of(L, index); - // Allow lua_nil to be transformed to nullptr - if (indextype == type::lua_nil) { - tracking.use(1); - return true; - } - return checker, type::userdata, C>{}.check(L, index, std::forward(handler), tracking); + return check_usertype(L, index, std::forward(handler), tracking); } }; @@ -8052,9 +8286,313 @@ namespace sol { // end of sol/overload.hpp -#ifdef SOL_CODECVT_SUPPORT -#include -#endif // codecvt header support +// beginning of sol/unicode.hpp + +#pragma once + +#include + +namespace sol { + // Everything here was lifted pretty much straight out of + // ogonek, because fuck figuring it out= + namespace unicode { + enum error_code { + ok = 0, + invalid_code_point, + invalid_code_unit, + invalid_leading_surrogate, + invalid_trailing_surrogate, + sequence_too_short, + overlong_sequence, + }; + + inline const string_view& to_string(error_code ec) { + static const string_view arr[4] = { + "ok", + "invalid code points", + "invalid code unit", + "overlong sequence" + }; + return arr[static_cast(ec)]; + } + + template + struct decoded_result { + error_code error; + char32_t codepoint; + It next; + }; + + template + struct encoded_result { + error_code error; + std::size_t code_units_size; + std::array code_units; + }; + + struct unicode_detail { + // codepoint related + static constexpr char32_t last_code_point = 0x10FFFF; + + static constexpr char32_t first_lead_surrogate = 0xD800; + static constexpr char32_t last_lead_surrogate = 0xDBFF; + + static constexpr char32_t first_trail_surrogate = 0xDC00; + static constexpr char32_t last_trail_surrogate = 0xDFFF; + + static constexpr char32_t first_surrogate = first_lead_surrogate; + static constexpr char32_t last_surrogate = last_trail_surrogate; + + static constexpr bool is_lead_surrogate(char32_t u) { + return u >= first_lead_surrogate && u <= last_lead_surrogate; + } + static constexpr bool is_trail_surrogate(char32_t u) { + return u >= first_trail_surrogate && u <= last_trail_surrogate; + } + static constexpr bool is_surrogate(char32_t u) { + return u >= first_surrogate && u <= last_surrogate; + } + + // utf8 related + static constexpr auto last_1byte_value = 0x7Fu; + static constexpr auto last_2byte_value = 0x7FFu; + static constexpr auto last_3byte_value = 0xFFFFu; + + static constexpr auto start_2byte_mask = 0x80u; + static constexpr auto start_3byte_mask = 0xE0u; + static constexpr auto start_4byte_mask = 0xF0u; + + static constexpr auto continuation_mask = 0xC0u; + static constexpr auto continuation_signature = 0x80u; + + static constexpr int sequence_length(unsigned char b) { + return (b & start_2byte_mask) == 0 ? 1 + : (b & start_3byte_mask) != start_3byte_mask ? 2 + : (b & start_4byte_mask) != start_4byte_mask ? 3 + : 4; + } + + static constexpr char32_t decode(unsigned char b0, unsigned char b1) { + return ((b0 & 0x1F) << 6) | (b1 & 0x3F); + } + static constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2) { + return ((b0 & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F); + } + static constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2, unsigned char b3) { + return ((b0 & 0x07) << 18) | ((b1 & 0x3F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F); + } + + // utf16 related + static constexpr char32_t last_bmp_value = 0xFFFF; + static constexpr char32_t normalizing_value = 0x10000; + static constexpr int lead_surrogate_bitmask = 0xFFC00; + static constexpr int trail_surrogate_bitmask = 0x3FF; + static constexpr int lead_shifted_bits = 10; + + static char32_t combine_surrogates(char16_t lead, char16_t trail) { + auto hi = lead - first_lead_surrogate; + auto lo = trail - first_trail_surrogate; + return normalizing_value + ((hi << lead_shifted_bits) | lo); + } + }; + + inline encoded_result code_point_to_utf8(char32_t codepoint) { + encoded_result er; + er.error = error_code::ok; + if (codepoint <= unicode_detail::last_1byte_value) { + er.code_units_size = 1; + er.code_units = std::array{ { static_cast(codepoint) } }; + } + else if (codepoint <= unicode_detail::last_2byte_value) { + er.code_units_size = 2; + er.code_units = std::array{{ + static_cast(0xC0 | ((codepoint & 0x7C0) >> 6)), + static_cast(0x80 | (codepoint & 0x3F)), + }}; + } + else if (codepoint <= unicode_detail::last_3byte_value) { + er.code_units_size = 3; + er.code_units = std::array{{ + static_cast(0xE0 | ((codepoint & 0xF000) >> 12)), + static_cast(0x80 | ((codepoint & 0xFC0) >> 6)), + static_cast(0x80 | (codepoint & 0x3F)), + }}; + } + else { + er.code_units_size = 4; + er.code_units = std::array{ { + static_cast(0xF0 | ((codepoint & 0x1C0000) >> 18)), + static_cast(0x80 | ((codepoint & 0x3F000) >> 12)), + static_cast(0x80 | ((codepoint & 0xFC0) >> 6)), + static_cast(0x80 | (codepoint & 0x3F)), + } }; + } + return er; + } + + inline encoded_result code_point_to_utf16(char32_t codepoint) { + encoded_result er; + + if (codepoint <= unicode_detail::last_bmp_value) { + er.code_units_size = 1; + er.code_units = std::array{ { static_cast(codepoint) } }; + er.error = error_code::ok; + } + else { + auto normal = codepoint - unicode_detail::normalizing_value; + auto lead = unicode_detail::first_lead_surrogate + ((normal & unicode_detail::lead_surrogate_bitmask) >> unicode_detail::lead_shifted_bits); + auto trail = unicode_detail::first_trail_surrogate + (normal & unicode_detail::trail_surrogate_bitmask); + er.code_units = std::array{ { + static_cast(lead), + static_cast(trail) + } }; + er.code_units_size = 2; + er.error = error_code::ok; + } + return er; + } + + inline encoded_result code_point_to_utf32(char32_t codepoint) { + encoded_result er; + er.code_units_size = 1; + er.code_units[0] = codepoint; + er.error = error_code::ok; + return er; + } + + template + inline decoded_result utf8_to_code_point(It it, It last) { + decoded_result dr; + if (it == last) { + dr.next = it; + dr.error = error_code::sequence_too_short; + return dr; + } + + unsigned char b0 = *it; + std::size_t length = unicode_detail::sequence_length(b0); + + if (length == 1) { + dr.codepoint = static_cast(b0); + dr.error = error_code::ok; + ++it; + dr.next = it; + return dr; + } + + auto is_invalid = [](unsigned char b) { return b == 0xC0 || b == 0xC1 || b > 0xF4; }; + auto is_continuation = [](unsigned char b) { + return (b & unicode_detail::continuation_mask) == unicode_detail::continuation_signature; + }; + + if (is_invalid(b0) || is_continuation(b0)) { + dr.error = error_code::invalid_code_unit; + dr.next = it; + return dr; + } + + ++it; + std::array b; + b[0] = b0; + for (std::size_t i = 1; i < length; ++i) { + b[i] = *it; + if (!is_continuation(b[i])) { + dr.error = error_code::invalid_code_unit; + dr.next = it; + return dr; + } + ++it; + } + + char32_t decoded; + switch (length) { + case 2: + decoded = unicode_detail::decode(b[0], b[1]); + break; + case 3: + decoded = unicode_detail::decode(b[0], b[1], b[2]); + break; + default: + decoded = unicode_detail::decode(b[0], b[1], b[2], b[3]); + break; + } + + auto is_overlong = [](char32_t u, std::size_t bytes) { + return u <= unicode_detail::last_1byte_value + || (u <= unicode_detail::last_2byte_value && bytes > 2) + || (u <= unicode_detail::last_3byte_value && bytes > 3); + }; + if (is_overlong(decoded, length)) { + dr.error = error_code::overlong_sequence; + return dr; + } + if (unicode_detail::is_surrogate(decoded) || decoded > unicode_detail::last_code_point) { + dr.error = error_code::invalid_code_point; + return dr; + } + + // then everything is fine + dr.codepoint = decoded; + dr.error = error_code::ok; + dr.next = it; + return dr; + } + + template + inline decoded_result utf16_to_code_point(It it, It last) { + decoded_result dr; + if (it == last) { + dr.next = it; + dr.error = error_code::sequence_too_short; + return dr; + } + + char16_t lead = static_cast(*it); + + if (!unicode_detail::is_surrogate(lead)) { + ++it; + dr.codepoint = static_cast(lead); + dr.next = it; + dr.error = error_code::ok; + return dr; + } + if (!unicode_detail::is_lead_surrogate(lead)) { + dr.error = error_code::invalid_leading_surrogate; + dr.next = it; + return dr; + } + + ++it; + auto trail = *it; + if (!unicode_detail::is_trail_surrogate(trail)) { + dr.error = error_code::invalid_trailing_surrogate; + dr.next = it; + return dr; + } + + dr.codepoint = unicode_detail::combine_surrogates(lead, trail); + dr.next = ++it; + dr.error = error_code::ok; + return dr; + } + + template + inline decoded_result utf32_to_code_point(It it, It last) { + decoded_result dr; + if (it == last) { + dr.next = it; + dr.error = error_code::sequence_too_short; + return dr; + } + dr.codepoint = static_cast(*it); + dr.next = ++it; + dr.error = error_code::ok; + return dr; + } + } +} +// end of sol/unicode.hpp + #ifdef SOL_CXX17_FEATURES #endif // C++17 @@ -8459,111 +8997,137 @@ namespace stack { } }; - template <> - struct getter { + template + struct getter> { static string_view get(lua_State* L, int index, record& tracking) { tracking.use(1); size_t sz; const char* str = lua_tolstring(L, index, &sz); - return string_view(str, sz); + return basic_string_view(str, sz); } }; -#ifdef SOL_CODECVT_SUPPORT - template <> - struct getter { - static std::wstring get(lua_State* L, int index, record& tracking) { + template + struct getter> { + typedef std::basic_string S; + static S get(lua_State* L, int index, record& tracking) { + typedef std::conditional_t Ch; + typedef typename std::allocator_traits::template rebind_alloc ChAl; + typedef std::char_traits ChTraits; + getter> g; + (void)g; + return g.template get_into(L, index, tracking); + } + }; + + template + struct getter> { + template + static S get_into(lua_State* L, int index, record& tracking) { + typedef typename S::value_type Ch; tracking.use(1); size_t len; - auto str = lua_tolstring(L, index, &len); + auto utf8p = lua_tolstring(L, index, &len); if (len < 1) - return std::wstring(); - if (sizeof(wchar_t) == 2) { - thread_local std::wstring_convert> convert; - std::wstring r = convert.from_bytes(str, str + len); -#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 7 - // Fuck you, MinGW, and fuck you libstdc++ for introducing this absolutely asinine bug - // https://sourceforge.net/p/mingw-w64/bugs/538/ - // http://chat.stackoverflow.com/transcript/message/32271369#32271369 - for (auto& c : r) { - uint8_t* b = reinterpret_cast(&c); - std::swap(b[0], b[1]); - } -#endif - return r; + return S(); + std::size_t needed_size = 0; + const char* strb = utf8p; + const char* stre = utf8p + len; + for (const char* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf8_to_code_point(strtarget, stre); + auto er = unicode::code_point_to_utf16(dr.codepoint); + needed_size += er.code_units_size; + strtarget = dr.next; + } + S r(needed_size, static_cast(0)); + r.resize(needed_size); + Ch* target = &r[0]; + for (const char* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf8_to_code_point(strtarget, stre); + auto er = unicode::code_point_to_utf16(dr.codepoint); + std::memcpy(target, er.code_units.data(), er.code_units_size * sizeof(Ch)); + strtarget = dr.next; + target += er.code_units_size; } - thread_local std::wstring_convert> convert; - std::wstring r = convert.from_bytes(str, str + len); return r; } + + static std::basic_string get(lua_State* L, int index, record& tracking) { + return get_into>(L, index, tracking); + } }; - template <> - struct getter { - static std::u16string get(lua_State* L, int index, record& tracking) { + template + struct getter> { + template + static S get_into(lua_State* L, int index, record& tracking) { + typedef typename S::value_type Ch; tracking.use(1); size_t len; - auto str = lua_tolstring(L, index, &len); + auto utf8p = lua_tolstring(L, index, &len); if (len < 1) - return std::u16string(); -#ifdef _MSC_VER - thread_local std::wstring_convert, int16_t> convert; - auto intd = convert.from_bytes(str, str + len); - std::u16string r(intd.size(), '\0'); - std::memcpy(&r[0], intd.data(), intd.size() * sizeof(char16_t)); -#else - thread_local std::wstring_convert, char16_t> convert; - std::u16string r = convert.from_bytes(str, str + len); -#endif // VC++ is a shit + return S(); + std::size_t needed_size = 0; + const char* strb = utf8p; + const char* stre = utf8p + len; + for (const char* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf8_to_code_point(strtarget, stre); + auto er = unicode::code_point_to_utf32(dr.codepoint); + needed_size += er.code_units_size; + strtarget = dr.next; + } + S r(needed_size, static_cast(0)); + r.resize(needed_size); + Ch* target = &r[0]; + for (const char* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf8_to_code_point(strtarget, stre); + auto er = unicode::code_point_to_utf32(dr.codepoint); + std::memcpy(target, er.code_units.data(), er.code_units_size * sizeof(Ch)); + strtarget = dr.next; + target += er.code_units_size; + } return r; } - }; - template <> - struct getter { - static std::u32string get(lua_State* L, int index, record& tracking) { - tracking.use(1); - size_t len; - auto str = lua_tolstring(L, index, &len); - if (len < 1) - return std::u32string(); -#ifdef _MSC_VER - thread_local std::wstring_convert, int32_t> convert; - auto intd = convert.from_bytes(str, str + len); - std::u32string r(intd.size(), '\0'); - std::memcpy(&r[0], intd.data(), r.size() * sizeof(char32_t)); -#else - thread_local std::wstring_convert, char32_t> convert; - std::u32string r = convert.from_bytes(str, str + len); -#endif // VC++ is a shit - return r; - } - }; - - template <> - struct getter { - static wchar_t get(lua_State* L, int index, record& tracking) { - auto str = getter{}.get(L, index, tracking); - return str.size() > 0 ? str[0] : wchar_t(0); + static std::basic_string get(lua_State* L, int index, record& tracking) { + return get_into>(L, index, tracking); } }; template <> struct getter { static char16_t get(lua_State* L, int index, record& tracking) { - auto str = getter{}.get(L, index, tracking); - return str.size() > 0 ? str[0] : char16_t(0); + string_view utf8 = stack::get(L, index, tracking); + const char* strb = utf8.data(); + const char* stre = utf8.data() + utf8.size(); + auto dr = unicode::utf8_to_code_point(strb, stre); + auto er = unicode::code_point_to_utf16(dr.codepoint); + return er.code_units[0]; } }; template <> struct getter { static char32_t get(lua_State* L, int index, record& tracking) { - auto str = getter{}.get(L, index, tracking); - return str.size() > 0 ? str[0] : char32_t(0); + string_view utf8 = stack::get(L, index, tracking); + const char* strb = utf8.data(); + const char* stre = utf8.data() + utf8.size(); + auto dr = unicode::utf8_to_code_point(strb, stre); + auto er = unicode::code_point_to_utf32(dr.codepoint); + return er.code_units[0]; + } + }; + + template <> + struct getter { + static wchar_t get(lua_State* L, int index, record& tracking) { + typedef std::conditional_t Ch; + getter g; + (void)g; + auto c = g.get(L, index, tracking); + return static_cast(c); } }; -#endif // codecvt header support template <> struct getter { @@ -8658,7 +9222,6 @@ namespace stack { template struct getter> { static T* get_no_lua_nil(lua_State* L, int index, record& tracking) { - tracking.use(1); void* memory = lua_touserdata(L, index); #ifdef SOL_ENABLE_INTEROP userdata_getter> ug; @@ -8668,6 +9231,7 @@ namespace stack { return ugr.second; } #endif // interop extensibility + tracking.use(1); void* rawdata = detail::align_usertype_pointer(memory); void** pudata = static_cast(rawdata); void* udata = *pudata; @@ -8677,9 +9241,9 @@ namespace stack { static T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) { if (detail::has_derived::value && luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) { void* basecastdata = lua_touserdata(L, -1); - detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata; + detail::inheritance_cast_function ic = reinterpret_cast(basecastdata); // use the casting function to properly adjust the pointer for the desired T - udata = ic(udata, detail::id_for::value); + udata = ic(udata, usertype_traits::qualified_name()); lua_pop(L, 1); } T* obj = static_cast(udata); @@ -8870,7 +9434,7 @@ namespace stack { int isnum = 0; const lua_Number value = lua_tonumberx(L, index, &isnum); if (isnum != 0) { -#if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) +#if defined(SOL_SAFE_NUMERICS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) const auto integer_value = llround(value); if (static_cast(integer_value) == value) { tracking.use(1); @@ -8978,8 +9542,6 @@ namespace stack { // beginning of sol/stack_push.hpp #include -#ifdef SOL_CODECVT_SUPPORT -#endif // codecvt support #ifdef SOL_CXX17_FEATURES #endif // C++17 @@ -9017,7 +9579,7 @@ namespace stack { // just the sizeof(T*), and nothing else. T* obj = detail::usertype_allocate(L); std::allocator alloc{}; - alloc.construct(obj, std::forward(args)...); + std::allocator_traits>::construct(alloc, obj, std::forward(args)...); f(); return 1; } @@ -9156,7 +9718,7 @@ namespace stack { return 1; } #endif -#if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) +#if defined(SOL_SAFE_NUMERICS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) if (static_cast(llround(static_cast(value))) != value) { #ifdef SOL_NO_EXCEPTIONS // Is this really worth it? @@ -9328,6 +9890,7 @@ namespace stack { return 1; } }; + #ifdef SOL_NOEXCEPT_FUNCTION_TYPE template <> struct pusher> { @@ -9398,8 +9961,8 @@ namespace stack { static int push_with(lua_State* L, Key&& name, Args&&... args) { // A dumb pusher T* data = detail::user_allocate(L); - std::allocator alloc; - alloc.construct(data, std::forward(args)...); + std::allocator alloc{}; + std::allocator_traits>::construct(alloc, data, std::forward(args)...); if (with_meta) { // Make sure we have a plain GC set for this data if (luaL_newmetatable(L, name) != 0) { @@ -9530,26 +10093,26 @@ namespace stack { } }; - template <> - struct pusher { - static int push(lua_State* L, const std::string& str) { + template + struct pusher> { + static int push(lua_State* L, const std::basic_string& str) { lua_pushlstring(L, str.c_str(), str.size()); return 1; } - static int push(lua_State* L, const std::string& str, std::size_t sz) { + static int push(lua_State* L, const std::basic_string& str, std::size_t sz) { lua_pushlstring(L, str.c_str(), sz); return 1; } }; - template <> - struct pusher { - static int push(lua_State* L, const string_view& sv) { + template + struct 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 string_view& sv, std::size_t n) { + static int push(lua_State* L, const basic_string_view& sv, std::size_t n) { return stack::push(L, sv.data(), n); } }; @@ -9587,7 +10150,6 @@ namespace stack { } }; -#ifdef SOL_CODECVT_SUPPORT template <> struct pusher { static int push(lua_State* L, const wchar_t* wstr) { @@ -9600,13 +10162,13 @@ namespace stack { static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { if (sizeof(wchar_t) == 2) { - thread_local std::wstring_convert> convert; - std::string u8str = convert.to_bytes(strb, stre); - return stack::push(L, u8str); + const char16_t* sb = reinterpret_cast(strb); + const char16_t* se = reinterpret_cast(stre); + return stack::push(L, sb, se); } - thread_local std::wstring_convert> convert; - std::string u8str = convert.to_bytes(strb, stre); - return stack::push(L, u8str); + const char32_t* sb = reinterpret_cast(strb); + const char32_t* se = reinterpret_cast(stre); + return stack::push(L, sb, se); } }; @@ -9633,6 +10195,20 @@ namespace stack { template <> struct pusher { + static int convert_into(lua_State* L, char* start, std::size_t, const char16_t* strb, const char16_t* stre) { + char* target = start; + 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); + 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)); } @@ -9642,14 +10218,30 @@ namespace stack { } static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { -#ifdef _MSC_VER - thread_local std::wstring_convert, int16_t> convert; - std::string u8str = convert.to_bytes(reinterpret_cast(strb), reinterpret_cast(stre)); -#else - thread_local std::wstring_convert, char16_t> convert; - std::string u8str = convert.to_bytes(strb, stre); -#endif // VC++ is a shit - return stack::push(L, u8str); + // TODO: use new unicode methods + // TODO: use new unicode methods + 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); } }; @@ -9676,6 +10268,19 @@ namespace stack { template <> struct pusher { + static int convert_into(lua_State* L, char* start, std::size_t, const char32_t* strb, const char32_t* stre) { + char* target = start; + 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); + 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)); } @@ -9685,14 +10290,29 @@ namespace stack { } static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { -#ifdef _MSC_VER - thread_local std::wstring_convert, int32_t> convert; - std::string u8str = convert.to_bytes(reinterpret_cast(strb), reinterpret_cast(stre)); -#else - thread_local std::wstring_convert, char32_t> convert; - std::string u8str = convert.to_bytes(strb, stre); -#endif // VC++ is a shit - return stack::push(L, u8str); + // TODO: use new unicode methods + 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); } }; @@ -9754,7 +10374,7 @@ namespace stack { struct pusher { static int push(lua_State* L, wchar_t c) { const wchar_t str[2] = { c, '\0' }; - return stack::push(L, str, 1); + return stack::push(L, &str[0], 1); } }; @@ -9762,7 +10382,7 @@ namespace stack { struct pusher { static int push(lua_State* L, char16_t c) { const char16_t str[2] = { c, '\0' }; - return stack::push(L, str, 1); + return stack::push(L, &str[0], 1); } }; @@ -9770,77 +10390,43 @@ namespace stack { struct pusher { static int push(lua_State* L, char32_t c) { const char32_t str[2] = { c, '\0' }; - return stack::push(L, str, 1); + return stack::push(L, &str[0], 1); } }; - template <> - struct pusher { - static int push(lua_State* L, const std::wstring& wstr) { - return push(L, wstr.data(), wstr.size()); + template + struct pusher> { + static int push(lua_State* L, const std::basic_string& wstr) { + return push(L, wstr, wstr.size()); } - static int push(lua_State* L, const std::wstring& wstr, std::size_t sz) { + static int push(lua_State* L, const std::basic_string& wstr, std::size_t sz) { return stack::push(L, wstr.data(), wstr.data() + sz); } }; - template <> - struct pusher { - static int push(lua_State* L, const std::u16string& u16str) { + template + struct pusher> { + static int push(lua_State* L, const std::basic_string& u16str) { return push(L, u16str, u16str.size()); } - static int push(lua_State* L, const std::u16string& u16str, std::size_t sz) { + static int push(lua_State* L, const std::basic_string& u16str, std::size_t sz) { return stack::push(L, u16str.data(), u16str.data() + sz); } }; - template <> - struct pusher { - static int push(lua_State* L, const std::u32string& u32str) { + template + struct pusher> { + static int push(lua_State* L, const std::basic_string& u32str) { return push(L, u32str, u32str.size()); } - static int push(lua_State* L, const std::u32string& u32str, std::size_t sz) { + static int push(lua_State* L, const std::basic_string& u32str, std::size_t sz) { return stack::push(L, u32str.data(), u32str.data() + sz); } }; - template <> - struct pusher { - static int push(lua_State* L, const wstring_view& sv) { - return stack::push(L, sv.data(), sv.length()); - } - - static int push(lua_State* L, const wstring_view& sv, std::size_t n) { - return stack::push(L, sv.data(), n); - } - }; - - template <> - struct pusher { - static int push(lua_State* L, const u16string_view& sv) { - return stack::push(L, sv.data(), sv.length()); - } - - static int push(lua_State* L, const u16string_view& sv, std::size_t n) { - return stack::push(L, sv.data(), n); - } - }; - - template <> - struct pusher { - static int push(lua_State* L, const u32string_view& sv) { - return stack::push(L, sv.data(), sv.length()); - } - - static int push(lua_State* L, const u32string_view& sv, std::size_t n) { - return stack::push(L, sv.data(), n); - } - }; -#endif // codecvt Header Support - template struct pusher> { template @@ -9955,14 +10541,18 @@ namespace stack { struct popper { inline static decltype(auto) pop(lua_State* L) { record tracking{}; +#ifdef __INTEL_COMPILER + auto&& r = get(L, -lua_size::value, tracking); +#else decltype(auto) r = get(L, -lua_size::value, tracking); +#endif lua_pop(L, tracking.used); return r; } }; template - struct popper>::value>> { + struct popper>::value>> { static_assert(meta::neg>>::value, "You cannot pop something that derives from stack_reference: it will not remain on the stack and thusly will go out of scope!"); }; } @@ -10280,8 +10870,6 @@ namespace stack { // end of sol/stack_probe.hpp -#include - namespace sol { namespace detail { using typical_chunk_name_t = char[32]; @@ -10320,10 +10908,10 @@ namespace sol { template inline int push_as_upvalues(lua_State* L, T& item) { typedef std::decay_t TValue; - const static std::size_t itemsize = sizeof(TValue); - const static std::size_t voidsize = sizeof(void*); - const static std::size_t voidsizem1 = voidsize - 1; - const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; + static const std::size_t itemsize = sizeof(TValue); + static const std::size_t voidsize = sizeof(void*); + static const std::size_t voidsizem1 = voidsize - 1; + static const std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; typedef std::array data_t; data_t data{ {} }; @@ -10337,7 +10925,7 @@ namespace sol { template inline std::pair get_as_upvalues(lua_State* L, int index = 2) { - const static std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); + static const std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); typedef std::array data_t; data_t voiddata{ {} }; for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { @@ -10358,7 +10946,7 @@ namespace sol { } }; - template ::value>> + template ::value >> inline decltype(auto) call(types, types ta, std::index_sequence tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { #ifndef _MSC_VER static_assert(meta::all...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); @@ -10369,7 +10957,7 @@ namespace sol { return evaluator{}.eval(ta, tai, L, start, tracking, std::forward(fx), std::forward(args)...); } - template + template inline void call(types, types ta, std::index_sequence tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { #ifndef _MSC_VER static_assert(meta::all...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); @@ -10387,41 +10975,41 @@ namespace sol { return luaL_ref(L, tableindex); } - template ::value>> + template ::value>> inline decltype(auto) call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { typedef std::make_index_sequence args_indices; return stack_detail::call(tr, ta, args_indices(), L, start, std::forward(fx), std::forward(args)...); } - template ::value>> + template ::value>> inline decltype(auto) call(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { return call(tr, ta, L, 1, std::forward(fx), std::forward(args)...); } - template + template inline void call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { typedef std::make_index_sequence args_indices; stack_detail::call(tr, ta, args_indices(), L, start, std::forward(fx), std::forward(args)...); } - template + template inline void call(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { call(tr, ta, L, 1, std::forward(fx), std::forward(args)...); } - template ::value>> + template ::value>> inline decltype(auto) call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { typedef meta::count_for_pack expected_count; return call(tr, ta, L, (std::max)(static_cast(lua_gettop(L) - expected_count::value), static_cast(0)), std::forward(fx), std::forward(args)...); } - template + template inline void call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { typedef meta::count_for_pack expected_count; call(tr, ta, L, (std::max)(static_cast(lua_gettop(L) - expected_count::value), static_cast(0)), std::forward(fx), std::forward(args)...); } - template + template inline int call_into_lua(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { call(tr, ta, L, start, std::forward(fx), std::forward(fxargs)...); if (clean_stack) { @@ -10430,7 +11018,7 @@ namespace sol { return 0; } - template >::value>> + template >::value>> inline int call_into_lua(types, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { decltype(auto) r = call(types>(), ta, L, start, std::forward(fx), std::forward(fxargs)...); typedef meta::unqualified_t R; @@ -10445,7 +11033,7 @@ namespace sol { return push_reference(L, std::forward(r)); } - template + template inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { typedef lua_bind_traits> traits_type; typedef typename traits_type::args_list args_list; @@ -10453,11 +11041,11 @@ namespace sol { return call_into_lua(returns_list(), args_list(), L, start, std::forward(fx), std::forward(fxargs)...); } - inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) { + inline call_syntax get_call_syntax(lua_State* L, const string_view& key, int index) { if (lua_gettop(L) == 0) { return call_syntax::dot; } - luaL_getmetatable(L, key.c_str()); + luaL_getmetatable(L, key.data()); auto pn = pop_n(L, 1); if (lua_compare(L, -1, index, LUA_OPEQ) != 1) { return call_syntax::dot; @@ -10551,13 +11139,12 @@ namespace sol { namespace sol { template - struct stack_iterator : std::iterator, std::ptrdiff_t, std::conditional_t, std::conditional_t> { - typedef std::iterator, std::ptrdiff_t, std::conditional_t, std::conditional_t> base_t; - typedef typename base_t::reference reference; - typedef typename base_t::pointer pointer; - typedef typename base_t::value_type value_type; - typedef typename base_t::difference_type difference_type; - typedef typename base_t::iterator_category iterator_category; + struct stack_iterator { + typedef std::conditional_t reference; + typedef std::conditional_t pointer; + typedef proxy_t value_type; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; lua_State* L; int index; int stacktop; @@ -10752,10 +11339,6 @@ namespace sol { namespace sol { struct stack_proxy : public stack_proxy_base { - private: - lua_State* L; - int index; - public: stack_proxy() : stack_proxy_base() { @@ -10803,9 +11386,10 @@ namespace sol { template decltype(auto) tagged_get(types>, int index_offset) const { + typedef decltype(stack::get>(L, index)) ret_t; int target = index + index_offset; if (!valid()) { - return optional(nullopt); + return ret_t(nullopt); } return stack::get>(L, target); } @@ -10813,7 +11397,7 @@ namespace sol { template decltype(auto) tagged_get(types, int index_offset) const { int target = index + index_offset; -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_PROXIES if (!valid()) { type t = type_of(L, target); type_panic_c_str(L, target, t, type::none, "bad get from protected_function_result (is not an error)"); @@ -10832,7 +11416,7 @@ namespace sol { error tagged_get(types, int index_offset) const { int target = index + index_offset; -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_PROXIES if (valid()) { type t = type_of(L, target); type_panic_c_str(L, target, t, type::none, "bad get from protected_function_result (is an error)"); @@ -11445,10 +12029,16 @@ namespace sol { namespace sol { namespace function_detail { - template + template inline int call(lua_State* L) { Fx& fx = stack::get>(L, upvalue_index(start)); - return fx(L); + int nr = fx(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } } } // namespace sol::function_detail @@ -11783,7 +12373,7 @@ namespace sol { inline int construct(lua_State* L) { static const auto& meta = usertype_traits::metatable(); int argcount = lua_gettop(L); - call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits::user_metatable()[0], 1) : call_syntax::dot; + call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits::user_metatable(), 1) : call_syntax::dot; argcount -= static_cast(syntax); T* obj = detail::usertype_allocate(L); @@ -11928,7 +12518,7 @@ namespace sol { } }; - template + template struct lua_call_wrapper : agnostic_lua_call_wrapper {}; template @@ -12082,7 +12672,7 @@ namespace sol { static int call(lua_State* L, F&) { const auto& metakey = usertype_traits::metatable(); int argcount = lua_gettop(L); - call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits::user_metatable()[0], 1) : call_syntax::dot; + call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits::user_metatable(), 1) : call_syntax::dot; argcount -= static_cast(syntax); T* obj = detail::usertype_allocate(L); @@ -12131,7 +12721,7 @@ namespace sol { }; static int call(lua_State* L, F& f) { - call_syntax syntax = stack::get_call_syntax(L, &usertype_traits::user_metatable()[0], 1); + call_syntax syntax = stack::get_call_syntax(L, usertype_traits::user_metatable(), 1); int syntaxval = static_cast(syntax); int argcount = lua_gettop(L) - syntaxval; return construct_match>...>(onmatch(), L, argcount, 1 + syntaxval, f); @@ -12290,12 +12880,12 @@ namespace sol { } }; - template + template inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) { return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::forward(fx), std::forward(args)...); } - template + template inline int call_user(lua_State* L) { auto& fx = stack::get>(L, upvalue_index(start)); return call_wrapped(L, fx); @@ -12426,12 +13016,12 @@ namespace sol { template inline int c_call(lua_State* L) { typedef meta::unqualified_t Fu; - return function_detail::c_call_raw(std::integral_constant < bool, std::is_same::value + typedef std::integral_constant::value #ifdef SOL_NOEXCEPT_FUNCTION_TYPE - || std::is_same::value + || std::is_same::value #endif - > (), - L); + > is_raw; + return function_detail::c_call_raw(is_raw(), L); } template @@ -12461,7 +13051,7 @@ namespace sol { namespace sol { namespace function_detail { - template + template struct upvalue_free_function { typedef std::remove_pointer_t> function_type; typedef meta::bind_traits traits_type; @@ -12473,7 +13063,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -12481,7 +13077,7 @@ namespace function_detail { } }; - template + template struct upvalue_member_function { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; @@ -12500,7 +13096,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -12508,7 +13110,7 @@ namespace function_detail { } }; - template + template struct upvalue_member_variable { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; @@ -12534,7 +13136,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -12542,8 +13150,8 @@ namespace function_detail { } }; - template - struct upvalue_member_variable> { + template + struct upvalue_member_variable, is_yielding> { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; @@ -12566,7 +13174,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -12574,7 +13188,7 @@ namespace function_detail { } }; - template + template struct upvalue_this_member_function { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; @@ -12588,7 +13202,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -12596,7 +13216,7 @@ namespace function_detail { } }; - template + template struct upvalue_this_member_variable { typedef std::remove_pointer_t> function_type; @@ -12616,7 +13236,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -12624,8 +13250,8 @@ namespace function_detail { } }; - template - struct upvalue_this_member_variable> { + template + struct upvalue_this_member_variable, is_yielding> { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; @@ -12643,7 +13269,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -12659,7 +13291,7 @@ namespace function_detail { namespace sol { namespace function_detail { - template + template struct functor_function { typedef std::decay_t> function_type; function_type fx; @@ -12670,7 +13302,13 @@ namespace function_detail { } int call(lua_State* L) { - return call_detail::call_wrapped(L, fx); + int nr = call_detail::call_wrapped(L, fx); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -12679,7 +13317,7 @@ namespace function_detail { } }; - template + template struct member_function { typedef std::remove_pointer_t> function_type; typedef meta::function_return_t return_type; @@ -12693,7 +13331,13 @@ namespace function_detail { } int call(lua_State* L) { - return call_detail::call_wrapped(L, invocation, detail::unwrap(detail::deref(member))); + int nr = call_detail::call_wrapped(L, invocation, detail::unwrap(detail::deref(member))); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -12702,7 +13346,7 @@ namespace function_detail { } }; - template + template struct member_variable { typedef std::remove_pointer_t> function_type; typedef typename meta::bind_traits::return_type return_type; @@ -12717,14 +13361,26 @@ namespace function_detail { } int call(lua_State* L) { - M mem = detail::unwrap(detail::deref(member)); - switch (lua_gettop(L)) { - case 0: - return call_detail::call_wrapped(L, var, mem); - case 1: - return call_detail::call_wrapped(L, var, mem); - default: - return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + int nr; + { + M mem = detail::unwrap(detail::deref(member)); + switch (lua_gettop(L)) { + case 0: + nr = call_detail::call_wrapped(L, var, mem); + break; + case 1: + nr = call_detail::call_wrapped(L, var, mem); + break; + default: + nr = luaL_error(L, "sol: incorrect number of arguments to member variable function"); + break; + } + } + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; } } @@ -12928,50 +13584,51 @@ namespace sol { struct call_indicator {}; } // namespace function_detail + namespace stack { template struct pusher> { - template + template static void select_convertible(std::false_type, types, lua_State* L, Fx&& fx, Args&&... args) { typedef std::remove_pointer_t> clean_fx; - typedef function_detail::functor_function F; - set_fx(L, std::forward(fx), std::forward(args)...); + typedef function_detail::functor_function F; + set_fx(L, std::forward(fx), std::forward(args)...); } - template + template static void select_convertible(std::true_type, types, lua_State* L, Fx&& fx, Args&&... args) { using fx_ptr_t = R (*)(A...); fx_ptr_t fxptr = detail::unwrap(std::forward(fx)); - select_function(std::true_type(), L, fxptr, std::forward(args)...); + select_function(std::true_type(), L, fxptr, std::forward(args)...); } - template + template static void select_convertible(types t, lua_State* L, Fx&& fx, Args&&... args) { typedef std::decay_t> raw_fx_t; typedef R (*fx_ptr_t)(A...); typedef std::is_convertible is_convertible; - select_convertible(is_convertible(), t, L, std::forward(fx), std::forward(args)...); + select_convertible(is_convertible(), t, L, std::forward(fx), std::forward(args)...); } - template + template static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { typedef meta::function_signature_t> Sig; - select_convertible(types(), L, std::forward(fx), std::forward(args)...); + select_convertible(types(), L, std::forward(fx), std::forward(args)...); } - template + template static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef std::remove_pointer_t> clean_fx; - typedef function_detail::member_variable, clean_fx> F; - set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); + typedef function_detail::member_variable, clean_fx, is_yielding> F; + set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); } - template + template static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef std::decay_t dFx; dFx memfxptr(std::forward(fx)); auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_member_variable, meta::unqualified_t>::call; + lua_CFunction freefunc = &function_detail::upvalue_member_variable, meta::unqualified_t, is_yielding>::call; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -12980,49 +13637,51 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_convertible(types(), L, std::forward(fx), std::forward(args)...); + select_convertible(types(), L, std::forward(fx), std::forward(args)...); } - template >> = meta::enabler> + template >> = meta::enabler> static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef meta::boolean>::value || std::is_pointer::value> is_reference; - select_reference_member_variable(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); + select_reference_member_variable(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); } - template + template static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; + int upvalues = 0; upvalues += stack::push(L, nullptr); upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { typedef typename meta::bind_traits>::object_type C; - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; + int upvalues = 0; upvalues += stack::push(L, nullptr); upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef std::decay_t clean_fx; - typedef function_detail::member_function, clean_fx> F; - set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); + typedef function_detail::member_function, clean_fx, is_yielding> F; + set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); } - template + template static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef std::decay_t dFx; dFx memfxptr(std::forward(fx)); auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_member_function, meta::unqualified_t>::call; + lua_CFunction freefunc = &function_detail::upvalue_member_function, meta::unqualified_t, is_yielding>::call; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -13031,45 +13690,47 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_variable(meta::is_member_object>(), L, std::forward(fx), std::forward(args)...); + select_member_variable(meta::is_member_object>(), L, std::forward(fx), std::forward(args)...); } - template >> = meta::enabler> + template >> = meta::enabler> static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef meta::boolean>::value || std::is_pointer::value> is_reference; - select_reference_member_function(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); + select_reference_member_function(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); } - template + template static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { - lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; + int upvalues = 0; upvalues += stack::push(L, nullptr); upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { typedef typename meta::bind_traits>::object_type C; - lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; + int upvalues = 0; upvalues += stack::push(L, nullptr); upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_function(std::is_member_function_pointer>(), L, std::forward(fx), std::forward(args)...); + select_member_function(std::is_member_function_pointer>(), L, std::forward(fx), std::forward(args)...); } - template + template static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) { std::decay_t target(std::forward(fx), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_free_function::call; + lua_CFunction freefunc = &function_detail::upvalue_free_function::call; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -13077,29 +13738,34 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } + template static void select_function(std::true_type, lua_State* L, lua_CFunction f) { + // TODO: support yielding stack::push(L, f); } #ifdef SOL_NOEXCEPT_FUNCTION_TYPE + template static void select_function(std::true_type, lua_State* L, detail::lua_CFunction_noexcept f) { + // TODO: support yielding stack::push(L, f); } #endif // noexcept function type - template >> = meta::enabler> + template >> = meta::enabler> static void select(lua_State* L, Fx&& fx, Args&&... args) { - select_function(std::is_function>>(), L, std::forward(fx), std::forward(args)...); + select_function(std::is_function>>(), L, std::forward(fx), std::forward(args)...); } - template >> = meta::enabler> + template >> = meta::enabler> static void select(lua_State* L, Fx&& fx) { + // TODO: hoist into lambda in this case?? stack::push(L, std::forward(fx)); } - template + template static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = function_detail::call, 2>; + lua_CFunction freefunc = function_detail::call, 2, is_yielding>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -13107,12 +13773,36 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } - template - static int push(lua_State* L, Args&&... args) { + template >> = meta::enabler> + static int push(lua_State* L, Arg0&& arg0, Args&&... args) { // Set will always place one thing (function) on the stack - select(L, std::forward(args)...); + select(L, std::forward(arg0), std::forward(args)...); return 1; } + + template + static int push(lua_State* L, detail::yield_tag_t, Args&&... args) { + // Set will always place one thing (function) on the stack + select(L, std::forward(args)...); + return 1; + } + }; + + template + struct pusher> { + template + static int push(lua_State* L, const yielding_t& f, Args&&... args) { + pusher> p{}; + (void)p; + return p.push(L, detail::yield_tag, f.func, std::forward(args)...); + } + + template + static int push(lua_State* L, yielding_t&& f, Args&&... args) { + pusher> p{}; + (void)p; + return p.push(L, detail::yield_tag, f.func, std::forward(args)...); + } }; template @@ -13146,7 +13836,9 @@ namespace sol { struct pusher::value>> { template static int push(lua_State* L, F&& f, Args&&... args) { - return pusher>{}.push(L, std::forward(f), std::forward(args)...); + pusher> p{}; + (void)p; + return p.push(L, std::forward(f), std::forward(args)...); } }; @@ -13166,14 +13858,16 @@ namespace sol { template struct pusher> { static int push(lua_State* L, overload_set&& set) { + // TODO: yielding typedef function_detail::overloaded_function<0, Functions...> F; - pusher>{}.set_fx(L, std::move(set.functions)); + pusher>{}.set_fx(L, std::move(set.functions)); return 1; } static int push(lua_State* L, const overload_set& set) { + // TODO: yielding typedef function_detail::overloaded_function<0, Functions...> F; - pusher>{}.set_fx(L, set.functions); + pusher>{}.set_fx(L, set.functions); return 1; } }; @@ -13241,25 +13935,25 @@ namespace sol { struct pusher> { static int push(lua_State* L, const factory_wrapper& fw) { typedef function_detail::overloaded_function<0, Functions...> F; - pusher>{}.set_fx(L, fw.functions); + pusher>{}.set_fx(L, fw.functions); return 1; } static int push(lua_State* L, factory_wrapper&& fw) { typedef function_detail::overloaded_function<0, Functions...> F; - pusher>{}.set_fx(L, std::move(fw.functions)); + pusher>{}.set_fx(L, std::move(fw.functions)); return 1; } static int push(lua_State* L, const factory_wrapper& set, function_detail::call_indicator) { typedef function_detail::overloaded_function<1, Functions...> F; - pusher>{}.set_fx(L, set.functions); + pusher>{}.set_fx(L, set.functions); return 1; } static int push(lua_State* L, factory_wrapper&& set, function_detail::call_indicator) { typedef function_detail::overloaded_function<1, Functions...> F; - pusher>{}.set_fx(L, std::move(set.functions)); + pusher>{}.set_fx(L, std::move(set.functions)); return 1; } }; @@ -13279,7 +13973,7 @@ namespace sol { template struct pusher>> { static int push(lua_State* L, detail::tagged>) { - lua_CFunction cf = call_detail::construct; + lua_CFunction cf = call_detail::construct; return stack::push(L, cf); } }; @@ -13378,10 +14072,10 @@ namespace sol { using base_t::lua_state; basic_function() = default; - template , basic_function>>, meta::neg>, is_lua_reference>> = meta::enabler> + template , basic_function>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> basic_function(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES if (!is_function>::value) { auto pp = stack::push_pop(*this); constructor_handler handler{}; @@ -13399,10 +14093,13 @@ namespace sol { basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) { } + basic_function(lua_nil_t n) + : base_t(n) { + } template >> = meta::enabler> basic_function(lua_State* L, T&& r) : base_t(L, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); @@ -13410,14 +14107,14 @@ namespace sol { } basic_function(lua_State* L, int index = -1) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(L, index, handler); #endif // Safety } basic_function(lua_State* L, ref_index index) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); @@ -13449,9 +14146,11 @@ namespace sol { // beginning of sol/protected_function.hpp +// beginning of sol/protected_handler.hpp + namespace sol { namespace detail { - inline const char (&default_handler_name())[9] { + inline const char(&default_handler_name())[9]{ static const char name[9] = "sol.\xF0\x9F\x94\xA9"; return name; } @@ -13463,7 +14162,7 @@ namespace sol { int stackindex; protected_handler(std::false_type, const target_t& target) - : target(target), stackindex(0) { + : target(target), stackindex(0) { if (b) { stackindex = lua_gettop(target.lua_state()) + 1; target.push(); @@ -13471,14 +14170,14 @@ namespace sol { } protected_handler(std::true_type, const target_t& target) - : target(target), stackindex(0) { + : target(target), stackindex(0) { if (b) { stackindex = target.stack_index(); } } protected_handler(const target_t& target) - : protected_handler(is_stack(), target) { + : protected_handler(is_stack(), target) { } bool valid() const noexcept { @@ -13496,36 +14195,49 @@ namespace sol { basic_function force_cast(T& p) { return p; } - } // namespace detail + template + static Reference get_default_handler(lua_State* L) { + if (is_stack_based::value || L == nullptr) + return Reference(L, lua_nil); + L = is_main_ref ? main_thread(L, L) : L; + lua_getglobal(L, default_handler_name()); + auto pp = stack::pop_n(L, 1); + return Reference(L, -1); + } + + template + static void set_default_handler(lua_State* L, const T& ref) { + if (L == nullptr) { + return; + } + if (!ref.valid()) { + lua_pushnil(L); + lua_setglobal(L, default_handler_name()); + } + else { + ref.push(L); + lua_setglobal(L, default_handler_name()); + } + } + } // namespace detail +} // namespace sol + +// end of sol/protected_handler.hpp + +namespace sol { template class basic_protected_function : public base_t { public: typedef is_stack_based is_stack_handler; static handler_t get_default_handler(lua_State* L) { - if (is_stack_handler::value || L == nullptr) - return handler_t(L, lua_nil); - L = is_main_threaded::value ? main_thread(L, L) : L; - lua_getglobal(L, detail::default_handler_name()); - auto pp = stack::pop_n(L, 1); - return handler_t(L, -1); + return detail::get_default_handler::value>(L); } template static void set_default_handler(const T& ref) { - if (ref.lua_state() == nullptr) { - return; - } - lua_State* L = ref.lua_state(); - if (!ref.valid()) { - lua_pushnil(L); - lua_setglobal(L, detail::default_handler_name()); - } - else { - ref.push(); - lua_setglobal(L, detail::default_handler_name()); - } + detail::set_default_handler(ref.lua_state(), ref); } private: @@ -13620,10 +14332,10 @@ namespace sol { handler_t error_handler; basic_protected_function() = default; - template , basic_protected_function>>, meta::neg>>, meta::neg>, is_lua_reference>> = meta::enabler> + template , basic_protected_function>>, meta::neg>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> basic_protected_function(T&& r) noexcept : base_t(std::forward(r)), error_handler(get_default_handler(r.lua_state())) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES if (!is_function>::value) { auto pp = stack::push_pop(*this); constructor_handler handler{}; @@ -13680,19 +14392,23 @@ namespace sol { template >> = meta::enabler> basic_protected_function(lua_State* L, T&& r, handler_t eh) : base_t(L, std::forward(r)), error_handler(std::move(eh)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); #endif // Safety } + + basic_protected_function(lua_nil_t n) + : base_t(n), error_handler(n) { + } basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) { } basic_protected_function(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(L, index, handler); #endif // Safety @@ -13702,7 +14418,7 @@ namespace sol { } basic_protected_function(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(L, index, handler); #endif // Safety @@ -13712,7 +14428,7 @@ namespace sol { } basic_protected_function(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(L, index, handler); #endif // Safety @@ -13722,7 +14438,7 @@ namespace sol { } basic_protected_function(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); @@ -13842,7 +14558,7 @@ namespace sol { template static std::function get_std_func(types, types, lua_State* L, int index) { unsafe_function f(L, index); - auto fx = [ f = std::move(f), L, index ](Args && ... args) -> meta::return_type_t { + auto fx = [ f = std::move(f) ](Args && ... args) -> meta::return_type_t { return f.call(std::forward(args)...); }; return std::move(fx); @@ -13851,7 +14567,7 @@ namespace sol { template static std::function get_std_func(types, types, lua_State* L, int index) { unsafe_function f(L, index); - auto fx = [f = std::move(f), L, index](FxArgs&&... args) -> void { + auto fx = [f = std::move(f)](FxArgs&&... args) -> void { f(std::forward(args)...); }; return std::move(fx); @@ -13975,7 +14691,11 @@ namespace sol { template decltype(auto) call(Args&&... args) { +#ifdef SOL_SAFE_FUNCTION + return get().template call(std::forward(args)...); +#else return get().template call(std::forward(args)...); +#endif // Safe function usage } template @@ -13990,6 +14710,14 @@ namespace sol { return p; } + int push() const noexcept { + return push(this->lua_state()); + } + + int push(lua_State* L) const noexcept { + return get().push(L); + } + type get_type() const { type t = type::none; auto pp = stack::push_pop(tbl); @@ -14053,14 +14781,16 @@ namespace sol { template template basic_reference& basic_reference::operator=(proxy_base&& r) { - this->operator=(r.operator basic_reference()); + basic_reference v = r; + this->operator=(std::move(v)); return *this; } template template basic_reference& basic_reference::operator=(const proxy_base& r) { - this->operator=(r.operator basic_reference()); + basic_reference v = r; + this->operator=(std::move(v)); return *this; } @@ -14179,7 +14909,7 @@ namespace sol { template , basic_userdata>>, meta::neg>, is_lua_reference>> = meta::enabler> basic_userdata(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES if (!is_userdata>::value) { auto pp = stack::push_pop(*this); type_assert(lua_state(), -1, type::userdata); @@ -14199,7 +14929,7 @@ namespace sol { template >> = meta::enabler> basic_userdata(lua_State* L, T&& r) : base_t(L, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(L, -1, handler); @@ -14207,14 +14937,14 @@ namespace sol { } basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(L, index, handler); #endif // Safety } basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(L, -1, handler); @@ -14233,7 +14963,7 @@ namespace sol { template , basic_lightuserdata>>, meta::neg>, is_lua_reference>> = meta::enabler> basic_lightuserdata(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES if (!is_lightuserdata>::value) { auto pp = stack::push_pop(*this); type_assert(lua_state(), -1, type::lightuserdata); @@ -14253,7 +14983,7 @@ namespace sol { template >> = meta::enabler> basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); @@ -14261,14 +14991,14 @@ namespace sol { } basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(L, index, handler); #endif // Safety } basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), index, handler); @@ -14967,6 +15697,29 @@ namespace sol { return t.second; } + struct error_result { + int results; + const char* fmt; + std::array args; + + error_result() : results(0), fmt(nullptr) { + } + + error_result(int results) : results(results), fmt(nullptr) { + } + + error_result(const char* fmt, const char* msg) : results(0), fmt(fmt) { + args[0] = msg; + } + }; + + inline int handle_errors(lua_State* L, const error_result& er) { + if (er.fmt == nullptr) { + return er.results; + } + return luaL_error(L, er.fmt, er.args[0], er.args[1], er.args[2], er.args[3]); + } + template struct container_traits_default { private: @@ -15048,25 +15801,37 @@ namespace sol { typedef container_traits deferred_traits; typedef meta::is_associative is_associative; typedef meta::is_lookup is_lookup; + typedef meta::is_matched_lookup is_matched_lookup; typedef typename T::iterator iterator; typedef typename T::value_type value_type; - typedef std::conditional_t, std::pair>> - KV; + typedef std::conditional_t, + std::conditional_t + > + > KV; typedef typename KV::first_type K; typedef typename KV::second_type V; + typedef std::conditional_t next_K; typedef decltype(*std::declval()) iterator_return; + typedef std::conditional_t, + std::conditional_t + > captured_type; typedef typename meta::iterator_tag::type iterator_category; typedef std::is_same is_input_iterator; typedef std::conditional_t, iterator_return>>()))> - push_type; + decltype(detail::deref_non_pointer(std::declval())) + > push_type; typedef std::is_copy_assignable is_copyable; typedef meta::neg, std::is_const>, meta::neg>> - is_writable; + std::is_const, std::is_const>, meta::neg + >> is_writable; typedef meta::unqualified_t>()))> key_type; typedef meta::all, meta::neg>> is_linear_integral; @@ -15081,9 +15846,8 @@ namespace sol { }; static auto& get_src(lua_State* L) { - typedef std::remove_pointer_t> Tu; #ifdef SOL_SAFE_USERTYPE - auto p = stack::check_get(L, 1); + auto p = stack::check_get(L, 1); if (!p) { luaL_error(L, "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle().c_str()); } @@ -15092,29 +15856,30 @@ namespace sol { } return *p.value(); #else - return stack::get(L, 1); + return stack::get(L, 1); #endif // Safe getting with error } - static int get_associative(std::true_type, lua_State* L, iterator& it) { + static error_result get_associative(std::true_type, lua_State* L, iterator& it) { auto& v = *it; - return stack::stack_detail::push_reference(L, detail::deref(v.second)); + return stack::stack_detail::push_reference(L, detail::deref_non_pointer(v.second)); } - static int get_associative(std::false_type, lua_State* L, iterator& it) { - return stack::stack_detail::push_reference(L, detail::deref(*it)); + static error_result get_associative(std::false_type, lua_State* L, iterator& it) { + return stack::stack_detail::push_reference(L, detail::deref_non_pointer(*it)); } - static int get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) { - if (key < 1) { + static error_result get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) { + key += deferred_traits::index_adjustment(L, self); + if (key < 0) { return stack::push(L, lua_nil); } - auto it = begin(L, self); - auto e = end(L, self); + auto it = deferred_traits::begin(L, self); + auto e = deferred_traits::end(L, self); if (it == e) { return stack::push(L, lua_nil); } - while (key > 1) { + while (key > 0) { --key; ++it; if (it == e) { @@ -15124,187 +15889,184 @@ namespace sol { return get_associative(is_associative(), L, it); } - static int get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) { + static error_result get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) { std::ptrdiff_t len = static_cast(size_start(L, self)); - if (key < 1 || key > len) { + key += deferred_traits::index_adjustment(L, self); + if (key < 0 || key >= len) { return stack::push(L, lua_nil); } - --key; - auto it = std::next(begin(L, self), key); + auto it = std::next(deferred_traits::begin(L, self), key); return get_associative(is_associative(), L, it); } - static int get_it(std::true_type, lua_State* L, T& self, K& key) { + static error_result get_it(std::true_type, lua_State* L, T& self, K& key) { return get_category(iterator_category(), L, self, key); } - static int get_comparative(std::true_type, lua_State* L, T& self, K& key) { + static error_result get_comparative(std::true_type, lua_State* L, T& self, K& key) { auto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); }; - auto e = end(L, self); - auto it = std::find_if(begin(L, self), e, std::ref(fx)); + auto e = deferred_traits::end(L, self); + auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx)); if (it == e) { return stack::push(L, lua_nil); } return get_associative(is_associative(), L, it); } - static int get_comparative(std::false_type, lua_State* L, T&, K&) { - return luaL_error(L, "cannot get this key on '%s': no suitable way to increment iterator and compare to key value '%s'", detail::demangle().data(), detail::demangle().data()); + static error_result get_comparative(std::false_type, lua_State*, T&, K&) { + return error_result("cannot get this key on '%s': no suitable way to increment iterator and compare to key value '%s'", detail::demangle().data(), detail::demangle().data()); } - static int get_it(std::false_type, lua_State* L, T& self, K& key) { + static error_result get_it(std::false_type, lua_State* L, T& self, K& key) { return get_comparative(meta::supports_op_equal(), L, self, key); } - static void set_associative(std::true_type, iterator& it, stack_object value) { + static error_result set_associative(std::true_type, iterator& it, stack_object value) { auto& v = *it; v.second = value.as(); + return {}; } - static void set_associative(std::false_type, iterator& it, stack_object value) { + static error_result set_associative(std::false_type, iterator& it, stack_object value) { auto& v = *it; v = value.as(); + return {}; } - static void set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) { - set_associative(is_associative(), it, std::move(value)); + static error_result set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) { + return set_associative(is_associative(), it, std::move(value)); } - static void set_writable(std::false_type, lua_State* L, T&, iterator&, stack_object) { - luaL_error(L, "cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle().data()); + static error_result set_writable(std::false_type, lua_State*, T&, iterator&, stack_object) { + return error_result("cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle().data()); } - static void set_category(std::input_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) { + static error_result set_category(std::input_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) { decltype(auto) key = okey.as(); - auto e = end(L, self); - auto it = begin(L, self); + key += deferred_traits::index_adjustment(L, self); + auto e = deferred_traits::end(L, self); + auto it = deferred_traits::begin(L, self); auto backit = it; - for (; key > 1 && it != e; --key, ++it) { + for (; key > 0 && it != e; --key, ++it) { backit = it; } if (it == e) { - if (key == 1) { - add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after::value ? backit : it); - return; + if (key == 0) { + return add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after::value ? backit : it); } - luaL_error(L, "out of bounds (too big) for set on '%s'", detail::demangle().c_str()); - return; + return error_result("out of bounds (too big) for set on '%s'", detail::demangle().c_str()); } - set_writable(is_writable(), L, self, it, std::move(value)); + return set_writable(is_writable(), L, self, it, std::move(value)); } - static void set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) { + static error_result set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) { decltype(auto) key = okey.as(); - if (key < 1) { - luaL_error(L, "sol: out of bounds (too small) for set on '%s'", detail::demangle().c_str()); - return; + if (key <= 0) { + return error_result("sol: out of bounds (too small) for set on '%s'", detail::demangle().c_str()); } - --key; + key += deferred_traits::index_adjustment(L, self); std::ptrdiff_t len = static_cast(size_start(L, self)); if (key == len) { - add_copyable(is_copyable(), L, self, std::move(value)); - return; + return add_copyable(is_copyable(), L, self, std::move(value)); } else if (key > len) { - luaL_error(L, "sol: out of bounds (too big) for set on '%s'", detail::demangle().c_str()); - return; + return error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle().c_str()); } - auto it = std::next(begin(L, self), key); - set_writable(is_writable(), L, self, it, std::move(value)); + auto it = std::next(deferred_traits::begin(L, self), key); + return set_writable(is_writable(), L, self, it, std::move(value)); } - static void set_comparative(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) { + static error_result set_comparative(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) { decltype(auto) key = okey.as(); if (!is_writable::value) { - luaL_error(L, "cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle().data()); - ; - return; + return error_result("cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle().data()); } auto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); }; - auto e = end(L, self); - auto it = std::find_if(begin(L, self), e, std::ref(fx)); + auto e = deferred_traits::end(L, self); + auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx)); if (it == e) { - return; + return {}; } - set_writable(is_writable(), L, self, it, std::move(value)); + return set_writable(is_writable(), L, self, it, std::move(value)); } - static void set_comparative(std::false_type, lua_State* L, T&, stack_object, stack_object) { - luaL_error(L, "cannot set this value on '%s': no suitable way to increment iterator or compare to '%s' key", detail::demangle().data(), detail::demangle().data()); + static error_result set_comparative(std::false_type, lua_State*, T&, stack_object, stack_object) { + return error_result("cannot set this value on '%s': no suitable way to increment iterator or compare to '%s' key", detail::demangle().data(), detail::demangle().data()); } - static void set_associative_insert(std::true_type, lua_State*, T& self, iterator& it, K& key, stack_object value) { + static error_result set_associative_insert(std::true_type, lua_State*, T& self, iterator& it, K& key, stack_object value) { self.insert(it, value_type(key, value.as())); + return {}; } - static void set_associative_insert(std::false_type, lua_State*, T& self, iterator& it, K& key, stack_object) { + static error_result set_associative_insert(std::false_type, lua_State*, T& self, iterator& it, K& key, stack_object) { self.insert(it, key); + return {}; } - static void set_associative_find(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) { + static error_result set_associative_find(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) { decltype(auto) key = okey.as(); auto it = self.find(key); - if (it == end(L, self)) { - set_associative_insert(is_associative(), L, self, it, key, std::move(value)); - return; + if (it == deferred_traits::end(L, self)) { + return set_associative_insert(is_associative(), L, self, it, key, std::move(value)); } - set_writable(is_writable(), L, self, it, std::move(value)); + return set_writable(is_writable(), L, self, it, std::move(value)); } - static void set_associative_find(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) { - set_comparative(meta::supports_op_equal(), L, self, std::move(key), std::move(value)); + static error_result set_associative_find(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) { + return set_comparative(meta::supports_op_equal(), L, self, std::move(key), std::move(value)); } - static void set_it(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { - set_category(iterator_category(), L, self, std::move(key), std::move(value)); + static error_result set_it(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { + return set_category(iterator_category(), L, self, std::move(key), std::move(value)); } - static void set_it(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) { - set_associative_find(meta::all, meta::any>(), L, self, std::move(key), std::move(value)); + static error_result set_it(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) { + return set_associative_find(meta::all, meta::any>(), L, self, std::move(key), std::move(value)); } - static int find_has_associative_lookup(std::true_type, lua_State* L, T& self) { + static error_result find_has_associative_lookup(std::true_type, lua_State* L, T& self) { decltype(auto) key = stack::get(L, 2); auto it = self.find(key); - if (it == end(L, self)) { + if (it == deferred_traits::end(L, self)) { return stack::push(L, lua_nil); } return get_associative(is_associative(), L, it); } - static int find_has_associative_lookup(std::false_type, lua_State* L, T& self) { + static error_result find_has_associative_lookup(std::false_type, lua_State* L, T& self) { decltype(auto) value = stack::get(L, 2); auto it = self.find(value); - if (it == end(L, self)) { + if (it == deferred_traits::end(L, self)) { return stack::push(L, lua_nil); } return get_associative(is_associative(), L, it); } - static int find_has(std::true_type, lua_State* L, T& self) { + static error_result find_has(std::true_type, lua_State* L, T& self) { return find_has_associative_lookup(meta::any(), L, self); } - static int find_associative_lookup(std::true_type, lua_State* L, iterator& it, std::size_t) { + static error_result find_associative_lookup(std::true_type, lua_State* L, iterator& it, std::size_t) { return get_associative(is_associative(), L, it); } - static int find_associative_lookup(std::false_type, lua_State* L, iterator&, std::size_t index) { + static error_result find_associative_lookup(std::false_type, lua_State* L, iterator&, std::size_t index) { return stack::push(L, index); } - static int find_comparative(std::false_type, lua_State* L, T&) { - return luaL_error(L, "cannot call 'find' on '%s': there is no 'find' function and the value_type is not equality comparable", detail::demangle().c_str()); + static error_result find_comparative(std::false_type, lua_State*, T&) { + return error_result("cannot call 'find' on '%s': there is no 'find' function and the value_type is not equality comparable", detail::demangle().c_str()); } - static int find_comparative(std::true_type, lua_State* L, T& self) { + static error_result find_comparative(std::true_type, lua_State* L, T& self) { decltype(auto) value = stack::get(L, 2); - auto it = begin(L, self); - auto e = end(L, self); + auto it = deferred_traits::begin(L, self); + auto e = deferred_traits::end(L, self); std::size_t index = 1; for (;; ++it, ++index) { if (it == e) { @@ -15317,199 +16079,210 @@ namespace sol { return find_associative_lookup(meta::any(), L, it, index); } - static int find_has(std::false_type, lua_State* L, T& self) { + static error_result find_has(std::false_type, lua_State* L, T& self) { return find_comparative(meta::supports_op_equal(), L, self); } - static void add_insert_after(std::false_type, lua_State* L, T& self, stack_object value, iterator&) { - add_insert_after(std::false_type(), L, self, value); + static error_result add_insert_after(std::false_type, lua_State* L, T& self, stack_object value, iterator&) { + return add_insert_after(std::false_type(), L, self, value); } - static void add_insert_after(std::false_type, lua_State* L, T&, stack_object) { - luaL_error(L, "cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", detail::demangle().data()); + static error_result add_insert_after(std::false_type, lua_State*, T&, stack_object) { + return error_result("cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", detail::demangle().data()); } - static void add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& at) { + static error_result add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& at) { self.insert_after(at, value.as()); + return {}; } - static void add_insert_after(std::true_type, lua_State* L, T& self, stack_object value) { + static error_result add_insert_after(std::true_type, lua_State* L, T& self, stack_object value) { auto backit = self.before_begin(); { - auto e = end(L, self); - for (auto it = begin(L, self); it != e; ++backit, ++it) { + auto e = deferred_traits::end(L, self); + for (auto it = deferred_traits::begin(L, self); it != e; ++backit, ++it) { } } return add_insert_after(std::true_type(), L, self, value, backit); } - static void add_insert(std::true_type, lua_State*, T& self, stack_object value, iterator& at) { + static error_result add_insert(std::true_type, lua_State*, T& self, stack_object value, iterator& at) { self.insert(at, value.as()); + return {}; } - static void add_insert(std::true_type, lua_State* L, T& self, stack_object value) { - auto at = end(L, self); - add_insert(std::true_type(), L, self, value, at); + static error_result add_insert(std::true_type, lua_State* L, T& self, stack_object value) { + auto at = deferred_traits::end(L, self); + return add_insert(std::true_type(), L, self, value, at); } - static void add_insert(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) { + static error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) { return add_insert_after(meta::has_insert_after(), L, self, std::move(value), at); } - static void add_insert(std::false_type, lua_State* L, T& self, stack_object value) { + static error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value) { return add_insert_after(meta::has_insert_after(), L, self, std::move(value)); } - static void add_push_back(std::true_type, lua_State*, T& self, stack_object value, iterator&) { + static error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value, iterator&) { self.push_back(value.as()); + return {}; } - static void add_push_back(std::true_type, lua_State*, T& self, stack_object value) { + static error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value) { self.push_back(value.as()); + return {}; } - static void add_push_back(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) { - add_insert(meta::has_insert(), L, self, value, at); + static error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) { + return add_insert(meta::has_insert(), L, self, value, at); } - static void add_push_back(std::false_type, lua_State* L, T& self, stack_object value) { - add_insert(meta::has_insert(), L, self, value); + static error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value) { + return add_insert(meta::has_insert(), L, self, value); } - static void add_associative(std::true_type, lua_State* L, T& self, stack_object key, iterator& at) { + static error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key, iterator& at) { self.insert(at, value_type(key.as(), stack::get(L, 3))); + return {}; } - static void add_associative(std::true_type, lua_State* L, T& self, stack_object key) { - auto at = end(L, self); - add_associative(std::true_type(), L, self, std::move(key), at); + static error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key) { + auto at = deferred_traits::end(L, self); + return add_associative(std::true_type(), L, self, std::move(key), at); } - static void add_associative(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) { - add_push_back(meta::has_push_back(), L, self, value, at); + static error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) { + return add_push_back(meta::has_push_back(), L, self, value, at); } - static void add_associative(std::false_type, lua_State* L, T& self, stack_object value) { - add_push_back(meta::has_push_back(), L, self, value); + static error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value) { + return add_push_back(meta::has_push_back(), L, self, value); } - static void add_copyable(std::true_type, lua_State* L, T& self, stack_object value, iterator& at) { - add_associative(is_associative(), L, self, std::move(value), at); + static error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value, iterator& at) { + return add_associative(is_associative(), L, self, std::move(value), at); } - static void add_copyable(std::true_type, lua_State* L, T& self, stack_object value) { - add_associative(is_associative(), L, self, value); + static error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value) { + return add_associative(is_associative(), L, self, value); } - static void add_copyable(std::false_type, lua_State* L, T& self, stack_object value, iterator&) { - add_copyable(std::false_type(), L, self, std::move(value)); + static error_result add_copyable(std::false_type, lua_State* L, T& self, stack_object value, iterator&) { + return add_copyable(std::false_type(), L, self, std::move(value)); } - static void add_copyable(std::false_type, lua_State* L, T&, stack_object) { - luaL_error(L, "cannot call 'add' on '%s': value_type is non-copyable", detail::demangle().data()); + static error_result add_copyable(std::false_type, lua_State*, T&, stack_object) { + return error_result("cannot call 'add' on '%s': value_type is non-copyable", detail::demangle().data()); } - static void insert_lookup(std::true_type, lua_State* L, T& self, stack_object, stack_object value) { + static error_result insert_lookup(std::true_type, lua_State* L, T& self, stack_object, stack_object value) { // TODO: should we warn or error about someone calling insert on an ordered / lookup container with no associativity? - add_copyable(std::true_type(), L, self, std::move(value)); + return add_copyable(std::true_type(), L, self, std::move(value)); } - static void insert_lookup(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) { - auto it = begin(L, self); + static error_result insert_lookup(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) { + auto it = deferred_traits::begin(L, self); auto key = where.as(); - --key; + key += deferred_traits::index_adjustment(L, self); std::advance(it, key); self.insert(it, value.as()); + return {}; } - static void insert_after_has(std::true_type, lua_State* L, T& self, stack_object where, stack_object value) { + static error_result insert_after_has(std::true_type, lua_State* L, T& self, stack_object where, stack_object value) { auto key = where.as(); auto backit = self.before_begin(); { - --key; - auto e = end(L, self); - for (auto it = begin(L, self); key > 0; ++backit, ++it, --key) { + key += deferred_traits::index_adjustment(L, self); + auto e = deferred_traits::end(L, self); + for (auto it = deferred_traits::begin(L, self); key > 0; ++backit, ++it, --key) { if (backit == e) { - luaL_error(L, "sol: out of bounds (too big) for set on '%s'", detail::demangle().c_str()); - return; + return error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle().c_str()); } } } self.insert_after(backit, value.as()); + return {}; } - static void insert_after_has(std::false_type, lua_State* L, T&, stack_object, stack_object) { - luaL_error(L, "cannot call 'insert' on '%s': no suitable or similar functionality detected on this container", detail::demangle().data()); + static error_result insert_after_has(std::false_type, lua_State*, T&, stack_object, stack_object) { + return error_result("cannot call 'insert' on '%s': no suitable or similar functionality detected on this container", detail::demangle().data()); } - static void insert_has(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { - insert_lookup(meta::all(), L, self, std::move(key), std::move(value)); + static error_result insert_has(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { + return insert_lookup(meta::any(), L, self, std::move(key), std::move(value)); } - static void insert_has(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) { - insert_after_has(meta::has_insert_after(), L, self, where, value); + static error_result insert_has(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) { + return insert_after_has(meta::has_insert_after(), L, self, where, value); } - static void insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { - insert_has(meta::has_insert(), L, self, std::move(key), std::move(value)); + static error_result insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { + return insert_has(meta::has_insert(), L, self, std::move(key), std::move(value)); } - static void insert_copyable(std::false_type, lua_State* L, T&, stack_object, stack_object) { - luaL_error(L, "cannot call 'insert' on '%s': value_type is non-copyable", detail::demangle().data()); + static error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) { + return error_result("cannot call 'insert' on '%s': value_type is non-copyable", detail::demangle().data()); } - static void erase_integral(std::true_type, lua_State* L, T& self, K& key) { - auto it = begin(L, self); - --key; + static error_result erase_integral(std::true_type, lua_State* L, T& self, K& key) { + auto it = deferred_traits::begin(L, self); + key += deferred_traits::index_adjustment(L, self); std::advance(it, key); self.erase(it); + + return {}; } - static void erase_integral(std::false_type, lua_State* L, T& self, const K& key) { + static error_result erase_integral(std::false_type, lua_State* L, T& self, const K& key) { auto fx = [&](const value_type& r) -> bool { return key == r; }; - auto e = end(L, self); - auto it = std::find_if(begin(L, self), e, std::ref(fx)); + auto e = deferred_traits::end(L, self); + auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx)); if (it == e) { - return; + return {}; } self.erase(it); + + return {}; } - static void erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) { + static error_result erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) { self.erase(key); + return {}; } - static void erase_associative_lookup(std::false_type, lua_State* L, T& self, K& key) { - erase_integral(std::is_integral(), L, self, key); + static error_result erase_associative_lookup(std::false_type, lua_State* L, T& self, K& key) { + return erase_integral(std::is_integral(), L, self, key); } - static void erase_after_has(std::true_type, lua_State* L, T& self, K& key) { + static error_result erase_after_has(std::true_type, lua_State* L, T& self, K& key) { auto backit = self.before_begin(); { - --key; - auto e = end(L, self); - for (auto it = begin(L, self); key > 0; ++backit, ++it, --key) { + key += deferred_traits::index_adjustment(L, self); + auto e = deferred_traits::end(L, self); + for (auto it = deferred_traits::begin(L, self); key > 0; ++backit, ++it, --key) { if (backit == e) { - luaL_error(L, "sol: out of bounds for erase on '%s'", detail::demangle().c_str()); - return; + return error_result("sol: out of bounds for erase on '%s'", detail::demangle().c_str()); } } } self.erase_after(backit); + return {}; } - static void erase_after_has(std::false_type, lua_State* L, T&, const K&) { - luaL_error(L, "sol: cannot call erase on '%s'", detail::demangle().c_str()); + static error_result erase_after_has(std::false_type, lua_State*, T&, const K&) { + return error_result("sol: cannot call erase on '%s'", detail::demangle().c_str()); } - static void erase_has(std::true_type, lua_State* L, T& self, K& key) { - erase_associative_lookup(meta::any(), L, self, key); + static error_result erase_has(std::true_type, lua_State* L, T& self, K& key) { + return erase_associative_lookup(meta::any(), L, self, key); } - static void erase_has(std::false_type, lua_State* L, T& self, K& key) { - erase_after_has(has_erase_after(), L, self, key); + static error_result erase_has(std::false_type, lua_State* L, T& self, K& key) { + return erase_after_has(has_erase_after(), L, self, key); } static auto size_has(std::false_type, lua_State* L, T& self) { @@ -15536,12 +16309,12 @@ namespace sol { return deferred_traits::begin(L, self) == deferred_traits::end(L, self); } - static int get_start(lua_State* L, T& self, K& key) { + static error_result get_start(lua_State* L, T& self, K& key) { return get_it(is_linear_integral(), L, self, key); } - static void set_start(lua_State* L, T& self, stack_object key, stack_object value) { - set_it(is_linear_integral(), L, self, std::move(key), std::move(value)); + static error_result set_start(lua_State* L, T& self, stack_object key, stack_object value) { + return set_it(is_linear_integral(), L, self, std::move(key), std::move(value)); } static std::size_t size_start(lua_State* L, T& self) { @@ -15555,9 +16328,9 @@ namespace sol { static bool empty_start(lua_State* L, T& self) { return empty_has(has_empty(), L, self); } - - static void erase_start(lua_State* L, T& self, K& key) { - erase_has(has_erase(), L, self, key); + + static error_result erase_start(lua_State* L, T& self, K& key) { + return erase_has(has_erase(), L, self, key); } template @@ -15576,11 +16349,33 @@ namespace sol { else { p = stack::push_reference(L, it->first); } - p += stack::stack_detail::push_reference(L, detail::deref(it->second)); + p += stack::stack_detail::push_reference(L, detail::deref_non_pointer(it->second)); std::advance(it, 1); return p; } + template + static int next_associative(std::false_type, lua_State* L) { + iter& i = stack::get>(L, 1); + auto& source = i.source; + auto& it = i.it; + next_K k = stack::get(L, 2); + if (it == deferred_traits::end(L, source)) { + return 0; + } + int p; + p = stack::push_reference(L, k + 1); + p += stack::stack_detail::push_reference(L, detail::deref_non_pointer(*it)); + std::advance(it, 1); + return p; + } + + template + static int next(lua_State* L) { + typedef meta::any>> is_assoc; + return next_associative(is_assoc(), L); + } + template static int pairs_associative(std::true_type, lua_State* L) { auto& src = get_src(L); @@ -15590,22 +16385,6 @@ namespace sol { return 3; } - template - static int next_associative(std::false_type, lua_State* L) { - iter& i = stack::get>(L, 1); - auto& source = i.source; - auto& it = i.it; - K k = stack::get(L, 2); - if (it == deferred_traits::end(L, source)) { - return 0; - } - int p; - p = stack::push_reference(L, k + 1); - p += stack::stack_detail::push_reference(L, detail::deref(*it)); - std::advance(it, 1); - return p; - } - template static int pairs_associative(std::false_type, lua_State* L) { auto& src = get_src(L); @@ -15615,16 +16394,15 @@ namespace sol { return 3; } - template - static int next(lua_State* L) { - return next_associative(is_associative(), L); - } - public: static int get(lua_State* L) { auto& self = get_src(L); - decltype(auto) key = stack::get(L); - return get_start(L, self, key); + error_result er; + { + decltype(auto) key = stack::get(L); + er = get_start(L, self, key); + } + return handle_errors(L, er); } static int index_get(lua_State* L) { @@ -15637,8 +16415,8 @@ namespace sol { return erase(L); } auto& self = get_src(L); - set_start(L, self, stack_object(L, raw_index(2)), std::move(value)); - return 0; + error_result er = set_start(L, self, stack_object(L, raw_index(2)), std::move(value)); + return handle_errors(L, er); } static int index_set(lua_State* L) { @@ -15647,19 +16425,20 @@ namespace sol { static int add(lua_State* L) { auto& self = get_src(L); - add_copyable(is_copyable(), L, self, stack_object(L, raw_index(2))); - return 0; + error_result er = add_copyable(is_copyable(), L, self, stack_object(L, raw_index(2))); + return handle_errors(L, er); } static int insert(lua_State* L) { auto& self = get_src(L); - insert_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)), stack_object(L, raw_index(3))); - return 0; + error_result er = insert_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)), stack_object(L, raw_index(3))); + return handle_errors(L, er); } static int find(lua_State* L) { auto& self = get_src(L); - return find_has(has_find(), L, self); + error_result er = find_has(has_find(), L, self); + return handle_errors(L, er); } static iterator begin(lua_State*, T& self) { @@ -15686,9 +16465,12 @@ namespace sol { static int erase(lua_State* L) { auto& self = get_src(L); - decltype(auto) key = stack::get(L, 2); - erase_start(L, self, key); - return 0; + error_result er; + { + decltype(auto) key = stack::get(L, 2); + er = erase_start(L, self, key); + } + return handle_errors(L, er); } static int empty(lua_State* L) { @@ -15696,12 +16478,18 @@ namespace sol { return stack::push(L, empty_start(L, self)); } + static std::ptrdiff_t index_adjustment(lua_State*, T&) { + return static_cast(-1); + } + static int pairs(lua_State* L) { - return pairs_associative(is_associative(), L); + typedef meta::any>> is_assoc; + return pairs_associative(is_assoc(), L); } static int ipairs(lua_State* L) { - return pairs_associative(is_associative(), L); + typedef meta::any>> is_assoc; + return pairs_associative(is_assoc(), L); } }; @@ -15762,7 +16550,7 @@ namespace sol { } int p; p = stack::push_reference(L, k + 1); - p += stack::push_reference(L, detail::deref(*it)); + p += stack::push_reference(L, detail::deref_non_pointer(*it)); std::advance(it, 1); return p; } @@ -15787,11 +16575,11 @@ namespace sol { static int get(lua_State* L) { T& self = get_src(L); std::ptrdiff_t idx = stack::get(L, 2); - if (idx > static_cast(std::extent::value) || idx < 1) { + idx += deferred_traits::index_adjustment(L, self); + if (idx >= static_cast(std::extent::value) || idx < 0) { return stack::push(L, lua_nil); } - --idx; - return stack::push_reference(L, detail::deref(self[idx])); + return stack::push_reference(L, detail::deref_non_pointer(self[idx])); } static int index_get(lua_State* L) { @@ -15801,13 +16589,13 @@ namespace sol { static int set(lua_State* L) { T& self = get_src(L); std::ptrdiff_t idx = stack::get(L, 2); - if (idx > static_cast(std::extent::value)) { + idx += deferred_traits::index_adjustment(L, self); + if (idx >= static_cast(std::extent::value)) { return luaL_error(L, "sol: index out of bounds (too big) for set on '%s'", detail::demangle().c_str()); } - if (idx < 1) { + if (idx < 0) { return luaL_error(L, "sol: index out of bounds (too small) for set on '%s'", detail::demangle().c_str()); } - --idx; self[idx] = stack::get(L, 3); return 0; } @@ -15840,6 +16628,10 @@ namespace sol { return pairs(L); } + static std::ptrdiff_t index_adjustment(lua_State*, T&) { + return -1; + } + static iterator begin(lua_State*, T& self) { return std::addressof(self[0]); } @@ -16350,7 +17142,13 @@ namespace sol { template > = meta::enabler> inline void make_length_op(Regs& l, int& index) { const char* name = to_string(meta_function::length).c_str(); +#ifdef __clang__ l[index] = luaL_Reg{ name, &c_call }; +#else + typedef decltype(std::declval().size()) R; + using sz_func = R(T::*)()const; + l[index] = luaL_Reg{ name, &c_call(&T::size)), static_cast(&T::size)> }; +#endif ++index; } @@ -16380,7 +17178,12 @@ namespace sol { } template - void insert_default_registrations(Regs& l, int& index, Fx&& fx) { + void insert_default_registrations(std::false_type, Regs&, int&, Fx&&) { + // no-op + } + + template + void insert_default_registrations(std::true_type, Regs& l, int& index, Fx&& fx) { if (fx(meta_function::less_than)) { const char* name = to_string(meta_function::less_than).c_str(); usertype_detail::make_reg_op, meta::supports_op_less>(l, index, name); @@ -16408,6 +17211,11 @@ namespace sol { usertype_detail::make_call_op(l, index); } } + + template + void insert_default_registrations(Regs& l, int& index, Fx&& fx) { + insert_default_registrations(is_automagical(), l, index, std::forward(fx)); + } } // namespace usertype_detail namespace stack { namespace stack_detail { @@ -16451,9 +17259,27 @@ namespace sol { // end of sol/usertype_core.hpp #include +#include + +#ifdef SOL_USE_BOOST +#include +#endif // Using Boost namespace sol { namespace usertype_detail { +#if defined(SOL_USE_BOOST) +#if defined(SOL_CXX17_FEATURES) + template , typename E = std::equal_to<>> + using map_t = boost::unordered_map; +#else + template , typename E = std::equal_to<>> + using map_t = boost::unordered_map; +#endif // C++17 or not, WITH boost +#else + template , typename E = std::equal_to<>> + using map_t = std::unordered_map; +#endif // Boost map target + const int metatable_index = 2; const int metatable_core_index = 3; const int filler_index = 4; @@ -16478,8 +17304,8 @@ namespace sol { : index(index), new_index(newindex), runtime_target(runtimetarget) { } }; - - typedef std::unordered_map mapping_t; + + typedef map_t mapping_t; struct variable_wrapper { virtual int index(lua_State* L) = 0; @@ -16505,8 +17331,8 @@ namespace sol { } }; - typedef std::unordered_map> variable_map; - typedef std::unordered_map function_map; + typedef map_t> variable_map; + typedef map_t function_map; struct simple_map { const char* metakey; @@ -16627,8 +17453,8 @@ namespace sol { inline int indexing_fail(lua_State* L) { if (is_index) { #if 0 //def SOL_SAFE_USERTYPE - auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); - string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); + auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); + string_view accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); #else if (is_toplevel(L)) { @@ -16658,13 +17484,21 @@ namespace sol { if (is_simple) { simple_map& sm = stack::get>(L, upvalue_index(simple_metatable_index)); function_map& functions = sm.functions; - optional maybeaccessor = stack::get>(L, 2); + optional maybeaccessor = stack::get>(L, 2); if (!maybeaccessor) { return; } - std::string& accessor = maybeaccessor.value(); + string_view& accessor_view = maybeaccessor.value(); +#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH + auto preexistingit = functions.find(accessor_view, string_view_hash(), std::equal_to()); +#else + std::string accessor(accessor_view.data(), accessor_view.size()); auto preexistingit = functions.find(accessor); +#endif if (preexistingit == functions.cend()) { +#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH + std::string accessor(accessor_view.data(), accessor_view.size()); +#endif functions.emplace_hint(preexistingit, std::move(accessor), object(L, 3)); } else { @@ -16676,18 +17510,26 @@ namespace sol { bool mustindex = umc.mustindex; if (!mustindex) return; - optional maybeaccessor = stack::get>(L, 2); + optional maybeaccessor = stack::get>(L, 2); if (!maybeaccessor) { return; } - std::string& accessor = maybeaccessor.value(); + string_view& accessor_view = maybeaccessor.value(); mapping_t& mapping = umc.mapping; std::vector& runtime = umc.runtime; int target = static_cast(runtime.size()); +#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH + auto preexistingit = mapping.find(accessor_view, string_view_hash(), std::equal_to()); +#else + std::string accessor(accessor_view.data(), accessor_view.size()); auto preexistingit = mapping.find(accessor); +#endif if (preexistingit == mapping.cend()) { +#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH + std::string accessor(accessor_view.data(), accessor_view.size()); +#endif runtime.emplace_back(L, 3); - mapping.emplace_hint(mapping.cend(), accessor, call_information(&runtime_object_call, &runtime_new_index, target)); + mapping.emplace_hint(mapping.cend(), std::move(accessor), call_information(&runtime_object_call, &runtime_new_index, target)); } else { target = preexistingit->second.runtime_target; @@ -16810,7 +17652,7 @@ namespace sol { void* baseclasscheck; void* baseclasscast; bool secondarymeta; - std::array properties; + std::bitset<32> properties; template >> = meta::enabler> lua_CFunction make_func() const { @@ -16875,45 +17717,42 @@ namespace sol { luaL_Reg reg = usertype_detail::make_reg(std::forward(n), make_func()); for (std::size_t i = 0; i < properties.size(); ++i) { meta_function mf = static_cast(i); - bool& prop = properties[i]; const std::string& mfname = to_string(mf); if (mfname == reg.name) { switch (mf) { case meta_function::construct: - if (prop) { + if (properties[i]) { #ifndef SOL_NO_EXCEPTIONS - throw error( + throw error("sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); #else - assert(false && + assert(false && "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); #endif - "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); } break; case meta_function::garbage_collect: if (destructfunc != nullptr) { #ifndef SOL_NO_EXCEPTIONS - throw error( + throw error("sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); #else - assert(false && + assert(false && "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); #endif - "sol: 2 separate garbage_collect functions were set on this type. Please specify only 1 sol::meta_function::gc type AND wrap the function in a sol::destruct call, as shown by the documentation and examples"); } destructfunc = reg.func; return; case meta_function::index: indexfunc = reg.func; mustindex = true; - prop = true; + properties.set(i); return; case meta_function::new_index: newindexfunc = reg.func; mustindex = true; - prop = true; + properties.set(i); return; default: break; } - prop = true; + properties.set(i); break; } } @@ -16924,7 +17763,7 @@ namespace sol { template > usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail, &usertype_detail::metatable_newindex), usertype_detail::registrar(), functions(std::forward(args)...), destructfunc(nullptr), callconstructfunc(nullptr), indexbase(&core_indexing_call), newindexbase(&core_indexing_call), indexbaseclasspropogation(usertype_detail::walk_all_bases), newindexbaseclasspropogation(usertype_detail::walk_all_bases), baseclasscheck(nullptr), baseclasscast(nullptr), secondarymeta(contains_variable()), properties() { - properties.fill(false); + properties.reset(); std::initializer_list ilist{{std::pair(usertype_detail::make_string(std::get(functions)), usertype_detail::call_information(&usertype_metatable::real_find_call, &usertype_metatable::real_find_call))}...}; @@ -16970,14 +17809,26 @@ namespace sol { if (toplevel && stack::get(L, keyidx) != type::string) { return is_index ? f.indexfunc(L) : f.newindexfunc(L); } - std::string name = stack::get(L, keyidx); - auto memberit = f.mapping.find(name); - if (memberit != f.mapping.cend()) { - const usertype_detail::call_information& ci = memberit->second; - const usertype_detail::member_search& member = is_index ? ci.index : ci.new_index; - return (member)(L, static_cast(&f), ci.runtime_target); + int runtime_target = 0; + usertype_detail::member_search member = nullptr; + { +#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH + string_view name = stack::get(L, keyidx); + auto memberit = f.mapping.find(name, string_view_hash(), std::equal_to()); +#else + std::string name = stack::get(L, keyidx); + auto memberit = f.mapping.find(name); +#endif + if (memberit != f.mapping.cend()) { + const usertype_detail::call_information& ci = memberit->second; + member = is_index ? ci.index : ci.new_index; + runtime_target = ci.runtime_target; + } } - string_view accessor = name; + if (member != nullptr) { + return (member)(L, static_cast(&f), runtime_target); + } + string_view accessor = stack::get(L, keyidx); int ret = 0; bool found = false; // Otherwise, we need to do propagating calls through the bases @@ -17231,7 +18082,7 @@ namespace sol { function_map& functions = sm.functions; static const int keyidx = -2 + static_cast(is_index); if (toplevel) { - if (stack::get(L, keyidx) != type::string) { + if (type_of(L, keyidx) != type::string) { if (has_indexing) { object& indexingfunc = is_index ? sm.index @@ -17246,35 +18097,54 @@ namespace sol { } } string_view accessor = stack::get(L, keyidx); - std::string accessorkey = accessor.data(); - auto vit = variables.find(accessorkey); - if (vit != variables.cend()) { - auto& varwrap = *(vit->second); - if (is_index) { - return varwrap.index(L); + variable_wrapper* varwrap = nullptr; + { +#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH + string_view& accessorkey = accessor; + auto vit = variables.find(accessorkey, string_view_hash(), std::equal_to()); +#else + std::string accessorkey(accessor.data(), accessor.size()); + auto vit = variables.find(accessorkey); +#endif // Compatible Hash + if (vit != variables.cend()) { + varwrap = vit->second.get(); } - return varwrap.new_index(L); } - auto fit = functions.find(accessorkey); - if (fit != functions.cend()) { - object& func = fit->second; - if (is_index) { - return stack::push(L, func); - } - else { - if (has_indexing && !is_toplevel(L)) { - object& indexingfunc = is_index - ? sm.index - : sm.newindex; - return call_indexing_object(L, indexingfunc); + if (varwrap != nullptr) { + return is_index ? varwrap->index(L) : varwrap->new_index(L); + } + bool function_failed = false; + { +#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH + string_view& accessorkey = accessor; + auto fit = functions.find(accessorkey, string_view_hash(), std::equal_to()); +#else + std::string accessorkey(accessor.data(), accessor.size()); + auto fit = functions.find(accessorkey); +#endif // Compatible Hash + if (fit != functions.cend()) { + object& func = fit->second; + if (is_index) { + return stack::push(L, func); } else { - return is_index - ? indexing_fail(L) - : metatable_newindex(L); + function_failed = true; } } } + if (function_failed) { + if (has_indexing && !is_toplevel(L)) { + object& indexingfunc = is_index + ? sm.index + : sm.newindex; + return call_indexing_object(L, indexingfunc); + } + else { + return is_index + ? indexing_fail(L) + : metatable_newindex(L); + } + } /* Check table storage first for a method that works luaL_getmetatable(L, sm.metakey); if (type_of(L, -1) != type::lua_nil) { @@ -17495,8 +18365,8 @@ namespace sol { static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report."); static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report."); - baseclasscheck = (void*)&detail::inheritance::type_check; - baseclasscast = (void*)&detail::inheritance::type_cast; + baseclasscheck = reinterpret_cast(&detail::inheritance::type_check); + baseclasscast = reinterpret_cast(&detail::inheritance::type_cast); indexbaseclasspropogation = usertype_detail::walk_all_bases; newindexbaseclasspropogation = usertype_detail::walk_all_bases; } @@ -17613,21 +18483,19 @@ namespace sol { case meta_function::construct: if (prop) { #ifndef SOL_NO_EXCEPTIONS - throw error( + throw error("sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); #else - assert(false && + assert(false && "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); #endif - "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); } break; case meta_function::garbage_collect: if (prop) { #ifndef SOL_NO_EXCEPTIONS - throw error( + throw error("sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); #else - assert(false && + assert(false && "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); #endif - "sol: 2 separate garbage_collect functions were set on this type. Please specify only 1 sol::meta_function::gc type AND wrap the function in a sol::destruct call, as shown by the documentation and examples"); } return; default: @@ -17909,17 +18777,14 @@ namespace sol { template class basic_table_iterator : public std::iterator> { - private: - typedef std::iterator> base_t; - public: typedef object key_type; typedef object mapped_type; - typedef base_t::value_type value_type; - typedef base_t::iterator_category iterator_category; - typedef base_t::difference_type difference_type; - typedef base_t::pointer pointer; - typedef base_t::reference reference; + typedef std::pair value_type; + typedef std::input_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; typedef const value_type& const_reference; private: @@ -18148,13 +19013,16 @@ namespace sol { } protected: + basic_table_core(detail::no_safety_tag, lua_nil_t n) + : base_t(n) { + } basic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) { } basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) { } - template , basic_table_core>>, meta::neg>, is_lua_reference>> = meta::enabler> + template , basic_table_core>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward(r)) { } @@ -18183,37 +19051,37 @@ namespace sol { template >> = meta::enabler> basic_table_core(lua_State* L, T&& r) : base_t(L, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); #endif // Safety } - basic_table_core(lua_State* L, new_table nt) - : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) { + basic_table_core(lua_State* L, const new_table& nt) + : base_t(L, -stack::push(L, nt)) { if (!is_stack_based>::value) { lua_pop(L, 1); } } basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(L, index, handler); #endif // Safety } basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); #endif // Safety } - template , basic_table_core>>, meta::neg>, is_lua_reference>> = meta::enabler> + template , basic_table_core>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES if (!is_table>::value) { auto pp = stack::push_pop(*this); constructor_handler handler{}; @@ -18221,6 +19089,9 @@ namespace sol { } #endif // Safety } + basic_table_core(lua_nil_t r) noexcept + : basic_table_core(detail::no_safety, r) { + } iterator begin() const { return iterator(*this); @@ -18416,7 +19287,7 @@ namespace sol { template table new_enum(const string_view& name, std::initializer_list> items) { - table target = create(items.size(), 0); + table target = create(static_cast(items.size()), static_cast(0)); for (const auto& kvp : items) { target.set(kvp.first, kvp.second); } @@ -18623,7 +19494,7 @@ namespace sol { basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(this->lua_state(), -1, handler); #endif // Safety @@ -18632,7 +19503,7 @@ namespace sol { template basic_environment(env_t, const basic_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(this->lua_state(), -1, handler); #endif // Safety @@ -18640,23 +19511,23 @@ namespace sol { } basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(L, index, handler); #endif // Safety } basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(L, -1, handler); #endif // Safety } - template , basic_environment>>, meta::neg>, is_lua_reference>> = meta::enabler> + template , basic_environment>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> basic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES if (!is_environment>::value) { auto pp = stack::push_pop(*this); constructor_handler handler{}; @@ -18664,10 +19535,14 @@ namespace sol { } #endif // Safety } + basic_environment(lua_nil_t r) noexcept + : base_t(detail::no_safety, r) { + } + template >> = meta::enabler> basic_environment(lua_State* L, T&& r) noexcept : base_t(detail::no_safety, L, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES if (!is_environment>::value) { auto pp = stack::push_pop(*this); constructor_handler handler{}; @@ -18805,9 +19680,9 @@ namespace sol { template decltype(auto) tagged_get(types) const { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_PROXIES if (!valid()) { - type_panic_c_str(L, index, type_of(L, index), type::none, ""); + type_panic_c_str(L, index, type_of(L, index), type::none); } #endif // Check Argument Safety return stack::get(L, index); @@ -18821,9 +19696,9 @@ namespace sol { } error tagged_get(types) const { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_PROXIES if (valid()) { - type_panic_c_str(L, index, type_of(L, index), type::none); + type_panic_c_str(L, index, type_of(L, index), type::none, "expecting an error type (a string, from Lua)"); } #endif // Check Argument Safety return error(detail::direct_error, stack::get(L, index)); @@ -18945,27 +19820,65 @@ namespace sol { return result; } - inline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) { - type t = type_of(L, pfr.stack_index()); + inline protected_function_result script_throw_on_error(lua_State*L, protected_function_result result) { + type t = type_of(L, result.stack_index()); std::string err = "sol: "; - err += to_string(pfr.status()); - err += " error:"; + err += to_string(result.status()); + err += " error"; +#ifndef SOL_NO_EXCEPTIONS + std::exception_ptr eptr = std::current_exception(); + if (eptr) { + err += " with a "; + try { + std::rethrow_exception(eptr); + } + catch (const std::exception& ex) { + err += "std::exception -- "; + err.append(ex.what()); + } + catch (const std::string& message) { + err += "thrown message -- "; + err.append(message); + } + catch (const char* message) { + err += "thrown message -- "; + err.append(message); + } + catch (...) { + err.append("thrown but unknown type, cannot serialize into error message"); + } + } +#endif // serialize exception information if possible if (t == type::string) { - err += " "; - string_view serr = stack::get(L, pfr.stack_index()); + err += ": "; + string_view serr = stack::get(L, result.stack_index()); err.append(serr.data(), serr.size()); } #ifdef SOL_NO_EXCEPTIONS // replacing information of stack error into pfr - if (t != type::none) { - lua_pop(L, 1); + int target = result.stack_index(); + if (result.pop_count() > 0) { + stack::remove(L, target, result.pop_count()); + } + int pushed = stack::push(L, err); + int top = lua_gettop(L); + int towards = top - target; + if (towards != 0) { + lua_rotate(L, top, towards); } - stack::push(L, err); #else // just throw our error throw error(detail::direct_error, err); #endif - return pfr; + return result; + } + + inline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) { +#ifdef SOL_DEFAULT_PASS_ON_ERROR + return script_pass_on_error(L, std::move(pfr)); +#else + return script_throw_on_error(L, std::move(pfr)); +#endif } class state_view { @@ -19196,7 +20109,7 @@ namespace sol { return pf(); } - template >> = meta::enabler> + template >, meta::is_specialization_of>> = meta::enabler> protected_function_result safe_script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result pfr = do_string(code, chunkname, mode); if (!pfr.valid()) { @@ -19223,7 +20136,7 @@ namespace sol { return safe_script(code, script_default_on_error, chunkname, mode); } - template >> = meta::enabler> + template >, meta::is_specialization_of>> = meta::enabler> protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { protected_function_result pfr = do_file(filename, mode); if (!pfr.valid()) { @@ -19298,12 +20211,12 @@ namespace sol { return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); } - template >> = meta::enabler> + template >, meta::is_specialization_of>> = meta::enabler> protected_function_result script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { return safe_script(code, std::forward(on_error), chunkname, mode); } - template >> = meta::enabler> + template >, meta::is_specialization_of>> = meta::enabler> protected_function_result script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { return safe_script_file(filename, std::forward(on_error), mode); } @@ -19511,13 +20424,13 @@ namespace sol { } template - state_view& new_enum(const std::string& name, Args&&... args) { + state_view& new_enum(const string_view& name, Args&&... args) { global.new_enum(name, std::forward(args)...); return *this; } template - state_view& new_enum(const std::string& name, std::initializer_list> items) { + state_view& new_enum(const string_view& name, std::initializer_list> items) { global.new_enum(name, std::move(items)); return *this; } @@ -19677,7 +20590,7 @@ namespace sol { template , basic_thread>>, is_lua_reference>> = meta::enabler> basic_thread(T&& r) : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); @@ -19692,7 +20605,7 @@ namespace sol { template >> = meta::enabler> basic_thread(lua_State* L, T&& r) : base_t(L, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); @@ -19700,14 +20613,14 @@ namespace sol { } basic_thread(lua_State* L, int index = -1) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(L, index, handler); #endif // Safety } basic_thread(lua_State* L, ref_index index) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); @@ -19721,7 +20634,7 @@ namespace sol { } basic_thread(lua_State* L, lua_thread_state actualthread) : base_t(L, -stack::push(L, actualthread)) { -#ifdef SOL_CHECK_ARGUMENTS +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; stack::check(lua_state(), -1, handler); #endif // Safety @@ -19746,10 +20659,15 @@ namespace sol { thread_status status() const { lua_State* lthread = thread_state(); - thread_status lstat = static_cast(lua_status(lthread)); - if (lstat != thread_status::ok && lua_gettop(lthread) == 0) { - // No thing on the basic_thread's stack means its dead - return thread_status::dead; + auto lstat = static_cast(lua_status(lthread)); + if (lstat == thread_status::ok) { + lua_Debug ar; + if (lua_getstack(lthread, 0, &ar) > 0) + return thread_status::ok; + else if (lua_gettop(lthread) == 0) + return thread_status::dead; + else + return thread_status::yielded; } return lstat; } @@ -19812,13 +20730,13 @@ namespace sol { } } // namespace detail - class state : private std::unique_ptr, public state_view { + class state : private std::unique_ptr, public state_view { private: - typedef std::unique_ptr unique_base; + typedef std::unique_ptr unique_base; public: state(lua_CFunction panic = detail::default_at_panic) - : unique_base(luaL_newstate(), lua_close), state_view(unique_base::get()) { + : unique_base(luaL_newstate()), state_view(unique_base::get()) { set_panic(panic); lua_CFunction f = c_call; protected_function::set_default_handler(object(lua_state(), in_place, f)); @@ -19827,7 +20745,7 @@ namespace sol { } state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) - : unique_base(lua_newstate(alfunc, alpointer), lua_close), state_view(unique_base::get()) { + : unique_base(lua_newstate(alfunc, alpointer)), state_view(unique_base::get()) { set_panic(panic); lua_CFunction f = c_call; protected_function::set_default_handler(object(lua_state(), in_place, f)); @@ -19858,6 +20776,10 @@ namespace sol { namespace sol { template class basic_coroutine : public base_t { + public: + typedef reference handler_t; + handler_t error_handler; + private: call_status stats = call_status::yielded; @@ -19883,57 +20805,133 @@ namespace sol { } protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) { - int stacksize = lua_gettop(lua_state()); - int firstreturn = (std::max)(1, stacksize - static_cast(n)); + int firstreturn = 1; luacall(n, LUA_MULTRET); - int poststacksize = lua_gettop(lua_state()); + int poststacksize = lua_gettop(this->lua_state()); int returncount = poststacksize - (firstreturn - 1); if (error()) { - return protected_function_result(lua_state(), lua_absindex(lua_state(), -1), 1, returncount, status()); + if (error_handler.valid()) { + string_view err = stack::get(this->lua_state(), poststacksize); + error_handler.push(); + stack::push(this->lua_state(), err); + lua_call(lua_state(), 1, 1); + } + return protected_function_result(this->lua_state(), lua_absindex(this->lua_state(), -1), 1, returncount, status()); } - return protected_function_result(lua_state(), firstreturn, returncount, returncount, status()); + return protected_function_result(this->lua_state(), firstreturn, returncount, returncount, status()); } public: using base_t::lua_state; - - basic_coroutine() noexcept = default; - basic_coroutine(const basic_coroutine&) noexcept = default; - basic_coroutine(basic_coroutine&&) noexcept = default; - basic_coroutine& operator=(const basic_coroutine&) noexcept = default; - basic_coroutine& operator=(basic_coroutine&&) noexcept = default; - template , basic_coroutine>>, is_lua_reference>> = meta::enabler> - basic_coroutine(T&& r) - : base_t(std::forward(r)) { + + basic_coroutine() = default; + template , basic_coroutine>>, meta::neg>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> + basic_coroutine(T&& r) noexcept + : base_t(std::forward(r)), error_handler(detail::get_default_handler::value>(r.lua_state())) { +#ifdef SOL_SAFE_REFERENCES + if (!is_function>::value) { + auto pp = stack::push_pop(*this); + constructor_handler handler{}; + stack::check(lua_state(), -1, handler); + } +#endif // Safety } - basic_coroutine(lua_nil_t r) - : base_t(r) { + basic_coroutine(const basic_coroutine&) = default; + basic_coroutine& operator=(const basic_coroutine&) = default; + basic_coroutine(basic_coroutine&&) = default; + basic_coroutine& operator=(basic_coroutine&&) = default; + basic_coroutine(const basic_function& b) + : basic_coroutine(b, detail::get_default_handler::value>(b.lua_state())) { } - basic_coroutine(const stack_reference& r) noexcept - : basic_coroutine(r.lua_state(), r.stack_index()) { + basic_coroutine(basic_function&& b) + : basic_coroutine(std::move(b), detail::get_default_handler::value>(b.lua_state())) { } - basic_coroutine(stack_reference&& r) noexcept - : basic_coroutine(r.lua_state(), r.stack_index()) { + basic_coroutine(const basic_function& b, handler_t eh) + : base_t(b), error_handler(std::move(eh)) { } + basic_coroutine(basic_function&& b, handler_t eh) + : base_t(std::move(b)), error_handler(std::move(eh)) { + } + basic_coroutine(const stack_reference& r) + : basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler::value>(r.lua_state())) { + } + basic_coroutine(stack_reference&& r) + : basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler::value>(r.lua_state())) { + } + basic_coroutine(const stack_reference& r, handler_t eh) + : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) { + } + basic_coroutine(stack_reference&& r, handler_t eh) + : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) { + } + + template + basic_coroutine(const proxy_base& p) + : basic_coroutine(p, detail::get_default_handler::value>(p.lua_state())) { + } + template + basic_coroutine(proxy_base&& p) + : basic_coroutine(std::move(p), detail::get_default_handler::value>(p.lua_state())) { + } + template >, meta::neg>>> = meta::enabler> + basic_coroutine(Proxy&& p, Handler&& eh) + : basic_coroutine(detail::force_cast(p), std::forward(eh)) { + } + template >> = meta::enabler> basic_coroutine(lua_State* L, T&& r) - : base_t(L, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS + : basic_coroutine(L, std::forward(r), detail::get_default_handler::value>(L)) { + } + template >> = meta::enabler> + basic_coroutine(lua_State* L, T&& r, handler_t eh) + : base_t(L, std::forward(r)), error_handler(std::move(eh)) { +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); #endif // Safety } + + basic_coroutine(lua_nil_t n) + : base_t(n), error_handler(n) { + } + basic_coroutine(lua_State* L, int index = -1) - : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS + : basic_coroutine(L, index, detail::get_default_handler::value>(L)) { + } + basic_coroutine(lua_State* L, int index, handler_t eh) + : base_t(L, index), error_handler(std::move(eh)) { +#ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; - stack::check(lua_state(), index, handler); + stack::check(L, index, handler); +#endif // Safety + } + basic_coroutine(lua_State* L, absolute_index index) + : basic_coroutine(L, index, detail::get_default_handler::value>(L)) { + } + basic_coroutine(lua_State* L, absolute_index index, handler_t eh) + : base_t(L, index), error_handler(std::move(eh)) { +#ifdef SOL_SAFE_REFERENCES + constructor_handler handler{}; + stack::check(L, index, handler); +#endif // Safety + } + basic_coroutine(lua_State* L, raw_index index) + : basic_coroutine(L, index, detail::get_default_handler::value>(L)) { + } + basic_coroutine(lua_State* L, raw_index index, handler_t eh) + : base_t(L, index), error_handler(std::move(eh)) { +#ifdef SOL_SAFE_REFERENCES + constructor_handler handler{}; + stack::check(L, index, handler); #endif // Safety } basic_coroutine(lua_State* L, ref_index index) - : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS + : basic_coroutine(L, index, detail::get_default_handler::value>(L)) { + } + basic_coroutine(lua_State* L, ref_index index, handler_t eh) + : base_t(L, index), error_handler(std::move(eh)) { +#ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); @@ -19974,7 +20972,6 @@ namespace sol { // and try to use it with sol::coroutine without ever calling the first resume in Lua // this makes the stack incompatible with other kinds of stacks: protect against this // make sure coroutines don't screw us over - stack::coroutine_create_guard(lua_state()); base_t::push(); int pushcount = stack::multi_push_reference(lua_state(), std::forward(args)...); return invoke(types(), std::make_index_sequence(), pushcount);