diff options
Diffstat (limited to '3rdparty/sol2/sol/sol.hpp')
-rw-r--r-- | 3rdparty/sol2/sol/sol.hpp | 8857 |
1 files changed, 5545 insertions, 3312 deletions
diff --git a/3rdparty/sol2/sol/sol.hpp b/3rdparty/sol2/sol/sol.hpp index 9e0b5f85338..8b0b7d36ea4 100644 --- a/3rdparty/sol2/sol/sol.hpp +++ b/3rdparty/sol2/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2020-10-03 21:34:24.496436 UTC -// This header was generated with sol v3.2.1 (revision 48eea7b5) +// Generated 2022-06-25 08:14:19.151876 UTC +// This header was generated with sol v3.3.0 (revision eba86625) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -36,50 +36,123 @@ #include <sol/config.hpp> -#include <cstdint> - #define SOL_VERSION_MAJOR 3 -#define SOL_VERSION_MINOR 5 -#define SOL_VERSION_PATCH 0 -#define SOL_VERSION_STRING "3.5.0" +#define SOL_VERSION_MINOR 2 +#define SOL_VERSION_PATCH 3 +#define SOL_VERSION_STRING "3.2.3" #define SOL_VERSION ((SOL_VERSION_MAJOR * 100000) + (SOL_VERSION_MINOR * 100) + (SOL_VERSION_PATCH)) -#define SOL_IS_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) != 0) -#define SOL_IS_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3) == 0) -#define SOL_IS_DEFAULT_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) > 3) -#define SOL_IS_DEFAULT_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3 OP_SYMBOL 3) < 0) +#define SOL_TOKEN_TO_STRING_POST_EXPANSION_I_(_TOKEN) #_TOKEN +#define SOL_TOKEN_TO_STRING_I_(_TOKEN) SOL_TOKEN_TO_STRING_POST_EXPANSION_I_(_TOKEN) + +#define SOL_CONCAT_TOKENS_POST_EXPANSION_I_(_LEFT, _RIGHT) _LEFT##_RIGHT +#define SOL_CONCAT_TOKENS_I_(_LEFT, _RIGHT) SOL_CONCAT_TOKENS_POST_EXPANSION_I_(_LEFT, _RIGHT) + +#define SOL_RAW_IS_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) != 0) +#define SOL_RAW_IS_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3) == 0) +#define SOL_RAW_IS_DEFAULT_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) > 3) +#define SOL_RAW_IS_DEFAULT_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3 OP_SYMBOL 3) < 0) + +#define SOL_IS_ON(OP_SYMBOL) SOL_RAW_IS_ON(OP_SYMBOL ## _I_) +#define SOL_IS_OFF(OP_SYMBOL) SOL_RAW_IS_OFF(OP_SYMBOL ## _I_) +#define SOL_IS_DEFAULT_ON(OP_SYMBOL) SOL_RAW_IS_DEFAULT_ON(OP_SYMBOL ## _I_) +#define SOL_IS_DEFAULT_OFF(OP_SYMBOL) SOL_RAW_IS_DEFAULT_OFF(OP_SYMBOL ## _I_) #define SOL_ON | #define SOL_OFF ^ #define SOL_DEFAULT_ON + #define SOL_DEFAULT_OFF - -#if defined(_MSC_VER) - #define SOL_COMPILER_CLANG_I_ SOL_OFF - #define SOL_COMPILER_GCC_I_ SOL_OFF - #define SOL_COMPILER_EDG_I_ SOL_OFF - #define SOL_COMPILER_VCXX_I_ SOL_ON -#elif defined(__clang__) - #define SOL_COMPILER_CLANG_I_ SOL_ON - #define SOL_COMPILER_GCC_I_ SOL_OFF - #define SOL_COMPILER_EDG_I_ SOL_OFF - #define SOL_COMPILER_VCXX_I_ SOL_OFF +#if defined(SOL_BUILD_CXX_MODE) + #if (SOL_BUILD_CXX_MODE != 0) + #define SOL_BUILD_CXX_MODE_I_ SOL_ON + #else + #define SOL_BUILD_CXX_MODE_I_ SOL_OFF + #endif +#elif defined(__cplusplus) + #define SOL_BUILD_CXX_MODE_I_ SOL_DEFAULT_ON +#else + #define SOL_BUILD_CXX_MODE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_BUILD_C_MODE) + #if (SOL_BUILD_C_MODE != 0) + #define SOL_BUILD_C_MODE_I_ SOL_ON + #else + #define SOL_BUILD_C_MODE_I_ SOL_OFF + #endif +#elif defined(__STDC__) + #define SOL_BUILD_C_MODE_I_ SOL_DEFAULT_ON +#else + #define SOL_BUILD_C_MODE_I_ SOL_DEFAULT_OFF +#endif + +#if SOL_IS_ON(SOL_BUILD_C_MODE) + #include <stddef.h> + #include <stdint.h> + #include <limits.h> +#else + #include <cstddef> + #include <cstdint> + #include <climits> +#endif + +#if defined(SOL_COMPILER_VCXX) + #if defined(SOL_COMPILER_VCXX != 0) + #define SOL_COMPILER_VCXX_I_ SOL_ON + #else + #define SOL_COMPILER_VCXX_I_ SOL_OFF + #endif +#elif defined(_MSC_VER) + #define SOL_COMPILER_VCXX_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_VCXX_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_GCC) + #if defined(SOL_COMPILER_GCC != 0) + #define SOL_COMPILER_GCC_I_ SOL_ON + #else + #define SOL_COMPILER_GCC_I_ SOL_OFF + #endif #elif defined(__GNUC__) - #define SOL_COMPILER_CLANG_I_ SOL_OFF - #define SOL_COMPILER_GCC_I_ SOL_ON - #define SOL_COMPILER_EDG_I_ SOL_OFF - #define SOL_COMPILER_VCXX_I_ SOL_OFF + #define SOL_COMPILER_GCC_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_GCC_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_CLANG) + #if defined(SOL_COMPILER_CLANG != 0) + #define SOL_COMPILER_CLANG_I_ SOL_ON + #else + #define SOL_COMPILER_CLANG_I_ SOL_OFF + #endif +#elif defined(__clang__) + #define SOL_COMPILER_CLANG_I_ SOL_DEFAULT_ON #else - #define SOL_COMPILER_CLANG_I_ SOL_OFF - #define SOL_COMPILER_GCC_I_ SOL_OFF - #define SOL_COMPILER_EDG_I_ SOL_OFF - #define SOL_COMPILER_VCXX_I_ SOL_OFF + #define SOL_COMPILER_CLANG_I_ SOL_DEFAULT_OFF #endif -#if defined(__MINGW32__) - #define SOL_COMPILER_FRONTEND_MINGW_I_ SOL_ON +#if defined(SOL_COMPILER_EDG) + #if defined(SOL_COMPILER_EDG != 0) + #define SOL_COMPILER_EDG_I_ SOL_ON + #else + #define SOL_COMPILER_EDG_I_ SOL_OFF + #endif #else - #define SOL_COMPILER_FRONTEND_MINGW_I_ SOL_OFF + #define SOL_COMPILER_EDG_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_MINGW) + #if (SOL_COMPILER_MINGW != 0) + #define SOL_COMPILER_MINGW_I_ SOL_ON + #else + #define SOL_COMPILER_MINGW_I_ SOL_OFF + #endif +#elif defined(__MINGW32__) + #define SOL_COMPILER_MINGW_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_MINGW_I_ SOL_DEFAULT_OFF #endif #if SIZE_MAX <= 0xFFFFULL @@ -99,25 +172,64 @@ #define SOL_PLATFORM_ARM32_I_ SOL_OFF #define SOL_PLATFORM_ARM64_I_ SOL_OFF -#if defined(_WIN32) - #define SOL_PLATFORM_WINDOWS_I_ SOL_ON +#if defined(SOL_PLATFORM_WINDOWS) + #if (SOL_PLATFORM_WINDOWS != 0) + #define SOL_PLATFORM_WINDOWS_I_ SOL_ON + #else + #define SOL_PLATFORM_WINDOWS_I_ SOL_OFF + #endif +#elif defined(_WIN32) + #define SOL_PLATFORM_WINDOWS_I_ SOL_DEFAULT_ON #else - #define SOL_PLATFORM_WINDOWS_I_ SOL_OFF + #define SOL_PLATFORM_WINDOWS_I_ SOL_DEFAULT_OFF #endif -#if defined(__APPLE__) - #define SOL_PLATFORM_APPLE_I_ SOL_ON + +#if defined(SOL_PLATFORM_CYGWIN) + #if (SOL_PLATFORM_CYGWIN != 0) + #define SOL_PLATFORM_CYGWIN_I_ SOL_ON + #else + #define SOL_PLATFORM_CYGWIN_I_ SOL_ON + #endif +#elif defined(__CYGWIN__) + #define SOL_PLATFORM_CYGWIN_I_ SOL_DEFAULT_ON #else - #define SOL_PLATFORM_APPLE_I_ SOL_OFF + #define SOL_PLATFORM_CYGWIN_I_ SOL_DEFAULT_OFF #endif -#if defined(__unix__) - #define SOL_PLATFORM_UNIXLIKE_I_ SOL_ON + +#if defined(SOL_PLATFORM_APPLE) + #if (SOL_PLATFORM_APPLE != 0) + #define SOL_PLATFORM_APPLE_I_ SOL_ON + #else + #define SOL_PLATFORM_APPLE_I_ SOL_OFF + #endif +#elif defined(__APPLE__) + #define SOL_PLATFORM_APPLE_I_ SOL_DEFAULT_ON #else - #define SOL_PLATFORM_UNIXLIKE_I_ SOL_OFF + #define SOL_PLATFORM_APPLE_I_ SOL_DEFAULT_OFF #endif -#if defined(__linux__) - #define SOL_PLATFORM_LINUXLIKE_I_ SOL_ON + +#if defined(SOL_PLATFORM_UNIX) + #if (SOL_PLATFORM_UNIX != 0) + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_ON + #else + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_OFF + #endif +#elif defined(__unix__) + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_DEFAUKT_ON +#else + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_PLATFORM_LINUX) + #if (SOL_PLATFORM_LINUX != 0) + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_ON + #else + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_OFF + #endif +#elif defined(__LINUX__) + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_DEFAUKT_ON #else - #define SOL_PLATFORM_LINUXLIKE_I_ SOL_OFF + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_DEFAULT_OFF #endif #define SOL_PLATFORM_APPLE_IPHONE_I_ SOL_OFF @@ -130,9 +242,9 @@ #define SOL_DEBUG_BUILD_I_ SOL_OFF #endif #elif !defined(NDEBUG) - #if SOL_IS_ON(SOL_COMPILER_VCXX_I_) && defined(_DEBUG) + #if SOL_IS_ON(SOL_COMPILER_VCXX) && defined(_DEBUG) #define SOL_DEBUG_BUILD_I_ SOL_ON - #elif (SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_)) && !defined(__OPTIMIZE__) + #elif (SOL_IS_ON(SOL_COMPILER_CLANG) || SOL_IS_ON(SOL_COMPILER_GCC)) && !defined(__OPTIMIZE__) #define SOL_DEBUG_BUILD_I_ SOL_ON #else #define SOL_DEBUG_BUILD_I_ SOL_OFF @@ -147,13 +259,13 @@ #else #define SOL_EXCEPTIONS_I_ SOL_ON #endif -#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#elif SOL_IS_ON(SOL_COMPILER_VCXX) #if !defined(_CPPUNWIND) #define SOL_EXCEPTIONS_I_ SOL_OFF #else #define SOL_EXCEPTIONS_I_ SOL_ON #endif -#elif SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_) +#elif SOL_IS_ON(SOL_COMPILER_CLANG) || SOL_IS_ON(SOL_COMPILER_GCC) #if !defined(__EXCEPTIONS) #define SOL_EXCEPTIONS_I_ SOL_OFF #else @@ -169,13 +281,13 @@ #else #define SOL_RTTI_I_ SOL_ON #endif -#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#elif SOL_IS_ON(SOL_COMPILER_VCXX) #if !defined(_CPPRTTI) #define SOL_RTTI_I_ SOL_OFF #else #define SOL_RTTI_I_ SOL_ON #endif -#elif SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_) +#elif SOL_IS_ON(SOL_COMPILER_CLANG) || SOL_IS_ON(SOL_COMPILER_GCC) #if !defined(__GXX_RTTI) #define SOL_RTTI_I_ SOL_OFF #else @@ -185,124 +297,192 @@ #define SOL_RTTI_I_ SOL_DEFAULT_ON #endif -#if defined(SOL_NO_THREAD_LOCAL) && (SOL_NO_THREAD_LOCAL != 0) - #define SOL_USE_THREAD_LOCAL_I_ SOL_OFF +#if defined(SOL_NO_THREAD_LOCAL) + #if SOL_NO_THREAD_LOCAL != 0 + #define SOL_USE_THREAD_LOCAL_I_ SOL_OFF + #else + #define SOL_USE_THREAD_LOCAL_I_ SOL_ON + #endif #else #define SOL_USE_THREAD_LOCAL_I_ SOL_DEFAULT_ON #endif // thread_local keyword is bjorked on some platforms -#if defined(SOL_ALL_SAFETIES_ON) && (SOL_ALL_SAFETIES_ON != 0) - #define SOL_ALL_SAFETIES_ON_I_ SOL_ON +#if defined(SOL_ALL_SAFETIES_ON) + #if SOL_ALL_SAFETIES_ON != 0 + #define SOL_ALL_SAFETIES_ON_I_ SOL_ON + #else + #define SOL_ALL_SAFETIES_ON_I_ SOL_OFF + #endif #else #define SOL_ALL_SAFETIES_ON_I_ SOL_DEFAULT_OFF #endif -#if defined(SOL_SAFE_GETTER) && (SOL_SAFE_GETTER != 0) - #define SOL_SAFE_GETTER_I_ SOL_ON +#if defined(SOL_SAFE_GETTER) + #if SOL_SAFE_GETTER != 0 + #define SOL_SAFE_GETTER_I_ SOL_ON + #else + #define SOL_SAFE_GETTER_I_ SOL_OFF + #endif #else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) #define SOL_SAFE_GETTER_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) + #elif SOL_IS_ON(SOL_DEBUG_BUILD) #define SOL_SAFE_GETTER_I_ SOL_DEFAULT_ON #else #define SOL_SAFE_GETTER_I_ SOL_DEFAULT_OFF #endif #endif -#if defined(SOL_SAFE_USERTYPE) && (SOL_SAFE_USERTYPE != 0) - #define SOL_SAFE_USERTYPE_I_ SOL_ON +#if defined(SOL_SAFE_USERTYPE) + #if SOL_SAFE_USERTYPE != 0 + #define SOL_SAFE_USERTYPE_I_ SOL_ON + #else + #define SOL_SAFE_USERTYPE_I_ SOL_OFF + #endif #else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) #define SOL_SAFE_USERTYPE_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) + #elif SOL_IS_ON(SOL_DEBUG_BUILD) #define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_ON #else #define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_OFF #endif #endif -#if defined(SOL_SAFE_REFERENCES) && (SOL_SAFE_REFERENCES != 0) - #define SOL_SAFE_REFERENCES_I_ SOL_ON +#if defined(SOL_SAFE_REFERENCES) + #if SOL_SAFE_REFERENCES != 0 + #define SOL_SAFE_REFERENCES_I_ SOL_ON + #else + #define SOL_SAFE_REFERENCES_I_ SOL_OFF + #endif #else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) #define SOL_SAFE_REFERENCES_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) + #elif SOL_IS_ON(SOL_DEBUG_BUILD) #define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_ON #else #define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_OFF #endif #endif -#if (defined(SOL_SAFE_FUNCTIONS) && (SOL_SAFE_FUNCTIONS != 0)) \ - || (defined(SOL_SAFE_FUNCTION_OBJECTS) && (SOL_SAFE_FUNCTION_OBJECTS != 0)) - #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON +#if defined(SOL_SAFE_FUNCTIONS) + #if SOL_SAFE_FUNCTIONS != 0 + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON + #else + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF + #endif +#elif defined (SOL_SAFE_FUNCTION_OBJECTS) + #if SOL_SAFE_FUNCTION_OBJECTS != 0 + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON + #else + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF + #endif #else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) + #elif SOL_IS_ON(SOL_DEBUG_BUILD) #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_ON #else #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_OFF #endif #endif -#if defined(SOL_SAFE_FUNCTION_CALLS) && (SOL_SAFE_FUNCTION_CALLS != 0) - #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON +#if defined(SOL_SAFE_FUNCTION_CALLS) + #if SOL_SAFE_FUNCTION_CALLS != 0 + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON + #else + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_OFF + #endif #else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) + #elif SOL_IS_ON(SOL_DEBUG_BUILD) #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_ON #else #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_OFF #endif #endif -#if defined(SOL_SAFE_PROXIES) && (SOL_SAFE_PROXIES != 0) - #define SOL_SAFE_PROXIES_I_ SOL_ON +#if defined(SOL_SAFE_PROXIES) + #if SOL_SAFE_PROXIES != 0 + #define SOL_SAFE_PROXIES_I_ SOL_ON + #else + #define SOL_SAFE_PROXIES_I_ SOL_OFF + #endif #else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) #define SOL_SAFE_PROXIES_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) + #elif SOL_IS_ON(SOL_DEBUG_BUILD) #define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_ON #else #define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_OFF #endif #endif -#if defined(SOL_SAFE_NUMERICS) && (SOL_SAFE_NUMERICS != 0) - #define SOL_SAFE_NUMERICS_I_ SOL_ON +#if defined(SOL_SAFE_NUMERICS) + #if SOL_SAFE_NUMERICS != 0 + #define SOL_SAFE_NUMERICS_I_ SOL_ON + #else + #define SOL_SAFE_NUMERICS_I_ SOL_OFF + #endif #else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) #define SOL_SAFE_NUMERICS_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) + #elif SOL_IS_ON(SOL_DEBUG_BUILD) #define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_ON #else #define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_OFF #endif #endif -#if defined(SOL_SAFE_STACK_CHECK) && (SOL_SAFE_STACK_CHECK != 0) - #define SOL_SAFE_STACK_CHECK_I_ SOL_ON +#if defined(SOL_ALL_INTEGER_VALUES_FIT) + #if (SOL_ALL_INTEGER_VALUES_FIT != 0) + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_ON + #else + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_OFF + #endif +#elif !SOL_IS_DEFAULT_OFF(SOL_SAFE_NUMERICS) && SOL_IS_OFF(SOL_SAFE_NUMERICS) + // if numerics is intentionally turned off, flip this on + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_DEFAULT_ON +#else + // default to off + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_SAFE_STACK_CHECK) + #if SOL_SAFE_STACK_CHECK != 0 + #define SOL_SAFE_STACK_CHECK_I_ SOL_ON + #else + #define SOL_SAFE_STACK_CHECK_I_ SOL_OFF + #endif #else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) #define SOL_SAFE_STACK_CHECK_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) + #elif SOL_IS_ON(SOL_DEBUG_BUILD) #define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_ON #else #define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_OFF #endif #endif -#if (defined(SOL_NO_CHECK_NUMBER_PRECISION) && (SOL_NO_CHECK_NUMBER_PRECISION != 0)) \ - || (defined(SOL_NO_CHECKING_NUMBER_PRECISION) && (SOL_NO_CHECKING_NUMBER_PRECISION != 0)) - #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF +#if defined(SOL_NO_CHECK_NUMBER_PRECISION) + #if SOL_NO_CHECK_NUMBER_PRECISION != 0 + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF + #else + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON + #endif +#elif defined(SOL_NO_CHECKING_NUMBER_PRECISION) + #if SOL_NO_CHECKING_NUMBER_PRECISION != 0 + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF + #else + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON + #endif #else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON - #elif SOL_IS_ON(SOL_SAFE_NUMERICS_I_) + #elif SOL_IS_ON(SOL_SAFE_NUMERICS) #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) + #elif SOL_IS_ON(SOL_DEBUG_BUILD) #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_ON #else #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_OFF @@ -319,9 +499,18 @@ #define SOL_STRINGS_ARE_NUMBERS_I_ SOL_DEFAULT_OFF #endif -#if defined(SOL_ENABLE_INTEROP) && (SOL_ENABLE_INTEROP != 0) \ - || defined(SOL_USE_INTEROP) && (SOL_USE_INTEROP != 0) - #define SOL_USE_INTEROP_I_ SOL_ON +#if defined(SOL_ENABLE_INTEROP) + #if SOL_ENABLE_INTEROP != 0 + #define SOL_USE_INTEROP_I_ SOL_ON + #else + #define SOL_USE_INTEROP_I_ SOL_OFF + #endif +#elif defined(SOL_USE_INTEROP) + #if SOL_USE_INTEROP != 0 + #define SOL_USE_INTEROP_I_ SOL_ON + #else + #define SOL_USE_INTEROP_I_ SOL_OFF + #endif #else #define SOL_USE_INTEROP_I_ SOL_DEFAULT_OFF #endif @@ -371,15 +560,15 @@ #define SOL_STD_VARIANT_I_ SOL_OFF #endif #else - #if SOL_IS_ON(SOL_COMPILER_CLANG_I_) && SOL_IS_ON(SOL_PLATFORM_APPLE_I_) + #if SOL_IS_ON(SOL_COMPILER_CLANG) && SOL_IS_ON(SOL_PLATFORM_APPLE) #if defined(__has_include) #if __has_include(<variant>) - #define SOL_STD_VARIANT_I_ SOL_ON + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_ON #else - #define SOL_STD_VARIANT_I_ SOL_OFF + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_OFF #endif #else - #define SOL_STD_VARIANT_I_ SOL_OFF + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_OFF #endif #else #define SOL_STD_VARIANT_I_ SOL_DEFAULT_ON @@ -395,7 +584,7 @@ #else #if defined(__cpp_noexcept_function_type) #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON - #elif SOL_IS_ON(SOL_COMPILER_VCXX_I_) && (defined(_MSVC_LANG) && (_MSVC_LANG < 201403L)) + #elif SOL_IS_ON(SOL_COMPILER_VCXX) && (defined(_MSVC_LANG) && (_MSVC_LANG < 201403L)) // There is a bug in the VC++ compiler?? // on /std:c++latest under x86 conditions (VS 15.5.2), // compiler errors are tossed for noexcept markings being on function types @@ -434,25 +623,23 @@ #define SOL_PRINT_ERRORS_I_ SOL_OFF #endif #else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) #define SOL_PRINT_ERRORS_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) + #elif SOL_IS_ON(SOL_DEBUG_BUILD) #define SOL_PRINT_ERRORS_I_ SOL_DEFAULT_ON #else #define SOL_PRINT_ERRORS_I_ SOL_OFF #endif #endif -#if defined(SOL_DEFAULT_PASS_ON_ERROR) && (SOL_DEFAULT_PASS_ON_ERROR != 0) - #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_ON -#else - #if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_) +#if defined(SOL_DEFAULT_PASS_ON_ERROR) + #if (SOL_DEFAULT_PASS_ON_ERROR != 0) #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_ON - #elif SOL_IS_ON(SOL_DEBUG_BUILD_I_) - #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_DEFAULT_ON #else #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_OFF #endif +#else + #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_DEFAULT_OFF #endif #if defined(SOL_USING_CXX_LUA) @@ -468,7 +655,7 @@ #define SOL_USE_CXX_LUA_I_ SOL_OFF #endif #else - #define SOL_USE_CXX_LUA_I_ SOL_OFF + #define SOL_USE_CXX_LUA_I_ SOL_DEFAULT_OFF #endif #if defined(SOL_USING_CXX_LUAJIT) @@ -484,7 +671,7 @@ #define SOL_USE_CXX_LUAJIT_I_ SOL_OFF #endif #else - #define SOL_USE_CXX_LUAJIT_I_ SOL_OFF + #define SOL_USE_CXX_LUAJIT_I_ SOL_DEFAULT_OFF #endif #if defined(SOL_NO_LUA_HPP) @@ -532,7 +719,7 @@ #define SOL_USE_BOOST_I_ SOL_OFF #endif #else - #define SOL_USE_BOOST_I_ SOL_OFF + #define SOL_USE_BOOST_I_ SOL_DEFAULT_OFF #endif #if defined(SOL_USE_UNSAFE_BASE_LOOKUP) @@ -542,7 +729,7 @@ #define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_OFF #endif #else - #define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_OFF + #define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_DEFAULT_OFF #endif #if defined(SOL_INSIDE_UNREAL) @@ -553,7 +740,7 @@ #endif #else #if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER) - #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_ON + #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_DEFAULT_ON #else #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_DEFAULT_OFF #endif @@ -579,31 +766,334 @@ #define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_DEFAULT_OFF #endif -#if SOL_IS_ON(SOL_COMPILER_FRONTEND_MINGW_I_) && defined(__GNUC__) && (__GNUC__ < 6) +#if defined(SOL_FUNCTION_CALL_VALUE_SEMANTICS) + #if (SOL_FUNCTION_CALL_VALUE_SEMANTICS != 0) + #define SOL_FUNCTION_CALL_VALUE_SEMANTICS_I_ SOL_ON + #else + #define SOL_FUNCTION_CALL_VALUE_SEMANTICS_I_ SOL_OFF + #endif +#else + #define SOL_FUNCTION_CALL_VALUE_SEMANTICS_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_MINGW_CCTYPE_IS_POISONED) + #if (SOL_MINGW_CCTYPE_IS_POISONED != 0) + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_ON + #else + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_OFF + #endif +#elif SOL_IS_ON(SOL_COMPILER_MINGW) && defined(__GNUC__) && (__GNUC__ < 6) // MinGW is off its rocker in some places... - #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_ON + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_DEFAULT_ON #else #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_DEFAULT_OFF #endif +#if defined(SOL_CHAR8_T) + #if (SOL_CHAR8_T != 0) + #define SOL_CHAR8_T_I_ SOL_ON + #else + #define SOL_CHAR8_T_I_ SOL_OFF + #endif +#else + #if defined(__cpp_char8_t) + #define SOL_CHAR8_T_I_ SOL_DEFAULT_ON + #else + #define SOL_CHAR8_T_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if SOL_IS_ON(SOL_USE_BOOST) + #include <boost/version.hpp> + + #if BOOST_VERSION >= 107500 // Since Boost 1.75.0 boost::none is constexpr + #define SOL_BOOST_NONE_CONSTEXPR_I_ constexpr + #else + #define SOL_BOOST_NONE_CONSTEXPR_I_ const + #endif // BOOST_VERSION +#else + // assume boost isn't using a garbage version + #define SOL_BOOST_NONE_CONSTEXPR_I_ constexpr +#endif + +#if defined(SOL2_CI) + #if (SOL2_CI != 0) + #define SOL2_CI_I_ SOL_ON + #else + #define SOL2_CI_I_ SOL_OFF + #endif +#else + #define SOL2_CI_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_C_ASSERT) + #define SOL_USER_C_ASSERT_I_ SOL_ON +#else + #define SOL_USER_C_ASSERT_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_M_ASSERT) + #define SOL_USER_M_ASSERT_I_ SOL_ON +#else + #define SOL_USER_M_ASSERT_I_ SOL_DEFAULT_OFF +#endif + +// beginning of sol/prologue.hpp + +#if defined(SOL_PROLOGUE_I_) + #error "[sol2] Library Prologue was already included in translation unit and not properly ended with an epilogue." +#endif + +#define SOL_PROLOGUE_I_ 1 + +#if SOL_IS_ON(SOL_BUILD_CXX_MODE) + #define _FWD(...) static_cast<decltype( __VA_ARGS__ )&&>( __VA_ARGS__ ) + + #if SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define _MOVE(...) static_cast<__typeof( __VA_ARGS__ )&&>( __VA_ARGS__ ) + #else + #include <type_traits> + + #define _MOVE(...) static_cast<::std::remove_reference_t<( __VA_ARGS__ )>&&>( __VA_OPT__(,) ) + #endif +#endif + +// end of sol/prologue.hpp + +// beginning of sol/epilogue.hpp + +#if !defined(SOL_PROLOGUE_I_) + #error "[sol2] Library Prologue is missing from this translation unit." +#else + #undef SOL_PROLOGUE_I_ +#endif + +#if SOL_IS_ON(SOL_BUILD_CXX_MODE) + #undef _FWD + #undef _MOVE +#endif + +// end of sol/epilogue.hpp + +// beginning of sol/detail/build_version.hpp + +#if defined(SOL_DLL) + #if (SOL_DLL != 0) + #define SOL_DLL_I_ SOL_ON + #else + #define SOL_DLL_I_ SOL_OFF + #endif +#elif SOL_IS_ON(SOL_COMPILER_VCXX) && (defined(DLL_) || defined(_DLL)) + #define SOL_DLL_I_ SOL_DEFAULT_ON +#else + #define SOL_DLL_I_ SOL_DEFAULT_OFF +#endif // DLL definition + +#if defined(SOL_HEADER_ONLY) + #if (SOL_HEADER_ONLY != 0) + #define SOL_HEADER_ONLY_I_ SOL_ON + #else + #define SOL_HEADER_ONLY_I_ SOL_OFF + #endif +#else + #define SOL_HEADER_ONLY_I_ SOL_DEFAULT_OFF +#endif // Header only library + +#if defined(SOL_BUILD) + #if (SOL_BUILD != 0) + #define SOL_BUILD_I_ SOL_ON + #else + #define SOL_BUILD_I_ SOL_OFF + #endif +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_BUILD_I_ SOL_DEFAULT_OFF +#else + #define SOL_BUILD_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_UNITY_BUILD) + #if (SOL_UNITY_BUILD != 0) + #define SOL_UNITY_BUILD_I_ SOL_ON + #else + #define SOL_UNITY_BUILD_I_ SOL_OFF + #endif +#else + #define SOL_UNITY_BUILD_I_ SOL_DEFAULT_OFF +#endif // Header only library + +#if defined(SOL_C_FUNCTION_LINKAGE) + #define SOL_C_FUNCTION_LINKAGE_I_ SOL_C_FUNCTION_LINKAGE +#else + #if SOL_IS_ON(SOL_BUILD_CXX_MODE) + // C++ + #define SOL_C_FUNCTION_LINKAGE_I_ extern "C" + #else + // normal + #define SOL_C_FUNCTION_LINKAGE_I_ + #endif // C++ or not +#endif // Linkage specification for C functions + +#if defined(SOL_API_LINKAGE) + #define SOL_API_LINKAGE_I_ SOL_API_LINKAGE +#else + #if SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) || SOL_IS_ON(SOL_PLATFORM_WINDOWS) || SOL_IS_ON(SOL_PLATFORM_CYGWIN) + // MSVC Compiler; or, Windows, or Cygwin platforms + #if SOL_IS_ON(SOL_BUILD) + // Building the library + #if SOL_IS_ON(SOL_COMPILER_GCC) + // Using GCC + #define SOL_API_LINKAGE_I_ __attribute__((dllexport)) + #else + // Using Clang, MSVC, etc... + #define SOL_API_LINKAGE_I_ __declspec(dllexport) + #endif + #else + #if SOL_IS_ON(SOL_COMPILER_GCC) + #define SOL_API_LINKAGE_I_ __attribute__((dllimport)) + #else + #define SOL_API_LINKAGE_I_ __declspec(dllimport) + #endif + #endif + #else + // extern if building normally on non-MSVC + #define SOL_API_LINKAGE_I_ extern + #endif + #elif SOL_IS_ON(SOL_UNITY_BUILD) + // Built-in library, like how stb typical works + #if SOL_IS_ON(SOL_HEADER_ONLY) + // Header only, so functions are defined "inline" + #define SOL_API_LINKAGE_I_ inline + #else + // Not header only, so seperately compiled files + #define SOL_API_LINKAGE_I_ extern + #endif + #else + // Normal static library + #if SOL_IS_ON(SOL_BUILD_CXX_MODE) + #define SOL_API_LINKAGE_I_ + #else + #define SOL_API_LINKAGE_I_ extern + #endif + #endif // DLL or not +#endif // Build definitions + +#if defined(SOL_PUBLIC_FUNC_DECL) + #define SOL_PUBLIC_FUNC_DECL_I_ SOL_PUBLIC_FUNC_DECL +#else + #define SOL_PUBLIC_FUNC_DECL_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_INTERNAL_FUNC_DECL_) + #define SOL_INTERNAL_FUNC_DECL_I_ SOL_INTERNAL_FUNC_DECL_ +#else + #define SOL_INTERNAL_FUNC_DECL_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_PUBLIC_FUNC_DEF) + #define SOL_PUBLIC_FUNC_DEF_I_ SOL_PUBLIC_FUNC_DEF +#else + #define SOL_PUBLIC_FUNC_DEF_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_INTERNAL_FUNC_DEF) + #define SOL_INTERNAL_FUNC_DEF_I_ SOL_INTERNAL_FUNC_DEF +#else + #define SOL_INTERNAL_FUNC_DEF_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_FUNC_DECL) + #define SOL_FUNC_DECL_I_ SOL_FUNC_DECL +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_FUNC_DECL_I_ +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_FUNC_DECL_I_ extern __declspec(dllexport) + #else + #define SOL_FUNC_DECL_I_ extern __declspec(dllimport) + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_FUNC_DECL_I_ extern __attribute__((visibility("default"))) + #else + #define SOL_FUNC_DECL_I_ extern + #endif +#endif + +#if defined(SOL_FUNC_DEFN) + #define SOL_FUNC_DEFN_I_ SOL_FUNC_DEFN +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_FUNC_DEFN_I_ inline +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_FUNC_DEFN_I_ __declspec(dllexport) + #else + #define SOL_FUNC_DEFN_I_ __declspec(dllimport) + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_FUNC_DEFN_I_ __attribute__((visibility("default"))) + #else + #define SOL_FUNC_DEFN_I_ + #endif +#endif + +#if defined(SOL_HIDDEN_FUNC_DECL) + #define SOL_HIDDEN_FUNC_DECL_I_ SOL_HIDDEN_FUNC_DECL +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_HIDDEN_FUNC_DECL_I_ +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_HIDDEN_FUNC_DECL_I_ extern __declspec(dllexport) + #else + #define SOL_HIDDEN_FUNC_DECL_I_ extern __declspec(dllimport) + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_HIDDEN_FUNC_DECL_I_ extern __attribute__((visibility("default"))) + #else + #define SOL_HIDDEN_FUNC_DECL_I_ extern + #endif +#endif + +#if defined(SOL_HIDDEN_FUNC_DEFN) + #define SOL_HIDDEN_FUNC_DEFN_I_ SOL_HIDDEN_FUNC_DEFN +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_HIDDEN_FUNC_DEFN_I_ inline +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_HIDDEN_FUNC_DEFN_I_ + #else + #define SOL_HIDDEN_FUNC_DEFN_I_ + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_HIDDEN_FUNC_DEFN_I_ __attribute__((visibility("hidden"))) + #else + #define SOL_HIDDEN_FUNC_DEFN_I_ + #endif +#endif + +// end of sol/detail/build_version.hpp + // end of sol/version.hpp -#if SOL_IS_ON(SOL_INSIDE_UNREAL_ENGINE_I_) +#if SOL_IS_ON(SOL_INSIDE_UNREAL_ENGINE) #ifdef check #pragma push_macro("check") #undef check #endif #endif // Unreal Engine 4 Bullshit -#if SOL_IS_ON(SOL_COMPILER_GCC_I_) +#if SOL_IS_ON(SOL_COMPILER_GCC) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Wconversion" #if __GNUC__ > 6 #pragma GCC diagnostic ignored "-Wnoexcept-type" #endif -#elif SOL_IS_ON(SOL_COMPILER_CLANG_I_) -#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#elif SOL_IS_ON(SOL_COMPILER_CLANG) +#elif SOL_IS_ON(SOL_COMPILER_VCXX) #pragma warning(push) #pragma warning(disable : 4505) // unreferenced local function has been removed GEE THANKS #endif // clang++ vs. g++ vs. VC++ @@ -617,7 +1107,7 @@ #include <type_traits> #include <string_view> -#if SOL_IS_ON(SOL_USE_CXX_LUA_I_) || SOL_IS_ON(SOL_USE_CXX_LUAJIT_I_) +#if SOL_IS_ON(SOL_USE_CXX_LUA) || SOL_IS_ON(SOL_USE_CXX_LUAJIT) struct lua_State; #else extern "C" { @@ -704,7 +1194,7 @@ namespace sol { using main_protected_function = main_safe_function; using stack_protected_function = stack_safe_function; using stack_aligned_protected_function = stack_aligned_safe_function; -#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS_I_) +#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS) using function = protected_function; using main_function = main_protected_function; using stack_function = stack_protected_function; @@ -720,7 +1210,7 @@ namespace sol { struct unsafe_function_result; struct protected_function_result; using safe_function_result = protected_function_result; -#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS_I_) +#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS) using function_result = safe_function_result; #else using function_result = unsafe_function_result; @@ -737,6 +1227,8 @@ namespace sol { template <typename base_t> class basic_coroutine; template <typename base_t> + class basic_packaged_coroutine; + template <typename base_t> class basic_thread; using object = basic_object<reference>; @@ -744,6 +1236,7 @@ namespace sol { using lightuserdata = basic_lightuserdata<reference>; using thread = basic_thread<reference>; using coroutine = basic_coroutine<reference>; + using packaged_coroutine = basic_packaged_coroutine<reference>; using main_object = basic_object<main_reference>; using main_userdata = basic_userdata<main_reference>; using main_lightuserdata = basic_lightuserdata<main_reference>; @@ -818,7 +1311,7 @@ namespace sol { struct record; } -#if SOL_IS_OFF(SOL_USE_BOOST_I_) +#if SOL_IS_OFF(SOL_USE_BOOST) template <class T> class optional; @@ -865,15 +1358,15 @@ namespace sol { namespace sol { namespace detail { - struct unchecked_t {}; - const unchecked_t unchecked = unchecked_t{}; + struct unchecked_t { }; + const unchecked_t unchecked = unchecked_t {}; } // namespace detail namespace meta { using sfinae_yes_t = std::true_type; using sfinae_no_t = std::false_type; - template <typename T> + template <typename...> using void_t = void; template <typename T> @@ -884,13 +1377,13 @@ namespace sol { namespace meta_detail { template <typename T> - struct unqualified_non_alias : unqualified<T> {}; + struct unqualified_non_alias : unqualified<T> { }; template <template <class...> class Test, class, class... Args> - struct is_detected : std::false_type {}; + struct is_detected : std::false_type { }; template <template <class...> class Test, class... Args> - struct is_detected<Test, void_t<Test<Args...>>, Args...> : std::true_type {}; + struct is_detected<Test, void_t<Test<Args...>>, Args...> : std::true_type { }; } // namespace meta_detail template <template <class...> class Trait, class... Args> @@ -919,9 +1412,9 @@ namespace sol { namespace meta_detail { template <typename T, template <typename...> class Templ> - struct is_specialization_of : std::false_type {}; + struct is_specialization_of : std::false_type { }; template <typename... T, template <typename...> class Templ> - struct is_specialization_of<Templ<T...>, Templ> : std::true_type {}; + struct is_specialization_of<Templ<T...>, Templ> : std::true_type { }; } // namespace meta_detail template <typename T, template <typename...> class Templ> @@ -941,6 +1434,19 @@ namespace sol { template <typename T> using is_builtin_type = std::integral_constant<bool, std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_array<T>::value>; + namespace meta_detail { + template <typename T, typename = void> + struct has_internal_marker_impl : std::false_type { }; + template <typename T> + struct has_internal_marker_impl<T, void_t<typename T::SOL_INTERNAL_UNSPECIALIZED_MARKER_>> : std::true_type { }; + + template <typename T> + using has_internal_marker = has_internal_marker_impl<T>; + + template <typename T> + constexpr inline bool has_internal_marker_v = has_internal_marker<T>::value; + } // namespace meta_detail + } // namespace meta } // namespace sol @@ -963,10 +1469,14 @@ namespace sol { namespace detail { template <typename... Args> - struct tuple_types_ { typedef types<Args...> type; }; + struct tuple_types_ { + typedef types<Args...> type; + }; template <typename... Args> - struct tuple_types_<std::tuple<Args...>> { typedef types<Args...> type; }; + struct tuple_types_<std::tuple<Args...>> { + typedef types<Args...> type; + }; } // namespace detail template <typename... Args> @@ -1011,26 +1521,20 @@ namespace sol { namespace sol { namespace meta { namespace meta_detail { - - template <class F> - struct check_deducible_signature { - struct nat {}; - template <class G> - static auto test(int) -> decltype(&G::operator(), void()); - template <class> - static auto test(...) -> nat; - - using type = std::is_void<decltype(test<F>(0))>; - }; + template <typename F> + using detect_deducible_signature = decltype(&F::operator()); } // namespace meta_detail - template <class F> - struct has_deducible_signature : meta_detail::check_deducible_signature<F>::type {}; + template <typename F> + using call_operator_deducible = typename is_detected<meta_detail::detect_deducible_signature, F>::type; + + template <typename F> + constexpr inline bool call_operator_deducible_v = call_operator_deducible<F>::value; namespace meta_detail { template <std::size_t I, typename T> - struct void_tuple_element : meta::tuple_element<I, T> {}; + struct void_tuple_element : meta::tuple_element<I, T> { }; template <std::size_t I> struct void_tuple_element<I, std::tuple<>> { @@ -1065,429 +1569,427 @@ namespace sol { namespace meta { using arg_at = void_tuple_element_t<i, args_tuple>; }; - template <typename Signature, bool b = has_deducible_signature<Signature>::value> - struct fx_traits : basic_traits<false, false, void, void> {}; + template <typename Signature, bool b = call_operator_deducible<Signature>::value> + struct fx_traits : public basic_traits<false, false, void, void> { }; // Free Functions template <typename R, typename... Args> - struct fx_traits<R(Args...), false> : basic_traits<false, false, void, R, Args...> { + struct fx_traits<R(Args...), false> : public basic_traits<false, false, void, R, Args...> { typedef R (*function_pointer_type)(Args...); }; template <typename R, typename... Args> - struct fx_traits<R (*)(Args...), false> : basic_traits<false, false, void, R, Args...> { + struct fx_traits<R (*)(Args...), false> : public basic_traits<false, false, void, R, Args...> { typedef R (*function_pointer_type)(Args...); }; template <typename R, typename... Args> - struct fx_traits<R(Args..., ...), false> : basic_traits<false, true, void, R, Args...> { + struct fx_traits<R(Args..., ...), false> : public basic_traits<false, true, void, R, Args...> { typedef R (*function_pointer_type)(Args..., ...); }; template <typename R, typename... Args> - struct fx_traits<R (*)(Args..., ...), false> : basic_traits<false, true, void, R, Args...> { + struct fx_traits<R (*)(Args..., ...), false> : public basic_traits<false, true, void, R, Args...> { typedef R (*function_pointer_type)(Args..., ...); }; // Member Functions /* C-Style Variadics */ template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...), false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...), false> : public basic_traits<false, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...); }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...), false> : basic_traits<false, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...), false> : public basic_traits<false, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...); }; /* Const Volatile */ template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const, false> : public basic_traits<false, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const, false> : basic_traits<false, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const, false> : public basic_traits<false, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const volatile, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const volatile, false> : public basic_traits<false, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const volatile; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const volatile, false> : basic_traits<false, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const volatile, false> : public basic_traits<false, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const volatile; }; /* Member Function Qualifiers */ template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...)&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...)&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) &; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...)&, false> : basic_traits<false, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...)&, false> : public basic_traits<false, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) &; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const&, false> : basic_traits<false, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const&, false> : public basic_traits<false, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const volatile&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const volatile&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const volatile&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const volatile&, false> : basic_traits<false, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const volatile&, false> : public basic_traits<false, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const volatile&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...)&&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...)&&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) &&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...)&&, false> : basic_traits<false, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...)&&, false> : public basic_traits<false, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) &&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const&&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const&&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const&&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const&&, false> : basic_traits<false, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const&&, false> : public basic_traits<false, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const&&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const volatile&&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const volatile&&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const volatile&&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const volatile&&, false> : basic_traits<false, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const volatile&&, false> : public basic_traits<false, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const volatile&&; }; -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) template <typename R, typename... Args> - struct fx_traits<R(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> { + struct fx_traits<R(Args...) noexcept, false> : public basic_traits<true, false, void, R, Args...> { typedef R (*function_pointer_type)(Args...) noexcept; }; template <typename R, typename... Args> - struct fx_traits<R (*)(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> { + struct fx_traits<R (*)(Args...) noexcept, false> : public basic_traits<true, false, void, R, Args...> { typedef R (*function_pointer_type)(Args...) noexcept; }; template <typename R, typename... Args> - struct fx_traits<R(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> { + struct fx_traits<R(Args..., ...) noexcept, false> : public basic_traits<true, true, void, R, Args...> { typedef R (*function_pointer_type)(Args..., ...) noexcept; }; template <typename R, typename... Args> - struct fx_traits<R (*)(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> { + struct fx_traits<R (*)(Args..., ...) noexcept, false> : public basic_traits<true, true, void, R, Args...> { typedef R (*function_pointer_type)(Args..., ...) noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) noexcept; }; /* Const Volatile */ template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const volatile noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const volatile noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const volatile noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const volatile noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const volatile noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const volatile noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) & noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...)& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) & noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) & noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...)& noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) & noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const& noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const& noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const& noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const& noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const& noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const volatile& noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const volatile& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const volatile& noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const volatile& noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const volatile& noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const volatile& noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) && noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...)&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) && noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) && noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...)&& noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) && noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const&& noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const&& noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const&& noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const&& noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const&& noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args...) const volatile&& noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (T::*)(Args...) const volatile&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (T::*function_pointer_type)(Args...) const volatile&& noexcept; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (T::*)(Args..., ...) const volatile&& noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (T::*)(Args..., ...) const volatile&& noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (T::*function_pointer_type)(Args..., ...) const volatile&& noexcept; }; #endif // noexcept is part of a function's type -#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) && SOL_IS_ON(SOL_PLATFORM_X86_I_) +#if SOL_IS_ON(SOL_COMPILER_VCXX) && SOL_IS_ON(SOL_PLATFORM_X86) template <typename R, typename... Args> - struct fx_traits<R __stdcall(Args...), false> : basic_traits<false, false, void, R, Args...> { + struct fx_traits<R __stdcall(Args...), false> : public basic_traits<false, false, void, R, Args...> { typedef R(__stdcall* function_pointer_type)(Args...); }; template <typename R, typename... Args> - struct fx_traits<R(__stdcall*)(Args...), false> : basic_traits<false, false, void, R, Args...> { + struct fx_traits<R(__stdcall*)(Args...), false> : public basic_traits<false, false, void, R, Args...> { typedef R(__stdcall* function_pointer_type)(Args...); }; template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...), false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...), false> : public basic_traits<false, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...); }; /* Const Volatile */ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const, false> : public basic_traits<false, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const volatile, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const volatile, false> : public basic_traits<false, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile; }; /* Member Function Qualifiers */ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...)&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...)&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) &; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const volatile&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const volatile&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...)&&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...)&&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) &&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const&&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const&&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const&&; }; template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const volatile&&, false> : basic_traits<false, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const volatile&&, false> : public basic_traits<false, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&&; }; -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) template <typename R, typename... Args> - struct fx_traits<R __stdcall(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> { + struct fx_traits<R __stdcall(Args...) noexcept, false> : public basic_traits<true, false, void, R, Args...> { typedef R(__stdcall* function_pointer_type)(Args...) noexcept; }; template <typename R, typename... Args> - struct fx_traits<R(__stdcall*)(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> { + struct fx_traits<R(__stdcall*)(Args...) noexcept, false> : public basic_traits<true, false, void, R, Args...> { typedef R(__stdcall* function_pointer_type)(Args...) noexcept; }; /* __stdcall cannot be applied to functions with varargs*/ /*template <typename R, typename... Args> - struct fx_traits<__stdcall R(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> { + struct fx_traits<__stdcall R(Args..., ...) noexcept, false> : public basic_traits<true, true, void, R, Args...> { typedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept; }; template <typename R, typename... Args> - struct fx_traits<R (__stdcall *)(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> { + struct fx_traits<R (__stdcall *)(Args..., ...) noexcept, false> : public basic_traits<true, true, void, R, Args...> { typedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept; };*/ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) noexcept; }; /* __stdcall does not work with varargs */ /*template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args..., ...) noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args..., ...) noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) noexcept; };*/ /* Const Volatile */ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const noexcept; }; /* __stdcall does not work with varargs */ /*template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args..., ...) const noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args..., ...) const noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const noexcept; };*/ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const volatile noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const volatile noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile noexcept; }; /* __stdcall does not work with varargs */ /*template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile noexcept; };*/ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) & noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...)& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) & noexcept; }; /* __stdcall does not work with varargs */ /*template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args..., ...) & noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args..., ...) & noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) & noexcept; };*/ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const& noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const& noexcept; }; /* __stdcall does not work with varargs */ /*template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args..., ...) const& noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args..., ...) const& noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const& noexcept; };*/ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const volatile& noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const volatile& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile& noexcept; }; /* __stdcall does not work with varargs */ /*template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile& noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile& noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile& noexcept; };*/ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) && noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...)&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) && noexcept; }; /* __stdcall does not work with varargs */ /*template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args..., ...) && noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args..., ...) && noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) && noexcept; };*/ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const&& noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const&& noexcept; }; /* __stdcall does not work with varargs */ /*template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args..., ...) const&& noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args..., ...) const&& noexcept, false> : public basic_traits<true, true, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const&& noexcept; };*/ template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args...) const volatile&& noexcept, false> : basic_traits<true, false, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args...) const volatile&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&& noexcept; }; /* __stdcall does not work with varargs */ /*template <typename T, typename R, typename... Args> - struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile&& noexcept, false> : basic_traits<true, true, T, R, Args...> { + struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile&& noexcept, false> : public basic_traits<true, true, T, R, Args...> { 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 template <typename Signature> - struct fx_traits<Signature, true> - : public fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> {}; + struct fx_traits<Signature, true> : public fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> { }; template <typename Signature, bool b = std::is_member_object_pointer<Signature>::value> - struct callable_traits - : public fx_traits<std::decay_t<Signature>> {}; + struct callable_traits : public fx_traits<std::decay_t<Signature>> { }; template <typename R, typename T> struct callable_traits<R(T::*), true> { @@ -1513,7 +2015,21 @@ namespace sol { namespace meta { } // namespace meta_detail template <typename Signature> - struct bind_traits : meta_detail::callable_traits<Signature> {}; + using bind_traits = meta_detail::callable_traits<Signature>; + + namespace meta_detail { + template <typename, bool> + struct is_probably_stateless_lambda : std::false_type { }; + + template <typename T> + struct is_probably_stateless_lambda<T, true> : std::is_convertible<T, typename bind_traits<T>::function_type*>::type { }; + } // namespace meta_detail + + template <typename T> + using is_probably_stateless_lambda = typename meta_detail::is_probably_stateless_lambda<T, std::is_empty_v<T> && call_operator_deducible_v<T>>::type; + + template <typename T> + inline constexpr bool is_probably_stateless_lambda_v = is_probably_stateless_lambda<T>::value; template <typename Signature> using function_args_t = typename bind_traits<Signature>::args_list; @@ -1531,6 +2047,7 @@ namespace sol { namespace meta { #include <utility> #include <type_traits> +#include <memory> namespace sol { @@ -1541,10 +2058,11 @@ namespace sol { template <typename T> using is_explicitly_dereferenceable_test = decltype(std::declval<T>().operator*()); - } + } // namespace meta_detail template <typename T> - using is_pointer_like = std::integral_constant<bool, !std::is_array_v<T> && (std::is_pointer_v<T> || is_detected_v<meta_detail::is_explicitly_dereferenceable_test, T>)>; + using is_pointer_like = std::integral_constant<bool, + !std::is_array_v<T> && (std::is_pointer_v<T> || is_detected_v<meta_detail::is_explicitly_dereferenceable_test, T>)>; template <typename T> constexpr inline bool is_pointer_like_v = is_pointer_like<T>::value; @@ -1630,7 +2148,7 @@ namespace sol { #include <array> #include <iterator> #include <iosfwd> -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#if SOL_IS_ON(SOL_STD_VARIANT) #include <variant> #endif // variant is weird on XCode, thanks XCode @@ -1649,7 +2167,7 @@ namespace sol { namespace meta { using unwrapped_t = typename unwrapped<T>::type; template <typename T> - struct unwrap_unqualified : unwrapped<unqualified_t<T>> {}; + struct unwrap_unqualified : unwrapped<unqualified_t<T>> { }; template <typename T> using unwrap_unqualified_t = typename unwrap_unqualified<T>::type; @@ -1671,16 +2189,16 @@ namespace sol { namespace meta { using remove_member_pointer_t = remove_member_pointer<T>; template <typename T, typename...> - struct all_same : std::true_type {}; + struct all_same : std::true_type { }; template <typename T, typename U, typename... Args> - struct all_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value && all_same<T, Args...>::value> {}; + struct all_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value && all_same<T, Args...>::value> { }; template <typename T, typename...> - struct any_same : std::false_type {}; + struct any_same : std::false_type { }; template <typename T, typename U, typename... Args> - struct any_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value || any_same<T, Args...>::value> {}; + struct any_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value || any_same<T, Args...>::value> { }; template <typename T, typename... Args> constexpr inline bool any_same_v = any_same<T, Args...>::value; @@ -1698,22 +2216,22 @@ namespace sol { namespace meta { constexpr inline bool neg_v = neg<T>::value; template <typename... Args> - struct all : boolean<true> {}; + struct all : boolean<true> { }; template <typename T, typename... Args> - struct all<T, Args...> : std::conditional_t<T::value, all<Args...>, boolean<false>> {}; + struct all<T, Args...> : std::conditional_t<T::value, all<Args...>, boolean<false>> { }; template <typename... Args> - struct any : boolean<false> {}; + struct any : boolean<false> { }; template <typename T, typename... Args> - struct any<T, Args...> : std::conditional_t<T::value, boolean<true>, any<Args...>> {}; + struct any<T, Args...> : std::conditional_t<T::value, boolean<true>, any<Args...>> { }; - template <typename T, typename... Args> - constexpr inline bool all_v = all<T, Args...>::value; + template <typename... Args> + constexpr inline bool all_v = all<Args...>::value; - template <typename T, typename... Args> - constexpr inline bool any_v = any<T, Args...>::value; + template <typename... Args> + constexpr inline bool any_v = any<Args...>::value; enum class enable_t { _ }; @@ -1735,37 +2253,37 @@ namespace sol { namespace meta { using disable_any = std::enable_if_t<neg<any<Args...>>::value, enable_t>; template <typename V, typename... Vs> - struct find_in_pack_v : boolean<false> {}; + struct find_in_pack_v : boolean<false> { }; template <typename V, typename Vs1, typename... Vs> - struct find_in_pack_v<V, Vs1, Vs...> : any<boolean<(V::value == Vs1::value)>, find_in_pack_v<V, Vs...>> {}; + struct find_in_pack_v<V, Vs1, Vs...> : any<boolean<(V::value == Vs1::value)>, find_in_pack_v<V, Vs...>> { }; namespace meta_detail { template <std::size_t I, typename T, typename... Args> - struct index_in_pack : std::integral_constant<std::size_t, SIZE_MAX> {}; + struct index_in_pack : std::integral_constant<std::size_t, SIZE_MAX> { }; template <std::size_t I, typename T, typename T1, typename... Args> struct index_in_pack<I, T, T1, Args...> - : conditional_t<std::is_same<T, T1>::value, std::integral_constant<std::ptrdiff_t, I>, index_in_pack<I + 1, T, Args...>> {}; + : conditional_t<std::is_same<T, T1>::value, std::integral_constant<std::ptrdiff_t, I>, index_in_pack<I + 1, T, Args...>> { }; } // namespace meta_detail template <typename T, typename... Args> - struct index_in_pack : meta_detail::index_in_pack<0, T, Args...> {}; + struct index_in_pack : meta_detail::index_in_pack<0, T, Args...> { }; template <typename T, typename List> - struct index_in : meta_detail::index_in_pack<0, T, List> {}; + struct index_in : meta_detail::index_in_pack<0, T, List> { }; template <typename T, typename... Args> - struct index_in<T, types<Args...>> : meta_detail::index_in_pack<0, T, Args...> {}; + struct index_in<T, types<Args...>> : meta_detail::index_in_pack<0, T, Args...> { }; template <std::size_t I, typename... Args> - struct at_in_pack {}; + struct at_in_pack { }; template <std::size_t I, typename... Args> using at_in_pack_t = typename at_in_pack<I, Args...>::type; template <std::size_t I, typename Arg, typename... Args> - struct at_in_pack<I, Arg, Args...> : std::conditional<I == 0, Arg, at_in_pack_t<I - 1, Args...>> {}; + struct at_in_pack<I, Arg, Args...> : std::conditional<I == 0, Arg, at_in_pack_t<I - 1, Args...>> { }; template <typename Arg, typename... Args> struct at_in_pack<0, Arg, Args...> { @@ -1783,17 +2301,17 @@ namespace sol { namespace meta { using on_always = std::true_type; template <template <typename...> class When, std::size_t Limit, std::size_t I, template <typename...> class Pred, typename... Ts> - struct count_when_for_pack : std::integral_constant<std::size_t, 0> {}; + struct count_when_for_pack : std::integral_constant<std::size_t, 0> { }; template <template <typename...> class When, std::size_t Limit, std::size_t I, template <typename...> class Pred, typename T, typename... Ts> struct count_when_for_pack<When, Limit, I, Pred, T, Ts...> : conditional_t < sizeof...(Ts) == 0 || Limit<2, std::integral_constant<std::size_t, I + static_cast<std::size_t>(Limit != 0 && Pred<T>::value)>, count_when_for_pack<When, Limit - static_cast<std::size_t>(When<T, std::integral_constant<std::size_t, I>>::value), - I + static_cast<std::size_t>(When<T, std::integral_constant<std::size_t, I>>::value&& Pred<T>::value), Pred, Ts...>> {}; + I + static_cast<std::size_t>(When<T, std::integral_constant<std::size_t, I>>::value&& Pred<T>::value), Pred, Ts...>> { }; } // namespace meta_detail template <template <typename...> class Pred, typename... Ts> - struct count_for_pack : meta_detail::count_when_for_pack<meta_detail::on_always, sizeof...(Ts), 0, Pred, Ts...> {}; + struct count_for_pack : meta_detail::count_when_for_pack<meta_detail::on_always, sizeof...(Ts), 0, Pred, Ts...> { }; template <template <typename...> class Pred, typename... Ts> inline constexpr std::size_t count_for_pack_v = count_for_pack<Pred, Ts...>::value; @@ -1802,16 +2320,16 @@ namespace sol { namespace meta { struct count_for; template <template <typename...> class Pred, typename... Args> - struct count_for<Pred, types<Args...>> : count_for_pack<Pred, Args...> {}; + struct count_for<Pred, types<Args...>> : count_for_pack<Pred, Args...> { }; template <std::size_t Limit, template <typename...> class Pred, typename... Ts> - struct count_for_to_pack : meta_detail::count_when_for_pack<meta_detail::on_always, Limit, 0, Pred, Ts...> {}; + struct count_for_to_pack : meta_detail::count_when_for_pack<meta_detail::on_always, Limit, 0, Pred, Ts...> { }; template <std::size_t Limit, template <typename...> class Pred, typename... Ts> inline constexpr std::size_t count_for_to_pack_v = count_for_to_pack<Limit, Pred, Ts...>::value; template <template <typename...> class When, std::size_t Limit, template <typename...> class Pred, typename... Ts> - struct count_when_for_to_pack : meta_detail::count_when_for_pack<When, Limit, 0, Pred, Ts...> {}; + struct count_when_for_to_pack : meta_detail::count_when_for_pack<When, Limit, 0, Pred, Ts...> { }; template <template <typename...> class When, std::size_t Limit, template <typename...> class Pred, typename... Ts> inline constexpr std::size_t count_when_for_to_pack_v = count_when_for_to_pack<When, Limit, Pred, Ts...>::value; @@ -1848,7 +2366,7 @@ namespace sol { namespace meta { namespace meta_detail { template <typename> - struct always_true : std::true_type {}; + struct always_true : std::true_type { }; struct is_invokable_tester { template <typename Fun, typename... Args> static always_true<decltype(std::declval<Fun>()(std::declval<Args>()...))> test(int); @@ -1860,26 +2378,26 @@ namespace sol { namespace meta { template <typename T> struct is_invokable; template <typename Fun, typename... Args> - struct is_invokable<Fun(Args...)> : decltype(meta_detail::is_invokable_tester::test<Fun, Args...>(0)) {}; + struct is_invokable<Fun(Args...)> : decltype(meta_detail::is_invokable_tester::test<Fun, Args...>(0)) { }; namespace meta_detail { template <typename T, typename = void> - struct is_callable : std::is_function<std::remove_pointer_t<T>> {}; + struct is_invocable : std::is_function<std::remove_pointer_t<T>> { }; template <typename T> - struct is_callable<T, + struct is_invocable<T, std::enable_if_t<std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value - && std::is_same<decltype(void(&T::operator())), void>::value>> {}; + && std::is_same<decltype(void(&T::operator())), void>::value>> { }; template <typename T> - struct is_callable<T, + struct is_invocable<T, std::enable_if_t<!std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value && std::is_destructible<unqualified_t<T>>::value>> { struct F { void operator()() {}; }; - struct Derived : T, F {}; + struct Derived : T, F { }; template <typename U, U> struct Check; @@ -1893,7 +2411,7 @@ namespace sol { namespace meta { }; template <typename T> - struct is_callable<T, + struct is_invocable<T, std::enable_if_t<!std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value && !std::is_destructible<unqualified_t<T>>::value>> { struct F { @@ -1993,16 +2511,28 @@ namespace sol { namespace meta { }; template <typename T> + struct has_insert_with_iterator_test { + private: + template <typename C> + static sfinae_yes_t test(decltype(std::declval<C>().insert( + std::declval<std::add_rvalue_reference_t<typename C::iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); + template <typename C> + static sfinae_no_t test(...); + + public: + static constexpr bool value = !std::is_same_v<decltype(test<T>(0)), sfinae_no_t>; + }; + + template <typename T> struct has_insert_test { private: template <typename C> - static sfinae_yes_t test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), - std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); + static sfinae_yes_t test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); template <typename C> static sfinae_no_t test(...); public: - static constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>; + static constexpr bool value = !std::is_same_v<decltype(test<T>(0)), sfinae_no_t>; }; template <typename T> @@ -2055,95 +2585,113 @@ namespace sol { namespace meta { }; template <typename T, typename U, typename = void> - class supports_op_less_test : public std::false_type {}; + class supports_op_less_test : public std::false_type { }; template <typename T, typename U> class supports_op_less_test<T, U, void_t<decltype(std::declval<T&>() < std::declval<U&>())>> : public std::integral_constant<bool, - !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant>> {}; +#if SOL_IS_ON(SOL_STD_VARIANT) + !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant> +#else + true +#endif + > { + }; template <typename T, typename U, typename = void> - class supports_op_equal_test : public std::false_type {}; + class supports_op_equal_test : public std::false_type { }; template <typename T, typename U> class supports_op_equal_test<T, U, void_t<decltype(std::declval<T&>() == std::declval<U&>())>> : public std::integral_constant<bool, - !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant>> {}; +#if SOL_IS_ON(SOL_STD_VARIANT) + !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant> +#else + true +#endif + > { + }; template <typename T, typename U, typename = void> - class supports_op_less_equal_test : public std::false_type {}; + class supports_op_less_equal_test : public std::false_type { }; template <typename T, typename U> class supports_op_less_equal_test<T, U, void_t<decltype(std::declval<T&>() <= std::declval<U&>())>> : public std::integral_constant<bool, - !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant>> {}; +#if SOL_IS_ON(SOL_STD_VARIANT) + !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant> +#else + true +#endif + > { + }; template <typename T, typename U, typename = void> - class supports_op_left_shift_test : public std::false_type {}; + class supports_op_left_shift_test : public std::false_type { }; template <typename T, typename U> - class supports_op_left_shift_test<T, U, void_t<decltype(std::declval<T&>() << std::declval<U&>())>> : public std::true_type {}; + class supports_op_left_shift_test<T, U, void_t<decltype(std::declval<T&>() << std::declval<U&>())>> : public std::true_type { }; template <typename T, typename = void> - class supports_adl_to_string_test : public std::false_type {}; + class supports_adl_to_string_test : public std::false_type { }; template <typename T> - class supports_adl_to_string_test<T, void_t<decltype(to_string(std::declval<const T&>()))>> : public std::true_type {}; + class supports_adl_to_string_test<T, void_t<decltype(to_string(std::declval<const T&>()))>> : public std::true_type { }; template <typename T, bool b> - struct is_matched_lookup_impl : std::false_type {}; + struct is_matched_lookup_impl : std::false_type { }; template <typename T> - struct is_matched_lookup_impl<T, true> : std::is_same<typename T::key_type, typename T::value_type> {}; + struct is_matched_lookup_impl<T, true> : std::is_same<typename T::key_type, typename T::value_type> { }; template <typename T> using non_void_t = meta::conditional_t<std::is_void_v<T>, ::sol::detail::unchecked_t, T>; } // namespace meta_detail template <typename T, typename U = T> - class supports_op_less : public meta_detail::supports_op_less_test<T, U> {}; + class supports_op_less : public meta_detail::supports_op_less_test<T, U> { }; template <typename T, typename U = T> - class supports_op_equal : public meta_detail::supports_op_equal_test<T, U> {}; + class supports_op_equal : public meta_detail::supports_op_equal_test<T, U> { }; template <typename T, typename U = T> - class supports_op_less_equal : public meta_detail::supports_op_less_equal_test<T, U> {}; + class supports_op_less_equal : public meta_detail::supports_op_less_equal_test<T, U> { }; template <typename T, typename U = T> - class supports_op_left_shift : public meta_detail::supports_op_left_shift_test<T, U> {}; + class supports_op_left_shift : public meta_detail::supports_op_left_shift_test<T, U> { }; template <typename T> - class supports_adl_to_string : public meta_detail::supports_adl_to_string_test<T> {}; + class supports_adl_to_string : public meta_detail::supports_adl_to_string_test<T> { }; template <typename T> - class supports_to_string_member : public meta::boolean<meta_detail::has_to_string_test<meta_detail::non_void_t<T>>::value> {}; + class supports_to_string_member : public meta::boolean<meta_detail::has_to_string_test<meta_detail::non_void_t<T>>::value> { }; template <typename T> - using is_callable = boolean<meta_detail::is_callable<T>::value>; + using is_invocable = boolean<meta_detail::is_invocable<T>::value>; template <typename T> - constexpr inline bool is_callable_v = is_callable<T>::value; + constexpr inline bool is_invocable_v = is_invocable<T>::value; template <typename T> - struct has_begin_end : decltype(meta_detail::has_begin_end_impl::test<T>(0)) {}; + struct has_begin_end : decltype(meta_detail::has_begin_end_impl::test<T>(0)) { }; template <typename T> constexpr inline bool has_begin_end_v = has_begin_end<T>::value; template <typename T> - struct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test<T>(0)) {}; + struct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test<T>(0)) { }; template <typename T> - struct has_key_type : decltype(meta_detail::has_key_type_impl::test<T>(0)) {}; + struct has_key_type : decltype(meta_detail::has_key_type_impl::test<T>(0)) { }; template <typename T> - struct has_key_comp : decltype(meta_detail::has_key_comp_impl::test<T>(0)) {}; + struct has_key_comp : decltype(meta_detail::has_key_comp_impl::test<T>(0)) { }; template <typename T> - struct has_load_factor : decltype(meta_detail::has_load_factor_impl::test<T>(0)) {}; + struct has_load_factor : decltype(meta_detail::has_load_factor_impl::test<T>(0)) { }; template <typename T> - struct has_mapped_type : decltype(meta_detail::has_mapped_type_impl::test<T>(0)) {}; + struct has_mapped_type : decltype(meta_detail::has_mapped_type_impl::test<T>(0)) { }; template <typename T> - struct has_iterator : decltype(meta_detail::has_iterator_impl::test<T>(0)) {}; + struct has_iterator : decltype(meta_detail::has_iterator_impl::test<T>(0)) { }; template <typename T> - struct has_value_type : decltype(meta_detail::has_value_type_impl::test<T>(0)) {}; + struct has_value_type : decltype(meta_detail::has_value_type_impl::test<T>(0)) { }; template <typename T> using has_push_back = meta::boolean<meta_detail::has_push_back_test<T>::value>; @@ -2155,6 +2703,9 @@ namespace sol { namespace meta { using has_insert = meta::boolean<meta_detail::has_insert_test<T>::value>; template <typename T> + using has_insert_with_iterator = meta::boolean<meta_detail::has_insert_with_iterator_test<T>::value>; + + template <typename T> using has_insert_after = meta::boolean<meta_detail::has_insert_after_test<T>::value>; template <typename T> @@ -2185,25 +2736,29 @@ namespace sol { namespace meta { constexpr inline bool is_string_literal_array_of_v = is_string_literal_array_of<T, CharT>::value; template <typename T> - using is_string_literal_array = boolean<std::is_array_v<T> && any_same_v<std::remove_all_extents_t<T>, char, char16_t, char32_t, wchar_t>>; + using is_string_literal_array = boolean<std::is_array_v<T> && any_same_v<std::remove_all_extents_t<T>, char, +#if SOL_IS_ON(SOL_CHAR8_T) + char8_t, +#endif + char16_t, char32_t, wchar_t>>; template <typename T> constexpr inline bool is_string_literal_array_v = is_string_literal_array<T>::value; template <typename T, typename CharT> - struct is_string_of : std::false_type {}; + struct is_string_of : std::false_type { }; template <typename CharT, typename CharTargetT, typename TraitsT, typename AllocT> - struct is_string_of<std::basic_string<CharT, TraitsT, AllocT>, CharTargetT> : std::is_same<CharT, CharTargetT> {}; + struct is_string_of<std::basic_string<CharT, TraitsT, AllocT>, CharTargetT> : std::is_same<CharT, CharTargetT> { }; template <typename T, typename CharT> constexpr inline bool is_string_of_v = is_string_of<T, CharT>::value; template <typename T, typename CharT> - struct is_string_view_of : std::false_type {}; + struct is_string_view_of : std::false_type { }; template <typename CharT, typename CharTargetT, typename TraitsT> - struct is_string_view_of<std::basic_string_view<CharT, TraitsT>, CharTargetT> : std::is_same<CharT, CharTargetT> {}; + struct is_string_view_of<std::basic_string_view<CharT, TraitsT>, CharTargetT> : std::is_same<CharT, CharTargetT> { }; template <typename T, typename CharT> constexpr inline bool is_string_view_of_v = is_string_view_of<T, CharT>::value; @@ -2218,7 +2773,7 @@ namespace sol { namespace meta { template <typename T, typename CharT = char> using is_string_constructible = meta::boolean< is_string_literal_array_of_v<T, - CharT> || std::is_same_v<T, const CharT*> || std::is_same_v<T, CharT> || is_string_of_v<T, CharT> || std::is_same_v<T, std::initializer_list<CharT>> || is_string_view_of_v<T, CharT>>; + CharT> || std::is_same_v<T, const CharT*> || std::is_same_v<T, CharT> || is_string_of_v<T, CharT> || std::is_same_v<T, std::initializer_list<CharT>> || is_string_view_of_v<T, CharT> || std::is_null_pointer_v<T>>; template <typename T, typename CharT = char> constexpr inline bool is_string_constructible_v = is_string_constructible<T, CharT>::value; @@ -2227,14 +2782,13 @@ namespace sol { namespace meta { using is_string_like_or_constructible = meta::boolean<is_string_like_v<T> || is_string_constructible_v<T>>; template <typename T> - struct is_pair : std::false_type {}; + struct is_pair : std::false_type { }; template <typename T1, typename T2> - struct is_pair<std::pair<T1, T2>> : std::true_type {}; + struct is_pair<std::pair<T1, T2>> : std::true_type { }; template <typename T, typename Char> - using is_c_str_of = any<std::is_same<T, const Char*>, std::is_same<T, Char const* const>, std::is_same<T, Char*>, is_string_of<T, Char>, - is_string_literal_array_of<T, Char>>; + using is_c_str_of = any<std::is_same<T, const Char*>, std::is_same<T, Char const* const>, std::is_same<T, Char*>, is_string_literal_array_of<T, Char>>; template <typename T, typename Char> constexpr inline bool is_c_str_of_v = is_c_str_of<T, Char>::value; @@ -2245,8 +2799,20 @@ namespace sol { namespace meta { template <typename T> constexpr inline bool is_c_str_v = is_c_str<T>::value; + template <typename T, typename Char> + using is_c_str_or_string_of = any<is_c_str_of<T, Char>, is_string_of<T, Char>>; + + template <typename T, typename Char> + constexpr inline bool is_c_str_or_string_of_v = is_c_str_or_string_of<T, Char>::value; + + template <typename T> + using is_c_str_or_string = is_c_str_or_string_of<T, char>; + + template <typename T> + constexpr inline bool is_c_str_or_string_v = is_c_str_or_string<T>::value; + template <typename T> - struct is_move_only : all<neg<std::is_reference<T>>, neg<std::is_copy_constructible<unqualified_t<T>>>, std::is_move_constructible<unqualified_t<T>>> {}; + struct is_move_only : all<neg<std::is_reference<T>>, neg<std::is_copy_constructible<unqualified_t<T>>>, std::is_move_constructible<unqualified_t<T>>> { }; template <typename T> using is_not_move_only = neg<is_move_only<T>>; @@ -2285,7 +2851,7 @@ namespace sol { namespace meta { namespace sol { namespace detail { const bool default_safe_function_calls = -#if SOL_IS_ON(SOL_SAFE_FUNCTION_CALLS_I_) +#if SOL_IS_ON(SOL_SAFE_FUNCTION_CALLS) true; #else false; @@ -2308,17 +2874,84 @@ namespace sol { #endif // SOL_FORWARD_DETAIL_HPP // end of sol/forward_detail.hpp +// beginning of sol/assert.hpp + +#if SOL_IS_ON(SOL2_CI) + +struct pre_main { + pre_main() { +#ifdef _MSC_VER + _set_abort_behavior(0, _WRITE_ABORT_MSG); +#endif + } +} inline sol2_ci_dont_lock_ci_please = {}; + +#endif // Prevent lockup when doing Continuous Integration + +#if SOL_IS_ON(SOL_USER_C_ASSERT) + #define sol_c_assert(...) SOL_C_ASSERT(__VA_ARGS__) +#else + #if SOL_IS_ON(SOL_DEBUG_BUILD) + #include <exception> + #include <iostream> + #include <cstdlib> + + #define sol_c_assert(...) \ + do { \ + if (!(__VA_ARGS__)) { \ + std::cerr << "Assertion `" #__VA_ARGS__ "` failed in " << __FILE__ << " line " << __LINE__ << std::endl; \ + std::terminate(); \ + } \ + } while (false) + #else + #define sol_c_assert(...) \ + do { \ + if (false) { \ + (void)(__VA_ARGS__); \ + } \ + } while (false) + #endif +#endif + +#if SOL_IS_ON(SOL_USER_M_ASSERT) + #define sol_m_assert(message, ...) SOL_M_ASSERT(message, __VA_ARGS__) +#else + #if SOL_IS_ON(SOL_DEBUG_BUILD) + #include <exception> + #include <iostream> + #include <cstdlib> + + #define sol_m_assert(message, ...) \ + do { \ + if (!(__VA_ARGS__)) { \ + std::cerr << "Assertion `" #__VA_ARGS__ "` failed in " << __FILE__ << " line " << __LINE__ << ": " << message << std::endl; \ + std::terminate(); \ + } \ + } while (false) + #else + #define sol_m_assert(message, ...) \ + do { \ + if (false) { \ + (void)(__VA_ARGS__); \ + (void)sizeof(message); \ + } \ + } while (false) + #endif +#endif + +// end of sol/assert.hpp + // beginning of sol/bytecode.hpp // beginning of sol/compatibility.hpp // beginning of sol/compatibility/lua_version.hpp -#if SOL_IS_ON(SOL_USE_CXX_LUA_I_) +#if SOL_IS_ON(SOL_USE_CXX_LUA) #include <lua.h> #include <lualib.h> #include <lauxlib.h> -#elif SOL_IS_ON(SOL_USE_LUA_HPP_I_) +#elif SOL_IS_ON(SOL_USE_LUA_HPP) #include <lua.hpp> #else extern "C" { @@ -2335,14 +2968,14 @@ namespace sol { #define SOL_USE_LUAJIT_I_ SOL_OFF #endif #elif defined(LUAJIT_VERSION) - #define SOL_USE_LUAJIT_I_ SOL_OFF + #define SOL_USE_LUAJIT_I_ SOL_ON #else #define SOL_USE_LUAJIT_I_ SOL_DEFAULT_OFF #endif // luajit -#if SOL_IS_ON(SOL_USE_CXX_LUAJIT_I_) +#if SOL_IS_ON(SOL_USE_CXX_LUAJIT) #include <luajit.h> -#elif SOL_IS_ON(SOL_USE_LUAJIT_I_) +#elif SOL_IS_ON(SOL_USE_LUAJIT) extern "C" { #include <luajit.h> } @@ -2350,12 +2983,20 @@ namespace sol { #if defined(SOL_LUAJIT_VERSION) #define SOL_LUAJIT_VERSION_I_ SOL_LUAJIT_VERSION -#elif SOL_IS_ON(SOL_USE_LUAJIT_I_) +#elif SOL_IS_ON(SOL_USE_LUAJIT) #define SOL_LUAJIT_VERSION_I_ LUAJIT_VERSION_NUM #else #define SOL_LUAJIT_VERSION_I_ 0 #endif +#if defined(SOL_LUAJIT_FFI_DISABLED) + #define SOL_LUAJIT_FFI_DISABLED_I_ SOL_ON +#elif defined(LUAJIT_DISABLE_FFI) + #define SOL_LUAJIT_FFI_DISABLED_I_ SOL_ON +#else + #define SOL_LUAJIT_FFI_DISABLED_I_ SOL_DEFAULT_OFF +#endif + #if defined(MOONJIT_VERSION) #define SOL_USE_MOONJIT_I_ SOL_ON #else @@ -2377,9 +3018,9 @@ namespace sol { #endif // SOL_LUA_VERSION #if defined(SOL_LUA_VERSION) - #define SOL_LUA_VESION_I_ SOL_LUA_VERSION + #define SOL_LUA_VERSION_I_ SOL_LUA_VERSION #else - #define SOL_LUA_VESION_I_ 504 + #define SOL_LUA_VERSION_I_ 504 #endif #if defined(SOL_EXCEPTIONS_ALWAYS_UNSAFE) @@ -2399,7 +3040,7 @@ namespace sol { #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_ON #elif SOL_LUAJIT_VERSION_I_ >= 20000 // LuaJIT 2.0.x have exception support only on x64 builds - #if SOL_IS_ON(SOL_PLATFORM_X64_I_) + #if SOL_IS_ON(SOL_PLATFORM_X64) #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_ON #else #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_OFF @@ -2409,7 +3050,25 @@ namespace sol { // shoving exceptions through Lua and errors should // always be serialized #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_OFF -#endif // LuaJIT beta 02.01.00 have better exception handling on all platforms since beta3 +#endif + +#if defined(SOL_EXCEPTIONS_CATCH_ALL) + #if (SOL_EXCEPTIONS_CATCH_ALL != 0) + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_ON + #else + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_USE_LUAJIT) + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_OFF + #elif SOL_IS_ON(SOL_USE_CXX_LUAJIT) + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_OFF + #elif SOL_IS_ON(SOL_USE_CXX_LUA) + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_OFF + #else + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_ON + #endif +#endif #if defined(SOL_LUAJIT_USE_EXCEPTION_TRAMPOLINE) #if (SOL_LUAJIT_USE_EXCEPTION_TRAMPOLINE != 0) @@ -2418,7 +3077,7 @@ namespace sol { #define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_OFF #endif #else - #if SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS_I_) && SOL_IS_ON(SOL_USE_LUAJIT_I_) + #if SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS) && SOL_IS_ON(SOL_USE_LUAJIT) #define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_ON #else #define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_DEFAULT_OFF @@ -2432,18 +3091,48 @@ namespace sol { #define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_OFF #endif #else - #if SOL_IS_OFF(SOL_USE_LUAJIT_I_) && (SOL_LUA_VERSION > 501) + #if SOL_IS_OFF(SOL_USE_LUAJIT) && (SOL_LUA_VERSION > 501) #define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_ON #else #define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_DEFAULT_OFF #endif #endif +#if defined (SOL_LUA_BIT32_LIB) + #if SOL_LUA_BIT32_LIB != 0 + #define SOL_LUA_BIT32_LIB_I_ SOL_ON + #else + #define SOL_LUA_BIT32_LIB_I_ SOL_OFF + #endif +#else + // Lua 5.2 only (deprecated in 5.3 (503)) (Can be turned on with Compat flags) + // Lua 5.2, or other versions of Lua with the compat flag, or Lua that is not 5.2 with the specific define (5.4.1 either removed it entirely or broke it) + #if (SOL_LUA_VERSION_I_ == 502) || (defined(LUA_COMPAT_BITLIB) && (LUA_COMPAT_BITLIB != 0)) || (SOL_LUA_VERSION_I_ < 504 && (defined(LUA_COMPAT_5_2) && (LUA_COMPAT_5_2 != 0))) + #define SOL_LUA_BIT32_LIB_I_ SOL_ON + #else + #define SOL_LUA_BIT32_LIB_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined (SOL_LUA_NIL_IN_TABLES) + #if SOL_LUA_NIL_IN_TABLES != 0 + #define SOL_LUA_NIL_IN_TABLES_I_ SOL_ON + #else + #define SOL_LUA_NIL_IN_TABLES_I_ SOL_OFF + #endif +#else + #if defined(LUA_NILINTABLE) && (LUA_NILINTABLE != 0) + #define SOL_LUA_NIL_IN_TABLES_I_ SOL_DEFAULT_ON + #else + #define SOL_LUA_NIL_IN_TABLES_I_ SOL_DEFAULT_OFF + #endif +#endif + // end of sol/compatibility/lua_version.hpp -#if SOL_IS_ON(SOL_USE_COMPATIBILITY_LAYER_I_) +#if SOL_IS_ON(SOL_USE_COMPATIBILITY_LAYER) -#if SOL_IS_ON(SOL_USE_CXX_LUA_I_) || SOL_IS_ON(SOL_USE_CXX_LUAJIT_I_) +#if SOL_IS_ON(SOL_USE_CXX_LUA) || SOL_IS_ON(SOL_USE_CXX_LUAJIT) #ifndef COMPAT53_LUA_CPP #define COMPAT53_LUA_CPP 1 #endif // Build Lua Compat layer as C++ @@ -2961,18 +3650,18 @@ static void compat53_call_lua(lua_State* L, char const code[], size_t len, int n lua_call(L, nargs, nret); } -static const char compat53_arith_code[] - = "local op,a,b=...\n" - "if op==0 then return a+b\n" - "elseif op==1 then return a-b\n" - "elseif op==2 then return a*b\n" - "elseif op==3 then return a/b\n" - "elseif op==4 then return a%b\n" - "elseif op==5 then return a^b\n" - "elseif op==6 then return -a\n" - "end\n"; - COMPAT53_API void lua_arith(lua_State* L, int op) { + static const char compat53_arith_code[] + = "local op,a,b=...\n" + "if op==0 then return a+b\n" + "elseif op==1 then return a-b\n" + "elseif op==2 then return a*b\n" + "elseif op==3 then return a/b\n" + "elseif op==4 then return a%b\n" + "elseif op==5 then return a^b\n" + "elseif op==6 then return -a\n" + "end\n"; + if (op < LUA_OPADD || op > LUA_OPUNM) luaL_error(L, "invalid 'op' argument for lua_arith"); luaL_checkstack(L, 5, "not enough stack slots"); @@ -2983,11 +3672,11 @@ COMPAT53_API void lua_arith(lua_State* L, int op) { compat53_call_lua(L, compat53_arith_code, sizeof(compat53_arith_code) - 1, 3, 1); } -static const char compat53_compare_code[] - = "local a,b=...\n" - "return a<=b\n"; - COMPAT53_API int lua_compare(lua_State* L, int idx1, int idx2, int op) { + static const char compat53_compare_code[] + = "local a,b=...\n" + "return a<=b\n"; + int result = 0; switch (op) { case LUA_OPEQ: @@ -3504,7 +4193,11 @@ COMPAT53_API char* luaL_prepbuffsize(luaL_Buffer_53* B, size_t s) { newcap = B->nelems + s; if (newcap < B->capacity) /* overflow */ luaL_error(B->L2, "buffer too large"); +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504 + newptr = (char*)lua_newuserdatauv(B->L2, newcap, 0); +#else newptr = (char*)lua_newuserdata(B->L2, newcap); +#endif memcpy(newptr, B->ptr, B->nelems); if (B->ptr != B->b.buffer) lua_replace(B->L2, -2); /* remove old buffer */ @@ -3811,11 +4504,11 @@ namespace sol { }; template <typename Container> - inline int basic_insert_dump_writer(lua_State*, const void* memory, size_t memory_size, void* userdata) { + inline int basic_insert_dump_writer(lua_State*, const void* memory, size_t memory_size, void* userdata_pointer) { using storage_t = Container; const std::byte* p_code = static_cast<const std::byte*>(memory); - storage_t& bc = *static_cast<storage_t*>(userdata); -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) + storage_t& bc = *static_cast<storage_t*>(userdata_pointer); +#if SOL_IS_OFF(SOL_EXCEPTIONS) bc.insert(bc.cend(), p_code, p_code + memory_size); #else try { @@ -3850,22 +4543,22 @@ namespace sol { namespace sol { namespace detail { - struct direct_error_tag {}; - const auto direct_error = direct_error_tag{}; + struct direct_error_tag { }; + const auto direct_error = direct_error_tag {}; struct error_result { int results; const char* format_string; - std::array<const char*, 4> args_strings; + std::array<const char*, 4> argument_strings; error_result() : results(0), format_string(nullptr) { } - error_result(int results) : results(results), format_string(nullptr) { + error_result(int results_) : results(results_), format_string(nullptr) { } - error_result(const char* fmt, const char* msg) : results(0), format_string(fmt) { - args_strings[0] = msg; + error_result(const char* format_string_, const char* first_message_) : results(0), format_string(format_string_), argument_strings() { + argument_strings[0] = first_message_; } }; @@ -3873,7 +4566,7 @@ namespace sol { if (er.format_string == nullptr) { return er.results; } - return luaL_error(L, er.format_string, er.args_strings[0], er.args_strings[1], er.args_strings[2], er.args_strings[3]); + return luaL_error(L, er.format_string, er.argument_strings[0], er.argument_strings[1], er.argument_strings[2], er.argument_strings[3]); } } // namespace detail @@ -3933,7 +4626,7 @@ namespace sol { // end of sol/in_place.hpp -#if SOL_IS_ON(SOL_USE_BOOST_I_) +#if SOL_IS_ON(SOL_USE_BOOST) #include <boost/optional.hpp> #else // beginning of sol/optional_implementation.hpp @@ -3978,10 +4671,10 @@ namespace sol { #define SOL_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX namespace sol { namespace detail { template <class T> - struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> {}; + struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> { }; #ifdef _GLIBCXX_VECTOR template <class T, class A> - struct is_trivially_copy_constructible<std::vector<T, A>> : std::is_trivially_copy_constructible<T> {}; + struct is_trivially_copy_constructible<std::vector<T, A>> : std::is_trivially_copy_constructible<T> { }; #endif }} // namespace sol::detail #endif @@ -4010,7 +4703,7 @@ namespace sol { #ifndef SOL_TL_MONOSTATE_INPLACE_MUTEX #define SOL_TL_MONOSTATE_INPLACE_MUTEX /// \brief Used to represent an optional with no data; essentially a bool - class monostate {}; + class monostate { }; #endif template <class T> @@ -4034,11 +4727,11 @@ namespace sol { // std::conjunction from C++17 template <class...> - struct conjunction : std::true_type {}; + struct conjunction : std::true_type { }; template <class B> - struct conjunction<B> : B {}; + struct conjunction<B> : B { }; template <class B, class... Bs> - struct conjunction<B, Bs...> : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {}; + struct conjunction<B, Bs...> : std::conditional<bool(B::value), conjunction<Bs...>, B>::type { }; #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L #define SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND @@ -4046,26 +4739,26 @@ namespace sol { #ifdef SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND template <class T> - struct is_pointer_to_non_const_member_func : std::false_type {}; + struct is_pointer_to_non_const_member_func : std::false_type { }; template <class T, class Ret, class... Args> - struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)> : std::true_type {}; + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)> : std::true_type { }; template <class T, class Ret, class... Args> - struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)&> : std::true_type {}; + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)&> : std::true_type { }; template <class T, class Ret, class... Args> - struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&> : std::true_type {}; + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&> : std::true_type { }; template <class T, class Ret, class... Args> - struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile> : std::true_type {}; + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile> : std::true_type { }; template <class T, class Ret, class... Args> - struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&> : std::true_type {}; + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&> : std::true_type { }; template <class T, class Ret, class... Args> - struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&&> : std::true_type {}; + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&&> : std::true_type { }; template <class T> - struct is_const_or_const_ref : std::false_type {}; + struct is_const_or_const_ref : std::false_type { }; template <class T> - struct is_const_or_const_ref<T const&> : std::true_type {}; + struct is_const_or_const_ref<T const&> : std::true_type { }; template <class T> - struct is_const_or_const_ref<T const> : std::true_type {}; + struct is_const_or_const_ref<T const> : std::true_type { }; #endif // std::invoke from C++17 @@ -4112,9 +4805,9 @@ namespace sol { // Trait for checking if a type is a sol::optional template <class T> - struct is_optional_impl : std::false_type {}; + struct is_optional_impl : std::false_type { }; template <class T> - struct is_optional_impl<optional<T>> : std::true_type {}; + struct is_optional_impl<optional<T>> : std::true_type { }; template <class T> using is_optional = is_optional_impl<decay_t<T>>; @@ -4129,7 +4822,7 @@ namespace sol { template <class F, class = void, class... U> struct returns_void_impl; template <class F, class... U> - struct returns_void_impl<F, void_t<invoke_result_t<F, U...>>, U...> : std::is_void<invoke_result_t<F, U...>> {}; + struct returns_void_impl<F, void_t<invoke_result_t<F, U...>>, U...> : std::is_void<invoke_result_t<F, U...>> { }; template <class F, class... U> using returns_void = returns_void_impl<F, void, U...>; @@ -4167,16 +4860,16 @@ namespace sol { #ifdef _MSC_VER // TODO make a version which works with MSVC template <class T, class U = T> - struct is_swappable : std::true_type {}; + struct is_swappable : std::true_type { }; template <class T, class U = T> - struct is_nothrow_swappable : std::true_type {}; + struct is_nothrow_swappable : std::true_type { }; #else // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept namespace swap_adl_tests { // if swap ADL finds this then it would call std::swap otherwise (same // signature) - struct tag {}; + struct tag { }; template <class T> tag swap(T&, T&); @@ -4197,36 +4890,36 @@ namespace sol { template <class T> struct is_std_swap_noexcept - : std::integral_constant<bool, std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value> {}; + : std::integral_constant<bool, std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value> { }; template <class T, std::size_t N> - struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {}; + struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> { }; template <class T, class U> - struct is_adl_swap_noexcept : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {}; + struct is_adl_swap_noexcept : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> { }; } // namespace swap_adl_tests template <class T, class U = T> struct is_swappable : std::integral_constant<bool, decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value && (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value - || (std::is_move_assignable<T>::value && std::is_move_constructible<T>::value))> {}; + || (std::is_move_assignable<T>::value && std::is_move_constructible<T>::value))> { }; template <class T, std::size_t N> struct is_swappable<T[N], T[N]> : std::integral_constant<bool, decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value - && (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value || is_swappable<T, T>::value)> {}; + && (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value || is_swappable<T, T>::value)> { }; template <class T, class U = T> struct is_nothrow_swappable : std::integral_constant<bool, is_swappable<T, U>::value && ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_std_swap_noexcept<T>::value) - || (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {}; + || (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> { }; #endif // The storage base manages the actual storage, and correctly propagates - // trivial destruction from T. This case is for when T is not trivially + // trivial destroyion from T. This case is for when T is not trivially // destructible. template <class T, bool = ::std::is_trivially_destructible<T>::value> struct optional_storage_base { @@ -4244,7 +4937,7 @@ namespace sol { } } - struct dummy {}; + struct dummy { }; union { dummy m_dummy; T m_value; @@ -4265,7 +4958,7 @@ namespace sol { // No destructor, so this class is trivially destructible - struct dummy {}; + struct dummy { }; union { dummy m_dummy; T m_value; @@ -4530,9 +5223,12 @@ namespace sol { /// ``` using std::nullopt; + /// @brief An exception for when an optional is accessed through specific methods while it is not engaged. class bad_optional_access : public std::exception { public: + /// @brief Default-constructs an optional exception. bad_optional_access() = default; + /// @brief Returns a pointer to a null-terminated string containing the reason for the exception. const char* what() const noexcept override { return "Optional has no value"; } @@ -4564,7 +5260,7 @@ namespace sol { /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` /// is returned. /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &; template <class F> SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & { using result = detail::invoke_result_t<F, T&>; @@ -4574,7 +5270,7 @@ namespace sol { } /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&; template <class F> SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && { using result = detail::invoke_result_t<F, T&&>; @@ -4584,7 +5280,7 @@ namespace sol { } /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &; template <class F> constexpr auto and_then(F&& f) const& { using result = detail::invoke_result_t<F, const T&>; @@ -4595,7 +5291,7 @@ namespace sol { #ifndef SOL_TL_OPTIONAL_NO_CONSTRR /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&; template <class F> constexpr auto and_then(F&& f) const&& { using result = detail::invoke_result_t<F, const T&&>; @@ -4614,7 +5310,7 @@ namespace sol { /// `*this` is empty, otherwise the return value of /// `std::invoke(std::forward<F>(f), value())` is returned. /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &; template <class F> SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) & { using result = detail::invoke_result_t<F, T&>; @@ -4624,7 +5320,7 @@ namespace sol { } /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&; template <class F> SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&&> and_then(F&& f) && { using result = detail::invoke_result_t<F, T&&>; @@ -4634,7 +5330,7 @@ namespace sol { } /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &; template <class F> constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const& { using result = detail::invoke_result_t<F, const T&>; @@ -4645,7 +5341,7 @@ namespace sol { #ifndef SOL_TL_OPTIONAL_NO_CONSTRR /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&; template <class F> constexpr detail::invoke_result_t<F, const T&&> and_then(F&& f) const&& { using result = detail::invoke_result_t<F, const T&&>; @@ -4846,14 +5542,14 @@ namespace sol { /// `std::forward<U>(u)()` is returned. /// /// \group map_or_else - /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) &; + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) &; template <class F, class U> detail::invoke_result_t<U> map_or_else(F&& f, U&& u) & { return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)(); } /// \group map_or_else - /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) /// &&; template <class F, class U> detail::invoke_result_t<U> map_or_else(F&& f, U&& u) && { @@ -4861,7 +5557,7 @@ namespace sol { } /// \group map_or_else - /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) /// const &; template <class F, class U> detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const& { @@ -4870,7 +5566,7 @@ namespace sol { #ifndef SOL_TL_OPTIONAL_NO_CONSTRR /// \group map_or_else - /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) /// const &&; template <class F, class U> detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const&& { @@ -4992,7 +5688,7 @@ namespace sol { } /// \group in_place - /// \synopsis template <class U, class... Args>\nconstexpr explicit optional(in_place_t, std::initializer_list<U>&, Args&&... args); + /// \synopsis template <class U, class... Args> \n constexpr explicit optional(in_place_t, std::initializer_list<U>&, Args&&... args); template <class U, class... Args> SOL_TL_OPTIONAL_11_CONSTEXPR explicit optional(detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, in_place_t>, std::initializer_list<U> il, Args&&... args) { @@ -5019,7 +5715,7 @@ namespace sol { /// \exclude constexpr optional(const T& u) : base(in_place, u) { } -#endif // sol3 modification +#endif // sol2 modification /// Converting copy constructor. /// \synopsis template <class U> optional(const optional<U> &rhs); @@ -5155,7 +5851,7 @@ namespace sol { } /// \group emplace - /// \synopsis template <class U, class... Args>\nT& emplace(std::initializer_list<U> il, Args &&... args); + /// \synopsis template <class U, class... Args> \n T& emplace(std::initializer_list<U> il, Args &&... args); template <class U, class... Args> detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, T&> emplace(std::initializer_list<U> il, Args&&... args) { *this = nullopt; @@ -5244,7 +5940,7 @@ namespace sol { SOL_TL_OPTIONAL_11_CONSTEXPR T& value() & { if (has_value()) return this->m_value; -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) +#if SOL_IS_OFF(SOL_EXCEPTIONS) std::abort(); #else throw bad_optional_access(); @@ -5255,7 +5951,7 @@ namespace sol { SOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const& { if (has_value()) return this->m_value; -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) +#if SOL_IS_OFF(SOL_EXCEPTIONS) std::abort(); #else throw bad_optional_access(); @@ -5265,7 +5961,7 @@ namespace sol { SOL_TL_OPTIONAL_11_CONSTEXPR T&& value() && { if (has_value()) return std::move(this->m_value); -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) +#if SOL_IS_OFF(SOL_EXCEPTIONS) std::abort(); #else throw bad_optional_access(); @@ -5277,7 +5973,7 @@ namespace sol { SOL_TL_OPTIONAL_11_CONSTEXPR const T&& value() const&& { if (has_value()) return std::move(this->m_value); -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) +#if SOL_IS_OFF(SOL_EXCEPTIONS) std::abort(); #else throw bad_optional_access(); @@ -5473,14 +6169,14 @@ namespace sol { return rhs.has_value() ? lhs >= *rhs : true; } - /// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T> &rhs); + /// \synopsis template <class T> \n void swap(optional<T> &lhs, optional<T> &rhs); template <class T, detail::enable_if_t<std::is_move_constructible<T>::value>* = nullptr, detail::enable_if_t<detail::is_swappable<T>::value>* = nullptr> void swap(optional<T>& lhs, optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs))) { return lhs.swap(rhs); } namespace detail { - struct i_am_secret {}; + struct i_am_secret { }; } // namespace detail template <class T = detail::i_am_secret, class U, class Ret = detail::conditional_t<std::is_same<T, detail::i_am_secret>::value, detail::decay_t<U>, T>> @@ -5499,7 +6195,7 @@ namespace sol { #if __cplusplus >= 201703L template <class T> - optional(T)->optional<T>; + optional(T) -> optional<T>; #endif /// \exclude @@ -5578,7 +6274,7 @@ namespace sol { /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` /// is returned. /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &; template <class F> SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & { using result = detail::invoke_result_t<F, T&>; @@ -5588,7 +6284,7 @@ namespace sol { } /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&; template <class F> SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && { using result = detail::invoke_result_t<F, T&>; @@ -5598,7 +6294,7 @@ namespace sol { } /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &; template <class F> constexpr auto and_then(F&& f) const& { using result = detail::invoke_result_t<F, const T&>; @@ -5609,7 +6305,7 @@ namespace sol { #ifndef SOL_TL_OPTIONAL_NO_CONSTRR /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&; template <class F> constexpr auto and_then(F&& f) const&& { using result = detail::invoke_result_t<F, const T&>; @@ -5628,7 +6324,7 @@ namespace sol { /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` /// is returned. /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &; template <class F> SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) & { using result = detail::invoke_result_t<F, T&>; @@ -5638,7 +6334,7 @@ namespace sol { } /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&; template <class F> SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) && { using result = detail::invoke_result_t<F, T&>; @@ -5648,7 +6344,7 @@ namespace sol { } /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &; template <class F> constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const& { using result = detail::invoke_result_t<F, const T&>; @@ -5659,7 +6355,7 @@ namespace sol { #ifndef SOL_TL_OPTIONAL_NO_CONSTRR /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&; template <class F> constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const&& { using result = detail::invoke_result_t<F, const T&>; @@ -5859,14 +6555,14 @@ namespace sol { /// `std::forward<U>(u)()` is returned. /// /// \group map_or_else - /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) &; + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) &; template <class F, class U> detail::invoke_result_t<U> map_or_else(F&& f, U&& u) & { return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)(); } /// \group map_or_else - /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) /// &&; template <class F, class U> detail::invoke_result_t<U> map_or_else(F&& f, U&& u) && { @@ -5874,7 +6570,7 @@ namespace sol { } /// \group map_or_else - /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) /// const &; template <class F, class U> detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const& { @@ -5883,7 +6579,7 @@ namespace sol { #ifndef SOL_TL_OPTIONAL_NO_CONSTRR /// \group map_or_else - /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) /// const &&; template <class F, class U> detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const&& { @@ -6115,7 +6811,7 @@ namespace sol { SOL_TL_OPTIONAL_11_CONSTEXPR T& value() { if (has_value()) return *m_value; -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) +#if SOL_IS_OFF(SOL_EXCEPTIONS) std::abort(); #else throw bad_optional_access(); @@ -6126,7 +6822,7 @@ namespace sol { SOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const { if (has_value()) return *m_value; -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) +#if SOL_IS_OFF(SOL_EXCEPTIONS) std::abort(); #else throw bad_optional_access(); @@ -6173,11 +6869,11 @@ namespace std { namespace sol { -#if SOL_IS_ON(SOL_USE_BOOST_I_) +#if SOL_IS_ON(SOL_USE_BOOST) template <typename T> using optional = boost::optional<T>; using nullopt_t = boost::none_t; - const nullopt_t nullopt = boost::none; + SOL_BOOST_NONE_CONSTEXPR_I_ nullopt_t nullopt = boost::none; #endif // Boost vs. Better optional namespace meta { @@ -6194,18 +6890,27 @@ namespace sol { inline static constexpr std::nullopt_t value = std::nullopt; }; -#if SOL_IS_ON(SOL_USE_BOOST_I_) +#if SOL_IS_ON(SOL_USE_BOOST) template <typename T> struct associated_nullopt<boost::optional<T>> { - inline static constexpr std::nullopt_t value = boost::nullopt; + inline static SOL_BOOST_NONE_CONSTEXPR_I_ boost::none_t value = boost::none; }; #endif // Boost nullopt +#if SOL_IS_ON(SOL_USE_BOOST) + template <typename T> + inline SOL_BOOST_NONE_CONSTEXPR_I_ auto associated_nullopt_v = associated_nullopt<T>::value; +#else template <typename T> inline constexpr auto associated_nullopt_v = associated_nullopt<T>::value; +#endif // Boost continues to lag behind, to not many people's surprise... } // namespace detail } // namespace sol +#if SOL_IS_ON(SOL_USE_BOOST) +#undef SOL_BOOST_NONE_CONSTEXPR_I_ +#endif + // end of sol/optional.hpp // beginning of sol/raii.hpp @@ -6218,7 +6923,7 @@ namespace sol { template <typename T, typename... Args> static void construct(T&& obj, Args&&... args) { typedef meta::unqualified_t<T> Tu; - std::allocator<Tu> alloc{}; + std::allocator<Tu> alloc {}; std::allocator_traits<std::allocator<Tu>>::construct(alloc, std::forward<T>(obj), std::forward<Args>(args)...); } @@ -6228,10 +6933,10 @@ namespace sol { } }; - struct default_destruct { + struct default_destroy { template <typename T> static void destroy(T&& obj) { - std::allocator<meta::unqualified_t<T>> alloc{}; + std::allocator<meta::unqualified_t<T>> alloc {}; alloc.destroy(obj); } @@ -6263,11 +6968,10 @@ namespace sol { struct tagged { private: T value_; - + public: template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, tagged>> = meta::enabler> - tagged(Arg&& arg, Args&&... args) - : value_(std::forward<Arg>(arg), std::forward<Args>(args)...) { + tagged(Arg&& arg, Args&&... args) : value_(std::forward<Arg>(arg), std::forward<Args>(args)...) { } T& value() & { @@ -6285,25 +6989,24 @@ namespace sol { } // namespace detail template <typename... Args> - struct constructor_list {}; + struct constructor_list { }; template <typename... Args> using constructors = constructor_list<Args...>; - const auto default_constructor = constructors<types<>>{}; + const auto default_constructor = constructors<types<>> {}; - struct no_construction {}; - const auto no_constructor = no_construction{}; + struct no_construction { }; + const auto no_constructor = no_construction {}; - struct call_construction {}; - const auto call_constructor = call_construction{}; + struct call_construction { }; + const auto call_constructor = call_construction {}; template <typename... Functions> struct constructor_wrapper { std::tuple<Functions...> functions; template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, constructor_wrapper>> = meta::enabler> - constructor_wrapper(Arg&& arg, Args&&... args) - : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { + constructor_wrapper(Arg&& arg, Args&&... args) : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { } }; @@ -6316,8 +7019,7 @@ namespace sol { struct factory_wrapper { std::tuple<Functions...> functions; template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, factory_wrapper>> = meta::enabler> - factory_wrapper(Arg&& arg, Args&&... args) - : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { + factory_wrapper(Arg&& arg, Args&&... args) : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { } }; @@ -6329,15 +7031,14 @@ namespace sol { template <typename Function> struct destructor_wrapper { Function fx; - destructor_wrapper(Function f) - : fx(std::move(f)) { + destructor_wrapper(Function f) : fx(std::move(f)) { } }; template <> - struct destructor_wrapper<void> {}; + struct destructor_wrapper<void> { }; - const destructor_wrapper<void> default_destructor{}; + const destructor_wrapper<void> default_destructor {}; template <typename Fx> inline auto destructor(Fx&& fx) { @@ -6354,14 +7055,14 @@ namespace sol { namespace sol { namespace detail { - struct policy_base_tag {}; + struct policy_base_tag { }; } // namespace detail template <int Target, int... In> - struct static_stack_dependencies : detail::policy_base_tag {}; + struct static_stack_dependencies : detail::policy_base_tag { }; typedef static_stack_dependencies<-1, 1> self_dependency; template <int... In> - struct returns_self_with : detail::policy_base_tag {}; + struct returns_self_with : detail::policy_base_tag { }; typedef returns_self_with<> returns_self; struct stack_dependencies : detail::policy_base_tag { @@ -6372,7 +7073,7 @@ namespace sol { template <typename... Args> stack_dependencies(int stack_target, Args&&... args) : target(stack_target), stack_indices(), len(sizeof...(Args)) { std::size_t i = 0; - (void)detail::swallow{ int(), (stack_indices[i++] = static_cast<int>(std::forward<Args>(args)), int())... }; + (void)detail::swallow { int(), (stack_indices[i++] = static_cast<int>(std::forward<Args>(args)), int())... }; } int& operator[](std::size_t i) { @@ -6425,43 +7126,47 @@ namespace sol { #include <type_traits> #include <utility> +#include <memory> namespace sol { namespace detail { template <typename T, std::size_t tag = 0, typename = void> struct ebco { - T value_; + T m_value; ebco() = default; ebco(const ebco&) = default; ebco(ebco&&) = default; ebco& operator=(const ebco&) = default; ebco& operator=(ebco&&) = default; - ebco(const T& v) : value_(v){}; - ebco(T&& v) : value_(std::move(v)){}; - ebco& operator=(const T& v) { - value_ = v; + ebco(const T& v) noexcept(std::is_nothrow_copy_constructible_v<T>) : m_value(v) {}; + ebco(T&& v) noexcept(std::is_nothrow_move_constructible_v<T>) : m_value(std::move(v)) {}; + ebco& operator=(const T& v) noexcept(std::is_nothrow_copy_assignable_v<T>) { + m_value = v; return *this; } - ebco& operator=(T&& v) { - value_ = std::move(v); + ebco& operator=(T&& v) noexcept(std::is_nothrow_move_assignable_v<T>) { + m_value = std::move(v); return *this; }; template <typename Arg, typename... Args, - typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, - ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T>>> - ebco(Arg&& arg, Args&&... args) : T(std::forward<Arg>(arg), std::forward<Args>(args)...){} + typename = std::enable_if_t< + !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, + ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T> && (sizeof...(Args) > 0 || !std::is_convertible_v<Arg, T>)>> + ebco(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Arg, Args...>) + : m_value(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } - T& value() & { - return value_; + T& value() & noexcept { + return m_value; } - T const& value() const & { - return value_; + T const& value() const& noexcept { + return m_value; } - T&& value() && { - return std::move(value_); + T&& value() && noexcept { + return std::move(m_value); } }; @@ -6470,56 +7175,59 @@ namespace sol { namespace detail { ebco() = default; ebco(const ebco&) = default; ebco(ebco&&) = default; - ebco(const T& v) : T(v){}; - ebco(T&& v) : T(std::move(v)){}; + ebco(const T& v) noexcept(std::is_nothrow_copy_constructible_v<T>) : T(v) {}; + ebco(T&& v) noexcept(std::is_nothrow_move_constructible_v<T>) : T(std::move(v)) {}; template <typename Arg, typename... Args, - typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, - ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T>>> - ebco(Arg&& arg, Args&&... args) : T(std::forward<Arg>(arg), std::forward<Args>(args)...) { + typename = std::enable_if_t< + !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, + ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T> && (sizeof...(Args) > 0 || !std::is_convertible_v<Arg, T>)>> + ebco(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Arg, Args...>) : T(std::forward<Arg>(arg), std::forward<Args>(args)...) { } ebco& operator=(const ebco&) = default; ebco& operator=(ebco&&) = default; - ebco& operator=(const T& v) { + ebco& operator=(const T& v) noexcept(std::is_nothrow_copy_assignable_v<T>) { static_cast<T&>(*this) = v; return *this; } - ebco& operator=(T&& v) { + ebco& operator=(T&& v) noexcept(std::is_nothrow_move_assignable_v<T>) { static_cast<T&>(*this) = std::move(v); return *this; }; - T& value() & { + T& value() & noexcept { return static_cast<T&>(*this); } - T const& value() const & { + T const& value() const& noexcept { return static_cast<T const&>(*this); } - T&& value() && { + T&& value() && noexcept { return std::move(static_cast<T&>(*this)); } }; template <typename T, std::size_t tag> struct ebco<T&, tag> { - T& ref; + private: + T* m_ref; + public: ebco() = default; ebco(const ebco&) = default; ebco(ebco&&) = default; - ebco(T& v) : ref(v){}; + ebco(T& v) noexcept : m_ref(std::addressof(v)) {}; ebco& operator=(const ebco&) = default; ebco& operator=(ebco&&) = default; - ebco& operator=(T& v) { - ref = v; + ebco& operator=(T& v) noexcept { + m_ref = std::addressof(v); return *this; } - T& value() const { - return const_cast<ebco<T&, tag>&>(*this).ref; + T& value() const noexcept { + return *(const_cast<ebco<T&, tag>&>(*this).m_ref); } }; @@ -6528,26 +7236,22 @@ namespace sol { namespace detail { T&& ref; ebco() = default; - ebco(const ebco&) = default; + ebco(const ebco&) = delete; ebco(ebco&&) = default; - ebco(T&& v) : ref(v){}; + ebco(T&& v) noexcept : ref(v) {}; - ebco& operator=(const ebco&) = default; - ebco& operator=(ebco&&) = default; - ebco& operator=(T&& v) { - ref = std::move(v); - return *this; - } + ebco& operator=(const ebco&) = delete; + ebco& operator=(ebco&&) = delete; - T& value() & { + T& value() & noexcept { return ref; } - const T& value() const & { + const T& value() const& noexcept { return ref; } - T&& value() && { + T&& value() && noexcept { return std::move(ref); } }; @@ -6561,38 +7265,49 @@ namespace sol { namespace detail { #include <string> #include <string_view> #include <optional> -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#include <memory> +#if SOL_IS_ON(SOL_STD_VARIANT) #include <variant> #endif // variant shenanigans (thanks, Mac OSX) namespace sol { + namespace d { + // shortest possible hidden detail namespace + // when types are transcribed, this saves + // quite a bit of space, actually. + // it's a little unfortunate, but here we are? + template <typename T> + struct u { }; + } // namespace d + namespace detail { -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) +#if SOL_IS_ON(SOL_USE_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 template <typename T> - struct unique_usertype { }; - - template <typename T> struct implicit_wrapper { - T& item; - implicit_wrapper(T* item) : item(*item) { + T& value; + + implicit_wrapper(T* value_) : value(*value_) { } - implicit_wrapper(T& item) : item(item) { + + implicit_wrapper(T& value_) : value(value_) { } + operator T&() { - return item; + return value; } + operator T*() { - return std::addressof(item); + return std::addressof(value); } }; struct yield_tag_t { }; - const yield_tag_t yield_tag = yield_tag_t {}; + inline constexpr yield_tag_t yield_tag {}; } // namespace detail struct lua_nil_t { }; @@ -6603,7 +7318,7 @@ namespace sol { inline bool operator!=(lua_nil_t, lua_nil_t) { return false; } -#if SOL_IS_ON(SOL_NIL_I_) +#if SOL_IS_ON(SOL_NIL) using nil_t = lua_nil_t; inline constexpr const nil_t& nil = lua_nil; #endif @@ -6613,13 +7328,16 @@ namespace sol { } // namespace detail struct metatable_key_t { }; - const metatable_key_t metatable_key = {}; + inline constexpr metatable_key_t metatable_key {}; + + struct global_tag_t { + } inline constexpr global_tag {}; struct env_key_t { }; - const env_key_t env_key = {}; + inline constexpr env_key_t env_key {}; struct no_metatable_t { }; - const no_metatable_t no_metatable = {}; + inline constexpr no_metatable_t no_metatable {}; template <typename T> struct yielding_t { @@ -6710,29 +7428,49 @@ namespace sol { }; struct userdata_value { - void* value; - userdata_value(void* data) : value(data) { + private: + void* m_value; + + public: + userdata_value(void* data) : m_value(data) { + } + + void* value() const { + return m_value; } + operator void*() const { - return value; + return value(); } }; - template <typename L> + template <typename T> struct light { - L* value; + private: + static_assert(!std::is_void_v<T>, "the type for light will never be void"); + T* m_value; - light(L& x) : value(std::addressof(x)) { + public: + light(T& x) : m_value(std::addressof(x)) { } - light(L* x) : value(x) { + light(T* x) : m_value(x) { } - light(void* x) : value(static_cast<L*>(x)) { + explicit light(void* x) : m_value(static_cast<T*>(x)) { } - operator L*() const { - return value; + + T* value() const { + return m_value; + } + + operator T*() const { + return m_value; + } + operator T&() const { + return *m_value; } - operator L&() const { - return *value; + + void* void_value() const { + return m_value; } }; @@ -6742,20 +7480,30 @@ namespace sol { return light<L>(l); } - template <typename U> - struct user { - U value; + template <typename T> + struct user : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using base_t::base_t; + + using base_t::value; - user(U&& x) : value(std::forward<U>(x)) { + operator std::add_pointer_t<std::remove_reference_t<T>>() { + return std::addressof(this->base_t::value()); } - operator std::add_pointer_t<std::remove_reference_t<U>>() { - return std::addressof(value); + + operator std::add_pointer_t<std::add_const_t<std::remove_reference_t<T>>>() const { + return std::addressof(this->base_t::value()); } - operator std::add_lvalue_reference_t<U>() { - return value; + + operator std::add_lvalue_reference_t<T>() { + return this->base_t::value(); } - operator std::add_const_t<std::add_lvalue_reference_t<U>> &() const { - return value; + + operator std::add_const_t<std::add_lvalue_reference_t<T>>&() const { + return this->base_t::value(); } }; @@ -6766,11 +7514,14 @@ namespace sol { } template <typename T> - struct metatable_registry_key { - T key; + struct metatable_registry_key : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; - metatable_registry_key(T key) : key(std::forward<T>(key)) { - } + public: + using base_t::base_t; + + using base_t::value; }; template <typename T> @@ -6821,9 +7572,9 @@ namespace sol { } template <typename T> - struct as_table_t { + struct as_table_t : private detail::ebco<T> { private: - T value_; + using base_t = detail::ebco<T>; public: as_table_t() = default; @@ -6831,36 +7582,32 @@ namespace sol { as_table_t(as_table_t&&) = default; as_table_t& operator=(const as_table_t&) = default; as_table_t& operator=(as_table_t&&) = default; - template <typename Arg, - meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, as_table_t>>, - meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> - as_table_t(Arg&& arg) : value_(std::forward<Arg>(arg)) { + as_table_t(const meta::unqualified_t<T>& obj) noexcept(std::is_nothrow_constructible_v<base_t, const meta::unqualified_t<T>&>) : base_t(obj) { } - template <typename Arg0, typename Arg1, typename... Args> - as_table_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) { + as_table_t(meta::unqualified_t<T>&& obj) noexcept(std::is_nothrow_constructible_v<base_t, meta::unqualified_t<T>&&>) : base_t(std::move(obj)) { } - - T& value() & { - return value_; + template <typename Arg, typename... Args, + std::enable_if_t< + !std::is_same_v<as_table_t, meta::unqualified_t<Arg>> && !std::is_same_v<meta::unqualified_t<T>, meta::unqualified_t<Arg>>>* = nullptr> + as_table_t(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<base_t, Arg, Args...>) + : base_t(std::forward<Arg>(arg), std::forward<Args>(args)...) { } - T&& value() && { - return std::move(value_); - } + using base_t::value; - const T& value() const& { - return value_; + operator std::add_lvalue_reference_t<T>() { + return this->base_t::value(); } - operator std::add_lvalue_reference_t<T>() { - return value_; + operator std::add_const_t<std::add_lvalue_reference_t<T>>() const { + return this->base_t::value(); } }; template <typename T> - struct nested { + struct nested : private detail::ebco<T> { private: - T value_; + using base_t = detail::ebco<T>; public: using nested_type = T; @@ -6870,29 +7617,25 @@ namespace sol { nested(nested&&) = default; nested& operator=(const nested&) = default; nested& operator=(nested&&) = default; - template <typename Arg, - meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, nested>>, - meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> - nested(Arg&& arg) : value_(std::forward<Arg>(arg)) { + nested(const meta::unqualified_t<T>& obj) noexcept(std::is_nothrow_constructible_v<base_t, const meta::unqualified_t<T>&>) : base_t(obj) { } - template <typename Arg0, typename Arg1, typename... Args> - nested(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) { + nested(meta::unqualified_t<T>&& obj) noexcept(std::is_nothrow_constructible_v<base_t, meta::unqualified_t<T>&&>) : base_t(std::move(obj)) { } - - T& value() & { - return value_; + template <typename Arg, typename... Args, + std::enable_if_t< + !std::is_same_v<nested, meta::unqualified_t<Arg>> && !std::is_same_v<meta::unqualified_t<T>, meta::unqualified_t<Arg>>>* = nullptr> + nested(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<base_t, Arg, Args...>) + : base_t(std::forward<Arg>(arg), std::forward<Args>(args)...) { } - T&& value() && { - return std::move(value_); - } + using base_t::value; - const T& value() const& { - return value_; + operator std::add_lvalue_reference_t<T>() { + return this->base_t::value(); } - operator std::add_lvalue_reference_t<T>() { - return value_; + operator std::add_const_t<std::add_lvalue_reference_t<T>>() const { + return this->base_t::value(); } }; @@ -6920,9 +7663,9 @@ namespace sol { } template <typename T> - struct as_container_t { + struct as_container_t : private detail::ebco<T> { private: - T value_; + using base_t = detail::ebco<T>; public: using type = T; @@ -6932,42 +7675,12 @@ namespace sol { as_container_t(as_container_t&&) = default; as_container_t& operator=(const as_container_t&) = default; as_container_t& operator=(as_container_t&&) = default; - template <typename Arg, - meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, as_container_t>>, - meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> - as_container_t(Arg&& arg) : value_(std::forward<Arg>(arg)) { - } - template <typename Arg0, typename Arg1, typename... Args> - as_container_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) { - } - T& value() & { - return value_; - } - - T&& value() && { - return std::move(value_); - } - - const T& value() const& { - return value_; - } - }; - - template <typename T> - struct as_container_t<T&> { - private: - std::reference_wrapper<T> value_; - - public: - as_container_t(T& value) : value_(value) { - } + using base_t::base_t; - T& value() { - return value_; - } + using base_t::value; - operator T&() { + operator std::add_lvalue_reference_t<T>() { return value(); } }; @@ -6978,9 +7691,9 @@ namespace sol { } template <typename T> - struct push_invoke_t { + struct push_invoke_t : private detail::ebco<T> { private: - T value_; + using base_t = detail::ebco<T>; public: push_invoke_t() = default; @@ -6988,43 +7701,37 @@ namespace sol { push_invoke_t(push_invoke_t&&) = default; push_invoke_t& operator=(const push_invoke_t&) = default; push_invoke_t& operator=(push_invoke_t&&) = default; - template <typename Arg, - meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, push_invoke_t>>, - meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> - push_invoke_t(Arg&& arg) : value_(std::forward<Arg>(arg)) { - } - template <typename Arg0, typename Arg1, typename... Args> - push_invoke_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) { - } - - T& value() & { - return value_; - } - T&& value() && { - return std::move(value_); - } + using base_t::base_t; - const T& value() const& { - return value_; - } + using base_t::value; }; + template <typename Fx> + auto push_invoke(Fx&& fx) { + return push_invoke_t<Fx>(std::forward<Fx>(fx)); + } + template <typename T> - struct push_invoke_t<T&> { - std::reference_wrapper<T> value_; + struct forward_as_value_t : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; - push_invoke_t(T& value) : value_(value) { - } + public: + forward_as_value_t() = default; + forward_as_value_t(const forward_as_value_t&) = default; + forward_as_value_t(forward_as_value_t&&) = default; + forward_as_value_t& operator=(const forward_as_value_t&) = default; + forward_as_value_t& operator=(forward_as_value_t&&) = default; - T& value() { - return value_; - } + using base_t::base_t; + + using base_t::value; }; - template <typename Fx> - auto push_invoke(Fx&& fx) { - return push_invoke_t<Fx>(std::forward<Fx>(fx)); + template <typename T> + auto pass_as_value(T& value_ref_) { + return forward_as_value_t<T>(value_ref_); } struct override_value_t { }; @@ -7093,13 +7800,13 @@ namespace sol { new_table& operator=(const new_table&) = default; new_table& operator=(new_table&&) = default; - new_table(int sequence_hint, int map_hint = 0) : sequence_hint(sequence_hint), map_hint(map_hint) { + new_table(int sequence_hint_, int map_hint_ = 0) noexcept : sequence_hint(sequence_hint_), map_hint(map_hint_) { } }; const new_table create = {}; - enum class lib : char { + enum class lib : unsigned char { // print, assert, and other base functions base, // require and other package functions @@ -7176,7 +7883,7 @@ namespace sol { enum class type : int { none = LUA_TNONE, lua_nil = LUA_TNIL, -#if SOL_IS_ON(SOL_NIL_I_) +#if SOL_IS_ON(SOL_NIL) nil = lua_nil, #endif // Objective C/C++ Keyword that's found in OSX SDK and OBJC -- check for all forms to protect string = LUA_TSTRING, @@ -7273,7 +7980,7 @@ namespace sol { return names[static_cast<std::size_t>(c)]; } - enum class meta_function { + enum class meta_function : unsigned { construct, index, new_index, @@ -7362,7 +8069,7 @@ namespace sol { } inline const std::string& to_string(meta_function mf) { - return meta_function_names()[static_cast<int>(mf)]; + return meta_function_names()[static_cast<std::size_t>(mf)]; } inline type type_of(lua_State* L, int index) { @@ -7374,8 +8081,20 @@ namespace sol { } template <typename T> + struct is_stateless_lua_reference + : std::integral_constant<bool, + (std::is_base_of_v<stateless_stack_reference, T> || std::is_base_of_v<stateless_reference, T>)&&( + !std::is_base_of_v<stack_reference, T> && !std::is_base_of_v<reference, T> && !std::is_base_of_v<main_reference, T>)> { }; + + template <typename T> + inline constexpr bool is_stateless_lua_reference_v = is_stateless_lua_reference<T>::value; + + template <typename T> struct is_lua_reference - : std::integral_constant<bool, std::is_base_of_v<reference, T> || std::is_base_of_v<main_reference, T> || std::is_base_of_v<stack_reference, T>> { }; + : std::integral_constant<bool, + std::is_base_of_v<reference, + T> || std::is_base_of_v<main_reference, T> || std::is_base_of_v<stack_reference, T> || std::is_base_of_v<stateless_stack_reference, T> || std::is_base_of_v<stateless_reference, T>> { + }; template <typename T> inline constexpr bool is_lua_reference_v = is_lua_reference<T>::value; @@ -7387,21 +8106,17 @@ namespace sol { inline constexpr bool is_lua_reference_or_proxy_v = is_lua_reference_or_proxy<T>::value; template <typename T> - struct is_transparent_argument : std::false_type { }; + struct is_transparent_argument + : std::integral_constant<bool, + std::is_same_v<meta::unqualified_t<T>, + this_state> || std::is_same_v<meta::unqualified_t<T>, this_main_state> || std::is_same_v<meta::unqualified_t<T>, this_environment> || std::is_same_v<meta::unqualified_t<T>, variadic_args>> { + }; template <typename T> constexpr inline bool is_transparent_argument_v = is_transparent_argument<T>::value; - template <> - struct is_transparent_argument<this_state> : std::true_type { }; - template <> - struct is_transparent_argument<this_main_state> : std::true_type { }; - template <> - struct is_transparent_argument<this_environment> : std::true_type { }; - template <> - struct is_transparent_argument<variadic_args> : std::true_type { }; template <typename T> - struct is_variadic_arguments : std::is_same<T, variadic_args> { }; + struct is_variadic_arguments : meta::any<std::is_same<T, variadic_args>, meta::is_optional<T>> { }; template <typename T> struct is_container @@ -7417,6 +8132,15 @@ namespace sol { struct is_to_stringable : meta::any<meta::supports_to_string_member<meta::unqualified_t<T>>, meta::supports_adl_to_string<meta::unqualified_t<T>>, meta::supports_op_left_shift<std::ostream, meta::unqualified_t<T>>> { }; + template <typename T> + inline constexpr bool is_to_stringable_v = is_to_stringable<T>::value; + + template <typename T> + struct is_callable : std::true_type { }; + + template <typename T> + inline constexpr bool is_callable_v = is_callable<T>::value; + namespace detail { template <typename T, typename = void> struct lua_type_of : std::integral_constant<type, type::userdata> { }; @@ -7433,6 +8157,11 @@ namespace sol { template <std::size_t N> struct lua_type_of<wchar_t[N]> : std::integral_constant<type, type::string> { }; +#if SOL_IS_ON(SOL_CHAR8_T) + template <std::size_t N> + struct lua_type_of<char8_t[N]> : std::integral_constant<type, type::string> { }; +#endif + template <std::size_t N> struct lua_type_of<char16_t[N]> : std::integral_constant<type, type::string> { }; @@ -7445,6 +8174,11 @@ namespace sol { template <> struct lua_type_of<wchar_t> : std::integral_constant<type, type::string> { }; +#if SOL_IS_ON(SOL_CHAR8_T) + template <> + struct lua_type_of<char8_t> : std::integral_constant<type, type::string> { }; +#endif + template <> struct lua_type_of<char16_t> : std::integral_constant<type, type::string> { }; @@ -7455,6 +8189,14 @@ namespace sol { struct lua_type_of<const char*> : std::integral_constant<type, type::string> { }; template <> + struct lua_type_of<const wchar_t*> : std::integral_constant<type, type::string> { }; + +#if SOL_IS_ON(SOL_CHAR8_T) + template <> + struct lua_type_of<const char8_t*> : std::integral_constant<type, type::string> { }; +#endif + + template <> struct lua_type_of<const char16_t*> : std::integral_constant<type, type::string> { }; template <> @@ -7598,7 +8340,7 @@ namespace sol { template <> struct lua_type_of<type> : std::integral_constant<type, type::poly> { }; -#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_) +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) template <typename T> struct lua_type_of<T*> : std::integral_constant<type, std::is_function_v<T> ? type::function : type::userdata> { }; #else @@ -7619,7 +8361,7 @@ namespace sol { template <> struct lua_type_of<meta_function> : std::integral_constant<type, type::string> { }; -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#if SOL_IS_ON(SOL_STD_VARIANT) template <typename... Tn> struct lua_type_of<std::variant<Tn...>> : std::integral_constant<type, type::poly> { }; #endif // std::variant deployment sucks on Clang @@ -7663,20 +8405,16 @@ namespace sol { inline constexpr int lua_size_v = lua_size<T>::value; namespace detail { - template <typename...> - struct void_ { - typedef void type; - }; - template <typename T, typename = void> - struct has_internal_marker_impl : std::false_type { }; - template <typename T> - struct has_internal_marker_impl<T, typename void_<typename T::SOL_INTERNAL_UNSPECIALIZED_MARKER_>::type> : std::true_type { }; - + // MSVC's decltype detection is broken, which breaks other + // parts of the code. So we add more workarounds. The moment it's fixed, + // we take it away and break everyone that doesn't upgrade. template <typename T> - using has_internal_marker = has_internal_marker_impl<T>; + using is_msvc_callable_rigged = meta::any<meta::is_specialization_of<T, push_invoke_t>, meta::is_specialization_of<T, as_table_t>, + meta::is_specialization_of<T, forward_as_value_t>, meta::is_specialization_of<T, as_container_t>, meta::is_specialization_of<T, nested>, + meta::is_specialization_of<T, yielding_t>>; template <typename T> - constexpr inline bool has_internal_marker_v = has_internal_marker<T>::value; + inline constexpr bool is_msvc_callable_rigged_v = is_msvc_callable_rigged<T>::value; } // namespace detail template <typename T> @@ -7684,16 +8422,32 @@ namespace sol { : std::integral_constant<bool, type::userdata != lua_type_of_v< - T> || ((type::userdata == lua_type_of_v<T>)&&detail::has_internal_marker_v<lua_type_of<T>> && !detail::has_internal_marker_v<lua_size<T>>) + T> || ((type::userdata == lua_type_of_v<T>)&&meta::meta_detail::has_internal_marker_v<lua_type_of<T>> && !meta::meta_detail::has_internal_marker_v<lua_size<T>>) || is_lua_reference_or_proxy_v<T> || meta::is_specialization_of_v<T, std::tuple> || meta::is_specialization_of_v<T, std::pair>> { }; template <typename T> constexpr inline bool is_lua_primitive_v = is_lua_primitive<T>::value; template <typename T> + struct is_value_semantic_for_function +#if SOL_IS_ON(SOL_FUNCTION_CALL_VALUE_SEMANTICS) + : std::true_type { + }; +#else + : std::false_type { + }; +#endif + + template <typename T> + constexpr inline bool is_value_semantic_for_function_v = is_value_semantic_for_function<T>::value; + + template <typename T> struct is_main_threaded : std::is_base_of<main_reference, T> { }; template <typename T> + inline constexpr bool is_main_threaded_v = is_main_threaded<T>::value; + + template <typename T> struct is_stack_based : std::is_base_of<stack_reference, T> { }; template <> struct is_stack_based<variadic_args> : std::true_type { }; @@ -7779,6 +8533,14 @@ namespace sol { inline constexpr bool is_table_v = is_table<T>::value; template <typename T> + struct is_global_table : std::false_type { }; + template <typename T> + struct is_global_table<basic_table_core<true, T>> : std::true_type { }; + + template <typename T> + inline constexpr bool is_global_table_v = is_global_table<T>::value; + + template <typename T> struct is_stack_table : std::false_type { }; template <bool x, typename T> struct is_stack_table<basic_table_core<x, T>> : std::integral_constant<bool, std::is_base_of_v<stack_reference, T>> { }; @@ -7822,7 +8584,7 @@ namespace sol { template <typename T> struct is_automagical : std::integral_constant<bool, - (SOL_IS_ON(SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_)) + (SOL_IS_ON(SOL_DEFAULT_AUTOMAGICAL_USERTYPES)) || (std::is_array_v< meta::unqualified_t<T>> || (!std::is_same_v<meta::unqualified_t<T>, state> && !std::is_same_v<meta::unqualified_t<T>, state_view>))> { }; @@ -7888,6 +8650,56 @@ namespace sol { template <typename T> inline constexpr bool is_lua_c_function_v = is_lua_c_function<T>::value; + enum class automagic_flags : unsigned { + none = 0x000u, + default_constructor = 0x001, + destructor = 0x002u, + pairs_operator = 0x004u, + to_string_operator = 0x008u, + call_operator = 0x010u, + less_than_operator = 0x020u, + less_than_or_equal_to_operator = 0x040u, + length_operator = 0x080u, + equal_to_operator = 0x100u, + all = default_constructor | destructor | pairs_operator | to_string_operator | call_operator | less_than_operator | less_than_or_equal_to_operator + | length_operator | equal_to_operator + }; + + inline constexpr automagic_flags operator|(automagic_flags left, automagic_flags right) noexcept { + return static_cast<automagic_flags>( + static_cast<std::underlying_type_t<automagic_flags>>(left) | static_cast<std::underlying_type_t<automagic_flags>>(right)); + } + + inline constexpr automagic_flags operator&(automagic_flags left, automagic_flags right) noexcept { + return static_cast<automagic_flags>( + static_cast<std::underlying_type_t<automagic_flags>>(left) & static_cast<std::underlying_type_t<automagic_flags>>(right)); + } + + inline constexpr automagic_flags& operator|=(automagic_flags& left, automagic_flags right) noexcept { + left = left | right; + return left; + } + + inline constexpr automagic_flags& operator&=(automagic_flags& left, automagic_flags right) noexcept { + left = left & right; + return left; + } + + template <typename Left, typename Right> + constexpr bool has_flag(Left left, Right right) noexcept { + return (left & right) == right; + } + + template <typename Left, typename Right> + constexpr bool has_any_flag(Left left, Right right) noexcept { + return (left & right) != static_cast<Left>(static_cast<std::underlying_type_t<Left>>(0)); + } + + template <typename Left, typename Right> + constexpr auto clear_flags(Left left, Right right) noexcept { + return static_cast<Left>(static_cast<std::underlying_type_t<Left>>(left) & ~static_cast<std::underlying_type_t<Right>>(right)); + } + struct automagic_enrollments { bool default_constructor = true; bool destructor = true; @@ -7900,6 +8712,9 @@ namespace sol { bool equal_to_operator = true; }; + template <automagic_flags compile_time_defaults = automagic_flags::all> + struct constant_automagic_enrollments : public automagic_enrollments { }; + } // namespace sol // end of sol/types.hpp @@ -7907,7 +8722,7 @@ namespace sol { #include <exception> #include <cstring> -#if SOL_IS_ON(SOL_PRINT_ERRORS_I_) +#if SOL_IS_ON(SOL_PRINT_ERRORS) #include <iostream> #endif @@ -7925,9 +8740,9 @@ namespace sol { // must push at least 1 object on the stack inline int default_exception_handler(lua_State* L, optional<const std::exception&>, string_view what) { -#if SOL_IS_ON(SOL_PRINT_ERRORS_I_) - std::cerr << "[sol3] An exception occurred: "; - std::cerr.write(what.data(), what.size()); +#if SOL_IS_ON(SOL_PRINT_ERRORS) + std::cerr << "[sol2] An exception occurred: "; + std::cerr.write(what.data(), static_cast<std::streamsize>(what.size())); std::cerr << std::endl; #endif lua_pushlstring(L, what.data(), what.size()); @@ -7950,13 +8765,13 @@ namespace sol { return exfunc(L, std::move(maybe_ex), std::move(what)); } -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) +#if SOL_IS_OFF(SOL_EXCEPTIONS) template <lua_CFunction f> int static_trampoline(lua_State* L) noexcept { return f(L); } -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) template <lua_CFunction_noexcept f> int static_trampoline_noexcept(lua_State* L) noexcept { return f(L); @@ -7979,9 +8794,8 @@ namespace sol { #else inline int lua_cfunction_trampoline(lua_State* L, lua_CFunction f) { -#if SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS_I_) +#if SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS) return f(L); - #else try { return f(L); @@ -7995,7 +8809,7 @@ namespace sol { catch (const std::exception& e) { call_exception_handler(L, optional<const std::exception&>(e), e.what()); } -#if SOL_IS_OFF(SOL_USE_LUAJIT_I_) +#if SOL_IS_ON(SOL_EXCEPTIONS_CATCH_ALL) // LuaJIT cannot have the catchall when the safe propagation is on // but LuaJIT will swallow all C++ errors // if we don't at least catch std::exception ones @@ -8012,7 +8826,7 @@ namespace sol { return lua_cfunction_trampoline(L, f); } -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) template <lua_CFunction_noexcept f> int static_trampoline_noexcept(lua_State* L) noexcept { return f(L); @@ -8030,7 +8844,7 @@ namespace sol { return f(L, std::forward<Args>(args)...); } else { -#if SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS_I_) +#if SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS) return f(L, std::forward<Args>(args)...); #else try { @@ -8045,7 +8859,7 @@ namespace sol { catch (const std::exception& e) { call_exception_handler(L, optional<const std::exception&>(e), e.what()); } -#if SOL_IS_OFF(SOL_USE_LUAJIT_I_) +#if SOL_IS_ON(SOL_EXCEPTIONS_CATCH_ALL) // LuaJIT cannot have the catchall when the safe propagation is on // but LuaJIT will swallow all C++ errors // if we don't at least catch std::exception ones @@ -8065,12 +8879,18 @@ namespace sol { template <typename F, F fx> inline int typed_static_trampoline(lua_State* L) { +#if 0 + // TODO: you must evaluate the get/check_get of every + // argument, to ensure it doesn't throw + // (e.g., for the sol_lua_check_access extension point!) + // This incluudes properly noexcept-ing all the above + // trampolines / safety nets if constexpr (meta::bind_traits<F>::is_noexcept) { return static_trampoline_noexcept<fx>(L); } - else { - return static_trampoline<fx>(L); - } + else +#endif + { return static_trampoline<fx>(L); } } } // namespace detail @@ -8097,7 +8917,7 @@ namespace sol { #include <string> #include <array> #include <cctype> -#if SOL_IS_ON(SOL_MINGW_CCTYPE_IS_POISONED_I_) +#if SOL_IS_ON(SOL_MINGW_CCTYPE_IS_POISONED) extern "C" { #include <ctype.h> } @@ -8115,7 +8935,7 @@ namespace sol { namespace detail { "`anonymous-namespace'", "`anonymous namespace'" } }; -#if SOL_IS_ON(SOL_COMPILER_GCC_I_) || SOL_IS_ON(SOL_COMPILER_CLANG_I_) +#if SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) inline std::string ctti_get_type_name_from_sig(std::string name) { // cardinal sins from MINGW using namespace std; @@ -8153,7 +8973,7 @@ namespace sol { namespace detail { inline std::string ctti_get_type_name() { return ctti_get_type_name_from_sig(__PRETTY_FUNCTION__); } -#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#elif SOL_IS_ON(SOL_COMPILER_VCXX) inline std::string ctti_get_type_name_from_sig(std::string name) { std::size_t start = name.find("get_type_name"); if (start == std::string::npos) @@ -8206,8 +9026,8 @@ namespace sol { namespace detail { { "operator<", "operator<<", "operator<<=", "operator<=", "operator>", "operator>>", "operator>>=", "operator>=", "operator->", "operator->*" } }; int level = 0; - std::ptrdiff_t idx = 0; - for (idx = static_cast<std::ptrdiff_t>(realname.empty() ? 0 : realname.size() - 1); idx > 0; --idx) { + std::size_t idx = 0; + for (idx = static_cast<std::size_t>(realname.empty() ? 0 : realname.size() - 1); idx > 0; --idx) { if (level == 0 && realname[idx] == ':') { break; } @@ -8222,7 +9042,7 @@ namespace sol { namespace detail { continue; std::size_t nisopidx = idx - op.size() + 1; if (nisop == nisopidx) { - idx = static_cast<std::ptrdiff_t>(nisopidx); + idx = static_cast<std::size_t>(nisopidx); earlybreak = true; } break; @@ -8299,94 +9119,207 @@ namespace sol { namespace sol { - template <typename T> - struct unique_usertype_traits { - typedef T type; - typedef T actual_type; - template <typename X> - using rebind_base = void; + namespace detail { + template <typename T> + struct unique_fallback { + using SOL_INTERNAL_UNSPECIALIZED_MARKER_ = int; + }; - static const bool value = false; + template <typename T> + struct unique_fallback<std::shared_ptr<T>> { + private: + using pointer = typename std::pointer_traits<std::shared_ptr<T>>::element_type*; - template <typename U> - static bool is_null(U&&) { - return false; - } + public: + // rebind is non-void + // if and only if unique usertype + // is cast-capable + template <typename X> + using rebind_actual_type = std::shared_ptr<X>; - template <typename U> - static auto get(U&& value) { - return std::addressof(detail::deref(value)); - } - }; + static bool is_null(lua_State*, const std::shared_ptr<T>& p) noexcept { + return p == nullptr; + } - template <typename T> - struct unique_usertype_traits<std::shared_ptr<T>> { - typedef T type; - typedef std::shared_ptr<T> actual_type; - // rebind is non-void - // if and only if unique usertype - // is cast-capable - template <typename X> - using rebind_base = std::shared_ptr<X>; + static pointer get(lua_State*, const std::shared_ptr<T>& p) noexcept { + return p.get(); + } + }; - static const bool value = true; + template <typename T, typename D> + struct unique_fallback<std::unique_ptr<T, D>> { + private: + using pointer = typename std::unique_ptr<T, D>::pointer; - static bool is_null(const actual_type& p) { - return p == nullptr; - } + public: + static bool is_null(lua_State*, const std::unique_ptr<T, D>& p) noexcept { + return p == nullptr; + } - static type* get(const actual_type& p) { - return p.get(); - } - }; + static pointer get(lua_State*, const std::unique_ptr<T, D>& p) noexcept { + return p.get(); + } + }; + } // namespace detail - template <typename T, typename D> - struct unique_usertype_traits<std::unique_ptr<T, D>> { - using type = T; - using actual_type = std::unique_ptr<T, D>; + namespace meta { namespace meta_detail { + template <typename T, typename = void> + struct unique_actual_type; - static const bool value = true; + template <typename T> + struct unique_actual_type<T, meta::void_t<typename T::actual_type>> { + using type = typename T::actual_type; + }; - static bool is_null(const actual_type& p) { - return p == nullptr; - } + template <typename T, typename... Rest, template <typename...> class Templ> + struct unique_actual_type<Templ<T, Rest...>> { + using type = T; + }; - static type* get(const actual_type& p) { - return p.get(); - } - }; + }} // namespace meta::meta_detail template <typename T> - struct is_unique_usertype : std::integral_constant<bool, unique_usertype_traits<T>::value> {}; + using unique_usertype_actual_t = typename meta::meta_detail::unique_actual_type<unique_usertype_traits<T>>::type; + + namespace meta { namespace meta_detail { + template <typename T> + using value_test_t = decltype(T::value); + + template <typename T> + using type_test_t = typename T::type; + + template <typename T> + using type_element_type_t = typename T::element_type; + + template <typename T, typename = void> + struct unique_element_type { + using type = typename std::pointer_traits<typename unique_actual_type<T>::type>::element_type; + }; + + template <typename T> + struct unique_element_type<T, std::enable_if_t<meta::is_detected_v<type_element_type_t, T>>> { + using type = typename T::element_type; + }; + + template <typename T> + struct unique_element_type<T, std::enable_if_t<meta::is_detected_v<type_test_t, T>>> { + using type = typename T::type; + }; + + template <typename T, typename = void> + struct unique_valid : std::integral_constant<bool, !has_internal_marker_v<T>> { }; + + template <typename T> + struct unique_valid<T, meta::void_t<decltype(T::value)>> : std::integral_constant<bool, T::value> { }; + }} // namespace meta::meta_detail template <typename T> - inline constexpr bool is_unique_usertype_v = is_unique_usertype<T>::value; + using unique_usertype_element_t = typename meta::meta_detail::unique_element_type<unique_usertype_traits<T>>::type; - namespace detail { - template <typename T, typename Rebind = void> - using is_base_rebindable_test = typename T::template rebind_base<Rebind>; - } + template <typename T, typename Element = void> + using unique_usertype_rebind_actual_t = typename unique_usertype_traits<T>::template rebind_actual_type<Element>; + + template <typename T> + struct unique_usertype_traits : public detail::unique_fallback<T> { }; template <typename T> - using is_base_rebindable = meta::is_detected<detail::is_base_rebindable_test, T>; + struct is_unique_usertype : std::integral_constant<bool, meta::meta_detail::unique_valid<unique_usertype_traits<T>>::value> { }; template <typename T> - inline constexpr bool is_base_rebindable_v = is_base_rebindable<T>::value; + inline constexpr bool is_unique_usertype_v = is_unique_usertype<T>::value; + + namespace meta { namespace meta_detail { + template <typename T> + using adl_sol_lua_check_access_test_t + = decltype(sol_lua_check_access(types<T>(), static_cast<lua_State*>(nullptr), -1, std::declval<stack::record&>())); + + template <typename T> + inline constexpr bool is_adl_sol_lua_check_access_v = meta::is_detected_v<adl_sol_lua_check_access_test_t, T>; + + template <typename T> + using unique_usertype_get_with_state_test_t + = decltype(unique_usertype_traits<T>::get(static_cast<lua_State*>(nullptr), std::declval<unique_usertype_actual_t<T>>())); + + template <typename T> + inline constexpr bool unique_usertype_get_with_state_v = meta::is_detected_v<unique_usertype_get_with_state_test_t, T>; + + template <typename T> + using unique_usertype_is_null_with_state_test_t + = decltype(unique_usertype_traits<T>::is_null(static_cast<lua_State*>(nullptr), std::declval<unique_usertype_actual_t<T>>())); + + template <typename T> + inline constexpr bool unique_usertype_is_null_with_state_v = meta::is_detected_v<unique_usertype_is_null_with_state_test_t, T>; + }} // namespace meta::meta_detail namespace detail { - template <typename T, typename = void> - struct is_base_rebindable_non_void_sfinae : std::false_type {}; + template <typename T> + constexpr bool unique_is_null_noexcept() noexcept { + if constexpr (meta::meta_detail::unique_usertype_is_null_with_state_v<std::remove_cv_t<T>>) { + return noexcept( + unique_usertype_traits<T>::is_null(static_cast<lua_State*>(nullptr), std::declval<unique_usertype_actual_t<std::remove_cv_t<T>>>())); + } + else { + return noexcept(unique_usertype_traits<T>::is_null(std::declval<unique_usertype_actual_t<std::remove_cv_t<T>>>())); + } + } template <typename T> - struct is_base_rebindable_non_void_sfinae<T, std::enable_if_t<is_base_rebindable_v<T>>> - : std::integral_constant<bool, !std::is_void_v<typename T::template rebind_base<void>>> {}; + bool unique_is_null(lua_State* L_, T& value_) noexcept(unique_is_null_noexcept<std::remove_cv_t<T>>()) { + using Tu = std::remove_cv_t<T>; + if constexpr (meta::meta_detail::unique_usertype_is_null_with_state_v<Tu>) { + return unique_usertype_traits<Tu>::is_null(L_, value_); + } + else { + return unique_usertype_traits<Tu>::is_null(value_); + } + } + + template <typename T> + constexpr bool unique_get_noexcept() noexcept { + if constexpr (meta::meta_detail::unique_usertype_get_with_state_v<std::remove_cv_t<T>>) { + return noexcept( + unique_usertype_traits<T>::get(static_cast<lua_State*>(nullptr), std::declval<unique_usertype_actual_t<std::remove_cv_t<T>>>())); + } + else { + return noexcept(unique_usertype_traits<T>::get(std::declval<unique_usertype_actual_t<std::remove_cv_t<T>>>())); + } + } + + template <typename T> + auto unique_get(lua_State* L_, T& value_) noexcept(unique_get_noexcept<std::remove_cv_t<T>>()) { + using Tu = std::remove_cv_t<T>; + if constexpr (meta::meta_detail::unique_usertype_get_with_state_v<Tu>) { + return unique_usertype_traits<Tu>::get(L_, value_); + } + else { + return unique_usertype_traits<Tu>::get(value_); + } + } } // namespace detail - template <typename T> - using is_base_rebindable_non_void = meta::is_detected<detail::is_base_rebindable_test, T>; + namespace meta { namespace meta_detail { + template <typename T, typename Element = void> + using is_rebind_actual_type_test_t = typename T::template rebind_actual_type<Element>; - template <typename T> - inline constexpr bool is_base_rebindable_non_void_v = is_base_rebindable_non_void<T>::value; + template <typename T, typename Element = void> + using is_rebind_actual_type = meta::is_detected<is_rebind_actual_type_test_t, T, Element>; + + template <typename T, typename Element = void> + inline constexpr bool is_rebind_actual_type_v = is_rebind_actual_type<T, Element>::value; + + template <typename T, typename Element, bool = is_rebind_actual_type_v<T, Element>> + struct is_actual_type_rebindable_for_test : std::false_type { }; + + template <typename T, typename Element> + struct is_actual_type_rebindable_for_test<T, Element, true> + : std::integral_constant<bool, !std::is_void_v<typename T::template rebind_actual_type<Element>>> { }; + }} // namespace meta::meta_detail + + template <typename T, typename Element = void> + using is_actual_type_rebindable_for = typename meta::meta_detail::is_actual_type_rebindable_for_test<unique_usertype_traits<T>, Element>::type; + + template <typename T, typename Element = void> + inline constexpr bool is_actual_type_rebindable_for_v = is_actual_type_rebindable_for<T, Element>::value; } // namespace sol @@ -8394,7 +9327,7 @@ namespace sol { namespace sol { template <typename... Args> - struct base_list {}; + struct base_list { }; template <typename... Args> using bases = base_list<Args...>; @@ -8402,7 +9335,7 @@ namespace sol { const auto base_classes = base_classes_tag(); template <typename... Args> - struct is_to_stringable<base_list<Args...>> : std::false_type {}; + struct is_to_stringable<base_list<Args...>> : std::false_type { }; namespace detail { @@ -8443,7 +9376,7 @@ namespace sol { return ti == usertype_traits<T>::qualified_name() || type_check_bases(bases_t(), ti); } - template <typename ...Bases> + template <typename... Bases> static bool type_check_with(const string_view& ti) { return ti == usertype_traits<T>::qualified_name() || type_check_bases(types<Bases...>(), ti); } @@ -8455,7 +9388,8 @@ namespace sol { template <typename Base, typename... Args> static void* type_cast_bases(types<Base, Args...>, T* data, const string_view& ti) { // Make sure to convert to T first, and then dynamic cast to the proper type - return ti != usertype_traits<Base>::qualified_name() ? type_cast_bases(types<Args...>(), data, ti) : static_cast<void*>(static_cast<Base*>(data)); + return ti != usertype_traits<Base>::qualified_name() ? type_cast_bases(types<Args...>(), data, ti) + : static_cast<void*>(static_cast<Base*>(data)); } static void* type_cast(void* voiddata, const string_view& ti) { @@ -8477,7 +9411,7 @@ namespace sol { template <typename U, typename Base, typename... Args> static int type_unique_cast_bases(types<Base, Args...>, void* source_data, void* target_data, const string_view& ti) { using uu_traits = unique_usertype_traits<U>; - using base_ptr = typename uu_traits::template rebind_base<Base>; + using base_ptr = typename uu_traits::template rebind_actual_type<Base>; string_view base_ti = usertype_traits<Base>::qualified_name(); if (base_ti == ti) { if (target_data != nullptr) { @@ -8493,11 +9427,10 @@ namespace sol { template <typename U> static int type_unique_cast(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) { - typedef unique_usertype_traits<U> uu_traits; - if constexpr (is_base_rebindable_v<uu_traits>) { - typedef typename uu_traits::template rebind_base<void> rebind_t; - typedef meta::conditional_t<std::is_void<rebind_t>::value, types<>, bases_t> cond_bases_t; - string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name(); + if constexpr (is_actual_type_rebindable_for_v<U>) { + using rebound_actual_type = unique_usertype_rebind_actual_t<U>; + using maybe_bases_or_empty = meta::conditional_t<std::is_void_v<rebound_actual_type>, types<>, bases_t>; + string_view this_rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); if (rebind_ti != this_rebind_ti) { // this is not even of the same unique type return 0; @@ -8507,7 +9440,7 @@ namespace sol { // direct match, return 1 return 1; } - return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti); + return type_unique_cast_bases<U>(maybe_bases_or_empty(), source_data, target_data, ti); } else { (void)rebind_ti; @@ -8523,11 +9456,10 @@ namespace sol { template <typename U, typename... Bases> static int type_unique_cast_with(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) { using uc_bases_t = types<Bases...>; - typedef unique_usertype_traits<U> uu_traits; - if constexpr (is_base_rebindable_v<uu_traits>) { - using rebind_t = typename uu_traits::template rebind_base<void>; - using cond_bases_t = meta::conditional_t<std::is_void<rebind_t>::value, types<>, uc_bases_t>; - string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name(); + if constexpr (is_actual_type_rebindable_for_v<U>) { + using rebound_actual_type = unique_usertype_rebind_actual_t<U>; + using cond_bases_t = meta::conditional_t<std::is_void_v<rebound_actual_type>, types<>, uc_bases_t>; + string_view this_rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); if (rebind_ti != this_rebind_ti) { // this is not even of the same unique type return 0; @@ -8577,7 +9509,7 @@ namespace sol { constexpr const char* not_enough_stack_space_integral = "not enough space left on Lua stack for an integral number"; constexpr const char* not_enough_stack_space_string = "not enough space left on Lua stack for a string"; constexpr const char* not_enough_stack_space_meta_function_name = "not enough space left on Lua stack for the name of a meta_function"; - constexpr const char* not_enough_stack_space_userdata = "not enough space left on Lua stack to create a sol3 userdata"; + constexpr const char* not_enough_stack_space_userdata = "not enough space left on Lua stack to create a sol2 userdata"; constexpr const char* not_enough_stack_space_generic = "not enough space left on Lua stack to push valuees"; constexpr const char* not_enough_stack_space_environment = "not enough space left on Lua stack to retrieve environment"; constexpr const char* protected_function_error = "caught (...) unknown error during protected_function call"; @@ -8596,7 +9528,7 @@ namespace sol { case type::poly: return "anything"; case type::userdata: { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 2, "not enough space to push get the type name"); #endif // make sure stack doesn't overflow if (lua_getmetatable(L, index) == 0) { @@ -8727,8 +9659,8 @@ namespace sol { class stateless_stack_reference { private: friend class stack_reference; - - int index = 0; + + int m_index = 0; int registry_index() const noexcept { return LUA_NOREF; @@ -8736,16 +9668,16 @@ namespace sol { public: stateless_stack_reference() noexcept = default; - stateless_stack_reference(lua_nil_t) noexcept : stateless_stack_reference(){}; - stateless_stack_reference(lua_State* L, int i) noexcept : stateless_stack_reference(absolute_index(L, i)) { + stateless_stack_reference(lua_nil_t) noexcept : stateless_stack_reference() {}; + stateless_stack_reference(lua_State* L_, int index_) noexcept : stateless_stack_reference(absolute_index(L_, index_)) { } - stateless_stack_reference(lua_State*, absolute_index i) noexcept : stateless_stack_reference(i) { + stateless_stack_reference(lua_State*, absolute_index index_) noexcept : stateless_stack_reference(index_) { } - stateless_stack_reference(lua_State*, raw_index i) noexcept : stateless_stack_reference(i) { + stateless_stack_reference(lua_State*, raw_index index_) noexcept : stateless_stack_reference(index_) { } - stateless_stack_reference(absolute_index i) noexcept : index(i) { + stateless_stack_reference(absolute_index index_) noexcept : m_index(index_) { } - stateless_stack_reference(raw_index i) noexcept : index(i) { + stateless_stack_reference(raw_index index_) noexcept : m_index(index_) { } stateless_stack_reference(lua_State*, ref_index) noexcept = delete; stateless_stack_reference(ref_index) noexcept = delete; @@ -8755,30 +9687,30 @@ namespace sol { stateless_stack_reference& operator=(stateless_stack_reference&&) noexcept = default; stateless_stack_reference& operator=(const stateless_stack_reference&) noexcept = default; - int push(lua_State* L) const noexcept { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) - luaL_checkstack(L, 1, "not enough Lua stack space to push a single reference value"); + int push(lua_State* L_) const noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push a single reference value"); #endif // make sure stack doesn't overflow - lua_pushvalue(L, index); + lua_pushvalue(L_, m_index); return 1; } - void pop(lua_State* L, int n = 1) const noexcept { - lua_pop(L, n); + void pop(lua_State* L_, int pop_count = 1) const noexcept { + lua_pop(L_, pop_count); } int stack_index() const noexcept { - return index; + return m_index; } - const void* pointer(lua_State* L) const noexcept { - const void* vp = lua_topointer(L, stack_index()); - return vp; + const void* pointer(lua_State* L_) const noexcept { + const void* pointer_id = lua_topointer(L_, stack_index()); + return pointer_id; } - type get_type(lua_State* L) const noexcept { - int result = lua_type(L, index); - return static_cast<type>(result); + type get_type(lua_State* L_) const noexcept { + int untyped_value = lua_type(L_, stack_index()); + return static_cast<type>(untyped_value); } bool valid(lua_State* L) const noexcept { @@ -8786,8 +9718,32 @@ namespace sol { return t != type::lua_nil && t != type::none; } - void abandon(lua_State* = nullptr) { - index = 0; + void reset(lua_State*) noexcept { + m_index = 0; + } + + void reset(lua_State* L_, int index_) noexcept { + m_index = absolute_index(L_, index_); + } + + void abandon(lua_State* = nullptr) noexcept { + m_index = 0; + } + + stateless_stack_reference copy(lua_State* L_) const noexcept { + return stateless_stack_reference(L_, raw_index(m_index)); + } + + void copy_assign(lua_State*, const stateless_stack_reference& right) noexcept { + m_index = right.m_index; + } + + bool equals(lua_State* L_, const stateless_stack_reference& r) const noexcept { + return lua_compare(L_, this->stack_index(), r.stack_index(), LUA_OPEQ) == 1; + } + + bool equals(lua_State* L_, lua_nil_t) const noexcept { + return valid(L_); } }; @@ -8797,8 +9753,7 @@ namespace sol { public: stack_reference() noexcept = default; - stack_reference(lua_nil_t) noexcept - : stack_reference() {}; + stack_reference(lua_nil_t) noexcept : stack_reference() {}; stack_reference(lua_State* L, lua_nil_t) noexcept : stateless_stack_reference(L, 0), luastate(L) { } stack_reference(lua_State* L, int i) noexcept : stateless_stack_reference(L, i), luastate(L) { @@ -8809,22 +9764,21 @@ namespace sol { } stack_reference(lua_State* L, ref_index i) noexcept = delete; stack_reference(lua_State* L, const reference& r) noexcept = delete; - stack_reference(lua_State* L, const stack_reference& r) noexcept - : luastate(L) { + stack_reference(lua_State* L, const stack_reference& r) noexcept : luastate(L) { if (!r.valid()) { - index = 0; + m_index = 0; return; } int i = r.stack_index(); if (detail::xmovable(lua_state(), r.lua_state())) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, "not enough Lua stack space to push a single reference value"); #endif // make sure stack doesn't overflow - lua_pushvalue(r.lua_state(), r.index); + lua_pushvalue(r.lua_state(), r.stack_index()); lua_xmove(r.lua_state(), luastate, 1); i = absolute_index(luastate, -1); } - index = i; + m_index = i; } stack_reference(stack_reference&& o) noexcept = default; stack_reference& operator=(stack_reference&&) noexcept = default; @@ -8835,16 +9789,16 @@ namespace sol { return push(lua_state()); } - int push(lua_State* Ls) const noexcept { - return stateless_stack_reference::push(Ls); + int push(lua_State* L_) const noexcept { + return stateless_stack_reference::push(L_); } void pop() const noexcept { pop(lua_state()); } - void pop(lua_State* Ls, int n = 1) const noexcept { - stateless_stack_reference::pop(Ls, n); + void pop(lua_State* L_, int pop_count_ = 1) const noexcept { + stateless_stack_reference::pop(L_, pop_count_); } const void* pointer() const noexcept { @@ -8863,13 +9817,13 @@ namespace sol { return stateless_stack_reference::valid(lua_state()); } - void abandon () { + void abandon() { stateless_stack_reference::abandon(lua_state()); } }; inline bool operator==(const stack_reference& l, const stack_reference& r) { - return lua_compare(l.lua_state(), l.stack_index(), r.stack_index(), LUA_OPEQ) == 0; + return lua_compare(l.lua_state(), l.stack_index(), r.stack_index(), LUA_OPEQ) == 1; } inline bool operator!=(const stack_reference& l, const stack_reference& r) { @@ -8892,7 +9846,43 @@ namespace sol { return rhs.valid(); } + inline bool operator==(const stateless_stack_reference& l, const stateless_stack_reference& r) { + return l.stack_index() == r.stack_index(); + } + + inline bool operator!=(const stateless_stack_reference& l, const stateless_stack_reference& r) { + return l.stack_index() != r.stack_index(); + } + + struct stateless_stack_reference_equals { + using is_transparent = std::true_type; + + stateless_stack_reference_equals(lua_State* L_) noexcept : m_L(L_) { + } + + lua_State* lua_state() const noexcept { + return m_L; + } + + bool operator()(const stateless_stack_reference& lhs, const stateless_stack_reference& rhs) const { + return lhs.equals(lua_state(), rhs); + } + + bool operator()(lua_nil_t lhs, const stateless_stack_reference& rhs) const { + return rhs.equals(lua_state(), lhs); + } + + bool operator()(const stateless_stack_reference& lhs, lua_nil_t rhs) const { + return lhs.equals(lua_state(), rhs); + } + + private: + lua_State* m_L; + }; + struct stack_reference_equals { + using is_transparent = std::true_type; + bool operator()(const lua_nil_t& lhs, const stack_reference& rhs) const { return lhs == rhs; } @@ -8906,11 +9896,33 @@ namespace sol { } }; + struct stateless_stack_reference_hash { + using argument_type = stateless_stack_reference; + using result_type = std::size_t; + using is_transparent = std::true_type; + + stateless_stack_reference_hash(lua_State* L_) noexcept : m_L(L_) { + } + + lua_State* lua_state() const noexcept { + return m_L; + } + + result_type operator()(const argument_type& lhs) const noexcept { + std::hash<const void*> h; + return h(lhs.pointer(lua_state())); + } + + private: + lua_State* m_L; + }; + struct stack_reference_hash { - typedef stack_reference argument_type; - typedef std::size_t result_type; + using argument_type = stack_reference; + using result_type = std::size_t; + using is_transparent = std::true_type; - result_type operator()(const argument_type& lhs) const { + result_type operator()(const argument_type& lhs) const noexcept { std::hash<const void*> h; return h(lhs.pointer()); } @@ -8930,29 +9942,29 @@ namespace sol { } // namespace detail namespace stack { - inline void remove(lua_State* L, int rawindex, int count) { + inline void remove(lua_State* L_, int rawindex, int count) { if (count < 1) return; - int top = lua_gettop(L); + 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<int>(count)); + lua_pop(L_, static_cast<int>(count)); return; } // Remove each item one at a time using stack operations // Probably slower, maybe, haven't benchmarked, // but necessary - int index = lua_absindex(L, rawindex); + int index = lua_absindex(L_, rawindex); if (index < 0) { - index = lua_gettop(L) + (index + 1); + index = lua_gettop(L_) + (index + 1); } int last = index + count; for (int i = index; i < last; ++i) { - lua_remove(L, index); + lua_remove(L_, index); } } @@ -8960,7 +9972,7 @@ namespace sol { lua_State* L; int index; int count; - push_popper_at(lua_State* luastate, int index = -1, int count = 1) : L(luastate), index(index), count(count) { + push_popper_at(lua_State* L_, int index_ = -1, int count_ = 1) : L(L_), index(index_), count(count_) { } ~push_popper_at() { remove(L, index, count); @@ -8970,15 +9982,15 @@ namespace sol { template <bool top_level> struct push_popper_n { lua_State* L; - int t; - push_popper_n(lua_State* luastate, int x) : L(luastate), t(x) { + int pop_count; + push_popper_n(lua_State* L_, int pop_count_) : L(L_), pop_count(pop_count_) { } push_popper_n(const push_popper_n&) = delete; push_popper_n(push_popper_n&&) = default; push_popper_n& operator=(const push_popper_n&) = delete; push_popper_n& operator=(push_popper_n&&) = default; ~push_popper_n() { - lua_pop(L, t); + lua_pop(L, pop_count); } }; @@ -8991,18 +10003,18 @@ namespace sol { template <bool, typename T, typename = void> struct push_popper { using Tu = meta::unqualified_t<T>; - T t; - int idx; + T m_object; + int m_index; - push_popper(T x) : t(x), idx(lua_absindex(t.lua_state(), -t.push())) { + push_popper(T object_) noexcept : m_object(object_), m_index(lua_absindex(m_object.lua_state(), -m_object.push())) { } - int index_of(const Tu&) { - return idx; + int index_of(const Tu&) const noexcept { + return m_index; } ~push_popper() { - t.pop(); + m_object.pop(); } }; @@ -9010,10 +10022,10 @@ namespace sol { struct push_popper<true, T, C> { using Tu = meta::unqualified_t<T>; - push_popper(T) { + push_popper(T) noexcept { } - int index_of(const Tu&) { + int index_of(const Tu&) const noexcept { return -1; } @@ -9025,69 +10037,122 @@ namespace sol { struct push_popper<false, T, std::enable_if_t<is_stack_based_v<meta::unqualified_t<T>>>> { using Tu = meta::unqualified_t<T>; - push_popper(T) { + push_popper(T) noexcept { } - int index_of(const Tu& r) { - return r.stack_index(); + int index_of(const Tu& object_) const noexcept { + return object_.stack_index(); } ~push_popper() { } }; + template <bool, typename T, typename = void> + struct stateless_push_popper { + using Tu = meta::unqualified_t<T>; + lua_State* m_L; + T m_object; + int m_index; + + stateless_push_popper(lua_State* L_, T object_) noexcept : m_L(L_), m_object(object_), m_index(lua_absindex(m_L, -m_object.push(m_L))) { + } + + int index_of(const Tu&) const noexcept { + return m_index; + } + + ~stateless_push_popper() { + m_object.pop(m_L); + } + }; + + template <typename T, typename C> + struct stateless_push_popper<true, T, C> { + using Tu = meta::unqualified_t<T>; + + stateless_push_popper(lua_State*, T) noexcept { + } + + int index_of(lua_State*, const Tu&) const noexcept { + return -1; + } + + ~stateless_push_popper() { + } + }; + + template <typename T> + struct stateless_push_popper<false, T, std::enable_if_t<is_stack_based_v<meta::unqualified_t<T>>>> { + using Tu = meta::unqualified_t<T>; + lua_State* m_L; + + stateless_push_popper(lua_State* L_, T) noexcept : m_L(L_) { + } + + int index_of(const Tu& object_) const noexcept { + return object_.stack_index(); + } + + ~stateless_push_popper() { + } + }; + template <bool top_level = false, typename T> push_popper<top_level, T> push_pop(T&& x) { return push_popper<top_level, T>(std::forward<T>(x)); } + template <bool top_level = false, typename T> + stateless_push_popper<top_level, T> push_pop(lua_State* L_, T&& object_) { + return stateless_push_popper<top_level, T>(L_, std::forward<T>(object_)); + } + template <typename T> - push_popper_at push_pop_at(T&& x) { - int c = x.push(); - lua_State* L = x.lua_state(); - return push_popper_at(L, lua_absindex(L, -c), c); + push_popper_at push_pop_at(T&& object_) { + int push_count = object_.push(); + lua_State* L = object_.lua_state(); + return push_popper_at(L, lua_absindex(L, -push_count), push_count); } template <bool top_level = false> - push_popper_n<top_level> pop_n(lua_State* L, int x) { - return push_popper_n<top_level>(L, x); + push_popper_n<top_level> pop_n(lua_State* L_, int pop_count_) { + return push_popper_n<top_level>(L_, pop_count_); } } // namespace stack - inline lua_State* main_thread(lua_State* L, lua_State* backup_if_unsupported = nullptr) { -#if SOL_LUA_VESION_I_ < 502 - if (L == nullptr) - return backup_if_unsupported; - lua_getglobal(L, detail::default_main_thread_name()); - auto pp = stack::pop_n(L, 1); - if (type_of(L, -1) == type::thread) { - return lua_tothread(L, -1); + inline lua_State* main_thread(lua_State* L_, lua_State* backup_if_unsupported_ = nullptr) { +#if SOL_LUA_VERSION_I_ < 502 + if (L_ == nullptr) + return backup_if_unsupported_; + lua_getglobal(L_, detail::default_main_thread_name()); + auto pp = stack::pop_n(L_, 1); + if (type_of(L_, -1) == type::thread) { + return lua_tothread(L_, -1); } - return backup_if_unsupported; + return backup_if_unsupported_; #else - if (L == nullptr) - return backup_if_unsupported; - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); - lua_State* Lmain = lua_tothread(L, -1); - lua_pop(L, 1); + if (L_ == nullptr) + return backup_if_unsupported_; + lua_rawgeti(L_, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); + lua_State* Lmain = lua_tothread(L_, -1); + lua_pop(L_, 1); return Lmain; #endif // Lua 5.2+ has the main thread unqualified_getter } namespace detail { - struct global_tag { - } const global_ {}; struct no_safety_tag { - } const no_safety {}; + } inline constexpr no_safety {}; template <bool b> - inline lua_State* pick_main_thread(lua_State* L, lua_State* backup_if_unsupported = nullptr) { - (void)L; + inline lua_State* pick_main_thread(lua_State* L_, lua_State* backup_if_unsupported = nullptr) { + (void)L_; (void)backup_if_unsupported; if (b) { - return main_thread(L, backup_if_unsupported); + return main_thread(L_, backup_if_unsupported); } - return L; + return L_; } } // namespace detail @@ -9098,24 +10163,24 @@ namespace sol { int ref = LUA_NOREF; - int copy(lua_State* L) const noexcept { + int copy_ref(lua_State* L_) const noexcept { if (ref == LUA_NOREF) return LUA_NOREF; - push(L); - return luaL_ref(L, LUA_REGISTRYINDEX); + push(L_); + return luaL_ref(L_, LUA_REGISTRYINDEX); } - lua_State* copy_assign(lua_State* L, lua_State* rL, const stateless_reference& r) { - if (valid(L)) { - deref(L); + lua_State* copy_assign_ref(lua_State* L_, lua_State* rL, const stateless_reference& r) { + if (valid(L_)) { + deref(L_); } - ref = r.copy(L); + ref = r.copy_ref(L_); return rL; } - lua_State* move_assign(lua_State* L, lua_State* rL, stateless_reference&& r) { - if (valid(L)) { - deref(L); + lua_State* move_assign(lua_State* L_, lua_State* rL, stateless_reference&& r) { + if (valid(L_)) { + deref(L_); } ref = r.ref; r.ref = LUA_NOREF; @@ -9127,12 +10192,12 @@ namespace sol { return -1; } - stateless_reference(lua_State* L, detail::global_tag) noexcept { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) - luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); + stateless_reference(lua_State* L_, global_tag_t) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); #endif // make sure stack doesn't overflow - lua_pushglobaltable(L); - ref = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushglobaltable(L_); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); } stateless_reference(int raw_ref_index) noexcept : ref(raw_ref_index) { @@ -9146,24 +10211,24 @@ namespace sol { } stateless_reference(stack_reference&& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) { } - stateless_reference(lua_State* L, const stateless_reference& r) noexcept { + stateless_reference(lua_State* L_, const stateless_reference& r) noexcept { if (r.ref == LUA_REFNIL) { ref = LUA_REFNIL; return; } - if (r.ref == LUA_NOREF || L == nullptr) { + if (r.ref == LUA_NOREF || L_ == nullptr) { ref = LUA_NOREF; return; } - ref = r.copy(L); + ref = r.copy_ref(L_); } - stateless_reference(lua_State* L, stateless_reference&& r) noexcept { + stateless_reference(lua_State* L_, stateless_reference&& r) noexcept { if (r.ref == LUA_REFNIL) { ref = LUA_REFNIL; return; } - if (r.ref == LUA_NOREF || L == nullptr) { + if (r.ref == LUA_NOREF || L_ == nullptr) { ref = LUA_NOREF; return; } @@ -9171,8 +10236,8 @@ namespace sol { r.ref = LUA_NOREF; } - stateless_reference(lua_State* L, const stack_reference& r) noexcept { - if (L == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { + stateless_reference(lua_State* L_, const stack_reference& r) noexcept { + if (L_ == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { ref = LUA_NOREF; return; } @@ -9180,24 +10245,28 @@ namespace sol { ref = LUA_REFNIL; return; } - if (L != r.lua_state() && !detail::xmovable(L, r.lua_state())) { + if (L_ != r.lua_state() && !detail::xmovable(L_, r.lua_state())) { return; } - r.push(L); - ref = luaL_ref(L, LUA_REGISTRYINDEX); + r.push(L_); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); } - stateless_reference(lua_State* L, int index = -1) noexcept { - // use L to stick with that state's execution stack -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) - luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); + stateless_reference(lua_State* L_, const stateless_stack_reference& r) noexcept : stateless_reference(L_, r.stack_index()) { + } + + stateless_reference(lua_State* L_, int index = -1) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); #endif // make sure stack doesn't overflow - lua_pushvalue(L, index); - ref = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushvalue(L_, index); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); } - stateless_reference(lua_State* L, ref_index index) noexcept { - lua_rawgeti(L, LUA_REGISTRYINDEX, index.index); - ref = luaL_ref(L, LUA_REGISTRYINDEX); + stateless_reference(lua_State* L_, absolute_index index_) noexcept : stateless_reference(L_, index_.index) { + } + stateless_reference(lua_State* L_, ref_index index_) noexcept { + lua_rawgeti(L_, LUA_REGISTRYINDEX, index_.index); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); } stateless_reference(lua_State*, lua_nil_t) noexcept { } @@ -9217,37 +10286,53 @@ namespace sol { return *this; } - int push(lua_State* L) const noexcept { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) - luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); + int push(lua_State* L_) const noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); #endif // make sure stack doesn't overflow - lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + lua_rawgeti(L_, LUA_REGISTRYINDEX, ref); return 1; } - void pop(lua_State* L, int n = 1) const noexcept { - lua_pop(L, n); + void pop(lua_State* L_, int n = 1) const noexcept { + lua_pop(L_, n); } int registry_index() const noexcept { return ref; } + void reset(lua_State* L_) noexcept { + if (valid(L_)) { + deref(L_); + } + ref = LUA_NOREF; + } + + void reset(lua_State* L_, int index_) noexcept { + reset(L_); +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_pushvalue(L_, index_); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); + } + bool valid(lua_State*) const noexcept { return !(ref == LUA_NOREF || ref == LUA_REFNIL); } - const void* pointer(lua_State* L) const noexcept { - int si = push(L); - const void* vp = lua_topointer(L, -si); - lua_pop(L, si); + const void* pointer(lua_State* L_) const noexcept { + int si = push(L_); + const void* vp = lua_topointer(L_, -si); + lua_pop(L_, si); return vp; } - type get_type(lua_State* L) const noexcept { - int p = push(L); - int result = lua_type(L, -1); - pop(L, p); + type get_type(lua_State* L_) const noexcept { + int p = push(L_); + int result = lua_type(L_, -1); + pop(L_, p); return static_cast<type>(result); } @@ -9255,8 +10340,40 @@ namespace sol { ref = LUA_NOREF; } - void deref(lua_State* L) const noexcept { - luaL_unref(L, LUA_REGISTRYINDEX, ref); + void deref(lua_State* L_) const noexcept { + luaL_unref(L_, LUA_REGISTRYINDEX, ref); + } + + stateless_reference copy(lua_State* L_) const noexcept { + if (!valid(L_)) { + return {}; + } + return stateless_reference(copy_ref(L_)); + } + + void copy_assign(lua_State* L_, const stateless_reference& right) noexcept { + if (valid(L_)) { + deref(L_); + } + if (!right.valid(L_)) { + return; + } + ref = right.copy_ref(L_); + } + + bool equals(lua_State* L_, const stateless_reference& r) const noexcept { + auto ppl = stack::push_pop(L_, *this); + auto ppr = stack::push_pop(L_, r); + return lua_compare(L_, -1, -2, LUA_OPEQ) == 1; + } + + bool equals(lua_State* L_, const stateless_stack_reference& r) const noexcept { + auto ppl = stack::push_pop(L_, *this); + return lua_compare(L_, -1, r.stack_index(), LUA_OPEQ) == 1; + } + + bool equals(lua_State* L_, lua_nil_t) const noexcept { + return valid(L_); } }; @@ -9268,7 +10385,7 @@ namespace sol { lua_State* luastate = nullptr; // non-owning template <bool r_main_only> - void copy_assign(const basic_reference<r_main_only>& r) { + void copy_assign_complex(const basic_reference<r_main_only>& r) { if (valid()) { deref(); } @@ -9288,7 +10405,7 @@ namespace sol { return; } luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); - ref = r.copy(); + ref = r.copy_ref(); } template <bool r_main_only> @@ -9319,11 +10436,10 @@ namespace sol { } protected: - basic_reference(lua_State* L, detail::global_tag) noexcept - : basic_reference(detail::pick_main_thread<main_only>(L, L), detail::global_, detail::global_) { + basic_reference(lua_State* L_, global_tag_t) noexcept : basic_reference(detail::pick_main_thread<main_only>(L_, L_), global_tag, global_tag) { } - basic_reference(lua_State* L, detail::global_tag, detail::global_tag) noexcept : stateless_reference(L, detail::global_), luastate(L) { + basic_reference(lua_State* L_, global_tag_t, global_tag_t) noexcept : stateless_reference(L_, global_tag), luastate(L_) { } basic_reference(lua_State* oL, const basic_reference<!main_only>& o) noexcept : stateless_reference(oL, o), luastate(oL) { @@ -9333,12 +10449,12 @@ namespace sol { return stateless_reference::deref(lua_state()); } - int copy() const noexcept { - return copy(lua_state()); + int copy_ref() const noexcept { + return copy_ref(lua_state()); } - int copy(lua_State* L) const noexcept { - return stateless_reference::copy(L); + int copy_ref(lua_State* L_) const noexcept { + return stateless_reference::copy_ref(L_); } public: @@ -9350,7 +10466,7 @@ namespace sol { basic_reference(stack_reference&& r) noexcept : basic_reference(r.lua_state(), r.stack_index()) { } template <bool r_main_only> - basic_reference(lua_State* L, const basic_reference<r_main_only>& r) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) { + basic_reference(lua_State* L_, const basic_reference<r_main_only>& r) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { if (r.ref == LUA_REFNIL) { ref = LUA_REFNIL; return; @@ -9364,11 +10480,11 @@ namespace sol { ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); return; } - ref = r.copy(); + ref = r.copy_ref(); } template <bool r_main_only> - basic_reference(lua_State* L, basic_reference<r_main_only>&& r) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) { + basic_reference(lua_State* L_, basic_reference<r_main_only>&& r) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { if (r.ref == LUA_REFNIL) { ref = LUA_REFNIL; return; @@ -9387,7 +10503,7 @@ namespace sol { r.luastate = nullptr; } - basic_reference(lua_State* L, const stack_reference& r) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) { + basic_reference(lua_State* L_, const stack_reference& r) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { if (lua_state() == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { ref = LUA_NOREF; return; @@ -9402,19 +10518,19 @@ namespace sol { r.push(lua_state()); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } - basic_reference(lua_State* L, int index = -1) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) { - // use L to stick with that state's execution stack -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) - luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); + basic_reference(lua_State* L_, int index = -1) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { + // use L_ to stick with that state's execution stack +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); #endif // make sure stack doesn't overflow - lua_pushvalue(L, index); - ref = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushvalue(L_, index); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); } - basic_reference(lua_State* L, ref_index index) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) { + basic_reference(lua_State* L_, ref_index index) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, index.index); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } - basic_reference(lua_State* L, lua_nil_t) noexcept : luastate(detail::pick_main_thread<main_only>(L, L)) { + basic_reference(lua_State* L_, lua_nil_t) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { } ~basic_reference() noexcept { @@ -9423,7 +10539,7 @@ namespace sol { deref(); } - basic_reference(const basic_reference& o) noexcept : stateless_reference(o.copy()), luastate(o.lua_state()) { + basic_reference(const basic_reference& o) noexcept : stateless_reference(o.copy_ref()), luastate(o.lua_state()) { } basic_reference(basic_reference&& o) noexcept : stateless_reference(std::move(o)), luastate(o.lua_state()) { @@ -9446,7 +10562,7 @@ namespace sol { } basic_reference& operator=(const basic_reference& r) noexcept { - copy_assign(r); + copy_assign_complex(r); return *this; } @@ -9456,16 +10572,12 @@ namespace sol { } basic_reference& operator=(const basic_reference<!main_only>& r) noexcept { - copy_assign(r); + copy_assign_complex(r); return *this; } basic_reference& operator=(const lua_nil_t&) noexcept { - if (valid()) { - deref(); - } - luastate = nullptr; - ref = LUA_NOREF; + reset(); return *this; } @@ -9479,17 +10591,22 @@ namespace sol { return push(lua_state()); } - int push(lua_State* L) const noexcept { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) - luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); + void reset() noexcept { + stateless_reference::reset(luastate); + luastate = nullptr; + } + + int push(lua_State* L_) const noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); #endif // make sure stack doesn't overflow if (lua_state() == nullptr) { - lua_pushnil(L); + lua_pushnil(L_); return 1; } lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, ref); - if (L != lua_state()) { - lua_xmove(lua_state(), L, 1); + if (L_ != lua_state()) { + lua_xmove(lua_state(), L_, 1); } return 1; } @@ -9498,8 +10615,8 @@ namespace sol { pop(lua_state()); } - void pop(lua_State* L, int n = 1) const noexcept { - stateless_reference::pop(L, n); + void pop(lua_State* L_, int n = 1) const noexcept { + stateless_reference::pop(L_, n); } int registry_index() const noexcept { @@ -9510,6 +10627,10 @@ namespace sol { return stateless_reference::valid(lua_state()); } + bool valid(lua_State* L_) const noexcept { + return stateless_reference::valid(L_); + } + const void* pointer() const noexcept { return stateless_reference::pointer(lua_state()); } @@ -9528,92 +10649,152 @@ namespace sol { }; template <bool lb, bool rb> - inline bool operator==(const basic_reference<lb>& l, const basic_reference<rb>& r) { + inline bool operator==(const basic_reference<lb>& l, const basic_reference<rb>& r) noexcept { auto ppl = stack::push_pop(l); auto ppr = stack::push_pop(r); return lua_compare(l.lua_state(), -1, -2, LUA_OPEQ) == 1; } template <bool lb, bool rb> - inline bool operator!=(const basic_reference<lb>& l, const basic_reference<rb>& r) { + inline bool operator!=(const basic_reference<lb>& l, const basic_reference<rb>& r) noexcept { return !operator==(l, r); } template <bool lb> - inline bool operator==(const basic_reference<lb>& l, const stack_reference& r) { + inline bool operator==(const basic_reference<lb>& l, const stack_reference& r) noexcept { auto ppl = stack::push_pop(l); return lua_compare(l.lua_state(), -1, r.stack_index(), LUA_OPEQ) == 1; } template <bool lb> - inline bool operator!=(const basic_reference<lb>& l, const stack_reference& r) { + inline bool operator!=(const basic_reference<lb>& l, const stack_reference& r) noexcept { return !operator==(l, r); } template <bool rb> - inline bool operator==(const stack_reference& l, const basic_reference<rb>& r) { + inline bool operator==(const stack_reference& l, const basic_reference<rb>& r) noexcept { auto ppr = stack::push_pop(r); return lua_compare(l.lua_state(), -1, r.stack_index(), LUA_OPEQ) == 1; } template <bool rb> - inline bool operator!=(const stack_reference& l, const basic_reference<rb>& r) { + inline bool operator!=(const stack_reference& l, const basic_reference<rb>& r) noexcept { return !operator==(l, r); } template <bool lb> - inline bool operator==(const basic_reference<lb>& lhs, const lua_nil_t&) { + inline bool operator==(const basic_reference<lb>& lhs, const lua_nil_t&) noexcept { return !lhs.valid(); } template <bool rb> - inline bool operator==(const lua_nil_t&, const basic_reference<rb>& rhs) { + inline bool operator==(const lua_nil_t&, const basic_reference<rb>& rhs) noexcept { return !rhs.valid(); } template <bool lb> - inline bool operator!=(const basic_reference<lb>& lhs, const lua_nil_t&) { + inline bool operator!=(const basic_reference<lb>& lhs, const lua_nil_t&) noexcept { return lhs.valid(); } template <bool rb> - inline bool operator!=(const lua_nil_t&, const basic_reference<rb>& rhs) { + inline bool operator!=(const lua_nil_t&, const basic_reference<rb>& rhs) noexcept { return rhs.valid(); } + inline bool operator==(const stateless_reference& l, const stateless_reference& r) noexcept { + return l.registry_index() == r.registry_index(); + } + + inline bool operator!=(const stateless_reference& l, const stateless_reference& r) noexcept { + return l.registry_index() != r.registry_index(); + } + + inline bool operator==(const stateless_reference& lhs, const lua_nil_t&) noexcept { + return lhs.registry_index() == LUA_REFNIL; + } + + inline bool operator==(const lua_nil_t&, const stateless_reference& rhs) noexcept { + return rhs.registry_index() == LUA_REFNIL; + } + + inline bool operator!=(const stateless_reference& lhs, const lua_nil_t&) noexcept { + return lhs.registry_index() != LUA_REFNIL; + } + + inline bool operator!=(const lua_nil_t&, const stateless_reference& rhs) noexcept { + return rhs.registry_index() != LUA_REFNIL; + } + + struct stateless_reference_equals : public stateless_stack_reference_equals { + using is_transparent = std::true_type; + + stateless_reference_equals(lua_State* L_) noexcept : stateless_stack_reference_equals(L_) { + } + + bool operator()(const lua_nil_t& lhs, const stateless_reference& rhs) const noexcept { + return rhs.equals(lua_state(), lhs); + } + + bool operator()(const stateless_reference& lhs, const lua_nil_t& rhs) const noexcept { + return lhs.equals(lua_state(), rhs); + } + + bool operator()(const stateless_reference& lhs, const stateless_reference& rhs) const noexcept { + return lhs.equals(lua_state(), rhs); + } + }; + struct reference_equals : public stack_reference_equals { + using is_transparent = std::true_type; + template <bool rb> - bool operator()(const lua_nil_t& lhs, const basic_reference<rb>& rhs) const { + bool operator()(const lua_nil_t& lhs, const basic_reference<rb>& rhs) const noexcept { return lhs == rhs; } template <bool lb> - bool operator()(const basic_reference<lb>& lhs, const lua_nil_t& rhs) const { + bool operator()(const basic_reference<lb>& lhs, const lua_nil_t& rhs) const noexcept { return lhs == rhs; } template <bool lb, bool rb> - bool operator()(const basic_reference<lb>& lhs, const basic_reference<rb>& rhs) const { + bool operator()(const basic_reference<lb>& lhs, const basic_reference<rb>& rhs) const noexcept { return lhs == rhs; } template <bool lb> - bool operator()(const basic_reference<lb>& lhs, const stack_reference& rhs) const { + bool operator()(const basic_reference<lb>& lhs, const stack_reference& rhs) const noexcept { return lhs == rhs; } template <bool rb> - bool operator()(const stack_reference& lhs, const basic_reference<rb>& rhs) const { + bool operator()(const stack_reference& lhs, const basic_reference<rb>& rhs) const noexcept { return lhs == rhs; } }; + struct stateless_reference_hash : public stateless_stack_reference_hash { + using argument_type = stateless_reference; + using result_type = std::size_t; + using is_transparent = std::true_type; + + stateless_reference_hash(lua_State* L_) noexcept : stateless_stack_reference_hash(L_) { + } + + result_type operator()(const stateless_reference& lhs) const noexcept { + std::hash<const void*> h; + return h(lhs.pointer(lua_state())); + } + }; + struct reference_hash : public stack_reference_hash { - typedef reference argument_type; - typedef std::size_t result_type; + using argument_type = reference; + using result_type = std::size_t; + using is_transparent = std::true_type; template <bool lb> - result_type operator()(const basic_reference<lb>& lhs) const { + result_type operator()(const basic_reference<lb>& lhs) const noexcept { std::hash<const void*> h; return h(lhs.pointer()); } @@ -9628,14 +10809,14 @@ namespace sol { namespace detail { template <typename T> - struct is_speshul : std::false_type {}; + struct is_speshul : std::false_type { }; } // namespace detail template <typename T> - struct tie_size : std::tuple_size<T> {}; + struct tie_size : std::tuple_size<T> { }; template <typename T> - struct is_tieable : std::integral_constant<bool, (::sol::tie_size<T>::value > 0)> {}; + struct is_tieable : std::integral_constant<bool, (::sol::tie_size<T>::value > 0)> { }; template <typename... Tn> struct tie_t : public std::tuple<std::add_lvalue_reference_t<Tn>...> { @@ -9659,15 +10840,13 @@ namespace sol { template <std::size_t... I, typename T> void set_extra(std::true_type, std::index_sequence<I...>, T&& target) { using std::get; - (void)detail::swallow{0, - (get<I>(static_cast<base_t&>(*this)) = get<I>(types<Tn...>(), target), 0)..., 0}; + (void)detail::swallow { 0, (get<I>(static_cast<base_t&>(*this)) = get<I>(types<Tn...>(), target), 0)..., 0 }; } template <std::size_t... I, typename T> void set_extra(std::false_type, std::index_sequence<I...>, T&& target) { using std::get; - (void)detail::swallow{0, - (get<I>(static_cast<base_t&>(*this)) = get<I>(target), 0)..., 0}; + (void)detail::swallow { 0, (get<I>(static_cast<base_t&>(*this)) = get<I>(target), 0)..., 0 }; } public: @@ -9682,7 +10861,7 @@ namespace sol { }; template <typename... Tn> - struct tie_size<tie_t<Tn...>> : std::tuple_size<std::tuple<Tn...>> {}; + struct tie_size<tie_t<Tn...>> : std::tuple_size<std::tuple<Tn...>> { }; namespace adl_barrier_detail { template <typename... Tn> @@ -9704,7 +10883,7 @@ namespace sol { namespace sol { namespace detail { inline void stack_fail(int, int) { -#if !(defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS) +#if SOL_IS_ON(SOL_EXCEPTIONS) throw error(detail::direct_error, "imbalanced stack after operation finish"); #else // Lol, what do you want, an error printout? :3c @@ -9743,9 +10922,11 @@ namespace sol { #include <bitset> #include <forward_list> #include <string> +#include <limits> #include <algorithm> #include <sstream> #include <optional> +#include <type_traits> namespace sol { namespace detail { @@ -9760,51 +10941,75 @@ namespace sol { template <typename T> struct as_table_tag { }; + template <typename Tag> + inline constexpr bool is_tagged_v + = meta::is_specialization_of_v<Tag, + detail:: + as_pointer_tag> || meta::is_specialization_of_v<Tag, as_value_tag> || meta::is_specialization_of_v<Tag, as_unique_tag> || meta::is_specialization_of_v<Tag, as_table_tag> || std::is_same_v<Tag, as_reference_tag> || std::is_same_v<Tag, with_function_tag>; + using lua_reg_table = luaL_Reg[64]; using unique_destructor = void (*)(void*); using unique_tag = detail::inheritance_unique_cast_function; - inline void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space, std::size_t& required_space) { - // this handels arbitrary alignments... + inline void* alloc_newuserdata(lua_State* L, std::size_t bytesize) { +#if SOL_LUA_VERSION_I_ >= 504 + return lua_newuserdatauv(L, bytesize, 1); +#else + return lua_newuserdata(L, bytesize); +#endif + } + + constexpr std::uintptr_t align(std::size_t alignment, std::uintptr_t ptr, std::size_t& space) { + // this handles arbitrary alignments... // make this into a power-of-2-only? // actually can't: this is a C++14-compatible framework, // power of 2 alignment is C++17 - std::uintptr_t initial = reinterpret_cast<std::uintptr_t>(ptr); - std::uintptr_t offby = static_cast<std::uintptr_t>(initial % alignment); + std::uintptr_t offby = static_cast<std::uintptr_t>(ptr % alignment); std::uintptr_t padding = (alignment - offby) % alignment; - required_space += size + padding; - if (space < required_space) { - return nullptr; - } - ptr = static_cast<void*>(static_cast<char*>(ptr) + padding); + ptr += padding; space -= padding; return ptr; } - inline void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space) { - std::size_t required_space = 0; - return align(alignment, size, ptr, space, required_space); + inline void* align(std::size_t alignment, void* ptr, std::size_t& space) { + return reinterpret_cast<void*>(align(alignment, reinterpret_cast<std::uintptr_t>(ptr), space)); } - inline void align_one(std::size_t a, std::size_t s, void*& target_alignment) { + constexpr std::uintptr_t align_one(std::size_t alignment, std::size_t size, std::uintptr_t ptr) { std::size_t space = (std::numeric_limits<std::size_t>::max)(); - target_alignment = align(a, s, target_alignment, space); - target_alignment = static_cast<void*>(static_cast<char*>(target_alignment) + s); + return align(alignment, ptr, space) + size; } template <typename... Args> - std::size_t aligned_space_for(void* alignment = nullptr) { - // use temporary storage to prevent strict UB shenanigans - char alignment_shim[(std::max)({ sizeof(Args)... }) + (std::max)({ alignof(Args)... })] {}; - char* start = alignment == nullptr ? static_cast<char*>(alignment) : alignment_shim; - (void)detail::swallow { int {}, (align_one(std::alignment_of_v<Args>, sizeof(Args), alignment), int {})... }; - return static_cast<char*>(alignment) - start; + constexpr std::size_t aligned_space_for(std::uintptr_t ptr) { + std::uintptr_t end = ptr; + ((end = align_one(alignof(Args), sizeof(Args), end)), ...); + return static_cast<std::size_t>(end - ptr); + } + + template <typename... Args> + constexpr std::size_t aligned_space_for() { + static_assert(sizeof...(Args) > 0); + + constexpr std::size_t max_arg_alignment = (std::max)({ alignof(Args)... }); + if constexpr (max_arg_alignment <= alignof(std::max_align_t)) { + // If all types are `good enough`, simply calculate alignment in case of the worst allocator + std::size_t worst_required_size = 0; + for (std::size_t ptr = 0; ptr < max_arg_alignment; ptr++) { + worst_required_size = (std::max)(worst_required_size, aligned_space_for<Args...>(ptr)); + } + return worst_required_size; + } + else { + // For over-aligned types let's assume that every Arg in Args starts at the worst aligned address + return (aligned_space_for<Args>(0x1) + ...); + } } inline void* align_usertype_pointer(void* ptr) { using use_align = std::integral_constant<bool, -#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_) +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) false #else (std::alignment_of<void*>::value > 1) @@ -9814,13 +11019,13 @@ namespace sol { return ptr; } std::size_t space = (std::numeric_limits<std::size_t>::max)(); - return align(std::alignment_of<void*>::value, sizeof(void*), ptr, space); + return align(std::alignment_of<void*>::value, ptr, space); } template <bool pre_aligned = false, bool pre_shifted = false> void* align_usertype_unique_destructor(void* ptr) { using use_align = std::integral_constant<bool, -#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_) +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) false #else (std::alignment_of<unique_destructor>::value > 1) @@ -9836,13 +11041,13 @@ namespace sol { return static_cast<void*>(static_cast<void**>(ptr) + 1); } std::size_t space = (std::numeric_limits<std::size_t>::max)(); - return align(std::alignment_of<unique_destructor>::value, sizeof(unique_destructor), ptr, space); + return align(std::alignment_of<unique_destructor>::value, ptr, space); } template <bool pre_aligned = false, bool pre_shifted = false> void* align_usertype_unique_tag(void* ptr) { using use_align = std::integral_constant<bool, -#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_) +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) false #else (std::alignment_of<unique_tag>::value > 1) @@ -9858,13 +11063,13 @@ namespace sol { return ptr; } std::size_t space = (std::numeric_limits<std::size_t>::max)(); - return align(std::alignment_of<unique_tag>::value, sizeof(unique_tag), ptr, space); + return align(std::alignment_of<unique_tag>::value, ptr, space); } template <typename T, bool pre_aligned = false, bool pre_shifted = false> void* align_usertype_unique(void* ptr) { typedef std::integral_constant<bool, -#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_) +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) false #else (std::alignment_of_v<T> > 1) @@ -9881,13 +11086,13 @@ namespace sol { return ptr; } std::size_t space = (std::numeric_limits<std::size_t>::max)(); - return align(std::alignment_of_v<T>, sizeof(T), ptr, space); + return align(std::alignment_of_v<T>, ptr, space); } template <typename T> void* align_user(void* ptr) { typedef std::integral_constant<bool, -#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_) +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) false #else (std::alignment_of_v<T> > 1) @@ -9898,13 +11103,13 @@ namespace sol { return ptr; } std::size_t space = (std::numeric_limits<std::size_t>::max)(); - return align(std::alignment_of_v<T>, sizeof(T), ptr, space); + return align(std::alignment_of_v<T>, ptr, space); } template <typename T> T** usertype_allocate_pointer(lua_State* L) { typedef std::integral_constant<bool, -#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_) +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) false #else (std::alignment_of<T*>::value > 1) @@ -9912,37 +11117,28 @@ namespace sol { > use_align; if (!use_align::value) { - T** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*))); + T** pointerpointer = static_cast<T**>(alloc_newuserdata(L, sizeof(T*))); return pointerpointer; } - static const std::size_t initial_size = aligned_space_for<T*>(nullptr); - static const std::size_t misaligned_size = aligned_space_for<T*>(reinterpret_cast<void*>(0x1)); + constexpr std::size_t initial_size = aligned_space_for<T*>(); std::size_t allocated_size = initial_size; - void* unadjusted = lua_newuserdata(L, initial_size); - void* adjusted = align(std::alignment_of<T*>::value, sizeof(T*), unadjusted, allocated_size); + void* unadjusted = alloc_newuserdata(L, initial_size); + void* adjusted = align(std::alignment_of<T*>::value, unadjusted, allocated_size); if (adjusted == nullptr) { + // trash allocator can burn in hell lua_pop(L, 1); - // what kind of absolute garbage trash allocator are we dealing with? - // whatever, add some padding in the case of MAXIMAL alignment waste... - allocated_size = misaligned_size; - unadjusted = lua_newuserdata(L, allocated_size); - adjusted = align(std::alignment_of<T*>::value, sizeof(T*), unadjusted, allocated_size); - if (adjusted == nullptr) { - // trash allocator can burn in hell - lua_pop(L, 1); - // luaL_error(L, "if you are the one that wrote this allocator you should feel bad for doing a - // worse job than malloc/realloc and should go read some books, yeah?"); - luaL_error(L, "cannot properly align memory for '%s'", detail::demangle<T*>().data()); - } + // luaL_error(L, "if you are the one that wrote this allocator you should feel bad for doing a + // worse job than malloc/realloc and should go read some books, yeah?"); + luaL_error(L, "cannot properly align memory for '%s'", detail::demangle<T*>().data()); } return static_cast<T**>(adjusted); } - inline bool attempt_alloc(lua_State* L, std::size_t ptr_align, std::size_t ptr_size, std::size_t value_align, std::size_t value_size, + inline bool attempt_alloc(lua_State* L, std::size_t ptr_align, std::size_t ptr_size, std::size_t value_align, std::size_t allocated_size, void*& pointer_adjusted, void*& data_adjusted) { - void* adjusted = lua_newuserdata(L, allocated_size); - pointer_adjusted = align(ptr_align, ptr_size, adjusted, allocated_size); + void* adjusted = alloc_newuserdata(L, allocated_size); + pointer_adjusted = align(ptr_align, adjusted, allocated_size); if (pointer_adjusted == nullptr) { lua_pop(L, 1); return false; @@ -9950,7 +11146,7 @@ namespace sol { // subtract size of what we're going to allocate there allocated_size -= ptr_size; adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + ptr_size); - data_adjusted = align(value_align, value_size, adjusted, allocated_size); + data_adjusted = align(value_align, adjusted, allocated_size); if (data_adjusted == nullptr) { lua_pop(L, 1); return false; @@ -9958,10 +11154,10 @@ namespace sol { return true; } - inline bool attempt_alloc_unique(lua_State* L, std::size_t ptr_align, std::size_t ptr_size, std::size_t real_align, std::size_t real_size, + inline bool attempt_alloc_unique(lua_State* L, std::size_t ptr_align, std::size_t ptr_size, std::size_t real_align, std::size_t allocated_size, void*& pointer_adjusted, void*& dx_adjusted, void*& id_adjusted, void*& data_adjusted) { - void* adjusted = lua_newuserdata(L, allocated_size); - pointer_adjusted = align(ptr_align, ptr_size, adjusted, allocated_size); + void* adjusted = alloc_newuserdata(L, allocated_size); + pointer_adjusted = align(ptr_align, adjusted, allocated_size); if (pointer_adjusted == nullptr) { lua_pop(L, 1); return false; @@ -9969,7 +11165,7 @@ namespace sol { allocated_size -= ptr_size; adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + ptr_size); - dx_adjusted = align(std::alignment_of_v<unique_destructor>, sizeof(unique_destructor), adjusted, allocated_size); + dx_adjusted = align(std::alignment_of_v<unique_destructor>, adjusted, allocated_size); if (dx_adjusted == nullptr) { lua_pop(L, 1); return false; @@ -9978,7 +11174,7 @@ namespace sol { adjusted = static_cast<void*>(static_cast<char*>(dx_adjusted) + sizeof(unique_destructor)); - id_adjusted = align(std::alignment_of_v<unique_tag>, sizeof(unique_tag), adjusted, allocated_size); + id_adjusted = align(std::alignment_of_v<unique_tag>, adjusted, allocated_size); if (id_adjusted == nullptr) { lua_pop(L, 1); return false; @@ -9986,7 +11182,7 @@ namespace sol { allocated_size -= sizeof(unique_tag); adjusted = static_cast<void*>(static_cast<char*>(id_adjusted) + sizeof(unique_tag)); - data_adjusted = align(real_align, real_size, adjusted, allocated_size); + data_adjusted = align(real_align, adjusted, allocated_size); if (data_adjusted == nullptr) { lua_pop(L, 1); return false; @@ -9997,7 +11193,7 @@ namespace sol { template <typename T> T* usertype_allocate(lua_State* L) { typedef std::integral_constant<bool, -#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_) +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) false #else (std::alignment_of<T*>::value > 1 || std::alignment_of_v<T> > 1) @@ -10005,51 +11201,27 @@ namespace sol { > use_align; if (!use_align::value) { - T** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T))); + T** pointerpointer = static_cast<T**>(alloc_newuserdata(L, sizeof(T*) + sizeof(T))); T*& pointerreference = *pointerpointer; T* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1); pointerreference = allocationtarget; return allocationtarget; } - /* the assumption is that `lua_newuserdata` -- unless someone - passes a specific lua_Alloc that gives us bogus, un-aligned pointers - -- uses malloc, which tends to hand out more or less aligned pointers to memory - (most of the time, anyhow) - - but it's not guaranteed, so we have to do a post-adjustment check and increase padding - - we do this preliminarily with compile-time stuff, to see - if we strike lucky with the allocator and alignment values - - otherwise, we have to re-allocate the userdata and - over-allocate some space for additional padding because - compilers are optimized for aligned reads/writes - (and clang will barf UBsan errors on us for not being aligned) - */ - static const std::size_t initial_size = aligned_space_for<T*, T>(nullptr); - static const std::size_t misaligned_size = aligned_space_for<T*, T>(reinterpret_cast<void*>(0x1)); + constexpr std::size_t initial_size = aligned_space_for<T*, T>(); void* pointer_adjusted; void* data_adjusted; bool result - = attempt_alloc(L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, sizeof(T), initial_size, pointer_adjusted, data_adjusted); + = attempt_alloc(L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, initial_size, pointer_adjusted, data_adjusted); if (!result) { - // we're likely to get something that fails to perform the proper allocation a second time, - // so we use the suggested_new_size bump to help us out here - pointer_adjusted = nullptr; - data_adjusted = nullptr; - result = attempt_alloc( - L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, sizeof(T), misaligned_size, pointer_adjusted, data_adjusted); - if (!result) { - if (pointer_adjusted == nullptr) { - luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); - } - else { - luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<T>().c_str()); - } - return nullptr; + if (pointer_adjusted == nullptr) { + luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); + } + else { + luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<T>().c_str()); } + return nullptr; } T** pointerpointer = reinterpret_cast<T**>(pointer_adjusted); @@ -10062,7 +11234,7 @@ namespace sol { template <typename T, typename Real> Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx, unique_tag*& id) { typedef std::integral_constant<bool, -#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_) +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) false #else (std::alignment_of<T*>::value > 1 || std::alignment_of<unique_tag>::value > 1 || std::alignment_of<unique_destructor>::value > 1 @@ -10071,15 +11243,14 @@ namespace sol { > use_align; if (!use_align::value) { - pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(detail::unique_destructor) + sizeof(unique_tag) + sizeof(Real))); + pref = static_cast<T**>(alloc_newuserdata(L, sizeof(T*) + sizeof(detail::unique_destructor) + sizeof(unique_tag) + sizeof(Real))); dx = static_cast<detail::unique_destructor*>(static_cast<void*>(pref + 1)); id = static_cast<unique_tag*>(static_cast<void*>(dx + 1)); Real* mem = static_cast<Real*>(static_cast<void*>(id + 1)); return mem; } - static const std::size_t initial_size = aligned_space_for<T*, unique_destructor, unique_tag, Real>(nullptr); - static const std::size_t misaligned_size = aligned_space_for<T*, unique_destructor, unique_tag, Real>(reinterpret_cast<void*>(0x1)); + constexpr std::size_t initial_size = aligned_space_for<T*, unique_destructor, unique_tag, Real>(); void* pointer_adjusted; void* dx_adjusted; @@ -10089,41 +11260,22 @@ namespace sol { std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<Real>, - sizeof(Real), initial_size, pointer_adjusted, dx_adjusted, id_adjusted, data_adjusted); if (!result) { - // we're likely to get something that fails to perform the proper allocation a second time, - // so we use the suggested_new_size bump to help us out here - pointer_adjusted = nullptr; - dx_adjusted = nullptr; - id_adjusted = nullptr; - data_adjusted = nullptr; - result = attempt_alloc_unique(L, - std::alignment_of_v<T*>, - sizeof(T*), - std::alignment_of_v<Real>, - sizeof(Real), - misaligned_size, - pointer_adjusted, - dx_adjusted, - id_adjusted, - data_adjusted); - if (!result) { - if (pointer_adjusted == nullptr) { - luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); - } - else if (dx_adjusted == nullptr) { - luaL_error(L, "aligned allocation of userdata block (deleter section) for '%s' failed", detail::demangle<T>().c_str()); - } - else { - luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<T>().c_str()); - } - return nullptr; + if (pointer_adjusted == nullptr) { + luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); + } + else if (dx_adjusted == nullptr) { + luaL_error(L, "aligned allocation of userdata block (deleter section) for '%s' failed", detail::demangle<T>().c_str()); + } + else { + luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<T>().c_str()); } + return nullptr; } pref = static_cast<T**>(pointer_adjusted); @@ -10136,7 +11288,7 @@ namespace sol { template <typename T> T* user_allocate(lua_State* L) { typedef std::integral_constant<bool, -#if SOL_IS_OFF(SOL_ALIGN_MEMORY_I_) +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) false #else (std::alignment_of_v<T> > 1) @@ -10144,32 +11296,24 @@ namespace sol { > use_align; if (!use_align::value) { - T* pointer = static_cast<T*>(lua_newuserdata(L, sizeof(T))); + T* pointer = static_cast<T*>(alloc_newuserdata(L, sizeof(T))); return pointer; } - static const std::size_t initial_size = aligned_space_for<T>(nullptr); - static const std::size_t misaligned_size = aligned_space_for<T>(reinterpret_cast<void*>(0x1)); + constexpr std::size_t initial_size = aligned_space_for<T>(); std::size_t allocated_size = initial_size; - void* unadjusted = lua_newuserdata(L, allocated_size); - void* adjusted = align(std::alignment_of_v<T>, sizeof(T), unadjusted, allocated_size); + void* unadjusted = alloc_newuserdata(L, allocated_size); + void* adjusted = align(std::alignment_of_v<T>, unadjusted, allocated_size); if (adjusted == nullptr) { lua_pop(L, 1); - // try again, add extra space for alignment padding - allocated_size = misaligned_size; - unadjusted = lua_newuserdata(L, allocated_size); - adjusted = align(std::alignment_of_v<T>, sizeof(T), unadjusted, allocated_size); - if (adjusted == nullptr) { - lua_pop(L, 1); - luaL_error(L, "cannot properly align memory for '%s'", detail::demangle<T>().data()); - } + luaL_error(L, "cannot properly align memory for '%s'", detail::demangle<T>().data()); } return static_cast<T*>(adjusted); } template <typename T> - int usertype_alloc_destruct(lua_State* L) { + int usertype_alloc_destroy(lua_State* L) noexcept { void* memory = lua_touserdata(L, 1); memory = align_usertype_pointer(memory); T** pdata = static_cast<T**>(memory); @@ -10180,7 +11324,7 @@ namespace sol { } template <typename T> - int unique_destruct(lua_State* L) { + int unique_destroy(lua_State* L) noexcept { void* memory = lua_touserdata(L, 1); memory = align_usertype_unique_destructor(memory); unique_destructor& dx = *static_cast<unique_destructor*>(memory); @@ -10190,28 +11334,28 @@ namespace sol { } template <typename T> - int user_alloc_destruct(lua_State* L) { + int user_alloc_destroy(lua_State* L) noexcept { void* memory = lua_touserdata(L, 1); - memory = align_user<T>(memory); - T* data = static_cast<T*>(memory); + void* aligned_memory = align_user<T>(memory); + T* typed_memory = static_cast<T*>(aligned_memory); std::allocator<T> alloc; - std::allocator_traits<std::allocator<T>>::destroy(alloc, data); + std::allocator_traits<std::allocator<T>>::destroy(alloc, typed_memory); return 0; } template <typename T, typename Real> void usertype_unique_alloc_destroy(void* memory) { - memory = align_usertype_unique<Real, true>(memory); - Real* target = static_cast<Real*>(memory); + void* aligned_memory = align_usertype_unique<Real, true>(memory); + Real* typed_memory = static_cast<Real*>(aligned_memory); std::allocator<Real> alloc; - std::allocator_traits<std::allocator<Real>>::destroy(alloc, target); + std::allocator_traits<std::allocator<Real>>::destroy(alloc, typed_memory); } template <typename T> - int cannot_destruct(lua_State* L) { + int cannot_destroy(lua_State* L) { return luaL_error(L, "cannot call the destructor for '%s': it is either hidden (protected/private) or removed with '= " - "delete' and thusly this type is being destroyed without properly destructing, invoking undefined " + "delete' and thusly this type is being destroyed without properly destroying, invoking undefined " "behavior: please bind a usertype and specify a custom destructor to define the behavior properly", detail::demangle<T>().data()); } @@ -10239,12 +11383,12 @@ namespace sol { std::bitset<64>& properties; automagic_enrollments& enrollments; - properties_enrollment_allowed(int& times, std::bitset<64>& props, automagic_enrollments& enroll) - : times_through(times), properties(props), enrollments(enroll) { + properties_enrollment_allowed(int& times_through_, std::bitset<64>& properties_, automagic_enrollments& enrollments_) + : times_through(times_through_), properties(properties_), enrollments(enrollments_) { } bool operator()(meta_function mf) const { - bool p = properties[static_cast<int>(mf)]; + bool p = properties[static_cast<std::size_t>(mf)]; if (times_through > 0) { return p; } @@ -10269,13 +11413,13 @@ namespace sol { }; struct indexed_insert { - lua_reg_table& l; + lua_reg_table& registration_table; int& index; - indexed_insert(lua_reg_table& cont, int& idx) : l(cont), index(idx) { + indexed_insert(lua_reg_table& registration_table_, int& index_ref_) : registration_table(registration_table_), index(index_ref_) { } - void operator()(meta_function mf, lua_CFunction f) { - l[index] = luaL_Reg { to_string(mf).c_str(), f }; + void operator()(meta_function meta_function_name_, lua_CFunction c_function_) { + registration_table[index] = luaL_Reg { to_string(meta_function_name_).c_str(), c_function_ }; ++index; } }; @@ -10351,7 +11495,6 @@ namespace sol { } // namespace stack namespace meta { namespace meta_detail { - template <typename T> using adl_sol_lua_get_test_t = decltype(sol_lua_get(types<T>(), static_cast<lua_State*>(nullptr), -1, std::declval<stack::record&>())); @@ -10360,15 +11503,15 @@ namespace sol { = decltype(sol_lua_interop_get(types<T>(), static_cast<lua_State*>(nullptr), -1, static_cast<void*>(nullptr), std::declval<stack::record&>())); template <typename T> - using adl_sol_lua_check_test_t = decltype(sol_lua_check(types<T>(), static_cast<lua_State*>(nullptr), -1, no_panic, std::declval<stack::record&>())); + using adl_sol_lua_check_test_t = decltype(sol_lua_check(types<T>(), static_cast<lua_State*>(nullptr), -1, &no_panic, std::declval<stack::record&>())); template <typename T> using adl_sol_lua_interop_check_test_t - = decltype(sol_lua_interop_check(types<T>(), static_cast<lua_State*>(nullptr), -1, type::none, no_panic, std::declval<stack::record&>())); + = decltype(sol_lua_interop_check(types<T>(), static_cast<lua_State*>(nullptr), -1, type::none, &no_panic, std::declval<stack::record&>())); template <typename T> using adl_sol_lua_check_get_test_t - = decltype(sol_lua_check_get(types<T>(), static_cast<lua_State*>(nullptr), -1, no_panic, std::declval<stack::record&>())); + = decltype(sol_lua_check_get(types<T>(), static_cast<lua_State*>(nullptr), -1, &no_panic, std::declval<stack::record&>())); template <typename... Args> using adl_sol_lua_push_test_t = decltype(sol_lua_push(static_cast<lua_State*>(nullptr), std::declval<Args>()...)); @@ -10405,7 +11548,7 @@ namespace sol { constexpr const char* not_enough_stack_space_integral = "not enough space left on Lua stack for an integral number"; constexpr const char* not_enough_stack_space_string = "not enough space left on Lua stack for a string"; constexpr const char* not_enough_stack_space_meta_function_name = "not enough space left on Lua stack for the name of a meta_function"; - constexpr const char* not_enough_stack_space_userdata = "not enough space left on Lua stack to create a sol3 userdata"; + constexpr const char* not_enough_stack_space_userdata = "not enough space left on Lua stack to create a sol2 userdata"; constexpr const char* not_enough_stack_space_generic = "not enough space left on Lua stack to push valuees"; constexpr const char* not_enough_stack_space_environment = "not enough space left on Lua stack to retrieve environment"; @@ -10447,7 +11590,6 @@ namespace sol { } else { unqualified_getter<Tu> g {}; - (void)g; return g.get(L, index, tracking); } } @@ -10459,7 +11601,6 @@ namespace sol { } else { qualified_getter<T> g {}; - (void)g; return g.get(L, index, tracking); } } @@ -10590,6 +11731,17 @@ namespace sol { clear(r.lua_state(), r.stack_index()); } + inline void clear(lua_State* L_, stateless_reference& r) { + r.push(L_); + int stack_index = absolute_index(L_, -1); + clear(L_, stack_index); + r.pop(L_); + } + + inline void clear(lua_State* L_, stateless_stack_reference& r) { + clear(L_, r.stack_index()); + } + template <typename T, typename... Args> int push(lua_State* L, T&& t, Args&&... args) { using Tu = meta::unqualified_t<T>; @@ -10604,7 +11756,6 @@ namespace sol { } else { unqualified_pusher<Tu> p {}; - (void)p; return p.push(L, std::forward<T>(t), std::forward<Args>(args)...); } } @@ -10619,12 +11770,11 @@ namespace sol { else if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<Tu, Arg, Args...>) { return sol_lua_push(types<Tu>(), L, std::forward<Arg>(arg), std::forward<Args>(args)...); } - else if constexpr (meta::meta_detail::is_adl_sol_lua_push_v<Arg, Args...>) { + else if constexpr (meta::meta_detail::is_adl_sol_lua_push_v<Arg, Args...> && !detail::is_tagged_v<Tu>) { return sol_lua_push(L, std::forward<Arg>(arg), std::forward<Args>(args)...); } else { unqualified_pusher<Tu> p {}; - (void)p; return p.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...); } } @@ -10651,10 +11801,18 @@ namespace sol { template <typename T, typename Arg, typename... Args> int push_reference(lua_State* L, Arg&& arg, Args&&... args) { - using use_reference_tag = meta::all<std::is_lvalue_reference<T>, - meta::neg<std::is_const<std::remove_reference_t<T>>>, - meta::neg<is_lua_primitive<meta::unqualified_t<T>>>, - meta::neg<is_unique_usertype<meta::unqualified_t<T>>>>; + // clang-format off + using use_reference_tag = + meta::all< + meta::neg<is_value_semantic_for_function<T>> +#if SOL_IS_OFF(SOL_FUNCTION_CALL_VALUE_SEMANTICS) + , std::is_lvalue_reference<T>, + meta::neg<std::is_const<std::remove_reference_t<T>>>, + meta::neg<is_lua_primitive<meta::unqualified_t<T>>>, + meta::neg<is_unique_usertype<meta::unqualified_t<T>>> +#endif + >; + // clang-format on using Tr = meta::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>; return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...); } @@ -10690,7 +11848,7 @@ namespace sol { template <typename T, typename... Args> int multi_push_reference(lua_State* L, T&& t, Args&&... args) { - int pushcount = push_reference(L, std::forward<T>(t)); + int pushcount = stack::push_reference(L, std::forward<T>(t)); void(detail::swallow { (pushcount += stack::push_reference(L, std::forward<Args>(args)), 0)... }); return pushcount; } @@ -10702,9 +11860,7 @@ namespace sol { return sol_lua_check(types<Tu>(), L, index, std::forward<Handler>(handler), tracking); } else { - unqualified_checker<Tu, lua_type_of_v<Tu>> c; - // VC++ has a bad warning here: shut it up - (void)c; + unqualified_checker<Tu, lua_type_of_v<Tu>> c{}; return c.check(L, index, std::forward<Handler>(handler), tracking); } } @@ -10717,7 +11873,7 @@ namespace sol { template <typename T> bool unqualified_check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { - auto handler = no_panic; + auto handler = &no_panic; return unqualified_check<T>(L, index, handler); } @@ -10728,9 +11884,7 @@ namespace sol { } else { using Tu = meta::unqualified_t<T>; - qualified_checker<T, lua_type_of_v<Tu>> c; - // VC++ has a bad warning here: shut it up - (void)c; + qualified_checker<T, lua_type_of_v<Tu>> c{}; return c.check(L, index, std::forward<Handler>(handler), tracking); } } @@ -10743,7 +11897,7 @@ namespace sol { template <typename T> bool check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { - auto handler = no_panic; + auto handler = &no_panic; return check<T>(L, index, handler); } @@ -10769,7 +11923,7 @@ namespace sol { template <typename T> bool check_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { - auto handler = no_panic; + auto handler = &no_panic; return check_usertype<T>(L, index, handler); } @@ -10784,7 +11938,6 @@ namespace sol { } else { unqualified_check_getter<Tu> cg {}; - (void)cg; return cg.get(L, index, std::forward<Handler>(handler), tracking); } } @@ -10797,7 +11950,7 @@ namespace sol { template <typename T> decltype(auto) unqualified_check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { - auto handler = no_panic; + auto handler = &no_panic; return unqualified_check_get<T>(L, index, handler); } @@ -10808,7 +11961,6 @@ namespace sol { } else { qualified_check_getter<T> cg {}; - (void)cg; return cg.get(L, index, std::forward<Handler>(handler), tracking); } } @@ -10821,7 +11973,7 @@ namespace sol { template <typename T> decltype(auto) check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { - auto handler = no_panic; + auto handler = &no_panic; return check_get<T>(L, index, handler); } @@ -10864,7 +12016,7 @@ namespace sol { template <typename T> auto unqualified_get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_unqualified_get<T>(L, index, tracking)) { -#if SOL_IS_ON(SOL_SAFE_GETTER_I_) +#if SOL_IS_ON(SOL_SAFE_GETTER) static constexpr bool is_op = meta::is_optional_v<T>; if constexpr (is_op) { return stack_detail::unchecked_unqualified_get<T>(L, index, tracking); @@ -10889,7 +12041,7 @@ namespace sol { template <typename T> auto get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) { -#if SOL_IS_ON(SOL_SAFE_GETTER_I_) +#if SOL_IS_ON(SOL_SAFE_GETTER) static constexpr bool is_op = meta::is_optional_v<T>; if constexpr (is_op) { return stack_detail::unchecked_get<T>(L, index, tracking); @@ -10919,14 +12071,14 @@ namespace sol { } template <typename T> - decltype(auto) get_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { + decltype(auto) get_usertype(lua_State* L, int index = -lua_size_v<meta::unqualified_t<T>>) { record tracking {}; return get_usertype<T>(L, index, tracking); } template <typename T> decltype(auto) pop(lua_State* L) { - return popper<meta::unqualified_t<T>> {}.pop(L); + return popper<T> {}.pop(L); } template <bool global = false, bool raw = false, typename Key> @@ -10991,13 +12143,12 @@ namespace sol { template <typename T, typename F> void modify_unique_usertype_as(const stack_reference& obj, F&& f) { - using u_traits = unique_usertype_traits<T>; void* raw = lua_touserdata(obj.lua_state(), obj.stack_index()); void* ptr_memory = detail::align_usertype_pointer(raw); void* uu_memory = detail::align_usertype_unique<T>(raw); T& uu = *static_cast<T*>(uu_memory); f(uu); - *static_cast<void**>(ptr_memory) = static_cast<void*>(u_traits::get(uu)); + *static_cast<void**>(ptr_memory) = static_cast<void*>(detail::unique_get(obj.lua_state(), uu)); } template <typename F> @@ -11008,6 +12159,24 @@ namespace sol { modify_unique_usertype_as<Tu>(obj, std::forward<F>(f)); } + namespace stack_detail { + template <typename T, typename Handler> + decltype(auto) check_get_arg(lua_State* L_, int index_, Handler&& handler_, record& tracking_) { + if constexpr (meta::meta_detail::is_adl_sol_lua_check_access_v<T>) { + sol_lua_check_access(types<meta::unqualified_t<T>>(), L_, index_, tracking_); + } + return check_get<T>(L_, index_, std::forward<Handler>(handler_), tracking_); + } + + template <typename T> + decltype(auto) unchecked_get_arg(lua_State* L_, int index_, record& tracking_) { + if constexpr (meta::meta_detail::is_adl_sol_lua_check_access_v<T>) { + sol_lua_check_access(types<meta::unqualified_t<T>>(), L_, index_, tracking_); + } + return unchecked_get<T>(L_, index_, tracking_); + } + } // namespace stack_detail + } // namespace stack namespace detail { @@ -11015,19 +12184,19 @@ namespace sol { template <typename T> lua_CFunction make_destructor(std::true_type) { if constexpr (is_unique_usertype_v<T>) { - return &unique_destruct<T>; + return &unique_destroy<T>; } else if constexpr (!std::is_pointer_v<T>) { - return &usertype_alloc_destruct<T>; + return &usertype_alloc_destroy<T>; } else { - return &cannot_destruct<T>; + return &cannot_destroy<T>; } } template <typename T> lua_CFunction make_destructor(std::false_type) { - return &cannot_destruct<T>; + return &cannot_destroy<T>; } template <typename T> @@ -11166,39 +12335,53 @@ namespace sol { #include <utility> #include <cmath> #include <optional> -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#if SOL_IS_ON(SOL_STD_VARIANT) #include <variant> #endif // variant shenanigans namespace sol { namespace stack { + template <typename Handler> + bool loose_table_check(lua_State* L_, int index, Handler&& handler, record& tracking) { + tracking.use(1); + type t = type_of(L_, index); + if (t == type::table) { + return true; + } + if (t != type::userdata) { + handler(L_, index, type::table, t, "value is not a table or a userdata that can behave like one"); + return false; + } + return true; + } + namespace stack_detail { - inline bool impl_check_metatable(lua_State* L, int index, const std::string& metakey, bool poptable) { - luaL_getmetatable(L, &metakey[0]); - const type expectedmetatabletype = static_cast<type>(lua_type(L, -1)); + inline bool impl_check_metatable(lua_State* L_, int index, const std::string& metakey, bool poptable) { + luaL_getmetatable(L_, &metakey[0]); + const type expectedmetatabletype = static_cast<type>(lua_type(L_, -1)); if (expectedmetatabletype != type::lua_nil) { - if (lua_rawequal(L, -1, index) == 1) { - lua_pop(L, 1 + static_cast<int>(poptable)); + if (lua_rawequal(L_, -1, index) == 1) { + lua_pop(L_, 1 + static_cast<int>(poptable)); return true; } } - lua_pop(L, 1); + lua_pop(L_, 1); return false; } template <typename T, bool poptable = true> - inline bool check_metatable(lua_State* L, int index = -2) { - return impl_check_metatable(L, index, usertype_traits<T>::metatable(), poptable); + inline bool check_metatable(lua_State* L_, int index = -2) { + return impl_check_metatable(L_, index, usertype_traits<T>::metatable(), poptable); } template <type expected, int (*check_func)(lua_State*, int)> struct basic_check { template <typename Handler> - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { tracking.use(1); - bool success = check_func(L, index) == 1; + bool success = check_func(L_, index) == 1; if (!success) { // expected type, actual type - handler(L, index, expected, type_of(L, index), ""); + handler(L_, index, expected, type_of(L_, index), ""); } return success; } @@ -11216,87 +12399,95 @@ namespace sol { namespace stack { template <typename T, typename> struct qualified_interop_checker { template <typename Handler> - static bool check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { - return stack_detail::unqualified_interop_check<T>(L, index, index_type, std::forward<Handler>(handler), tracking); + static bool check(lua_State* L_, int index, type index_type, Handler&& handler, record& tracking) { + return stack_detail::unqualified_interop_check<T>(L_, index, index_type, std::forward<Handler>(handler), tracking); } }; template <typename T, type expected, typename> struct unqualified_checker { template <typename Handler> - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { if constexpr (std::is_same_v<T, bool>) { tracking.use(1); - bool success = lua_isboolean(L, index) == 1; + bool success = lua_isboolean(L_, index) == 1; if (!success) { // expected type, actual type - handler(L, index, expected, type_of(L, index), ""); + handler(L_, index, expected, type_of(L_, index), ""); } return success; } - else if constexpr (meta::any_same_v<T, char /* , char8_t*/, char16_t, char32_t>) { - return stack::check<std::basic_string<T>>(L, index, std::forward<Handler>(handler), tracking); + else if constexpr (meta::any_same_v<T, + char +#if SOL_IS_ON(SOL_CHAR8_T) + , + char8_t +#endif + , + char16_t, + char32_t>) { + return stack::check<std::basic_string<T>>(L_, index, std::forward<Handler>(handler), tracking); } else if constexpr (std::is_integral_v<T> || std::is_same_v<T, lua_Integer>) { tracking.use(1); -#if SOL_LUA_VESION_I_ >= 503 +#if SOL_LUA_VERSION_I_ >= 503 // Lua 5.3 and greater checks for numeric precision -#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS_I_) +#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS) // imprecise, sloppy conversions int isnum = 0; - lua_tointegerx(L, index, &isnum); + 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), detail::not_a_number_or_number_string_integral); + handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string_integral); } -#elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_) +#elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS) // this check is precise, do not convert - if (lua_isinteger(L, index) == 1) { + if (lua_isinteger(L_, index) == 1) { return true; } const bool success = false; if (!success) { // expected type, actual type - handler(L, index, type::number, type_of(L, index), detail::not_a_number_integral); + handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_integral); } #else // Numerics are neither safe nor string-convertible - type t = type_of(L, index); + type t = type_of(L_, index); const bool success = t == type::number; #endif if (!success) { // expected type, actual type - handler(L, index, type::number, type_of(L, index), detail::not_a_number); + handler(L_, index, type::number, type_of(L_, index), detail::not_a_number); } return success; #else // Lua 5.2 and below checks -#if SOL_IS_OFF(SOL_STRINGS_ARE_NUMBERS_I_) +#if SOL_IS_OFF(SOL_STRINGS_ARE_NUMBERS) // must pre-check, because it will convert - type t = type_of(L, index); + type t = type_of(L_, index); if (t != type::number) { // expected type, actual type - handler(L, index, type::number, t, detail::not_a_number); + handler(L_, index, type::number, t, detail::not_a_number); return false; } #endif // Do not allow strings to be numbers -#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_) +#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS) int isnum = 0; - const lua_Number v = lua_tonumberx(L, index, &isnum); + const lua_Number v = lua_tonumberx(L_, index, &isnum); const bool success = isnum != 0 && static_cast<lua_Number>(llround(v)) == v; #else const bool success = true; #endif // Safe numerics and number precision checking if (!success) { // Use defines to provide a better error message! -#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS_I_) - handler(L, index, type::number, type_of(L, index), detail::not_a_number_or_number_string); -#elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_) - handler(L, index, type::number, t, detail::not_a_number_or_number_string); +#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS) + handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string); +#elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS) + handler(L_, index, type::number, t, detail::not_a_number_or_number_string); #else - handler(L, index, type::number, t, detail::not_a_number); + handler(L_, index, type::number, t, detail::not_a_number); #endif } return success; @@ -11304,154 +12495,155 @@ namespace sol { namespace stack { } else if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, lua_Number>) { tracking.use(1); -#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS_I_) - bool success = lua_isnumber(L, index) == 1; +#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS) + bool success = lua_isnumber(L_, index) == 1; if (!success) { // expected type, actual type - handler(L, index, type::number, type_of(L, index), detail::not_a_number_or_number_string); + handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string); } return success; #else - type t = type_of(L, index); + type t = type_of(L_, index); bool success = t == type::number; if (!success) { // expected type, actual type - handler(L, index, type::number, t, detail::not_a_number); + handler(L_, index, type::number, t, detail::not_a_number); } return success; #endif // Strings are Numbers } else if constexpr (meta::any_same_v<T, type, this_state, this_main_state, this_environment, variadic_args>) { - (void)L; + (void)L_; (void)index; (void)handler; tracking.use(0); return true; } else if constexpr (is_unique_usertype_v<T>) { - using proper_T = typename unique_usertype_traits<T>::type; - const type indextype = type_of(L, index); + using element = unique_usertype_element_t<T>; + using actual = unique_usertype_actual_t<T>; + const type indextype = type_of(L_, index); tracking.use(1); if (indextype != type::userdata) { - handler(L, index, type::userdata, indextype, "value is not a userdata"); + handler(L_, index, type::userdata, indextype, "value is not a userdata"); return false; } - if (lua_getmetatable(L, index) == 0) { + if (lua_getmetatable(L_, index) == 0) { return true; } - int metatableindex = lua_gettop(L); - if (stack_detail::check_metatable<detail::unique_usertype<proper_T>>(L, metatableindex)) { - void* memory = lua_touserdata(L, index); + int metatableindex = lua_gettop(L_); + if (stack_detail::check_metatable<d::u<element>>(L_, metatableindex)) { + void* memory = lua_touserdata(L_, index); memory = detail::align_usertype_unique_destructor(memory); detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); - bool success = &detail::usertype_unique_alloc_destroy<proper_T, T> == pdx; + bool success = &detail::usertype_unique_alloc_destroy<element, actual> == pdx; if (!success) { memory = detail::align_usertype_unique_tag<true>(memory); #if 0 - // New version + // New version, one day #else const char*& name_tag = *static_cast<const char**>(memory); success = usertype_traits<T>::qualified_name() == name_tag; #endif if (!success) { - handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); + handler(L_, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); } } return success; } - lua_pop(L, 1); - handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)"); + lua_pop(L_, 1); + handler(L_, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)"); return false; } else if constexpr (meta::any_same_v<T, lua_nil_t, std::nullopt_t, nullopt_t>) { - bool success = lua_isnil(L, index); + bool success = lua_isnil(L_, index); if (success) { tracking.use(1); return success; } tracking.use(0); - success = lua_isnone(L, index); + success = lua_isnone(L_, index); if (!success) { // expected type, actual type - handler(L, index, expected, type_of(L, index), ""); + handler(L_, index, expected, type_of(L_, index), ""); } return success; } else if constexpr (std::is_same_v<T, env_key_t>) { tracking.use(1); - type t = type_of(L, index); + type t = type_of(L_, index); if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) { return true; } - handler(L, index, type::table, t, "value cannot not have a valid environment"); + handler(L_, index, type::table, t, "value cannot not have a valid environment"); return true; } else if constexpr (std::is_same_v<T, detail::non_lua_nil_t>) { - return !stack::unqualified_check<lua_nil_t>(L, index, std::forward<Handler>(handler), tracking); + return !stack::unqualified_check<lua_nil_t>(L_, index, std::forward<Handler>(handler), tracking); } else if constexpr (meta::is_specialization_of_v<T, basic_lua_table>) { tracking.use(1); - type t = type_of(L, index); + type t = type_of(L_, index); if (t != type::table) { - handler(L, index, type::table, t, "value is not a table"); + handler(L_, index, type::table, t, "value is not a table"); return false; } return true; } else if constexpr (meta::is_specialization_of_v<T, basic_bytecode>) { tracking.use(1); - type t = type_of(L, index); + type t = type_of(L_, index); if (t != type::function) { - handler(L, index, type::function, t, "value is not a function that can be dumped"); + handler(L_, index, type::function, t, "value is not a function that can be dumped"); return false; } return true; } else if constexpr (meta::is_specialization_of_v<T, basic_environment>) { tracking.use(1); - if (lua_getmetatable(L, index) == 0) { + if (lua_getmetatable(L_, index) == 0) { return true; } - type t = type_of(L, -1); + type t = type_of(L_, -1); if (t == type::table || t == type::none || t == type::lua_nil) { - lua_pop(L, 1); + lua_pop(L_, 1); return true; } if (t != type::userdata) { - lua_pop(L, 1); - handler(L, index, type::table, t, "value does not have a valid metatable"); + lua_pop(L_, 1); + handler(L_, index, type::table, t, "value does not have a valid metatable"); return false; } return true; } else if constexpr (std::is_same_v<T, metatable_key_t>) { tracking.use(1); - if (lua_getmetatable(L, index) == 0) { + if (lua_getmetatable(L_, index) == 0) { return true; } - type t = type_of(L, -1); + type t = type_of(L_, -1); if (t == type::table || t == type::none || t == type::lua_nil) { - lua_pop(L, 1); + lua_pop(L_, 1); return true; } if (t != type::userdata) { - lua_pop(L, 1); - handler(L, index, expected, t, "value does not have a valid metatable"); + lua_pop(L_, 1); + handler(L_, index, expected, t, "value does not have a valid metatable"); return false; } return true; } else if constexpr (std::is_same_v<T, luaL_Stream*> || std::is_same_v<T, luaL_Stream>) { - if (lua_getmetatable(L, index) == 0) { - type t = type_of(L, index); - handler(L, index, expected, t, "value is not a valid luaL_Stream (has no metatable/is not a valid value)"); + if (lua_getmetatable(L_, index) == 0) { + type t = type_of(L_, index); + handler(L_, index, expected, t, "value is not a valid luaL_Stream (has no metatable/is not a valid value)"); return false; } - luaL_getmetatable(L, LUA_FILEHANDLE); - if (type_of(L, index) != type::table) { - type t = type_of(L, index); - lua_pop(L, 1); - handler(L, + luaL_getmetatable(L_, LUA_FILEHANDLE); + if (type_of(L_, index) != type::table) { + type t = type_of(L_, index); + lua_pop(L_, 1); + handler(L_, index, expected, t, @@ -11459,11 +12651,11 @@ namespace sol { namespace stack { "my_lua_state.open_libraries(sol::lib::state) or equivalent?)"); return false; } - int is_stream_table = lua_compare(L, -1, -2, LUA_OPEQ); - lua_pop(L, 2); + int is_stream_table = lua_compare(L_, -1, -2, LUA_OPEQ); + lua_pop(L_, 2); if (is_stream_table == 0) { - type t = type_of(L, index); - handler(L, index, expected, t, "value is not a valid luaL_Stream (incorrect metatable)"); + type t = type_of(L_, index); + handler(L_, index, expected, t, "value is not a valid luaL_Stream (incorrect metatable)"); return false; } return true; @@ -11471,7 +12663,7 @@ namespace sol { namespace stack { else if constexpr (meta::is_optional_v<T>) { using ValueType = typename T::value_type; (void)handler; - type t = type_of(L, index); + type t = type_of(L_, index); if (t == type::none) { tracking.use(0); return true; @@ -11480,124 +12672,115 @@ namespace sol { namespace stack { tracking.use(1); return true; } - return stack::unqualified_check<ValueType>(L, index, no_panic, tracking); + return stack::unqualified_check<ValueType>(L_, index, &no_panic, tracking); } -#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_) +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) else if constexpr (std::is_function_v<T> || (std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>)) { - return stack_detail::check_function_pointer<std::remove_pointer_t<T>>(L, index, std::forward<Handler>(handler), tracking); + return stack_detail::check_function_pointer<std::remove_pointer_t<T>>(L_, index, std::forward<Handler>(handler), tracking); } #endif else if constexpr (expected == type::userdata) { if constexpr (meta::any_same_v<T, userdata_value> || meta::is_specialization_of_v<T, basic_userdata>) { tracking.use(1); - type t = type_of(L, index); + type t = type_of(L_, index); bool success = t == type::userdata; if (!success) { // expected type, actual type - handler(L, index, type::userdata, t, ""); + handler(L_, index, type::userdata, t, ""); } return success; } else if constexpr (meta::is_specialization_of_v<T, user>) { unqualified_checker<lightuserdata_value, type::userdata> c; (void)c; - return c.check(L, index, std::forward<Handler>(handler), tracking); + return c.check(L_, index, std::forward<Handler>(handler), tracking); } else { if constexpr (std::is_pointer_v<T>) { - return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking); + return check_usertype<T>(L_, index, std::forward<Handler>(handler), tracking); } else if constexpr (meta::is_specialization_of_v<T, std::reference_wrapper>) { using T_internal = typename T::type; - return stack::check<T_internal>(L, index, std::forward<Handler>(handler), tracking); + return stack::check<T_internal>(L_, index, std::forward<Handler>(handler), tracking); } else { - return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking); + return check_usertype<T>(L_, index, std::forward<Handler>(handler), tracking); } } } else if constexpr (expected == type::poly) { tracking.use(1); - bool success = is_lua_reference_v<T> || !lua_isnone(L, index); + bool success = is_lua_reference_v<T> || !lua_isnone(L_, index); if (!success) { // expected type, actual type - handler(L, index, type::poly, type_of(L, index), ""); + handler(L_, index, type::poly, type_of(L_, index), ""); } return success; } else if constexpr (expected == type::lightuserdata) { tracking.use(1); - type t = type_of(L, index); + type t = type_of(L_, index); bool success = t == type::userdata || t == type::lightuserdata; if (!success) { // expected type, actual type - handler(L, index, type::lightuserdata, t, ""); + handler(L_, index, type::lightuserdata, t, ""); } return success; } else if constexpr (expected == type::function) { if constexpr (meta::any_same_v<T, lua_CFunction, std::remove_pointer_t<lua_CFunction>, c_closure>) { tracking.use(1); - bool success = lua_iscfunction(L, index) == 1; + bool success = lua_iscfunction(L_, index) == 1; if (!success) { // expected type, actual type - handler(L, index, expected, type_of(L, index), ""); + handler(L_, index, expected, type_of(L_, index), ""); } return success; } else { tracking.use(1); - type t = type_of(L, index); + type t = type_of(L_, index); if (t == type::lua_nil || t == type::none || t == type::function) { // allow for lua_nil to be returned return true; } if (t != type::userdata && t != type::table) { - handler(L, index, type::function, t, "must be a function or table or a userdata"); + handler(L_, index, type::function, t, "must be a function or table or a userdata"); return false; } // Do advanced check for call-style userdata? static const auto& callkey = to_string(meta_function::call); - if (lua_getmetatable(L, index) == 0) { + if (lua_getmetatable(L_, index) == 0) { // No metatable, no __call key possible - handler(L, index, type::function, t, "value is not a function and does not have overriden metatable"); + handler(L_, index, type::function, t, "value is not a function and does not have overriden metatable"); return false; } - if (lua_isnoneornil(L, -1)) { - lua_pop(L, 1); - handler(L, index, type::function, t, "value is not a function and does not have valid metatable"); + if (lua_isnoneornil(L_, -1)) { + lua_pop(L_, 1); + handler(L_, index, type::function, t, "value is not a function and does not have valid metatable"); return false; } - lua_getfield(L, -1, &callkey[0]); - if (lua_isnoneornil(L, -1)) { - lua_pop(L, 2); - handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type"); + lua_getfield(L_, -1, &callkey[0]); + if (lua_isnoneornil(L_, -1)) { + lua_pop(L_, 2); + handler(L_, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type"); return false; } // has call, is definitely a function - lua_pop(L, 2); + lua_pop(L_, 2); return true; } } else if constexpr (expected == type::table) { - tracking.use(1); - type t = type_of(L, index); - if (t == type::table) { - return true; - } - if (t != type::userdata) { - handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one"); - return false; - } - return true; + return stack::loose_table_check(L_, index, std::forward<Handler>(handler), tracking); } else { tracking.use(1); - const type indextype = type_of(L, index); + const type indextype = type_of(L_, index); bool success = expected == indextype; if (!success) { // expected type, actual type, message - handler(L, index, expected, indextype, ""); + handler(L_, index, expected, indextype, ""); } return success; } @@ -11610,64 +12793,70 @@ namespace sol { namespace stack { template <typename T> struct unqualified_checker<detail::as_value_tag<T>, type::userdata> { template <typename Handler> - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - const type indextype = type_of(L, index); - return check(types<T>(), L, index, indextype, std::forward<Handler>(handler), tracking); + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + const type indextype = type_of(L_, index); + return check(types<T>(), L_, index, indextype, std::forward<Handler>(handler), tracking); } template <typename U, typename Handler> - static bool check(types<U>, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { + static bool check(types<U>, lua_State* L_, int index, type indextype, Handler&& handler, record& tracking) { if constexpr ( std::is_same_v<T, lightuserdata_value> || std::is_same_v<T, userdata_value> || std::is_same_v<T, userdata> || std::is_same_v<T, lightuserdata>) { tracking.use(1); if (indextype != type::userdata) { - handler(L, index, type::userdata, indextype, "value is not a valid userdata"); + handler(L_, index, type::userdata, indextype, "value is not a valid userdata"); return false; } return true; } else { -#if SOL_IS_ON(SOL_USE_INTEROP_I_) - if (stack_detail::interop_check<U>(L, index, indextype, handler, tracking)) { +#if SOL_IS_ON(SOL_USE_INTEROP) + if (stack_detail::interop_check<U>(L_, index, indextype, handler, tracking)) { return true; } #endif // interop extensibility tracking.use(1); +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) + if (lua_iscfunction(L_, index) != 0) { + // a potential match... + return true; + } +#endif if (indextype != type::userdata) { - handler(L, index, type::userdata, indextype, "value is not a valid userdata"); + handler(L_, index, type::userdata, indextype, "value is not a valid userdata"); return false; } - if (lua_getmetatable(L, index) == 0) { + if (lua_getmetatable(L_, index) == 0) { return true; } - int metatableindex = lua_gettop(L); - if (stack_detail::check_metatable<U>(L, metatableindex)) + int metatableindex = lua_gettop(L_); + if (stack_detail::check_metatable<U>(L_, metatableindex)) return true; - if (stack_detail::check_metatable<U*>(L, metatableindex)) + if (stack_detail::check_metatable<U*>(L_, metatableindex)) return true; - if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex)) + if (stack_detail::check_metatable<d::u<U>>(L_, metatableindex)) return true; - if (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex)) + if (stack_detail::check_metatable<as_container_t<U>>(L_, metatableindex)) return true; bool success = false; bool has_derived = derive<T>::value || weak_derive<T>::value; if (has_derived) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, detail::not_enough_stack_space_string); #endif // make sure stack doesn't overflow - auto pn = stack::pop_n(L, 1); - lua_pushstring(L, &detail::base_class_check_key()[0]); - lua_rawget(L, metatableindex); - if (type_of(L, -1) != type::lua_nil) { - void* basecastdata = lua_touserdata(L, -1); + auto pn = stack::pop_n(L_, 1); + lua_pushstring(L_, &detail::base_class_check_key()[0]); + lua_rawget(L_, metatableindex); + if (type_of(L_, -1) != type::lua_nil) { + void* basecastdata = lua_touserdata(L_, -1); detail::inheritance_check_function ic = reinterpret_cast<detail::inheritance_check_function>(basecastdata); success = ic(usertype_traits<T>::qualified_name()); } } - lua_pop(L, 1); + lua_pop(L_, 1); if (!success) { - handler(L, index, type::userdata, indextype, "value at this index does not properly reflect the desired type"); + handler(L_, index, type::userdata, indextype, "value at this index does not properly reflect the desired type"); return false; } return true; @@ -11678,38 +12867,38 @@ namespace sol { namespace stack { template <typename T> struct unqualified_checker<detail::as_pointer_tag<T>, type::userdata> { template <typename Handler> - static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { + 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 check_usertype<std::remove_pointer_t<T>>(L, index, std::forward<Handler>(handler), tracking); + return check_usertype<std::remove_pointer_t<T>>(L_, index, std::forward<Handler>(handler), tracking); } template <typename Handler> - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - const type indextype = type_of(L, index); - return check(L, index, indextype, std::forward<Handler>(handler), tracking); + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + const type indextype = type_of(L_, index); + return check(L_, index, indextype, std::forward<Handler>(handler), tracking); } }; template <typename... Args> struct unqualified_checker<std::tuple<Args...>, type::poly> { template <typename Handler> - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking); + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + return stack::multi_check<Args...>(L_, index, std::forward<Handler>(handler), tracking); } }; template <typename A, typename B> struct unqualified_checker<std::pair<A, B>, type::poly> { template <typename Handler> - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking); + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + return stack::multi_check<A, B>(L_, index, std::forward<Handler>(handler), tracking); } }; -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#if SOL_IS_ON(SOL_STD_VARIANT) template <typename... Tn> struct unqualified_checker<std::variant<Tn...>, type::poly> { @@ -11718,31 +12907,31 @@ namespace sol { namespace stack { typedef std::integral_constant<bool, V_size::value == 0> V_is_empty; template <typename Handler> - static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) { + static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L_, int index, Handler&& handler, record& tracking) { if constexpr (V_is_empty::value) { - if (lua_isnone(L, index)) { + if (lua_isnone(L_, index)) { return true; } } tracking.use(1); - handler(L, index, type::poly, type_of(L, index), "value does not fit any type present in the variant"); + handler(L_, index, type::poly, type_of(L_, index), "value does not fit any type present in the variant"); return false; } template <std::size_t I, typename Handler> - static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) { + static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L_, int index, Handler&& handler, record& tracking) { typedef std::variant_alternative_t<I - 1, V> T; record temp_tracking = tracking; - if (stack::check<T>(L, index, no_panic, temp_tracking)) { + if (stack::check<T>(L_, index, &no_panic, temp_tracking)) { tracking = temp_tracking; return true; } - return is_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking); + return is_one(std::integral_constant<std::size_t, I - 1>(), L_, index, std::forward<Handler>(handler), tracking); } template <typename Handler> - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return is_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking); + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + return is_one(std::integral_constant<std::size_t, V_size::value>(), L_, index, std::forward<Handler>(handler), tracking); } }; @@ -11754,18 +12943,17 @@ namespace sol { namespace stack { // beginning of sol/stack_check_qualified.hpp -namespace sol { -namespace stack { +namespace sol { namespace stack { template <typename X, type expected, typename> struct qualified_checker { template <typename Handler> static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<X>) { - using u_traits = unique_usertype_traits<meta::unqualified_t<X>>; - using T = typename u_traits::type; - if constexpr (is_base_rebindable_non_void_v<u_traits>) { - using rebind_t = typename u_traits::template rebind_base<void>; + using no_cv_X = meta::unqualified_t<X>; + if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<no_cv_X>) { + using element = unique_usertype_element_t<no_cv_X>; + if constexpr (is_actual_type_rebindable_for_v<no_cv_X>) { + using rebound_actual_type = unique_usertype_rebind_actual_t<no_cv_X>; // we have a unique pointer type that can be // rebound to a base/derived type const type indextype = type_of(L, index); @@ -11777,14 +12965,14 @@ namespace stack { void* memory = lua_touserdata(L, index); memory = detail::align_usertype_unique_destructor(memory); detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); - if (&detail::usertype_unique_alloc_destroy<T, X> == pdx) { + if (&detail::usertype_unique_alloc_destroy<element, no_cv_X> == pdx) { return true; } - if constexpr (derive<T>::value) { + if constexpr (derive<element>::value) { memory = detail::align_usertype_unique_tag<true, false>(memory); detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory); - string_view ti = usertype_traits<T>::qualified_name(); - string_view rebind_ti = usertype_traits<rebind_t>::qualified_name(); + string_view ti = usertype_traits<element>::qualified_name(); + string_view rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); if (ic(nullptr, nullptr, ti, rebind_ti) != 0) { return true; } @@ -11796,7 +12984,7 @@ namespace stack { return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking); } } - else if constexpr (!std::is_reference_v<X> && is_container_v<X>) { + else if constexpr (!std::is_reference_v<X> && is_container_v<no_cv_X>) { if (type_of(L, index) == type::userdata) { return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking); } @@ -11813,8 +13001,7 @@ namespace stack { } } }; -} -} // namespace sol::stack +}} // namespace sol::stack // end of sol/stack_check_qualified.hpp @@ -11833,8 +13020,7 @@ namespace sol { struct overload_set { std::tuple<Functions...> functions; template <typename Arg, typename... Args, meta::disable<std::is_same<overload_set, meta::unqualified_t<Arg>>> = meta::enabler> - overload_set(Arg&& arg, Args&&... args) - : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { + overload_set(Arg&& arg, Args&&... args) : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { } overload_set(const overload_set&) = default; overload_set(overload_set&&) = default; @@ -11870,15 +13056,13 @@ namespace sol { }; inline const string_view& to_string(error_code ec) { - static const string_view storage[7] = { - "ok", + static const string_view storage[7] = { "ok", "invalid code points", "invalid code unit", "invalid leading surrogate", "invalid trailing surrogate", "sequence too short", - "overlong sequence" - }; + "overlong sequence" }; return storage[static_cast<std::size_t>(ec)]; } @@ -11945,20 +13129,21 @@ namespace sol { } 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; + 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); + return (static_cast<char32_t>((b0 & 0x1Fu) << 6u) | static_cast<char32_t>(b1 & 0x3Fu)); } static constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2) { - return ((b0 & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F); + return static_cast<char32_t>((b0 & 0x0Fu) << 12u) | static_cast<char32_t>((b1 & 0x3Fu) << 6u) | static_cast<char32_t>(b2 & 0x3Fu); } 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); + return static_cast<char32_t>(static_cast<char32_t>((b0 & 0x07u) << 18u) | static_cast<char32_t>((b1 & 0x3F) << 12) + | static_cast<char32_t>((b2 & 0x3Fu) << 6u) | static_cast<char32_t>(b3 & 0x3Fu)); } // utf16 related @@ -11981,30 +13166,30 @@ namespace sol { er.error = error_code::ok; if (codepoint <= unicode_detail::last_1byte_value) { er.code_units_size = 1; - er.code_units = std::array<char, 4>{ { static_cast<char>(codepoint) } }; + er.code_units = std::array<char, 4> { { static_cast<char>(codepoint) } }; } else if (codepoint <= unicode_detail::last_2byte_value) { er.code_units_size = 2; - er.code_units = std::array<char, 4>{{ + er.code_units = std::array<char, 4> { { static_cast<char>(0xC0 | ((codepoint & 0x7C0) >> 6)), static_cast<char>(0x80 | (codepoint & 0x3F)), - }}; + } }; } else if (codepoint <= unicode_detail::last_3byte_value) { er.code_units_size = 3; - er.code_units = std::array<char, 4>{{ + er.code_units = std::array<char, 4> { { static_cast<char>(0xE0 | ((codepoint & 0xF000) >> 12)), static_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)), static_cast<char>(0x80 | (codepoint & 0x3F)), - }}; + } }; } else { er.code_units_size = 4; - er.code_units = std::array<char, 4>{ { + er.code_units = std::array<char, 4> { { static_cast<char>(0xF0 | ((codepoint & 0x1C0000) >> 18)), - static_cast<char>(0x80 | ((codepoint & 0x3F000) >> 12)), - static_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)), - static_cast<char>(0x80 | (codepoint & 0x3F)), + static_cast<char>(0x80 | ((codepoint & 0x3F000) >> 12)), + static_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)), + static_cast<char>(0x80 | (codepoint & 0x3F)), } }; } return er; @@ -12015,17 +13200,14 @@ namespace sol { if (codepoint <= unicode_detail::last_bmp_value) { er.code_units_size = 1; - er.code_units = std::array<char16_t, 4>{ { static_cast<char16_t>(codepoint) } }; + er.code_units = std::array<char16_t, 4> { { static_cast<char16_t>(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<char16_t, 4>{ { - static_cast<char16_t>(lead), - static_cast<char16_t>(trail) - } }; + er.code_units = std::array<char16_t, 4> { { static_cast<char16_t>(lead), static_cast<char16_t>(trail) } }; er.code_units_size = 2; er.error = error_code::ok; } @@ -12049,8 +13231,8 @@ namespace sol { return dr; } - unsigned char b0 = *it; - std::size_t length = unicode_detail::sequence_length(b0); + unsigned char b0 = static_cast<unsigned char>(*it); + std::size_t length = static_cast<std::size_t>(unicode_detail::sequence_length(b0)); if (length == 1) { dr.codepoint = static_cast<char32_t>(b0); @@ -12070,7 +13252,7 @@ namespace sol { std::array<unsigned char, 4> b; b[0] = b0; for (std::size_t i = 1; i < length; ++i) { - b[i] = *it; + b[i] = static_cast<unsigned char>(*it); if (!unicode_detail::is_continuation(b[i])) { dr.error = error_code::invalid_code_unit; dr.next = it; @@ -12100,7 +13282,7 @@ namespace sol { dr.error = error_code::invalid_code_point; return dr; } - + // then everything is fine dr.codepoint = decoded; dr.error = error_code::ok; @@ -12118,7 +13300,7 @@ namespace sol { } char16_t lead = static_cast<char16_t>(*it); - + if (!unicode_detail::is_surrogate(lead)) { ++it; dr.codepoint = static_cast<char32_t>(lead); @@ -12139,7 +13321,7 @@ namespace sol { dr.next = it; return dr; } - + dr.codepoint = unicode_detail::combine_surrogates(lead, trail); dr.next = ++it; dr.error = error_code::ok; @@ -12159,8 +13341,8 @@ namespace sol { dr.error = error_code::ok; return dr; } - } -} + } // namespace unicode +} // namespace sol // end of sol/unicode.hpp #include <memory> @@ -12169,7 +13351,7 @@ namespace sol { #include <cstdlib> #include <cmath> #include <string_view> -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#if SOL_IS_ON(SOL_STD_VARIANT) #include <variant> #endif // Apple clang screwed up @@ -12259,7 +13441,7 @@ namespace sol { namespace stack { } else if constexpr (std::is_integral_v<T> || std::is_same_v<T, lua_Integer>) { tracking.use(1); -#if SOL_LUA_VESION_I_ >= 503 +#if SOL_LUA_VERSION_I_ >= 503 if (lua_isinteger(L, index) != 0) { return static_cast<T>(lua_tointeger(L, index)); } @@ -12271,21 +13453,27 @@ namespace sol { namespace stack { return static_cast<T>(lua_tonumber(L, index)); } else if constexpr (is_lua_reference_v<T>) { - tracking.use(1); - return T(L, index); + if constexpr (is_global_table_v<T>) { + tracking.use(1); + return T(L, global_tag); + } + else { + tracking.use(1); + return T(L, index); + } } else if constexpr (is_unique_usertype_v<T>) { - using Real = typename unique_usertype_traits<T>::actual_type; + using actual = unique_usertype_actual_t<T>; tracking.use(1); void* memory = lua_touserdata(L, index); - memory = detail::align_usertype_unique<Real>(memory); - Real* mem = static_cast<Real*>(memory); - return *mem; + void* aligned_memory = detail::align_usertype_unique<actual>(memory); + actual* typed_memory = static_cast<actual*>(aligned_memory); + return *typed_memory; } else if constexpr (meta::is_optional_v<T>) { using ValueType = typename T::value_type; - return unqualified_check_getter<ValueType>::template get_using<T>(L, index, no_panic, tracking); + return unqualified_check_getter<ValueType>::template get_using<T>(L, index, &no_panic, tracking); } else if constexpr (std::is_same_v<T, luaL_Stream*>) { luaL_Stream* pstream = static_cast<luaL_Stream*>(lua_touserdata(L, index)); @@ -12295,7 +13483,7 @@ namespace sol { namespace stack { luaL_Stream* pstream = static_cast<luaL_Stream*>(lua_touserdata(L, index)); return *pstream; } -#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_) +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) else if constexpr (std::is_function_v<T> || (std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>)) { return stack_detail::get_function_pointer<std::remove_pointer_t<T>>(L, index, tracking); } @@ -12321,34 +13509,37 @@ namespace sol { namespace stack { return stack_detail::unchecked_unqualified_get<sol::nested<Tu>>(L, index, tracking); } } - else if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<Tu> && !is_base_rebindable_non_void_v<unique_usertype_traits<Tu>>) { - using u_traits = unique_usertype_traits<Tu>; - using T = typename u_traits::type; - using Real = typename u_traits::actual_type; + else if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<Tu> && !is_actual_type_rebindable_for_v<Tu>) { + using element = unique_usertype_element_t<Tu>; + using actual = unique_usertype_actual_t<Tu>; tracking.use(1); void* memory = lua_touserdata(L, index); memory = detail::align_usertype_unique_destructor(memory); detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); - if (&detail::usertype_unique_alloc_destroy<T, X> == pdx) { + if (&detail::usertype_unique_alloc_destroy<element, Tu> == pdx) { memory = detail::align_usertype_unique_tag<true, false>(memory); - memory = detail::align_usertype_unique<Real, true, false>(memory); - Real* mem = static_cast<Real*>(memory); - return static_cast<Real>(*mem); - } - Real r(nullptr); - if constexpr (!derive<T>::value) { - // TODO: abort / terminate, maybe only in debug modes? - return static_cast<Real>(std::move(r)); + memory = detail::align_usertype_unique<actual, true, false>(memory); + actual* mem = static_cast<actual*>(memory); + return static_cast<actual>(*mem); + } + actual r {}; + if constexpr (!derive<element>::value) { +#if SOL_IS_ON(SOL_DEBUG_BUILD) + // In debug mode we would rather abort you for this grave failure rather + // than let you deref a null pointer and fuck everything over + std::abort(); +#endif + return static_cast<actual>(std::move(r)); } else { memory = detail::align_usertype_unique_tag<true, false>(memory); detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory); - memory = detail::align_usertype_unique<Real, true, false>(memory); - string_view ti = usertype_traits<T>::qualified_name(); + memory = detail::align_usertype_unique<actual, true, false>(memory); + string_view ti = usertype_traits<element>::qualified_name(); int cast_operation; - if constexpr (is_base_rebindable_v<u_traits>) { - using rebind_t = typename u_traits::template rebind_base<void>; - string_view rebind_ti = usertype_traits<rebind_t>::qualified_name(); + if constexpr (is_actual_type_rebindable_for_v<Tu>) { + using rebound_actual_type = unique_usertype_rebind_actual_t<Tu, void>; + string_view rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); cast_operation = ic(memory, &r, ti, rebind_ti); } else { @@ -12359,19 +13550,23 @@ namespace sol { namespace stack { case 1: { // it's a perfect match, // alias memory directly - Real* mem = static_cast<Real*>(memory); - return static_cast<Real>(*mem); + actual* mem = static_cast<actual*>(memory); + return static_cast<actual>(*mem); } case 2: // it's a base match, return the // aliased creation - return static_cast<Real>(std::move(r)); + return static_cast<actual>(std::move(r)); default: // uh oh.. break; } - // TODO: abort / terminate, maybe only in debug modes? - return static_cast<Real>(r); +#if SOL_IS_ON(SOL_DEBUG_BUILD) + // In debug mode we would rather abort you for this grave failure rather + // than let you deref a null pointer and fuck everything over + std::abort(); +#endif + return static_cast<actual>(r); } } else { @@ -12463,7 +13658,7 @@ namespace sol { namespace stack { int index = lua_absindex(L, relindex); T cont; std::size_t idx = 0; -#if SOL_LUA_VESION_I_ >= 503 +#if SOL_LUA_VERSION_I_ >= 503 // This method is HIGHLY performant over regular table iteration // thanks to the Lua API changes in 5.3 // Questionable in 5.4 @@ -12474,8 +13669,8 @@ namespace sol { namespace stack { } bool isnil = false; for (int vi = 0; vi < lua_size<V>::value; ++vi) { -#if defined(LUA_NILINTABLE) && LUA_NILINTABLE && SOL_LUA_VESION_I_ >= 600 -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_LUA_NIL_IN_TABLES) && SOL_LUA_VERSION_I_ >= 600 +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushinteger(L, static_cast<lua_Integer>(i + vi)); @@ -12495,7 +13690,7 @@ namespace sol { namespace stack { if (i == 0) { break; } -#if defined(LUA_NILINTABLE) && LUA_NILINTABLE && SOL_LUA_VESION_I_ >= 600 +#if SOL_IS_ON(SOL_LUA_NIL_IN_TABLES) && SOL_LUA_VERSION_I_ >= 600 lua_pop(L, vi); #else lua_pop(L, (vi + 1)); @@ -12505,7 +13700,7 @@ namespace sol { namespace stack { } } if (isnil) { -#if defined(LUA_NILINTABLE) && LUA_NILINTABLE && SOL_LUA_VESION_I_ >= 600 +#if SOL_IS_ON(SOL_LUA_NIL_IN_TABLES) && SOL_LUA_VERSION_I_ >= 600 #else lua_pop(L, lua_size<V>::value); #endif @@ -12523,7 +13718,7 @@ namespace sol { namespace stack { // see above comment goto done; } -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 2, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow bool isnil = false; @@ -12562,7 +13757,7 @@ namespace sol { namespace stack { static T get(types<K, V>, lua_State* L, int relindex, record& tracking) { tracking.use(1); -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 3, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow @@ -12605,7 +13800,7 @@ namespace sol { namespace stack { template <typename V> static C get(types<V>, lua_State* L, int relindex, record& tracking) { tracking.use(1); -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 3, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow @@ -12613,7 +13808,7 @@ namespace sol { namespace stack { C cont; auto at = cont.cbefore_begin(); std::size_t idx = 0; -#if SOL_LUA_VESION_I_ >= 503 +#if SOL_LUA_VERSION_I_ >= 503 // This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3 for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) { if (idx >= cont.max_size()) { @@ -12670,7 +13865,7 @@ namespace sol { namespace stack { static C get(types<K, V>, lua_State* L, int relindex, record& tracking) { tracking.use(1); -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 3, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow @@ -12700,23 +13895,17 @@ namespace sol { namespace stack { typedef typename T::value_type P; typedef typename P::first_type K; typedef typename P::second_type V; - unqualified_getter<as_table_t<T>> g; - // VC++ has a bad warning here: shut it up - (void)g; + unqualified_getter<as_table_t<T>> g{}; return g.get(types<K, nested<V>>(), L, index, tracking); } else { typedef typename T::value_type V; - unqualified_getter<as_table_t<T>> g; - // VC++ has a bad warning here: shut it up - (void)g; + unqualified_getter<as_table_t<T>> g{}; return g.get(types<nested<V>>(), L, index, tracking); } } else { - unqualified_getter<Tu> g; - // VC++ has a bad warning here: shut it up - (void)g; + unqualified_getter<Tu> g{}; return g.get(L, index, tracking); } } @@ -13002,7 +14191,7 @@ namespace sol { namespace stack { struct unqualified_getter<detail::as_value_tag<T>> { static T* get_no_lua_nil(lua_State* L, int index, record& tracking) { void* memory = lua_touserdata(L, index); -#if SOL_IS_ON(SOL_USE_INTEROP_I_) +#if SOL_IS_ON(SOL_USE_INTEROP) auto ugr = stack_detail::interop_get<T>(L, index, memory, tracking); if (ugr.first) { return ugr.second; @@ -13029,8 +14218,14 @@ namespace sol { namespace stack { lua_pop(L, 2); } } - T* obj = static_cast<T*>(udata); - return obj; + if constexpr (std::is_function_v<T>) { + T* func = reinterpret_cast<T*>(udata); + return func; + } + else { + T* obj = static_cast<T*>(udata); + return obj; + } } static T& get(lua_State* L, int index, record& tracking) { @@ -13046,9 +14241,7 @@ namespace sol { namespace stack { tracking.use(1); return nullptr; } - unqualified_getter<detail::as_value_tag<T>> g; - // Avoid VC++ warning - (void)g; + unqualified_getter<detail::as_value_tag<T>> g{}; return g.get_no_lua_nil(L, index, tracking); } }; @@ -13056,9 +14249,7 @@ namespace sol { namespace stack { template <typename T> struct unqualified_getter<non_null<T*>> { static T* get(lua_State* L, int index, record& tracking) { - unqualified_getter<detail::as_value_tag<T>> g; - // Avoid VC++ warning - (void)g; + unqualified_getter<detail::as_value_tag<T>> g{}; return g.get_no_lua_nil(L, index, tracking); } }; @@ -13066,9 +14257,7 @@ namespace sol { namespace stack { template <typename T> struct unqualified_getter<T&> { static T& get(lua_State* L, int index, record& tracking) { - unqualified_getter<detail::as_value_tag<T>> g; - // Avoid VC++ warning - (void)g; + unqualified_getter<detail::as_value_tag<T>> g{}; return g.get(L, index, tracking); } }; @@ -13076,9 +14265,7 @@ namespace sol { namespace stack { template <typename T> struct unqualified_getter<std::reference_wrapper<T>> { static T& get(lua_State* L, int index, record& tracking) { - unqualified_getter<T&> g; - // Avoid VC++ warning - (void)g; + unqualified_getter<T&> g{}; return g.get(L, index, tracking); } }; @@ -13086,20 +14273,16 @@ namespace sol { namespace stack { template <typename T> struct unqualified_getter<T*> { static T* get(lua_State* L, int index, record& tracking) { -#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_) +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) if constexpr (std::is_function_v<T>) { return stack_detail::get_function_pointer<T>(L, index, tracking); } else { - unqualified_getter<detail::as_pointer_tag<T>> g; - // Avoid VC++ warning - (void)g; + unqualified_getter<detail::as_pointer_tag<T>> g{}; return g.get(L, index, tracking); } #else - unqualified_getter<detail::as_pointer_tag<T>> g; - // Avoid VC++ warning - (void)g; + unqualified_getter<detail::as_pointer_tag<T>> g{}; return g.get(L, index, tracking); #endif } @@ -13135,7 +14318,7 @@ namespace sol { namespace stack { } }; -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#if SOL_IS_ON(SOL_STD_VARIANT) template <typename... Tn> struct unqualified_getter<std::variant<Tn...>> { @@ -13159,7 +14342,7 @@ namespace sol { namespace stack { static V get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, record& tracking) { typedef std::variant_alternative_t<I, V> T; record temp_tracking = tracking; - if (stack::check<T>(L, index, no_panic, temp_tracking)) { + if (stack::check<T>(L, index, &no_panic, temp_tracking)) { tracking = temp_tracking; return V(std::in_place_index<I>, stack::get<T>(L, index)); } @@ -13178,15 +14361,13 @@ namespace sol { namespace stack { // beginning of sol/stack_get_qualified.hpp -namespace sol { -namespace stack { +namespace sol { namespace stack { // There are no more enable_ifs that can be used here, // so this is just for posterity, I guess? // maybe I'll fill this file in later. -} -} // namespace sol::stack +}} // namespace sol::stack // end of sol/stack_get_qualified.hpp @@ -13199,7 +14380,7 @@ namespace stack { #include <cstdlib> #include <cmath> #include <optional> -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#if SOL_IS_ON(SOL_STD_VARIANT) #include <variant> #endif // variant shenanigans (thanks, Mac OSX) @@ -13212,19 +14393,28 @@ namespace sol { namespace stack { static Optional get_using(lua_State* L, int index, Handler&& handler, record& tracking) { if constexpr (!meta::meta_detail::is_adl_sol_lua_check_v<T> && !meta::meta_detail::is_adl_sol_lua_get_v<T>) { if constexpr (is_lua_reference_v<T>) { - // actually check if it's none here, otherwise - // we'll have a none object inside an optional! - bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, no_panic); - if (!success) { - // expected type, actual type - tracking.use(static_cast<int>(success)); - handler(L, index, type::poly, type_of(L, index), ""); - return detail::associated_nullopt_v<Optional>; + if constexpr (is_global_table_v<T>) { + (void)L; + (void)index; + (void)handler; + tracking.use(1); + return true; + } + else { + // actually check if it's none here, otherwise + // we'll have a none object inside an optional! + bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, &no_panic); + if (!success) { + // expected type, actual type + tracking.use(static_cast<int>(success)); + handler(L, index, type::poly, type_of(L, index), ""); + return detail::associated_nullopt_v<Optional>; + } + return stack_detail::unchecked_get<T>(L, index, tracking); } - return stack_detail::unchecked_get<T>(L, index, tracking); } else if constexpr ((std::is_integral_v<T> || std::is_same_v<T, lua_Integer>)&&!std::is_same_v<T, bool>) { -#if SOL_LUA_VESION_I_ >= 503 +#if SOL_LUA_VERSION_I_ >= 503 if (lua_isinteger(L, index) != 0) { tracking.use(1); return static_cast<T>(lua_tointeger(L, index)); @@ -13233,7 +14423,7 @@ namespace sol { namespace stack { int isnum = 0; const lua_Number value = lua_tonumberx(L, index, &isnum); if (isnum != 0) { -#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_) +#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS) const auto integer_value = llround(value); if (static_cast<lua_Number>(integer_value) == value) { tracking.use(1); @@ -13296,7 +14486,7 @@ namespace sol { namespace stack { } }; -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#if SOL_IS_ON(SOL_STD_VARIANT) template <typename... Tn, typename C> struct unqualified_check_getter<std::variant<Tn...>, C> { typedef std::variant<Tn...> V; @@ -13326,7 +14516,7 @@ namespace sol { namespace stack { template <std::size_t I, typename Handler> static optional<V> get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) { typedef std::variant_alternative_t<I - 1, V> T; - if (stack::check<T>(L, index, no_panic, tracking)) { + if (stack::check<T>(L, index, &no_panic, tracking)) { return V(std::in_place_index<I - 1>, stack::get<T>(L, index)); } return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking); @@ -13345,56 +14535,117 @@ namespace sol { namespace stack { // beginning of sol/stack_check_get_qualified.hpp namespace sol { namespace stack { - template <typename T, typename C> - struct qualified_check_getter { - typedef decltype(stack_detail::unchecked_get<T>(nullptr, -1, std::declval<record&>())) R; - template <typename Handler> - static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) { +#if SOL_IS_ON(SOL_COMPILER_GCC) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + + namespace stack_detail { + template <typename OptionalType, typename T, typename Handler> + OptionalType get_optional(lua_State* L, int index, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t<T>; + if constexpr (is_lua_reference_v<T>) { - // actually check if it's none here, otherwise - // we'll have a none object inside an optional! - bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, no_panic); - if (!success) { - // expected type, actual type - tracking.use(static_cast<int>(success)); - handler(L, index, type::poly, type_of(L, index), ""); - return nullopt; + if constexpr (is_global_table_v<Tu>) { + (void)L; + (void)index; + (void)handler; + tracking.use(1); + return true; + } + else { + // actually check if it's none here, otherwise + // we'll have a none object inside an optional! + bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, &no_panic); + if (!success) { + // expected type, actual type + tracking.use(static_cast<int>(success)); + handler(L, index, type::poly, type_of(L, index), ""); + return {}; + } + return OptionalType(stack_detail::unchecked_get<T>(L, index, tracking)); + } + } + else if constexpr (!std::is_reference_v<T> && is_unique_usertype_v<Tu> && !is_actual_type_rebindable_for_v<Tu>) { + // we can take shortcuts here to save on separate checking, and just return nullopt! + using element = unique_usertype_element_t<Tu>; + using actual = unique_usertype_actual_t<Tu>; + tracking.use(1); + void* memory = lua_touserdata(L, index); + memory = detail::align_usertype_unique_destructor(memory); + detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); + if (&detail::usertype_unique_alloc_destroy<element, Tu> == pdx) { + memory = detail::align_usertype_unique_tag<true, false>(memory); + memory = detail::align_usertype_unique<actual, true, false>(memory); + actual* mem = static_cast<actual*>(memory); + return static_cast<actual>(*mem); + } + if constexpr (!derive<element>::value) { + return OptionalType(); + } + else { + memory = detail::align_usertype_unique_tag<true, false>(memory); + detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory); + memory = detail::align_usertype_unique<actual, true, false>(memory); + string_view ti = usertype_traits<element>::qualified_name(); + int cast_operation; + actual r {}; + if constexpr (is_actual_type_rebindable_for_v<Tu>) { + using rebound_actual_type = unique_usertype_rebind_actual_t<Tu, void>; + string_view rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); + cast_operation = ic(memory, &r, ti, rebind_ti); + } + else { + string_view rebind_ti(""); + cast_operation = ic(memory, &r, ti, rebind_ti); + } + switch (cast_operation) { + case 1: { + // it's a perfect match, + // alias memory directly + actual* mem = static_cast<actual*>(memory); + return OptionalType(*mem); + } + case 2: + // it's a base match, return the + // aliased creation + return OptionalType(std::move(r)); + default: + break; + } + return OptionalType(); } - return stack_detail::unchecked_get<T>(L, index, tracking); } else { if (!check<T>(L, index, std::forward<Handler>(handler))) { tracking.use(static_cast<int>(!lua_isnone(L, index))); - return nullopt; + return OptionalType(); } - return stack_detail::unchecked_get<T>(L, index, tracking); + return OptionalType(stack_detail::unchecked_get<T>(L, index, tracking)); } } + } // namespace stack_detail + +#if SOL_IS_ON(SOL_COMPILER_GCC) +#pragma GCC diagnostic pop +#endif + + template <typename T, typename> + struct qualified_check_getter { + typedef decltype(stack_detail::unchecked_get<T>(nullptr, -1, std::declval<record&>())) R; + + template <typename Handler> + optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) { + return stack_detail::get_optional<optional<R>, T>(L, index, std::forward<Handler>(handler), tracking); + } }; - template <typename T> - struct qualified_getter<T, std::enable_if_t<meta::is_optional_v<T>>> { - static T get(lua_State* L, int index, record& tracking) { - using ValueType = typename meta::unqualified_t<T>::value_type; - if constexpr (is_lua_reference_v<ValueType>) { - // actually check if it's none here, otherwise - // we'll have a none object inside an optional! - bool success = lua_isnoneornil(L, index) == 0 && stack::check<ValueType>(L, index, no_panic); - if (!success) { - // expected type, actual type - tracking.use(static_cast<int>(success)); - return {}; - } - return stack_detail::unchecked_get<ValueType>(L, index, tracking); - } - else { - if (!check<ValueType>(L, index, &no_panic)) { - tracking.use(static_cast<int>(!lua_isnone(L, index))); - return {}; - } - return stack_detail::unchecked_get<ValueType>(L, index, tracking); - } + template <typename Optional> + struct qualified_getter<Optional, std::enable_if_t<meta::is_optional_v<Optional>>> { + static Optional get(lua_State* L, int index, record& tracking) { + using T = typename meta::unqualified_t<Optional>::value_type; + return stack_detail::get_optional<Optional, T>(L, index, &no_panic, tracking); } }; @@ -13412,15 +14663,56 @@ namespace sol { namespace stack { #include <limits> #include <cmath> #include <string_view> -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#if SOL_IS_ON(SOL_STD_VARIANT) #include <variant> #endif // Can use variant +// beginning of sol/debug.hpp + +#include <iostream> + +namespace sol { namespace detail { namespace debug { + inline std::string dump_types(lua_State* L) { + std::string visual; + std::size_t size = lua_gettop(L) + 1; + for (std::size_t i = 1; i < size; ++i) { + if (i != 1) { + visual += " | "; + } + visual += type_name(L, stack::get<type>(L, static_cast<int>(i))); + } + return visual; + } + + inline void print_stack(lua_State* L) { + std::cout << dump_types(L) << std::endl; + } + + inline void print_section(const std::string& message, lua_State* L) { + std::cout << "-- " << message << " -- [ " << dump_types(L) << " ]" << std::endl; + } +}}} // namespace sol::detail::debug + +// end of sol/debug.hpp + namespace sol { namespace stack { namespace stack_detail { template <typename T> inline bool integer_value_fits(const T& value) { - if constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed_v<T> && sizeof(T) == sizeof(lua_Integer))) { + // We check if we can rely on casts or a lack of padding bits to satisfy + // the requirements here + // If it lacks padding bits, we can jump back and forth between lua_Integer and whatever type without + // loss of information + constexpr bool is_same_signedness + = (std::is_signed_v<T> && std::is_signed_v<lua_Integer>) || (std::is_unsigned_v<T> && std::is_unsigned_v<lua_Integer>); + constexpr bool probaby_fits_within_lua_Integer = sizeof(T) == sizeof(lua_Integer) +#if SOL_IS_ON(SOL_ALL_INTEGER_VALUES_FIT) + && ((std::has_unique_object_representations_v<T> && std::has_unique_object_representations_v<lua_Integer>) ? true : is_same_signedness) +#else + && is_same_signedness +#endif + ; + if constexpr (sizeof(T) < sizeof(lua_Integer) || probaby_fits_within_lua_Integer) { (void)value; return true; } @@ -13435,7 +14727,15 @@ namespace sol { namespace stack { template <typename T> int msvc_is_ass_with_if_constexpr_push_enum(std::true_type, lua_State* L, const T& value) { - if constexpr (meta::any_same_v<std::underlying_type_t<T>, char /*, char8_t*/, char16_t, char32_t>) { + if constexpr (meta::any_same_v<std::underlying_type_t<T>, + char +#if SOL_IS_ON(SOL_CHAR8_T) + , + char8_t +#endif + , + char16_t, + char32_t>) { if constexpr (std::is_signed_v<T>) { return stack::push(L, static_cast<std::int_least32_t>(value)); } @@ -13454,18 +14754,38 @@ namespace sol { namespace stack { } } // namespace stack_detail - inline int push_environment_of(lua_State* L, int index = -1) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) + inline int push_environment_of(lua_State* L, int target_index = -1) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_environment); #endif // make sure stack doesn't overflow -#if SOL_LUA_VESION_I_ < 502 +#if SOL_LUA_VERSION_I_ < 502 // Use lua_getfenv - lua_getfenv(L, index); + lua_getfenv(L, target_index); #else - // Use upvalues as explained in Lua 5.2 and beyond's manual - if (lua_getupvalue(L, index, 1) == nullptr) { - push(L, lua_nil); - return 1; + + if (lua_iscfunction(L, target_index) != 0) { + const char* maybe_upvalue_name = lua_getupvalue(L, target_index, 1); + if (maybe_upvalue_name != nullptr) { + // it worked, take this one + return 1; + } + } + // Nominally, we search for the `"_ENV"` value. + // If we don't find it.... uh, well. We've got a problem? + for (int upvalue_index = 1;; ++upvalue_index) { + const char* maybe_upvalue_name = lua_getupvalue(L, target_index, upvalue_index); + if (maybe_upvalue_name == nullptr) { + push(L, lua_nil); + break; + } + + string_view upvalue_name(maybe_upvalue_name); + if (upvalue_name == "_ENV") { + // Keep this one! + break; + } + // Discard what we received, loop back around + lua_pop(L, 1); } #endif return 1; @@ -13473,15 +14793,20 @@ namespace sol { namespace stack { template <typename T> int push_environment_of(const T& target) { - target.push(); - return push_environment_of(target.lua_state(), -1) + 1; + lua_State* target_L = target.lua_state(); + int target_index = absolute_index(target_L, -target.push()); + int env_count = push_environment_of(target_L, target_index); + sol_c_assert(env_count == 1); + lua_rotate(target_L, target_index, 1); + lua_pop(target_L, 1); + return env_count; } template <typename T> struct unqualified_pusher<detail::as_value_tag<T>> { template <typename F, typename... Args> static int push_fx(lua_State* L, F&& f, Args&&... args) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); #endif // make sure stack doesn't overflow // Basically, we store all user-data like this: @@ -13526,7 +14851,7 @@ namespace sol { namespace stack { static int push_fx(lua_State* L, F&& f, T* obj) { if (obj == nullptr) return stack::push(L, lua_nil); -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); #endif // make sure stack doesn't overflow T** pref = detail::usertype_allocate_pointer<T>(L); @@ -13564,14 +14889,13 @@ namespace sol { namespace stack { namespace stack_detail { template <typename T> struct uu_pusher { - using u_traits = unique_usertype_traits<T>; - using P = typename u_traits::type; - using Real = typename u_traits::actual_type; + using element = unique_usertype_element_t<T>; + using actual = unique_usertype_actual_t<T>; template <typename Arg, typename... Args> static int push(lua_State* L, Arg&& arg, Args&&... args) { - if constexpr (std::is_base_of_v<Real, meta::unqualified_t<Arg>>) { - if (u_traits::is_null(arg)) { + if constexpr (std::is_base_of_v<actual, meta::unqualified_t<Arg>>) { + if (detail::unique_is_null(L, arg)) { return stack::push(L, lua_nil); } return push_deep(L, std::forward<Arg>(arg), std::forward<Args>(args)...); @@ -13583,26 +14907,26 @@ namespace sol { namespace stack { template <typename... Args> static int push_deep(lua_State* L, Args&&... args) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); #endif // make sure stack doesn't overflow - P** pref = nullptr; + element** pointer_to_memory = nullptr; detail::unique_destructor* fx = nullptr; detail::unique_tag* id = nullptr; - Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id); - if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) { - detail::lua_reg_table l {}; + actual* typed_memory = detail::usertype_unique_allocate<element, actual>(L, pointer_to_memory, fx, id); + if (luaL_newmetatable(L, &usertype_traits<d::u<std::remove_cv_t<element>>>::metatable()[0]) == 1) { + detail::lua_reg_table registration_table {}; int index = 0; - detail::indexed_insert insert_fx(l, index); - detail::insert_default_registrations<P>(insert_fx, detail::property_always_true); - l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() }; - luaL_setfuncs(L, l, 0); + detail::indexed_insert insert_callable(registration_table, index); + detail::insert_default_registrations<element>(insert_callable, detail::property_always_true); + registration_table[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() }; + luaL_setfuncs(L, registration_table, 0); } lua_setmetatable(L, -2); - *fx = detail::usertype_unique_alloc_destroy<P, Real>; - *id = &detail::inheritance<P>::template type_unique_cast<Real>; - detail::default_construct::construct(mem, std::forward<Args>(args)...); - *pref = unique_usertype_traits<T>::get(*mem); + *fx = detail::usertype_unique_alloc_destroy<element, actual>; + *id = &detail::inheritance<element>::template type_unique_cast<actual>; + detail::default_construct::construct(typed_memory, std::forward<Args>(args)...); + *pointer_to_memory = detail::unique_get<T>(L, *typed_memory); return 1; } }; @@ -13629,7 +14953,7 @@ namespace sol { namespace stack { return p[0]; } else if constexpr (std::is_same_v<Tu, bool>) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushboolean(L, std::forward<Args>(args)...); @@ -13637,20 +14961,20 @@ namespace sol { namespace stack { } else if constexpr (std::is_integral_v<Tu> || std::is_same_v<Tu, lua_Integer>) { const Tu& value(std::forward<Args>(args)...); -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_integral); #endif // make sure stack doesn't overflow -#if SOL_LUA_VESION_I_ >= 503 +#if SOL_LUA_VERSION_I_ >= 503 if (stack_detail::integer_value_fits<Tu>(value)) { lua_pushinteger(L, static_cast<lua_Integer>(value)); return 1; } #endif // Lua 5.3 and above -#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_) +#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS) if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) { -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) +#if SOL_IS_OFF(SOL_EXCEPTIONS) // Is this really worth it? - assert(false && "integer value will be misrepresented in lua"); + sol_m_assert(false, "integer value will be misrepresented in lua"); lua_pushinteger(L, static_cast<lua_Integer>(value)); return 1; #else @@ -13662,7 +14986,7 @@ namespace sol { namespace stack { return 1; } else if constexpr (std::is_floating_point_v<Tu> || std::is_same_v<Tu, lua_Number>) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_floating); #endif // make sure stack doesn't overflow lua_pushnumber(L, std::forward<Args>(args)...); @@ -13670,18 +14994,18 @@ namespace sol { namespace stack { } else if constexpr (std::is_same_v<Tu, luaL_Stream*>) { luaL_Stream* source { std::forward<Args>(args)... }; - luaL_Stream* stream = static_cast<luaL_Stream*>(lua_newuserdata(L, sizeof(luaL_Stream))); + luaL_Stream* stream = static_cast<luaL_Stream*>(detail::alloc_newuserdata(L, sizeof(luaL_Stream))); stream->f = source->f; -#if SOL_IS_ON(SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_) +#if SOL_IS_ON(SOL_LUAL_STREAM_USE_CLOSE_FUNCTION) stream->closef = source->closef; #endif // LuaJIT and Lua 5.1 and below do not have return 1; } else if constexpr (std::is_same_v<Tu, luaL_Stream>) { luaL_Stream& source(std::forward<Args>(args)...); - luaL_Stream* stream = static_cast<luaL_Stream*>(lua_newuserdata(L, sizeof(luaL_Stream))); + luaL_Stream* stream = static_cast<luaL_Stream*>(detail::alloc_newuserdata(L, sizeof(luaL_Stream))); stream->f = source.f; -#if SOL_IS_ON(SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_) +#if SOL_IS_ON(SOL_LUAL_STREAM_USE_CLOSE_FUNCTION) stream->closef = source.closef; #endif // LuaJIT and Lua 5.1 and below do not have return 1; @@ -13751,13 +15075,13 @@ namespace sol { namespace stack { int tableindex = lua_gettop(L); std::size_t index = 1; for (const auto& i : cont) { -#if SOL_LUA_VESION_I_ >= 503 +#if SOL_LUA_VERSION_I_ >= 503 int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); for (int pi = 0; pi < p; ++pi) { lua_seti(L, tableindex, static_cast<lua_Integer>(index++)); } #else -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushinteger(L, static_cast<lua_Integer>(index)); @@ -13770,7 +15094,7 @@ namespace sol { namespace stack { int firstindex = tableindex + 1 + 1; for (int pi = 0; pi < p; ++pi) { stack::push(L, index); -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushvalue(L, firstindex); @@ -13790,45 +15114,64 @@ namespace sol { namespace stack { template <typename T> struct unqualified_pusher<as_table_t<T>> { - static int push(lua_State* L, const T& v) { + static int push(lua_State* L, const as_table_t<T>& value_) { using inner_t = std::remove_pointer_t<meta::unwrap_unqualified_t<T>>; if constexpr (is_container_v<inner_t>) { - return stack::push<detail::as_table_tag<T>>(L, v); + return stack::push<detail::as_table_tag<T>>(L, value_.value()); } else { - return stack::push(L, v); + return stack::push(L, value_.value()); + } + } + + static int push(lua_State* L, const T& value_) { + using inner_t = std::remove_pointer_t<meta::unwrap_unqualified_t<T>>; + if constexpr (is_container_v<inner_t>) { + return stack::push<detail::as_table_tag<T>>(L, value_); + } + else { + return stack::push(L, value_); } } }; template <typename T> struct unqualified_pusher<nested<T>> { - static int push(lua_State* L, const T& tablecont) { + static int push(lua_State* L, const T& nested_value) noexcept { + using Tu = meta::unwrap_unqualified_t<T>; + using inner_t = std::remove_pointer_t<Tu>; + if constexpr (is_container_v<inner_t>) { + return stack::push<detail::as_table_tag<T>>(L, nested_value, nested_tag); + } + else { + return stack::push<Tu>(L, nested_value); + } + } + + static int push(lua_State* L, const nested<T>& nested_wrapper_) noexcept { using Tu = meta::unwrap_unqualified_t<T>; using inner_t = std::remove_pointer_t<Tu>; if constexpr (is_container_v<inner_t>) { - return stack::push<detail::as_table_tag<T>>(L, tablecont, nested_tag); + return stack::push<detail::as_table_tag<T>>(L, nested_wrapper_.value(), nested_tag); } else { - return stack::push<Tu>(L, tablecont); + return stack::push<Tu>(L, nested_wrapper_.value()); } } }; template <typename T> struct unqualified_pusher<std::initializer_list<T>> { - static int push(lua_State* L, const std::initializer_list<T>& il) { + static int push(lua_State* L, const std::initializer_list<T>& il) noexcept { unqualified_pusher<detail::as_table_tag<std::initializer_list<T>>> p {}; - // silence annoying VC++ warning - (void)p; return p.push(L, il); } }; template <> struct unqualified_pusher<lua_nil_t> { - static int push(lua_State* L, lua_nil_t) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) + static int push(lua_State* L, lua_nil_t) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushnil(L); @@ -13838,7 +15181,7 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<stack_count> { - static int push(lua_State*, stack_count st) { + static int push(lua_State*, stack_count st) noexcept { return st.count; } }; @@ -13846,7 +15189,7 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<metatable_key_t> { static int push(lua_State* L, metatable_key_t) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushlstring(L, to_string(meta_function::metatable).c_str(), 4); @@ -13856,8 +15199,8 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<std::remove_pointer_t<lua_CFunction>> { - static int push(lua_State* L, lua_CFunction func, int n = 0) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) + static int push(lua_State* L, lua_CFunction func, int n = 0) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushcclosure(L, func, n); @@ -13868,7 +15211,7 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<lua_CFunction> { static int push(lua_State* L, lua_CFunction func, int n = 0) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushcclosure(L, func, n); @@ -13876,11 +15219,11 @@ namespace sol { namespace stack { } }; -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) template <> struct unqualified_pusher<std::remove_pointer_t<detail::lua_CFunction_noexcept>> { static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushcclosure(L, func, n); @@ -13891,7 +15234,7 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<detail::lua_CFunction_noexcept> { static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushcclosure(L, func, n); @@ -13903,7 +15246,7 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<c_closure> { static int push(lua_State* L, c_closure cc) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushcclosure(L, cc.c_function, cc.upvalues); @@ -13928,8 +15271,8 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<void*> { - static int push(lua_State* L, void* userdata) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) + static int push(lua_State* L, void* userdata) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushlightuserdata(L, userdata); @@ -13939,8 +15282,8 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<const void*> { - static int push(lua_State* L, const void* userdata) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) + static int push(lua_State* L, const void* userdata) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushlightuserdata(L, const_cast<void*>(userdata)); @@ -13950,8 +15293,8 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<lightuserdata_value> { - static int push(lua_State* L, lightuserdata_value userdata) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) + static int push(lua_State* L, lightuserdata_value userdata) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushlightuserdata(L, userdata); @@ -13961,11 +15304,11 @@ namespace sol { namespace stack { template <typename T> struct unqualified_pusher<light<T>> { - static int push(lua_State* L, light<T> l) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) + static int push(lua_State* L, light<T> l) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow - lua_pushlightuserdata(L, static_cast<void*>(l.value)); + lua_pushlightuserdata(L, static_cast<void*>(l.value())); return 1; } }; @@ -13974,18 +15317,18 @@ namespace sol { namespace stack { struct unqualified_pusher<user<T>> { template <bool with_meta = true, typename Key, typename... Args> static int push_with(lua_State* L, Key&& name, Args&&... args) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); #endif // make sure stack doesn't overflow // A dumb pusher T* data = detail::user_allocate<T>(L); if (with_meta) { // Make sure we have a plain GC set for this data -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow if (luaL_newmetatable(L, name) != 0) { - lua_CFunction cdel = detail::user_alloc_destruct<T>; + lua_CFunction cdel = detail::user_alloc_destroy<T>; lua_pushcclosure(L, cdel, 0); lua_setfield(L, -2, "__gc"); } @@ -14020,28 +15363,28 @@ namespace sol { namespace stack { static int push(lua_State* L, user<T>&& u) { const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; - return push_with(L, name, std::move(u.value)); + return push_with(L, name, std::move(u.value())); } static int push(lua_State* L, no_metatable_t, const user<T>& u) { const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; - return push_with<false>(L, name, u.value); + return push_with<false>(L, name, u.value()); } static int push(lua_State* L, no_metatable_t, user<T>&& u) { const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; - return push_with<false>(L, name, std::move(u.value)); + return push_with<false>(L, name, std::move(u.value())); } }; template <> struct unqualified_pusher<userdata_value> { static int push(lua_State* L, userdata_value data) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); #endif // make sure stack doesn't overflow void** ud = detail::usertype_allocate_pointer<void>(L); - *ud = data.value; + *ud = data.value(); return 1; } }; @@ -14049,7 +15392,7 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<const char*> { static int push_sized(lua_State* L, const char* str, std::size_t len) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_string); #endif // make sure stack doesn't overflow lua_pushlstring(L, str, len); @@ -14063,7 +15406,7 @@ namespace sol { namespace stack { } static int push(lua_State* L, const char* strb, const char* stre) { - return push_sized(L, strb, stre - strb); + return push_sized(L, strb, static_cast<std::size_t>(stre - strb)); } static int push(lua_State* L, const char* str, std::size_t len) { @@ -14101,7 +15444,7 @@ namespace sol { namespace stack { template <size_t N> struct unqualified_pusher<char[N]> { static int push(lua_State* L, const char (&str)[N]) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_string); #endif // make sure stack doesn't overflow lua_pushlstring(L, str, std::char_traits<char>::length(str)); @@ -14109,7 +15452,7 @@ namespace sol { namespace stack { } static int push(lua_State* L, const char (&str)[N], std::size_t sz) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_string); #endif // make sure stack doesn't overflow lua_pushlstring(L, str, sz); @@ -14121,10 +15464,92 @@ namespace sol { namespace stack { struct unqualified_pusher<char> { static int push(lua_State* L, char c) { const char str[2] = { c, '\0' }; - return stack::push(L, static_cast<const char*>(str), 1); + return stack::push(L, static_cast<const char*>(str), 1u); } }; +#if SOL_IS_ON(SOL_CHAR8_T) + template <> + struct unqualified_pusher<const char8_t*> { + static int push_sized(lua_State* L, const char8_t* str, std::size_t len) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, reinterpret_cast<const char*>(str), len); + return 1; + } + + static int push(lua_State* L, const char8_t* str) { + if (str == nullptr) + return stack::push(L, lua_nil); + return push_sized(L, str, std::char_traits<char>::length(reinterpret_cast<const char*>(str))); + } + + static int push(lua_State* L, const char8_t* strb, const char8_t* stre) { + return push_sized(L, strb, static_cast<std::size_t>(stre - strb)); + } + + static int push(lua_State* L, const char8_t* str, std::size_t len) { + return push_sized(L, str, len); + } + }; + + template <> + struct unqualified_pusher<char8_t*> { + static int push_sized(lua_State* L, const char8_t* str, std::size_t len) { + unqualified_pusher<const char8_t*> p {}; + (void)p; + return p.push_sized(L, str, len); + } + + static int push(lua_State* L, const char8_t* str) { + unqualified_pusher<const char8_t*> p {}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char8_t* strb, const char8_t* stre) { + unqualified_pusher<const char8_t*> p {}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char8_t* str, std::size_t len) { + unqualified_pusher<const char8_t*> p {}; + (void)p; + return p.push(L, str, len); + } + }; + + template <size_t N> + struct unqualified_pusher<char8_t[N]> { + static int push(lua_State* L, const char8_t (&str)[N]) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + const char* str_as_char = reinterpret_cast<const char*>(static_cast<const char8_t*>(str)); + lua_pushlstring(L, str_as_char, std::char_traits<char>::length(str_as_char)); + return 1; + } + + static int push(lua_State* L, const char8_t (&str)[N], std::size_t sz) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, sz); + return 1; + } + }; + + template <> + struct unqualified_pusher<char8_t> { + static int push(lua_State* L, char8_t c) { + const char8_t str[2] = { c, '\0' }; + return stack::push(L, static_cast<const char8_t*>(str), 1u); + } + }; +#endif // char8_t + template <typename Ch, typename Traits, typename Al> struct unqualified_pusher<std::basic_string<Ch, Traits, Al>> { static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& str) { @@ -14132,7 +15557,7 @@ namespace sol { namespace stack { return stack::push(L, str.data(), str.size()); } else { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_string); #endif // make sure stack doesn't overflow lua_pushlstring(L, str.c_str(), str.size()); @@ -14145,7 +15570,7 @@ namespace sol { namespace stack { return stack::push(L, str.data(), sz); } else { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_string); #endif // make sure stack doesn't overflow lua_pushlstring(L, str.c_str(), sz); @@ -14168,7 +15593,7 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<meta_function> { static int push(lua_State* L, meta_function m) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_meta_function_name); #endif // make sure stack doesn't overflow const std::string& str = to_string(m); @@ -14180,7 +15605,7 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<absolute_index> { static int push(lua_State* L, absolute_index ai) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushvalue(L, ai); @@ -14191,7 +15616,7 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<raw_index> { static int push(lua_State* L, raw_index ri) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushvalue(L, ri); @@ -14202,7 +15627,7 @@ namespace sol { namespace stack { template <> struct unqualified_pusher<ref_index> { static int push(lua_State* L, ref_index ri) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_rawgeti(L, LUA_REGISTRYINDEX, ri); @@ -14290,7 +15715,7 @@ namespace sol { namespace stack { char sbo[SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_]; // if our max string space is small enough, use SBO // right off the bat - std::size_t max_possible_code_units = (stre - strb) * 4; + std::size_t max_possible_code_units = static_cast<std::size_t>(static_cast<std::size_t>(stre - strb) * static_cast<std::size_t>(4)); if (max_possible_code_units <= SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_) { return convert_into(L, sbo, max_possible_code_units, strb, stre); } @@ -14367,7 +15792,7 @@ namespace sol { namespace stack { char sbo[SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_]; // if our max string space is small enough, use SBO // right off the bat - std::size_t max_possible_code_units = (stre - strb) * 4; + std::size_t max_possible_code_units = static_cast<std::size_t>(static_cast<std::size_t>(stre - strb) * static_cast<std::size_t>(4)); if (max_possible_code_units <= SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_) { return convert_into(L, sbo, max_possible_code_units, strb, stre); } @@ -14450,7 +15875,7 @@ namespace sol { namespace stack { struct unqualified_pusher<wchar_t> { static int push(lua_State* L, wchar_t c) { const wchar_t str[2] = { c, '\0' }; - return stack::push(L, static_cast<const wchar_t*>(str), 1); + return stack::push(L, static_cast<const wchar_t*>(str), 1u); } }; @@ -14458,7 +15883,7 @@ namespace sol { namespace stack { struct unqualified_pusher<char16_t> { static int push(lua_State* L, char16_t c) { const char16_t str[2] = { c, '\0' }; - return stack::push(L, static_cast<const char16_t*>(str), 1); + return stack::push(L, static_cast<const char16_t*>(str), 1u); } }; @@ -14466,7 +15891,7 @@ namespace sol { namespace stack { struct unqualified_pusher<char32_t> { static int push(lua_State* L, char32_t c) { const char32_t str[2] = { c, '\0' }; - return stack::push(L, static_cast<const char32_t*>(str), 1); + return stack::push(L, static_cast<const char32_t*>(str), 1u); } }; @@ -14474,7 +15899,7 @@ namespace sol { namespace stack { struct unqualified_pusher<std::tuple<Args...>> { template <std::size_t... I, typename T> static int push(std::index_sequence<I...>, lua_State* L, T&& t) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, static_cast<int>(sizeof...(I)), detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow int pushcount = 0; @@ -14512,30 +15937,41 @@ namespace sol { namespace stack { } }; + template <typename T> + struct unqualified_pusher<forward_as_value_t<T>> { + static int push(lua_State* L, const forward_as_value_t<T>& value_) { + return stack::push<T>(L, value_.value()); + } + + static int push(lua_State* L, forward_as_value_t<T>&& value_) { + return stack::push<T>(L, std::move(value_).value()); + } + }; + template <> struct unqualified_pusher<nullopt_t> { - static int push(lua_State* L, nullopt_t) { + static int push(lua_State* L, nullopt_t) noexcept { return stack::push(L, lua_nil); } }; template <> struct unqualified_pusher<std::nullptr_t> { - static int push(lua_State* L, std::nullptr_t) { + static int push(lua_State* L, std::nullptr_t) noexcept { return stack::push(L, lua_nil); } }; template <> struct unqualified_pusher<this_state> { - static int push(lua_State*, const this_state&) { + static int push(lua_State*, const this_state&) noexcept { return 0; } }; template <> struct unqualified_pusher<this_main_state> { - static int push(lua_State*, const this_main_state&) { + static int push(lua_State*, const this_main_state&) noexcept { return 0; } }; @@ -14567,13 +16003,13 @@ namespace sol { namespace stack { } }; -#if SOL_IS_ON(SOL_STD_VARIANT_I_) +#if SOL_IS_ON(SOL_STD_VARIANT) namespace stack_detail { struct push_function { lua_State* L; - push_function(lua_State* L) : L(L) { + push_function(lua_State* L_) noexcept : L(L_) { } template <typename T> @@ -14605,8 +16041,7 @@ namespace sol { namespace stack { #include <utility> #include <tuple> -namespace sol { -namespace stack { +namespace sol { namespace stack { template <typename T, typename> struct popper { inline static decltype(auto) pop(lua_State* L) { @@ -14616,29 +16051,57 @@ namespace stack { "scope!"); } else { - record tracking{}; + record tracking {}; decltype(auto) r = get<T>(L, -lua_size<T>::value, tracking); lua_pop(L, tracking.used); return r; } } }; -} -} // namespace sol::stack +}} // namespace sol::stack // end of sol/stack_pop.hpp // beginning of sol/stack_field.hpp namespace sol { namespace stack { + + namespace stack_detail { + template <typename T, bool global, bool raw> + inline constexpr bool is_get_direct_tableless_v = (global && !raw && meta::is_c_str_or_string_v<T>); + + template <typename T, bool global, bool raw> + inline constexpr bool is_get_direct_v = (is_get_direct_tableless_v<T, global, raw>) // cf-hack + || (!global && !raw && (meta::is_c_str_or_string_v<T> || meta::is_string_of_v<T, char>)) // cf-hack + || (!global && raw && (std::is_integral_v<T> && !std::is_same_v<T, bool>)) +#if SOL_LUA_VERSION_I_ >= 503 + || (!global && !raw && (std::is_integral_v<T> && !std::is_same_v<T, bool>)) +#endif // integer keys 5.3 or better +#if SOL_LUA_VERSION_I_ >= 502 + || (!global && raw && std::is_pointer_v<T> && std::is_void_v<std::remove_pointer_t<T>>) +#endif // void pointer keys 5.2 or better + ; + + template <typename T, bool global, bool raw> + inline constexpr bool is_set_direct_tableless_v = (global && !raw && meta::is_c_str_or_string_v<T>); + + template <typename T, bool global, bool raw> + inline constexpr bool is_set_direct_v = (is_set_direct_tableless_v<T, global, raw>) // cf-hack + || (!global && !raw && (meta::is_c_str_or_string_v<T> || meta::is_string_of_v<T, char>)) // cf-hack + || (!global && raw && (std::is_integral_v<T> && !std::is_same_v<T, bool>)) // cf-hack +#if SOL_LUA_VERSION_I_ >= 503 + || (!global && !raw && (std::is_integral_v<T> && !std::is_same_v<T, bool>)) +#endif // integer keys 5.3 or better +#if SOL_LUA_VERSION_I_ >= 502 + || (!global && raw && (std::is_pointer_v<T> && std::is_void_v<std::remove_pointer_t<T>>)) +#endif // void pointer keys 5.2 or better + ; + } // namespace stack_detail + template <typename T, bool global, bool raw, typename> struct field_getter { - static constexpr int default_table_index = meta::conditional_t < meta::is_c_str_v<T> -#if SOL_LUA_VESION_I_ >= 503 - || (std::is_integral_v<T> && !std::is_same_v<T, bool>) -#endif // integer global keys 5.3 or better - || (raw && std::is_void_v<std::remove_pointer_t<T>>), - std::integral_constant<int, -1>, std::integral_constant<int, -2> > ::value; + static inline constexpr int default_table_index + = meta::conditional_t<stack_detail::is_get_direct_v<T, global, raw>, std::integral_constant<int, -1>, std::integral_constant<int, -2>>::value; template <typename Key> void get(lua_State* L, Key&& key, int tableindex = default_table_index) { @@ -14649,7 +16112,7 @@ namespace sol { namespace stack { } else if constexpr (std::is_same_v<T, env_key_t>) { (void)key; -#if SOL_LUA_VESION_I_ < 502 +#if SOL_LUA_VERSION_I_ < 502 // Use lua_setfenv lua_getfenv(L, tableindex); #else @@ -14668,8 +16131,8 @@ namespace sol { namespace stack { if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) { lua_rawgeti(L, tableindex, static_cast<lua_Integer>(key)); } -#if SOL_LUA_VESION_I_ >= 502 - else if constexpr (std::is_void_v<std::remove_pointer_t<T>>) { +#if SOL_LUA_VERSION_I_ >= 502 + else if constexpr (std::is_pointer_v<T> && std::is_void_v<std::remove_pointer_t<T>>) { lua_rawgetp(L, tableindex, key); } #endif // Lua 5.2.x+ @@ -14679,7 +16142,7 @@ namespace sol { namespace stack { } } else { - if constexpr (meta::is_c_str_v<T>) { + if constexpr (meta::is_c_str_or_string_v<T>) { if constexpr (global) { (void)tableindex; lua_getglobal(L, &key[0]); @@ -14688,7 +16151,11 @@ namespace sol { namespace stack { lua_getfield(L, tableindex, &key[0]); } } -#if SOL_LUA_VESION_I_ >= 503 + else if constexpr (std::is_same_v<T, meta_function>) { + const auto& real_key = to_string(key); + lua_getfield(L, tableindex, &real_key[0]); + } +#if SOL_LUA_VERSION_I_ >= 503 else if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) { lua_geti(L, tableindex, static_cast<lua_Integer>(key)); } @@ -14747,9 +16214,7 @@ namespace sol { namespace stack { template <typename T, bool global, bool raw, typename> struct field_setter { static constexpr int default_table_index - = meta::conditional_t < (meta::is_c_str_v<T> || meta::is_string_of_v<T, char>) || (std::is_integral_v<T> && !std::is_same_v<T, bool>) - || (std::is_integral_v<T> && !std::is_same_v<T, bool>) || (raw && std::is_void_v<std::remove_pointer_t<T>>), - std::integral_constant<int, -2>, std::integral_constant<int, -3> > ::value; + = meta::conditional_t<stack_detail::is_set_direct_v<T, global, raw>, std::integral_constant<int, -2>, std::integral_constant<int, -3>>::value; template <typename Key, typename Value> void set(lua_State* L, Key&& key, Value&& value, int tableindex = default_table_index) { @@ -14769,8 +16234,8 @@ namespace sol { namespace stack { push(L, std::forward<Value>(value)); lua_rawseti(L, tableindex, static_cast<lua_Integer>(key)); } -#if SOL_LUA_VESION_I_ >= 502 - else if constexpr (std::is_void_v<std::remove_pointer_t<T>>) { +#if SOL_LUA_VERSION_I_ >= 502 + else if constexpr (std::is_pointer_v<T> && std::is_void_v<std::remove_pointer_t<T>>) { push(L, std::forward<Value>(value)); lua_rawsetp(L, tableindex, std::forward<Key>(key)); } @@ -14782,7 +16247,7 @@ namespace sol { namespace stack { } } else { - if constexpr (meta::is_c_str_v<T> || meta::is_string_of_v<T, char>) { + if constexpr (meta::is_c_str_or_string_v<T>) { if constexpr (global) { push(L, std::forward<Value>(value)); lua_setglobal(L, &key[0]); @@ -14793,7 +16258,7 @@ namespace sol { namespace stack { lua_setfield(L, tableindex, &key[0]); } } -#if SOL_LUA_VESION_I_ >= 503 +#if SOL_LUA_VERSION_I_ >= 503 else if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) { push(L, std::forward<Value>(value)); lua_seti(L, tableindex, static_cast<lua_Integer>(key)); @@ -14850,13 +16315,12 @@ namespace sol { namespace stack { // beginning of sol/stack_probe.hpp -namespace sol { -namespace stack { +namespace sol { namespace stack { template <typename T, typename P, bool b, bool raw, typename> struct probe_field_getter { template <typename Key> probe get(lua_State* L, Key&& key, int tableindex = -2) { - if constexpr(!b) { + if constexpr (!b) { if (!maybe_indexable(L, tableindex)) { return probe(false, 0); } @@ -14886,7 +16350,7 @@ namespace stack { struct probe_field_getter<std::tuple<Args...>, P, b, raw, C> { template <std::size_t I, typename Keys> probe apply(std::index_sequence<I>, int sofar, lua_State* L, Keys&& keys, int tableindex) { - get_field<(I<1) && b, raw>(L, std::get<I>(keys), tableindex); + get_field<(I < 1) && b, raw>(L, std::get<I>(keys), tableindex); return probe(check<P>(L), sofar); } @@ -14912,8 +16376,7 @@ namespace stack { } } }; -} -} // namespace sol::stack +}} // namespace sol::stack // end of sol/stack_probe.hpp @@ -15023,46 +16486,80 @@ namespace sol { return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index); } - template <typename Fx, typename... Args> - static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, record&, Fx&& fx, Args&&... args) { + template <bool checked, typename Handler, typename Fx, typename... Args> + static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, Handler&&, record&, Fx&& fx, Args&&... args) { return std::forward<Fx>(fx)(std::forward<Args>(args)...); } - template <typename Fx, typename Arg, typename... Args, std::size_t I, std::size_t... Is, typename... FxArgs> - static decltype(auto) eval( - types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L, int start, record& tracking, Fx&& fx, FxArgs&&... fxargs) { - return eval(types<Args...>(), - std::index_sequence<Is...>(), - L, - start, - tracking, - std::forward<Fx>(fx), - std::forward<FxArgs>(fxargs)..., - stack_detail::unchecked_get<Arg>(L, start + tracking.used, tracking)); + template <bool checked, typename Arg, typename... Args, std::size_t I, std::size_t... Is, typename Handler, typename Fx, typename... FxArgs> + static decltype(auto) eval(types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L_, int start_index_, Handler&& handler_, + record& tracking_, Fx&& fx_, FxArgs&&... fxargs_) { +#if SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS) + // We can save performance/time by letting errors unwind produced arguments + // rather than checking everything once, and then potentially re-doing work + if constexpr (checked) { + return eval<checked>(types<Args...>(), + std::index_sequence<Is...>(), + L_, + start_index_, + std::forward<Handler>(handler_), + tracking_, + std::forward<Fx>(fx_), + std::forward<FxArgs>(fxargs_)..., + *stack_detail::check_get_arg<Arg>(L_, start_index_ + tracking_.used, handler_, tracking_)); + } + else +#endif + { + return eval<checked>(types<Args...>(), + std::index_sequence<Is...>(), + L_, + start_index_, + std::forward<Handler>(handler_), + tracking_, + std::forward<Fx>(fx_), + std::forward<FxArgs>(fxargs_)..., + stack_detail::unchecked_get_arg<Arg>(L_, start_index_ + tracking_.used, tracking_)); + } } template <bool checkargs = detail::default_safe_function_calls, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs> - inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { - static_assert(meta::all<meta::is_not_move_only<Args>...>::value, + inline decltype(auto) call(types<R>, types<Args...> argument_types_, std::index_sequence<I...> argument_indices_, lua_State* L_, + int start_index_, Fx&& fx_, FxArgs&&... args_) { + static_assert(meta::all_v<meta::is_not_move_only<Args>...>, "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."); + argument_handler<types<R, Args...>> handler {}; + record tracking {}; +#if SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS) if constexpr (checkargs) { - argument_handler<types<R, Args...>> handler {}; - multi_check<Args...>(L, start, handler); + multi_check<Args...>(L_, start_index_, handler); } - record tracking {}; +#endif if constexpr (std::is_void_v<R>) { - eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); + eval<checkargs>( + argument_types_, argument_indices_, L_, start_index_, handler, tracking, std::forward<Fx>(fx_), std::forward<FxArgs>(args_)...); } else { - return eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); + return eval<checkargs>( + argument_types_, argument_indices_, L_, start_index_, handler, tracking, std::forward<Fx>(fx_), std::forward<FxArgs>(args_)...); } } + + template <typename T> + void raw_table_set(lua_State* L, T&& arg, int tableindex = -2) { + int push_count = push(L, std::forward<T>(arg)); + sol_c_assert(push_count == 1); + std::size_t unique_index = static_cast<std::size_t>(luaL_len(L, tableindex) + 1u); + lua_rawseti(L, tableindex, unique_index); + } + } // namespace stack_detail template <typename T> int set_ref(lua_State* L, T&& arg, int tableindex = -2) { - push(L, std::forward<T>(arg)); + int push_count = push(L, std::forward<T>(arg)); + sol_c_assert(push_count == 1); return luaL_ref(L, tableindex); } @@ -15177,11 +16674,11 @@ namespace sol { } inline void luajit_exception_handler(lua_State* L, int (*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) { -#if SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_) +#if SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE) if (L == nullptr) { return; } -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushlightuserdata(L, (void*)handler); @@ -15194,7 +16691,7 @@ namespace sol { } inline void luajit_exception_off(lua_State* L) { -#if SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_) +#if SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE) if (L == nullptr) { return; } @@ -15266,7 +16763,7 @@ namespace sol { class basic_object_base : public ref_t { private: using base_t = ref_t; - + template <typename T> decltype(auto) as_stack(std::true_type) const { return stack::get<T>(base_t::lua_state(), base_t::stack_index()); @@ -15280,7 +16777,7 @@ namespace sol { template <typename T> bool is_stack(std::true_type) const { - return stack::check<T>(base_t::lua_state(), base_t::stack_index(), no_panic); + return stack::check<T>(base_t::lua_state(), base_t::stack_index(), &no_panic); } template <typename T> @@ -15291,7 +16788,7 @@ namespace sol { if (r == LUA_NOREF) return false; auto pp = stack::push_pop(*this); - return stack::check<T>(base_t::lua_state(), -1, no_panic); + return stack::check<T>(base_t::lua_state(), -1, &no_panic); } public: @@ -15301,8 +16798,7 @@ namespace sol { basic_object_base& operator=(const basic_object_base&) = default; basic_object_base& operator=(basic_object_base&&) = default; template <typename T, typename... Args, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object_base>>> = meta::enabler> - basic_object_base(T&& arg, Args&&... args) - : base_t(std::forward<T>(arg), std::forward<Args>(args)...) { + basic_object_base(T&& arg, Args&&... args) : base_t(std::forward<T>(arg), std::forward<Args>(args)...) { } template <typename T> @@ -15327,21 +16823,18 @@ namespace sol { typedef basic_object_base<base_type> base_t; template <bool invert_and_pop = false> - basic_object(std::integral_constant<bool, invert_and_pop>, lua_State* L, int index = -1) noexcept - : base_t(L, index) { + basic_object(std::integral_constant<bool, invert_and_pop>, lua_State* L_, int index_ = -1) noexcept : base_t(L_, index_) { if (invert_and_pop) { - lua_pop(L, -index); + lua_pop(L_, -index_); } } protected: basic_object(detail::no_safety_tag, lua_nil_t n) : base_t(n) { } - basic_object(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) { - } - basic_object(lua_State* L, detail::global_tag t) : base_t(L, t) { + basic_object(detail::no_safety_tag, lua_State* L_, int index_) : base_t(L_, index_) { } - basic_object(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) { + basic_object(detail::no_safety_tag, lua_State* L_, ref_index index_) : base_t(L_, index_) { } template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_type, stack_reference>>, @@ -15350,60 +16843,52 @@ namespace sol { } template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_object(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward<T>(r)) { + basic_object(detail::no_safety_tag, lua_State* L_, T&& r) noexcept : base_t(L_, std::forward<T>(r)) { } public: basic_object() noexcept = default; - template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_type, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_object(T&& r) - : base_t(std::forward<T>(r)) { + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_type, stack_reference>>, + is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_object(T&& r) : base_t(std::forward<T>(r)) { } template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_object(lua_State* L, T&& r) - : base_t(L, std::forward<T>(r)) { + basic_object(lua_State* L_, T&& r) : base_t(L_, std::forward<T>(r)) { + } + basic_object(lua_State* L_, global_tag_t t) : base_t(L_, t) { } - basic_object(lua_nil_t r) - : base_t(r) { + basic_object(lua_nil_t r) : base_t(r) { } basic_object(const basic_object&) = default; basic_object(basic_object&&) = default; - basic_object(const stack_reference& r) noexcept - : basic_object(r.lua_state(), r.stack_index()) { + basic_object(const stack_reference& r) noexcept : basic_object(r.lua_state(), r.stack_index()) { } - basic_object(stack_reference&& r) noexcept - : basic_object(r.lua_state(), r.stack_index()) { + basic_object(stack_reference&& r) noexcept : basic_object(r.lua_state(), r.stack_index()) { } template <typename Super> - basic_object(const proxy_base<Super>& r) noexcept - : basic_object(r.operator basic_object()) { + basic_object(const proxy_base<Super>& r) noexcept : basic_object(r.operator basic_object()) { } template <typename Super> - basic_object(proxy_base<Super>&& r) noexcept - : basic_object(r.operator basic_object()) { + basic_object(proxy_base<Super>&& r) noexcept : basic_object(r.operator basic_object()) { } - basic_object(lua_State* L, lua_nil_t r) noexcept - : base_t(L, r) { + basic_object(lua_State* L_, lua_nil_t r) noexcept : base_t(L_, r) { } - basic_object(lua_State* L, int index = -1) noexcept - : base_t(L, index) { + basic_object(lua_State* L_, int index_ = -1) noexcept : base_t(L_, index_) { } - basic_object(lua_State* L, absolute_index index) noexcept - : base_t(L, index) { + basic_object(lua_State* L_, absolute_index index_) noexcept : base_t(L_, index_) { } - basic_object(lua_State* L, raw_index index) noexcept - : base_t(L, index) { + basic_object(lua_State* L_, raw_index index_) noexcept : base_t(L_, index_) { } - basic_object(lua_State* L, ref_index index) noexcept - : base_t(L, index) { + basic_object(lua_State* L_, ref_index index_) noexcept : base_t(L_, index_) { } template <typename T, typename... Args> - basic_object(lua_State* L, in_place_type_t<T>, Args&&... args) noexcept - : basic_object(std::integral_constant<bool, !is_stack_based<base_t>::value>(), L, -stack::push<T>(L, std::forward<Args>(args)...)) { + basic_object(lua_State* L_, in_place_type_t<T>, Args&&... args) noexcept + : basic_object(std::integral_constant<bool, !is_stack_based<base_t>::value>(), L_, -stack::push<T>(L_, std::forward<Args>(args)...)) { } template <typename T, typename... Args> - basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept - : basic_object(L, in_place_type<T>, std::forward<T>(arg), std::forward<Args>(args)...) { + basic_object(lua_State* L_, in_place_t, T&& arg, Args&&... args) noexcept + : basic_object(L_, in_place_type<T>, std::forward<T>(arg), std::forward<Args>(args)...) { } basic_object& operator=(const basic_object&) = default; basic_object& operator=(basic_object&&) = default; @@ -15428,23 +16913,23 @@ namespace sol { }; template <typename T> - object make_object(lua_State* L, T&& value) { - return make_reference<object, true>(L, std::forward<T>(value)); + object make_object(lua_State* L_, T&& value) { + return make_reference<object, true>(L_, std::forward<T>(value)); } template <typename T, typename... Args> - object make_object(lua_State* L, Args&&... args) { - return make_reference<T, object, true>(L, std::forward<Args>(args)...); + object make_object(lua_State* L_, Args&&... args) { + return make_reference<T, object, true>(L_, std::forward<Args>(args)...); } template <typename T> - object make_object_userdata(lua_State* L, T&& value) { - return make_reference_userdata<object, true>(L, std::forward<T>(value)); + object make_object_userdata(lua_State* L_, T&& value) { + return make_reference_userdata<object, true>(L_, std::forward<T>(value)); } template <typename T, typename... Args> - object make_object_userdata(lua_State* L, Args&&... args) { - return make_reference_userdata<T, object, true>(L, std::forward<Args>(args)...); + object make_object_userdata(lua_State* L_, Args&&... args) { + return make_reference_userdata<T, object, true>(L_, std::forward<Args>(args)...); } } // namespace sol @@ -15461,7 +16946,7 @@ namespace sol { // beginning of sol/proxy_base.hpp namespace sol { - struct proxy_base_tag {}; + struct proxy_base_tag { }; namespace detail { template <typename T> @@ -15470,7 +16955,12 @@ namespace sol { } template <typename Super> - struct proxy_base : proxy_base_tag { + struct proxy_base : public proxy_base_tag { + lua_State* lua_state() const { + const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); + return super.lua_state(); + } + operator std::string() const { const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); return super.template get<std::string>(); @@ -15482,17 +16972,14 @@ namespace sol { return super.template get<T>(); } - template <typename T, meta::enable<meta::neg<meta::is_string_constructible<T>>, meta::neg<is_proxy_primitive<meta::unqualified_t<T>>>> = meta::enabler> + template <typename T, + meta::enable<meta::neg<meta::is_string_constructible<T>>, meta::neg<is_proxy_primitive<meta::unqualified_t<T>>>> = meta::enabler> operator T&() const { const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); return super.template get<T&>(); } - - lua_State* lua_state() const { - const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); - return super.lua_state(); - } }; + } // namespace sol // end of sol/proxy_base.hpp @@ -15515,14 +17002,11 @@ namespace sol { int stacktop; proxy_t sp; - stack_iterator() - : L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()), sp() { + stack_iterator() : L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()), sp() { } - stack_iterator(const stack_iterator<proxy_t, true>& r) - : L(r.L), index(r.index), stacktop(r.stacktop), sp(r.sp) { + stack_iterator(const stack_iterator<proxy_t, true>& r) : L(r.L), index(r.index), stacktop(r.stacktop), sp(r.sp) { } - stack_iterator(lua_State* luastate, int idx, int topidx) - : L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) { + stack_iterator(lua_State* luastate, int idx, int topidx) : L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) { } reference operator*() { @@ -15621,7 +17105,8 @@ namespace sol { }; template <typename proxy_t, bool is_const> - inline stack_iterator<proxy_t, is_const> operator+(typename stack_iterator<proxy_t, is_const>::difference_type n, const stack_iterator<proxy_t, is_const>& r) { + inline stack_iterator<proxy_t, is_const> operator+( + typename stack_iterator<proxy_t, is_const>::difference_type n, const stack_iterator<proxy_t, is_const>& r) { return r + n; } } // namespace sol @@ -15635,25 +17120,23 @@ namespace sol { namespace sol { struct stack_proxy_base : public proxy_base<stack_proxy_base> { private: - lua_State* L; - int index; + lua_State* m_L; + int m_index; public: - stack_proxy_base() - : L(nullptr), index(0) { + stack_proxy_base() : m_L(nullptr), m_index(0) { } - stack_proxy_base(lua_State* L, int index) - : L(L), index(index) { + stack_proxy_base(lua_State* L_, int index_) : m_L(L_), m_index(index_) { } template <typename T> decltype(auto) get() const { - return stack::get<T>(L, stack_index()); + return stack::get<T>(m_L, stack_index()); } template <typename T> bool is() const { - return stack::check<T>(L, stack_index()); + return stack::check<T>(m_L, stack_index()); } template <typename T> @@ -15666,34 +17149,34 @@ namespace sol { } int push() const { - return push(L); + return push(m_L); } - int push(lua_State* Ls) const { - lua_pushvalue(Ls, index); + int push(lua_State* L_) const { + lua_pushvalue(L_, m_index); return 1; } lua_State* lua_state() const { - return L; + return m_L; } int stack_index() const { - return index; + return m_index; } }; namespace stack { template <> struct unqualified_getter<stack_proxy_base> { - static stack_proxy_base get(lua_State* L, int index = -1) { - return stack_proxy_base(L, index); + static stack_proxy_base get(lua_State* L_, int index_ = -1) { + return stack_proxy_base(L_, index_); } }; template <> struct unqualified_pusher<stack_proxy_base> { - static int push(lua_State*, const stack_proxy_base& ref) { - return ref.push(); + static int push(lua_State*, const stack_proxy_base& proxy_reference) { + return proxy_reference.push(); } }; } // namespace stack @@ -15761,7 +17244,7 @@ namespace sol { typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - protected_function_result() noexcept = default; + protected_function_result() noexcept : protected_function_result(nullptr) {} protected_function_result(lua_State* Ls, int idx = -1, int retnum = 0, int popped = 0, call_status pferr = call_status::ok) noexcept : L(Ls), index(idx), returncount(retnum), popcount(popped), err(pferr) { } @@ -15806,6 +17289,11 @@ namespace sol { return status() == call_status::ok || status() == call_status::yielded; } +#if SOL_IS_ON(SOL_COMPILER_GCC) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + template <typename T> decltype(auto) get(int index_offset = 0) const { using UT = meta::unqualified_t<T>; @@ -15827,7 +17315,7 @@ namespace sol { } else { if constexpr (std::is_same_v<T, error>) { -#if SOL_IS_ON(SOL_SAFE_PROXIES_I_) +#if SOL_IS_ON(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)"); @@ -15836,7 +17324,7 @@ namespace sol { return error(detail::direct_error, stack::get<std::string>(L, target)); } else { -#if SOL_IS_ON(SOL_SAFE_PROXIES_I_) +#if SOL_IS_ON(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)"); @@ -15847,6 +17335,10 @@ namespace sol { } } +#if SOL_IS_ON(SOL_COMPILER_GCC) +#pragma GCC diagnostic pop +#endif + type get_type(int index_offset = 0) const noexcept { return type_of(L, index + static_cast<int>(index_offset)); } @@ -15913,6 +17405,8 @@ namespace sol { err = call_status::runtime; } ~protected_function_result() { + if (L == nullptr) + return; stack::remove(L, index, popcount); } }; @@ -15921,7 +17415,7 @@ namespace sol { template <> struct unqualified_pusher<protected_function_result> { static int push(lua_State* L, const protected_function_result& pfr) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, static_cast<int>(pfr.pop_count()), detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow int p = 0; @@ -15959,7 +17453,7 @@ namespace sol { typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - unsafe_function_result() noexcept = default; + unsafe_function_result() noexcept : unsafe_function_result(nullptr) {} unsafe_function_result(lua_State* Ls, int idx = -1, int retnum = 0) noexcept : L(Ls), index(idx), returncount(retnum) { } @@ -16066,7 +17560,9 @@ namespace sol { returncount = 0; } ~unsafe_function_result() { - lua_pop(L, returncount); + if (L != nullptr) { + lua_pop(L, returncount); + } } }; @@ -16093,13 +17589,13 @@ namespace sol { namespace detail { template <> - struct is_speshul<unsafe_function_result> : std::true_type {}; + struct is_speshul<unsafe_function_result> : std::true_type { }; template <> - struct is_speshul<protected_function_result> : std::true_type {}; + struct is_speshul<protected_function_result> : std::true_type { }; template <std::size_t I, typename... Args, typename T> stack_proxy get(types<Args...>, meta::index_value<0>, meta::index_value<I>, const T& fr) { - return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I)); + return stack_proxy(fr.lua_state(), fr.stack_index() + static_cast<int>(I)); } template <std::size_t I, std::size_t N, typename Arg, typename... Args, typename T, meta::enable<meta::boolean<(N > 0)>> = meta::enabler> @@ -16109,14 +17605,14 @@ namespace sol { } // namespace detail template <> - struct tie_size<unsafe_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {}; + struct tie_size<unsafe_function_result> : std::integral_constant<std::size_t, SIZE_MAX> { }; template <> - struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {}; + struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> { }; template <std::size_t I> stack_proxy get(const unsafe_function_result& fr) { - return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I)); + return stack_proxy(fr.lua_state(), fr.stack_index() + static_cast<int>(I)); } template <std::size_t I, typename... Args> @@ -16126,7 +17622,7 @@ namespace sol { template <std::size_t I> stack_proxy get(const protected_function_result& fr) { - return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I)); + return stack_proxy(fr.lua_state(), fr.stack_index() + static_cast<int>(I)); } template <std::size_t I, typename... Args> @@ -16295,99 +17791,100 @@ namespace sol { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...)> : public member_function_wrapper<R (O::*)(Args...), R, O, Args...> {}; + struct wrapper<R (O::*)(Args...)> : public member_function_wrapper<R (O::*)(Args...), R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const> : public member_function_wrapper<R (O::*)(Args...) const, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const> : public member_function_wrapper<R (O::*)(Args...) const, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const volatile> : public member_function_wrapper<R (O::*)(Args...) const volatile, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const volatile> : public member_function_wrapper<R (O::*)(Args...) const volatile, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...)&> : public member_function_wrapper<R (O::*)(Args...)&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...)&> : public member_function_wrapper<R (O::*)(Args...)&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const&> : public member_function_wrapper<R (O::*)(Args...) const&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const&> : public member_function_wrapper<R (O::*)(Args...) const&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const volatile&> : public member_function_wrapper<R (O::*)(Args...) const volatile&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const volatile&> : public member_function_wrapper<R (O::*)(Args...) const volatile&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args..., ...)&> : public member_function_wrapper<R (O::*)(Args..., ...)&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args..., ...)&> : public member_function_wrapper<R (O::*)(Args..., ...)&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args..., ...) const&> : public member_function_wrapper<R (O::*)(Args..., ...) const&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args..., ...) const&> : public member_function_wrapper<R (O::*)(Args..., ...) const&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args..., ...) const volatile&> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args..., ...) const volatile&> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) &&> : public member_function_wrapper<R (O::*)(Args...)&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) &&> : public member_function_wrapper<R (O::*)(Args...)&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const&&> : public member_function_wrapper<R (O::*)(Args...) const&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const&&> : public member_function_wrapper<R (O::*)(Args...) const&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const volatile&&> : public member_function_wrapper<R (O::*)(Args...) const volatile&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const volatile&&> : public member_function_wrapper<R (O::*)(Args...) const volatile&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args..., ...) &&> : public member_function_wrapper<R (O::*)(Args..., ...)&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args..., ...) &&> : public member_function_wrapper<R (O::*)(Args..., ...)&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args..., ...) const&&> : public member_function_wrapper<R (O::*)(Args..., ...) const&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args..., ...) const&&> : public member_function_wrapper<R (O::*)(Args..., ...) const&, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args..., ...) const volatile&&> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile&, R, O, Args...> {}; + struct wrapper<R (O::*)(Args..., ...) const volatile&&> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile&, R, O, Args...> { }; -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) // noexcept has become a part of a function's type template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) noexcept> : public member_function_wrapper<R (O::*)(Args...) noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) noexcept> : public member_function_wrapper<R (O::*)(Args...) noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const noexcept> : public member_function_wrapper<R (O::*)(Args...) const noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const noexcept> : public member_function_wrapper<R (O::*)(Args...) const noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const volatile noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const volatile noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) & noexcept> : public member_function_wrapper<R (O::*)(Args...) & noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...)& noexcept> : public member_function_wrapper<R (O::*)(Args...)& noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const& noexcept> : public member_function_wrapper<R (O::*)(Args...) const& noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const& noexcept> : public member_function_wrapper<R (O::*)(Args...) const& noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const volatile& noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile& noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const volatile& noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile& noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args..., ...) & noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) & noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args..., ...)& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...)& noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args..., ...) const& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const& noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args..., ...) const& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const& noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> struct wrapper<R (O::*)(Args..., ...) const volatile& noexcept> - : public member_function_wrapper<R (O::*)(Args..., ...) const volatile& noexcept, R, O, Args...> {}; + : public member_function_wrapper<R (O::*)(Args..., ...) const volatile& noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) && noexcept> : public member_function_wrapper<R (O::*)(Args...) & noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...)&& noexcept> : public member_function_wrapper<R (O::*)(Args...)& noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const&& noexcept> : public member_function_wrapper<R (O::*)(Args...) const& noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const&& noexcept> : public member_function_wrapper<R (O::*)(Args...) const& noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args...) const volatile&& noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile& noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args...) const volatile&& noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile& noexcept, R, O, Args...> { + }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args..., ...) && noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) & noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args..., ...)&& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...)& noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> - struct wrapper<R (O::*)(Args..., ...) const&& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const& noexcept, R, O, Args...> {}; + struct wrapper<R (O::*)(Args..., ...) const&& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const& noexcept, R, O, Args...> { }; template <typename R, typename O, typename... Args> struct wrapper<R (O::*)(Args..., ...) const volatile&& noexcept> - : public member_function_wrapper<R (O::*)(Args..., ...) const volatile& noexcept, R, O, Args...> {}; + : public member_function_wrapper<R (O::*)(Args..., ...) const volatile& noexcept, R, O, Args...> { }; #endif // noexcept is part of a function's type @@ -16397,8 +17894,7 @@ namespace sol { #include <memory> -namespace sol { -namespace function_detail { +namespace sol { namespace function_detail { template <typename Fx, int start = 1, bool is_yielding = false> int call(lua_State* L) { Fx& fx = stack::get<user<Fx>>(L, upvalue_index(start)); @@ -16410,8 +17906,7 @@ namespace function_detail { return nr; } } -} -} // namespace sol::function_detail +}} // namespace sol::function_detail // end of sol/function_types_core.hpp @@ -16426,8 +17921,8 @@ namespace function_detail { namespace sol { namespace detail { - struct no_prop {}; - } + struct no_prop { }; + } // namespace detail template <typename R, typename W> struct property_wrapper : detail::ebco<R, 0>, detail::ebco<W, 1> { @@ -16437,8 +17932,7 @@ namespace sol { public: template <typename Rx, typename Wx> - property_wrapper(Rx&& r, Wx&& w) - : read_base_t(std::forward<Rx>(r)), write_base_t(std::forward<Wx>(w)) { + property_wrapper(Rx&& r, Wx&& w) : read_base_t(std::forward<Rx>(r)), write_base_t(std::forward<Wx>(w)) { } W& write() { @@ -16530,13 +18024,16 @@ namespace sol { namespace meta { template <typename T> - struct is_member_object : std::is_member_object_pointer<T> {}; + using is_member_object = std::integral_constant<bool, std::is_member_object_pointer_v<T> || is_specialization_of_v<T, readonly_wrapper>>; template <typename T> - struct is_member_object<readonly_wrapper<T>> : std::true_type {}; + inline constexpr bool is_member_object_v = is_member_object<T>::value; template <typename T> - inline constexpr bool is_member_object_v = is_member_object<T>::value; + using is_member_object_or_function = std::integral_constant<bool, is_member_object_v<T> || std::is_member_pointer_v<T>>; + + template <typename T> + inline constexpr bool is_member_object_or_function_v = is_member_object_or_function<T>::value; } // namespace meta } // namespace sol @@ -16554,8 +18051,7 @@ namespace sol { T value; template <typename Arg, typename... Args, meta::disable<std::is_same<protect_t, meta::unqualified_t<Arg>>> = meta::enabler> - protect_t(Arg&& arg, Args&&... args) - : value(std::forward<Arg>(arg), std::forward<Args>(args)...) { + protect_t(Arg&& arg, Args&&... args) : value(std::forward<Arg>(arg), std::forward<Args>(args)...) { } protect_t(const protect_t&) = default; @@ -16593,14 +18089,14 @@ namespace sol { lua_createtable(L, static_cast<int>(sizeof...(In)), 0); stack_reference deps(L, -1); auto per_dep = [&L, &deps](int i) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushvalue(L, i); luaL_ref(L, deps.stack_index()); }; (void)per_dep; - (void)detail::swallow{ int(), (per_dep(In), int())... }; + (void)detail::swallow { int(), (per_dep(In), int())... }; lua_setuservalue(L, ai); } } @@ -16618,7 +18114,7 @@ namespace sol { } lua_createtable(L, static_cast<int>(sdeps.size()), 0); stack_reference deps(L, -1); -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) luaL_checkstack(L, static_cast<int>(sdeps.size()), detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow for (std::size_t i = 0; i < sdeps.size(); ++i) { @@ -16653,7 +18149,7 @@ namespace sol { } template <typename T, typename List> - struct void_call : void_call<T, meta::function_args_t<List>> {}; + struct void_call : void_call<T, meta::function_args_t<List>> { }; template <typename T, typename... Args> struct void_call<T, types<Args...>> { @@ -16664,14 +18160,29 @@ namespace sol { template <typename T, bool checked, bool clean_stack> struct constructor_match { T* obj_; + reference* obj_lua_ref_; + stack::stack_detail::undefined_metatable* p_umf_; - constructor_match(T* o) : obj_(o) { + constructor_match(T* obj_ptr, reference& obj_lua_ref, stack::stack_detail::undefined_metatable& umf) + : obj_(obj_ptr), obj_lua_ref_(&obj_lua_ref), p_umf_(&umf) { } template <typename Fx, std::size_t I, typename... R, typename... Args> int operator()(types<Fx>, meta::index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const { - detail::default_construct func{}; - return stack::call_into_lua<checked, clean_stack>(r, a, L, start, func, obj_); + detail::default_construct func {}; + int result = stack::call_into_lua<checked, clean_stack>(r, a, L, start, func, this->obj_); + // construct userdata table + // SPECIFICALLY, after we've created it successfully. + // If the constructor exits for any reason we have to break things down... + if constexpr (clean_stack) { + obj_lua_ref_->push(); + (*this->p_umf_)(); + obj_lua_ref_->pop(); + } + else { + (*this->p_umf_)(); + } + return result; } }; @@ -16712,8 +18223,8 @@ namespace sol { std::forward<Args>(args)...); } } - stack::record tracking{}; - if (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) { + stack::record tracking {}; + if (!stack::stack_detail::check_types(args_list(), L, start, &no_panic, tracking)) { return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), @@ -16805,8 +18316,8 @@ namespace sol { std::forward<Args>(args)...); } } - stack::record tracking{}; - if (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) { + stack::record tracking {}; + if (!stack::stack_detail::check_types(args_list(), L, start, &no_panic, tracking)) { return overload_match_arity(types<Fx1, Fxs...>(), std::index_sequence<I1, In...>(), std::index_sequence<M...>(), @@ -16856,11 +18367,10 @@ namespace sol { T* obj = detail::usertype_allocate<T>(L); reference userdataref(L, -1); stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>); - umf(); // put userdata at the first index lua_insert(L, 1); - construct_match<T, TypeLists...>(constructor_match<T, checked, clean_stack>(obj), L, argcount, 1 + static_cast<int>(syntax)); + construct_match<T, TypeLists...>(constructor_match<T, checked, clean_stack>(obj, userdataref, umf), L, argcount, 1 + static_cast<int>(syntax)); userdataref.push(); return 1; @@ -16890,11 +18400,10 @@ namespace sol { using wrap = wrapper<uFx>; using traits_type = typename wrap::traits_type; using fp_t = typename traits_type::function_pointer_type; - constexpr bool is_function_pointer_convertible - = std::is_class_v<uFx> && std::is_convertible_v<std::decay_t<Fx>, fp_t>; + constexpr bool is_function_pointer_convertible = std::is_class_v<uFx> && std::is_convertible_v<std::decay_t<Fx>, fp_t>; if constexpr (is_function_pointer_convertible) { fp_t fx = f; - return agnostic_lua_call_wrapper<fp_t, is_index, is_variable, checked, boost, clean_stack>{}.call( + return agnostic_lua_call_wrapper<fp_t, is_index, is_variable, checked, boost, clean_stack> {}.call( L, fx, std::forward<Args>(args)...); } else { @@ -16955,7 +18464,7 @@ namespace sol { } }; -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> struct agnostic_lua_call_wrapper<detail::lua_CFunction_noexcept, is_index, is_variable, checked, boost, clean_stack, C> { static int call(lua_State* L, detail::lua_CFunction_noexcept f) { @@ -16989,7 +18498,7 @@ namespace sol { template <typename T, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> struct agnostic_lua_call_wrapper<std::reference_wrapper<T>, is_index, is_variable, checked, boost, clean_stack, C> { static int call(lua_State* L, std::reference_wrapper<T> f) { - agnostic_lua_call_wrapper<T, is_index, is_variable, checked, boost, clean_stack> alcw{}; + agnostic_lua_call_wrapper<T, is_index, is_variable, checked, boost, clean_stack> alcw {}; return alcw.call(L, f.get()); } }; @@ -17004,8 +18513,11 @@ namespace sol { using object_type = typename wrap::object_type; if constexpr (sizeof...(Args) < 1) { using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>; - static_assert(std::is_base_of_v<object_type, Ta>, "It seems like you might have accidentally bound a class type with a member function method that does not correspond to the class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one class \"T\" but then bind member methods from a complete unrelated class. Check things over!"); -#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_) + static_assert(std::is_base_of_v<object_type, Ta>, + "It seems like you might have accidentally bound a class type with a member function method that does not correspond to the " + "class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one class \"T\" " + "but then bind member methods from a complete unrelated class. Check things over!"); +#if SOL_IS_ON(SOL_SAFE_USERTYPE) auto maybeo = stack::check_get<Ta*>(L, 1); if (!maybeo || maybeo.value() == nullptr) { return luaL_error(L, @@ -17034,8 +18546,11 @@ namespace sol { if constexpr (is_index) { if constexpr (sizeof...(Args) < 1) { using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>; - static_assert(std::is_base_of_v<object_type, Ta>, "It seems like you might have accidentally bound a class type with a member function method that does not correspond to the class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one class \"T\" but then bind member methods from a complete unrelated class. Check things over!"); -#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_) + static_assert(std::is_base_of_v<object_type, Ta>, + "It seems like you might have accidentally bound a class type with a member function method that does not correspond " + "to the class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one " + "class \"T\" but then bind member methods from a complete unrelated class. Check things over!"); +#if SOL_IS_ON(SOL_SAFE_USERTYPE) auto maybeo = stack::check_get<Ta*>(L, 1); if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { @@ -17068,7 +18583,7 @@ namespace sol { constexpr bool ret_is_const = std::is_const_v<std::remove_reference_t<return_type>>; if constexpr (ret_is_const) { (void)fx; - (void)detail::swallow{ 0, (static_cast<void>(args), 0)... }; + (void)detail::swallow { 0, (static_cast<void>(args), 0)... }; return luaL_error(L, "sol: cannot write to a readonly (const) variable"); } else { @@ -17076,7 +18591,7 @@ namespace sol { constexpr bool is_assignable = std::is_copy_assignable_v<u_return_type> || std::is_array_v<u_return_type>; if constexpr (!is_assignable) { (void)fx; - (void)detail::swallow{ 0, ((void)args, 0)... }; + (void)detail::swallow { 0, ((void)args, 0)... }; return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); } else { @@ -17093,7 +18608,7 @@ namespace sol { } else { using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>; -#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_) +#if SOL_IS_ON(SOL_SAFE_USERTYPE) auto maybeo = stack::check_get<Ta*>(L, 1); if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { @@ -17115,7 +18630,7 @@ namespace sol { } } else { - agnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost, clean_stack> alcw{}; + agnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost, clean_stack> alcw {}; return alcw.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...); } } @@ -17185,11 +18700,15 @@ namespace sol { T* obj = detail::usertype_allocate<T>(L); reference userdataref(L, -1); stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>); - umf(); // put userdata at the first index lua_insert(L, 1); - construct_match<T, Args...>(constructor_match<T, checked, clean_stack>(obj), L, argcount, boost + 1 + 1 + static_cast<int>(syntax)); + // Because of the way constructors work, + // we have to kill the data, but only if the cosntructor is successfulyl invoked... + // if it's not successfully invoked and we panic, + // we cannot actually deallcoate/delete the data. + construct_match<T, Args...>( + constructor_match<T, checked, clean_stack>(obj, userdataref, umf), L, argcount, boost + 1 + 1 + static_cast<int>(syntax)); userdataref.push(); return 1; @@ -17233,11 +18752,11 @@ namespace sol { template <typename F> static int call(lua_State* L, F&& f) { if constexpr (std::is_void_v<Fx>) { - return detail::usertype_alloc_destruct<T>(L); + return detail::usertype_alloc_destroy<T>(L); } else { using uFx = meta::unqualified_t<Fx>; - lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw{}; + lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw {}; return lcw.call(L, std::forward<F>(f).fx); } } @@ -17251,7 +18770,7 @@ namespace sol { template <typename Fx, std::size_t I, typename... R, typename... Args> int operator()(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) { auto& f = std::get<I>(fx.functions); - return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost>{}.call(L, f); + return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost> {}.call(L, f); } }; @@ -17268,7 +18787,7 @@ namespace sol { template <typename Fx, std::size_t I, typename... R, typename... Args> int operator()(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) { auto& f = std::get<I>(fx.functions); - return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f); + return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost, clean_stack> {}.call(L, f); } }; @@ -17295,12 +18814,12 @@ namespace sol { if constexpr (is_specialized) { if constexpr (is_index) { decltype(auto) p = f.read(); - lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack> lcw{}; + lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack> lcw {}; return lcw.call(L, p, std::forward<Args>(args)...); } else { decltype(auto) p = f.write(); - lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack> lcw{}; + lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack> lcw {}; return lcw.call(L, p, std::forward<Args>(args)...); } } @@ -17327,7 +18846,7 @@ namespace sol { using args_list = meta::pop_front_type_t<typename traits_type::free_args_list>; using Ta = T; using Oa = std::remove_pointer_t<object_type>; -#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_) +#if SOL_IS_ON(SOL_SAFE_USERTYPE) auto maybeo = stack::check_get<Ta*>(L, 1); if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { @@ -17362,7 +18881,7 @@ namespace sol { template <typename... Args> static int call(lua_State* L, F& fx, Args&&... args) { - return lua_call_wrapper<T, V, is_index, is_variable, true, boost, clean_stack>{}.call(L, fx.value, std::forward<Args>(args)...); + return lua_call_wrapper<T, V, is_index, is_variable, true, boost, clean_stack> {}.call(L, fx.value, std::forward<Args>(args)...); } }; @@ -17372,8 +18891,8 @@ namespace sol { template <std::size_t... In> static int call(std::index_sequence<In...>, lua_State* L, P& fx) { - int pushed = lua_call_wrapper<T, F, is_index, is_variable, checked, boost, false, C>{}.call(L, fx.value); - (void)detail::swallow{ int(), (policy_detail::handle_policy(std::get<In>(fx.policies), L, pushed), int())... }; + int pushed = lua_call_wrapper<T, F, is_index, is_variable, checked, boost, false, C> {}.call(L, fx.value); + (void)detail::swallow { int(), (policy_detail::handle_policy(std::get<In>(fx.policies), L, pushed), int())... }; return pushed; } @@ -17387,19 +18906,24 @@ namespace sol { struct lua_call_wrapper<T, yielding_t<Y>, is_index, is_variable, checked, boost, clean_stack, C> { template <typename F> static int call(lua_State* L, F&& f) { - return lua_call_wrapper<T, meta::unqualified_t<Y>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f.func); + return lua_call_wrapper<T, meta::unqualified_t<Y>, is_index, is_variable, checked, boost, clean_stack> {}.call(L, f.func); } }; template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, clean_stack, C> { static int call(lua_State* L, const function_arguments<Sig, P>& f) { - lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw{}; + lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw {}; + return lcw.call(L, std::get<0>(f.arguments)); + } + + static int call(lua_State* L, function_arguments<Sig, P>& f) { + lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw {}; return lcw.call(L, std::get<0>(f.arguments)); } static int call(lua_State* L, function_arguments<Sig, P>&& f) { - lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw{}; + lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw {}; return lcw.call(L, std::get<0>(std::move(f.arguments))); } }; @@ -17410,11 +18934,11 @@ namespace sol { using uFx = meta::unqualified_t<Fx>; if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) { using real_fx = meta::unqualified_t<decltype(std::forward<Fx>(fx).func)>; - lua_call_wrapper<T, real_fx, is_index, is_variable, checked, boost, clean_stack> lcw{}; + lua_call_wrapper<T, real_fx, is_index, is_variable, checked, boost, clean_stack> lcw {}; return lcw.call(L, std::forward<Fx>(fx).func, std::forward<Args>(args)...); } else { - lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw{}; + lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw {}; return lcw.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...); } } @@ -17434,38 +18958,38 @@ namespace sol { } template <typename T, typename = void> - struct is_var_bind : std::false_type {}; + struct is_var_bind : std::false_type { }; template <typename T> - struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type {}; + struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type { }; template <typename T> - struct is_var_bind<T, std::enable_if_t<is_lua_reference_or_proxy<T>::value>> : std::true_type {}; + struct is_var_bind<T, std::enable_if_t<is_lua_reference_or_proxy<T>::value>> : std::true_type { }; template <> - struct is_var_bind<detail::no_prop> : std::true_type {}; + struct is_var_bind<detail::no_prop> : std::true_type { }; template <typename R, typename W> - struct is_var_bind<property_wrapper<R, W>> : std::true_type {}; + struct is_var_bind<property_wrapper<R, W>> : std::true_type { }; template <typename T> - struct is_var_bind<var_wrapper<T>> : std::true_type {}; + struct is_var_bind<var_wrapper<T>> : std::true_type { }; template <typename T> - struct is_var_bind<readonly_wrapper<T>> : is_var_bind<meta::unqualified_t<T>> {}; + struct is_var_bind<readonly_wrapper<T>> : is_var_bind<meta::unqualified_t<T>> { }; template <typename F, typename... Policies> - struct is_var_bind<policy_wrapper<F, Policies...>> : is_var_bind<meta::unqualified_t<F>> {}; + struct is_var_bind<policy_wrapper<F, Policies...>> : is_var_bind<meta::unqualified_t<F>> { }; } // namespace call_detail template <typename T> - struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> {}; + struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> { }; template <typename T> using is_var_wrapper = meta::is_specialization_of<T, var_wrapper>; template <typename T> - struct is_function_binding : meta::neg<is_variable_binding<T>> {}; + struct is_function_binding : meta::neg<is_variable_binding<T>> { }; } // namespace sol @@ -17566,7 +19090,7 @@ namespace sol { typedef meta::unqualified_t<F> Fu; typedef std::integral_constant<bool, std::is_same<Fu, lua_CFunction>::value -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) || std::is_same<Fu, detail::lua_CFunction_noexcept>::value #endif > @@ -17578,7 +19102,7 @@ namespace sol { struct wrap { typedef F type; - static int call(lua_State* L) { + static int call(lua_State* L) noexcept(noexcept(c_call<type, f>(L))) { return c_call<type, f>(L); } }; @@ -17601,13 +19125,13 @@ namespace sol { // beginning of sol/function_types_stateless.hpp namespace sol { namespace function_detail { - template <typename Function, bool is_yielding> + template <typename Function> struct upvalue_free_function { using function_type = std::remove_pointer_t<std::decay_t<Function>>; using traits_type = meta::bind_traits<function_type>; static int real_call(lua_State* L) -#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#if SOL_IS_ON(SOL_COMPILER_VCXX) // MSVC is broken, what a surprise... #else noexcept(traits_type::is_noexcept) @@ -17618,8 +19142,15 @@ namespace sol { namespace function_detail { return call_detail::call_wrapped<void, true, false>(L, fx); } + template <bool is_yielding, bool no_trampoline> static int call(lua_State* L) { - int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } if (is_yielding) { return lua_yield(L, nr); } @@ -17627,19 +19158,15 @@ namespace sol { namespace function_detail { return nr; } } - - int operator()(lua_State* L) { - return call(L); - } }; - template <typename T, typename Function, bool is_yielding> + template <typename T, typename Function> struct upvalue_member_function { typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef lua_bind_traits<function_type> traits_type; static int real_call(lua_State* L) -#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#if SOL_IS_ON(SOL_COMPILER_VCXX) // MSVC is broken, what a surprise... #else noexcept(traits_type::is_noexcept) @@ -17655,14 +19182,21 @@ namespace sol { namespace function_detail { return call_detail::call_wrapped<T, true, false, -1>(L, memfx, item); } + template <bool is_yielding, bool no_trampoline> static int call(lua_State* L) -#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#if SOL_IS_ON(SOL_COMPILER_VCXX) // MSVC is broken, what a surprise... #else noexcept(traits_type::is_noexcept) #endif { - int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } if (is_yielding) { return lua_yield(L, nr); } @@ -17671,18 +19205,24 @@ namespace sol { namespace function_detail { } } - int operator()(lua_State* L) { + int operator()(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { return call(L); } }; - template <typename T, typename Function, bool is_yielding> + template <typename T, typename Function> struct upvalue_member_variable { typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef lua_bind_traits<function_type> traits_type; static int real_call(lua_State* L) -#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#if SOL_IS_ON(SOL_COMPILER_VCXX) // MSVC is broken, what a surprise... #else noexcept(traits_type::is_noexcept) @@ -17707,14 +19247,21 @@ namespace sol { namespace function_detail { } } + template <bool is_yielding, bool no_trampoline> static int call(lua_State* L) -#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#if SOL_IS_ON(SOL_COMPILER_VCXX) // MSVC is broken, what a surprise... #else noexcept(traits_type::is_noexcept) #endif { - int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } if (is_yielding) { return lua_yield(L, nr); } @@ -17723,18 +19270,24 @@ namespace sol { namespace function_detail { } } - int operator()(lua_State* L) { + int operator()(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { return call(L); } }; - template <typename T, typename Function, bool is_yielding> - struct upvalue_member_variable<T, readonly_wrapper<Function>, is_yielding> { + template <typename T, typename Function> + struct upvalue_member_variable<T, readonly_wrapper<Function>> { typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef lua_bind_traits<function_type> traits_type; static int real_call(lua_State* L) -#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#if SOL_IS_ON(SOL_COMPILER_VCXX) // MSVC is broken, what a surprise... #else noexcept(traits_type::is_noexcept) @@ -17757,14 +19310,21 @@ namespace sol { namespace function_detail { } } + template <bool is_yielding, bool no_trampoline> static int call(lua_State* L) -#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#if SOL_IS_ON(SOL_COMPILER_VCXX) // MSVC is broken, what a surprise... #else noexcept(traits_type::is_noexcept) #endif { - int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } if (is_yielding) { return lua_yield(L, nr); } @@ -17773,18 +19333,24 @@ namespace sol { namespace function_detail { } } - int operator()(lua_State* L) { + int operator()(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { return call(L); } }; - template <typename T, typename Function, bool is_yielding> + template <typename T, typename Function> struct upvalue_this_member_function { typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef lua_bind_traits<function_type> traits_type; static int real_call(lua_State* L) -#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#if SOL_IS_ON(SOL_COMPILER_VCXX) // MSVC is broken, what a surprise... #else noexcept(traits_type::is_noexcept) @@ -17796,14 +19362,21 @@ namespace sol { namespace function_detail { return call_detail::call_wrapped<T, false, false>(L, memfx); } + template <bool is_yielding, bool no_trampoline> static int call(lua_State* L) -#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#if SOL_IS_ON(SOL_COMPILER_VCXX) // MSVC is broken, what a surprise... #else noexcept(traits_type::is_noexcept) #endif { - int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } if (is_yielding) { return lua_yield(L, nr); } @@ -17812,16 +19385,22 @@ namespace sol { namespace function_detail { } } - int operator()(lua_State* L) { + int operator()(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { return call(L); } }; - template <typename T, typename Function, bool is_yielding> + template <typename T, typename Function> struct upvalue_this_member_variable { typedef std::remove_pointer_t<std::decay_t<Function>> function_type; - static int real_call(lua_State* L) noexcept(false) { + static int real_call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { // Layout: // idx 1...n: verbatim data of member variable pointer auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); @@ -17836,8 +19415,15 @@ namespace sol { namespace function_detail { } } - static int call(lua_State* L) { - int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + template <bool is_yielding, bool no_trampoline> + static int call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } if (is_yielding) { return lua_yield(L, nr); } @@ -17846,17 +19432,17 @@ namespace sol { namespace function_detail { } } - int operator()(lua_State* L) { + int operator()(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { return call(L); } }; - template <typename T, typename Function, bool is_yielding> - struct upvalue_this_member_variable<T, readonly_wrapper<Function>, is_yielding> { + template <typename T, typename Function> + struct upvalue_this_member_variable<T, readonly_wrapper<Function>> { typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef lua_bind_traits<function_type> traits_type; - static int real_call(lua_State* L) noexcept(false) { + static int real_call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { // Layout: // idx 1...n: verbatim data of member variable pointer auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); @@ -17869,8 +19455,15 @@ namespace sol { namespace function_detail { } } - static int call(lua_State* L) { - int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + template <bool is_yielding, bool no_trampoline> + static int call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } if (is_yielding) { return lua_yield(L, nr); } @@ -17879,7 +19472,7 @@ namespace sol { namespace function_detail { } } - int operator()(lua_State* L) { + int operator()(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { return call(L); } }; @@ -17889,20 +19482,19 @@ namespace sol { namespace function_detail { // beginning of sol/function_types_stateful.hpp -namespace sol { -namespace function_detail { +namespace sol { namespace function_detail { template <typename Func, bool is_yielding, bool no_trampoline> struct functor_function { typedef std::decay_t<meta::unwrap_unqualified_t<Func>> function_type; - function_type fx; + function_type invocation; template <typename... Args> - functor_function(function_type f, Args&&... args) - : fx(std::move(f), std::forward<Args>(args)...) { + functor_function(function_type f, Args&&... args) noexcept(std::is_nothrow_constructible_v<function_type, function_type, Args...>) + : invocation(std::move(f), std::forward<Args>(args)...) { } - int call(lua_State* L) { - int nr = call_detail::call_wrapped<void, true, false>(L, fx); + static int call(lua_State* L, functor_function& self) noexcept(noexcept(call_detail::call_wrapped<void, true, false>(L, self.invocation))) { + int nr = call_detail::call_wrapped<void, true, false>(L, self.invocation); if (is_yielding) { return lua_yield(L, nr); } @@ -17911,32 +19503,39 @@ namespace function_detail { } } - int operator()(lua_State* L) { - if (!no_trampoline) { - auto f = [&](lua_State*) -> int { return this->call(L); }; - return detail::trampoline(L, f); + int operator()(lua_State* L) noexcept(noexcept(call_detail::call_wrapped<void, true, false>(L, invocation))) { + if constexpr (no_trampoline) { + return call(L, *this); } else { - return call(L); + return detail::trampoline(L, &call, *this); } } }; - template <typename T, typename Function, bool is_yielding> + template <typename T, typename Function, bool is_yielding, bool no_trampoline> struct member_function { typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef meta::function_return_t<function_type> return_type; typedef meta::function_args_t<function_type> args_lists; + using traits_type = meta::bind_traits<function_type>; function_type invocation; T member; template <typename... Args> - member_function(function_type f, Args&&... args) + member_function(function_type f, Args&&... args) noexcept( + std::is_nothrow_constructible_v<function_type, function_type>&& std::is_nothrow_constructible_v<T, Args...>) : invocation(std::move(f)), member(std::forward<Args>(args)...) { } - int call(lua_State* L) { - int nr = call_detail::call_wrapped<T, true, false, -1>(L, invocation, detail::unwrap(detail::deref(member))); + static int call(lua_State* L, member_function& self) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + int nr = call_detail::call_wrapped<T, true, false, -1>(L, self.invocation, detail::unwrap(detail::deref(self.member))); if (is_yielding) { return lua_yield(L, nr); } @@ -17945,13 +19544,23 @@ namespace function_detail { } } - int operator()(lua_State* L) { - auto f = [&](lua_State*) -> int { return this->call(L); }; - return detail::trampoline(L, f); + int operator()(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + if constexpr (no_trampoline) { + return call(L, *this); + } + else { + return detail::trampoline(L, &call, *this); + } } }; - template <typename T, typename Function, bool is_yielding> + template <typename T, typename Function, bool is_yielding, bool no_trampoline> struct member_variable { typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef typename meta::bind_traits<function_type>::return_type return_type; @@ -17961,20 +19570,21 @@ namespace function_detail { typedef std::add_lvalue_reference_t<meta::unwrapped_t<std::remove_reference_t<decltype(detail::deref(member))>>> M; template <typename... Args> - member_variable(function_type v, Args&&... args) + member_variable(function_type v, Args&&... args) noexcept( + std::is_nothrow_constructible_v<function_type, function_type>&& std::is_nothrow_constructible_v<T, Args...>) : var(std::move(v)), member(std::forward<Args>(args)...) { } - int call(lua_State* L) { + static int call(lua_State* L, member_variable& self) noexcept(std::is_nothrow_copy_assignable_v<T>) { int nr; { - M mem = detail::unwrap(detail::deref(member)); + M mem = detail::unwrap(detail::deref(self.member)); switch (lua_gettop(L)) { case 0: - nr = call_detail::call_wrapped<T, true, false, -1>(L, var, mem); + nr = call_detail::call_wrapped<T, true, false, -1>(L, self.var, mem); break; case 1: - nr = call_detail::call_wrapped<T, false, false, -1>(L, var, mem); + nr = call_detail::call_wrapped<T, false, false, -1>(L, self.var, mem); break; default: nr = luaL_error(L, "sol: incorrect number of arguments to member variable function"); @@ -17989,32 +19599,32 @@ namespace function_detail { } } - int operator()(lua_State* L) { - auto f = [&](lua_State*) -> int { return this->call(L); }; - return detail::trampoline(L, f); + int operator()(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { + if constexpr (no_trampoline) { + return call(L, *this); + } + else { + return detail::trampoline(L, &call, *this); + } } }; -} -} // namespace sol::function_detail +}} // namespace sol::function_detail // end of sol/function_types_stateful.hpp // beginning of sol/function_types_overloaded.hpp -namespace sol { -namespace function_detail { +namespace sol { namespace function_detail { template <int start_skew, typename... Functions> struct overloaded_function { typedef std::tuple<Functions...> overload_list; typedef std::make_index_sequence<sizeof...(Functions)> indices; overload_list overloads; - overloaded_function(overload_list set) - : overloads(std::move(set)) { + overloaded_function(overload_list set) : overloads(std::move(set)) { } - overloaded_function(Functions... fxs) - : overloads(fxs...) { + overloaded_function(Functions... fxs) : overloads(fxs...) { } template <typename Fx, std::size_t I, typename... R, typename... Args> @@ -18024,13 +19634,19 @@ namespace function_detail { return nr; } + struct on_success { + template <typename... Args> + int operator()(Args&&... args) const { + return call(std::forward<Args>(args)...); + } + }; + int operator()(lua_State* L) { - auto mfx = [](auto&&... args) { return call(std::forward<decltype(args)>(args)...); }; - return call_detail::overload_match<Functions...>(mfx, L, 1 + start_skew, overloads); + on_success call_obj {}; + return call_detail::overload_match<Functions...>(call_obj, L, 1 + start_skew, overloads); } }; -} -} // namespace sol::function_detail +}} // namespace sol::function_detail // end of sol/function_types_overloaded.hpp @@ -18043,7 +19659,7 @@ namespace sol { namespace detail { template <typename R, typename... Args, typename F, typename = std::invoke_result_t<meta::unqualified_t<F>, Args...>> - inline constexpr auto resolve_i(types<R(Args...)>, F &&) -> R (meta::unqualified_t<F>::*)(Args...) { + inline constexpr auto resolve_i(types<R(Args...)>, F&&) -> R (meta::unqualified_t<F>::*)(Args...) { using Sig = R(Args...); typedef meta::unqualified_t<F> Fu; return static_cast<Sig Fu::*>(&Fu::operator()); @@ -18057,13 +19673,12 @@ namespace sol { template <typename F> inline constexpr void resolve_f(std::false_type, F&&) { - static_assert( - meta::has_deducible_signature<F>::value, "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); + static_assert(meta::call_operator_deducible_v<F>, "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); } template <typename F, typename U = meta::unqualified_t<F>> - inline constexpr auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature<U>(), std::forward<F>(f))) { - return resolve_f(meta::has_deducible_signature<U> {}, std::forward<F>(f)); + inline constexpr auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::call_operator_deducible<U>(), std::forward<F>(f))) { + return resolve_f(meta::call_operator_deducible<U> {}, std::forward<F>(f)); } template <typename... Args, typename F, typename R = std::invoke_result_t<F&, Args...>> @@ -18113,7 +19728,7 @@ namespace sol { namespace detail { template <typename R, typename... Args, typename F, typename = std::invoke_result_t<meta::unqualified_t<F>, Args...>> - inline auto resolve_i(types<R(Args...)>, F &&) -> R (meta::unqualified_t<F>::*)(Args...) { + inline auto resolve_i(types<R(Args...)>, F&&) -> R (meta::unqualified_t<F>::*)(Args...) { using Sig = R(Args...); typedef meta::unqualified_t<F> Fu; return static_cast<Sig Fu::*>(&Fu::operator()); @@ -18127,13 +19742,12 @@ namespace sol { template <typename F> inline void resolve_f(std::false_type, F&&) { - static_assert( - meta::has_deducible_signature<F>::value, "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); + static_assert(meta::call_operator_deducible_v<F>, "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); } template <typename F, typename U = meta::unqualified_t<F>> - inline auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature<U>(), std::forward<F>(f))) { - return resolve_f(meta::has_deducible_signature<U> {}, std::forward<F>(f)); + inline auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::call_operator_deducible<U>(), std::forward<F>(f))) { + return resolve_f(meta::call_operator_deducible<U> {}, std::forward<F>(f)); } template <typename... Args, typename F, typename R = std::invoke_result_t<F&, Args...>> @@ -18218,13 +19832,13 @@ namespace sol { struct c_function_invocation { }; - template <bool is_yielding, typename Fx, typename... Args> + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> void select(lua_State* L, Fx&& fx, Args&&... args); template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> void select_set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = no_trampoline ? detail::static_trampoline<function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>> - : function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>; + lua_CFunction freefunc = no_trampoline ? function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding> + : detail::static_trampoline<function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -18232,33 +19846,33 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } - template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args> + template <bool is_yielding, bool no_trampoline, typename R, typename... A, typename Fx, typename... Args> void select_convertible(types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) { using dFx = std::decay_t<meta::unwrap_unqualified_t<Fx>>; using fx_ptr_t = R (*)(A...); constexpr bool is_convertible = std::is_convertible_v<dFx, fx_ptr_t>; if constexpr (is_convertible) { fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx)); - select<is_yielding>(L, std::move(fxptr), std::forward<Args>(args)...); + select<is_yielding, no_trampoline>(L, std::move(fxptr), std::forward<Args>(args)...); } else { using F = function_detail::functor_function<dFx, false, true>; - select_set_fx<is_yielding, false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); } } - template <bool is_yielding, typename Fx, typename... Args> + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig; - select_convertible<is_yielding>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); + select_convertible<is_yielding, no_trampoline>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); } - template <bool is_yielding, typename Fx, typename... Args> + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) { using uFx = meta::unqualified_t<Fx>; if constexpr (sizeof...(Args) < 1) { using C = typename meta::bind_traits<uFx>::object_type; - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::template call<is_yielding, no_trampoline>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -18269,7 +19883,8 @@ namespace sol { using Tu = typename meta::meta_detail::unqualified_non_alias<Args...>::type; constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>; if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) { - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx, is_yielding>::call; + lua_CFunction freefunc + = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx>::template call<is_yielding, no_trampoline>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -18280,8 +19895,8 @@ namespace sol { typedef std::decay_t<Fx> dFx; dFx memfxptr(std::forward<Fx>(fx)); auto userptr = detail::ptr(std::forward<Args>(args)...); - lua_CFunction freefunc - = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call; + lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, + meta::unqualified_t<Fx>>::template call<is_yielding, no_trampoline>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -18291,26 +19906,26 @@ namespace sol { } else { using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>; - using F = function_detail::member_variable<Tu, clean_fx, is_yielding>; - select_set_fx<false, false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + using F = function_detail::member_variable<Tu, clean_fx, is_yielding, no_trampoline>; + select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); } } else { using C = typename meta::bind_traits<uFx>::object_type; using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>; - using F = function_detail::member_variable<C, clean_fx, is_yielding>; - select_set_fx<false, false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + using F = function_detail::member_variable<C, clean_fx, is_yielding, no_trampoline>; + select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); } } - template <bool is_yielding, typename Fx, typename T, typename... Args> + template <bool is_yielding, bool no_trampoline, typename Fx, typename T, typename... Args> void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) { using dFx = std::decay_t<Fx>; using Tu = meta::unqualified_t<T>; if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) { (void)obj; using C = typename Tu::type; - lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx>::template call<is_yielding, no_trampoline>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -18321,7 +19936,8 @@ namespace sol { constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>; if constexpr (is_reference) { auto userptr = detail::ptr(std::forward<T>(obj)); - lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, dFx, is_yielding>::call; + lua_CFunction freefunc + = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, dFx>::template call<is_yielding, no_trampoline>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -18330,18 +19946,18 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } else { - using F = function_detail::member_function<Tu, dFx, is_yielding>; - select_set_fx<false, false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); + using F = function_detail::member_function<Tu, dFx, is_yielding, no_trampoline>; + select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); } } } - template <bool is_yielding, typename Fx, typename... Args> + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> void select_member_function(lua_State* L, Fx&& fx, Args&&... args) { using dFx = std::decay_t<Fx>; if constexpr (sizeof...(Args) < 1) { using C = typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type; - lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx>::template call<is_yielding, no_trampoline>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -18349,11 +19965,11 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } else { - select_member_function_with<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + select_member_function_with<is_yielding, no_trampoline>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); } } - template <bool is_yielding, typename Fx, typename... Args> + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> void select(lua_State* L, Fx&& fx, Args&&... args) { using uFx = meta::unqualified_t<Fx>; if constexpr (is_lua_reference_v<uFx>) { @@ -18361,26 +19977,49 @@ namespace sol { stack::push(L, std::forward<Fx>(fx), std::forward<Args>(args)...); } else if constexpr (is_lua_c_function_v<uFx>) { - int upvalues = 0; - upvalues += stack::push(L, nullptr); - upvalues += stack::push(L, std::forward<Fx>(fx)); -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) - if constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) { - detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<is_yielding>; - lua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), 2); + if constexpr (no_trampoline) { + if (is_yielding) { + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, std::forward<Fx>(fx)); +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + if constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) { + detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<true>; + lua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), upvalues); + } + else +#endif + { + lua_CFunction cf = &function_detail::lua_c_wrapper<true>; + lua_pushcclosure(L, cf, upvalues); + } + } + else { + lua_pushcclosure(L, std::forward<Fx>(fx), 0); + } } else { - lua_CFunction cf = &lua_c_wrapper<is_yielding>; - lua_pushcclosure(L, cf, 2); - } + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, std::forward<Fx>(fx)); +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + if constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) { + detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<is_yielding>; + lua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), upvalues); + } + else { + lua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>; + lua_pushcclosure(L, cf, upvalues); + } #else - lua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>; - lua_pushcclosure(L, cf, 2); + lua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>; + lua_pushcclosure(L, cf, upvalues); #endif + } } else if constexpr (std::is_function_v<std::remove_pointer_t<uFx>>) { std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...); - lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx, is_yielding>::call; + lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::template call<is_yielding, no_trampoline>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -18388,13 +20027,13 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } else if constexpr (std::is_member_function_pointer_v<uFx>) { - select_member_function<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + select_member_function<is_yielding, no_trampoline>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); } else if constexpr (meta::is_member_object_v<uFx>) { - select_member_variable<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + select_member_variable<is_yielding, no_trampoline>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); } else { - select_convertible<is_yielding>(types<>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); + select_convertible<is_yielding, no_trampoline>(types<>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); } } } // namespace function_detail @@ -18403,7 +20042,7 @@ namespace sol { template <typename... Sigs> struct unqualified_pusher<function_sig<Sigs...>> { template <bool is_yielding, typename Arg0, typename... Args> - static int push(lua_State* L, Arg0&& arg0, Args&&... args) { + static int push_yielding(lua_State* L, Arg0&& arg0, Args&&... args) { if constexpr (meta::is_specialization_of_v<meta::unqualified_t<Arg0>, std::function>) { if constexpr (is_yielding) { return stack::push<meta::unqualified_t<Arg0>>(L, detail::yield_tag, std::forward<Arg0>(arg0), std::forward<Args>(args)...); @@ -18413,7 +20052,7 @@ namespace sol { } } else { - function_detail::select<is_yielding>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...); + function_detail::select<is_yielding, false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...); return 1; } } @@ -18421,13 +20060,13 @@ namespace sol { template <typename Arg0, typename... Args> static int push(lua_State* L, Arg0&& arg0, Args&&... args) { if constexpr (std::is_same_v<meta::unqualified_t<Arg0>, detail::yield_tag_t>) { - push<true>(L, std::forward<Args>(args)...); + push_yielding<true>(L, std::forward<Args>(args)...); } else if constexpr (meta::is_specialization_of_v<meta::unqualified_t<Arg0>, yielding_t>) { - push<true>(L, std::forward<Arg0>(arg0).func, std::forward<Args>(args)...); + push_yielding<true>(L, std::forward<Arg0>(arg0).func, std::forward<Args>(args)...); } else { - push<false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...); + push_yielding<false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...); } return 1; } @@ -18441,7 +20080,7 @@ namespace sol { return stack::push<T>(L, detail::yield_tag, f.func, std::forward<Args>(args)...); } else { - function_detail::select<true>(L, f.func, std::forward<Args>(args)...); + function_detail::select<true, false>(L, f.func, std::forward<Args>(args)...); return 1; } } @@ -18452,7 +20091,7 @@ namespace sol { return stack::push<T>(L, detail::yield_tag, std::move(f.func), std::forward<Args>(args)...); } else { - function_detail::select<true>(L, std::move(f.func), std::forward<Args>(args)...); + function_detail::select<true, false>(L, std::move(f.func), std::forward<Args>(args)...); return 1; } } @@ -18476,9 +20115,11 @@ namespace sol { template <typename Signature> struct unqualified_pusher<std::function<Signature>> { + using TargetFunctor = function_detail::functor_function<std::function<Signature>, false, true>; + static int push(lua_State* L, detail::yield_tag_t, const std::function<Signature>& fx) { if (fx) { - function_detail::select<true>(L, fx); + function_detail::select_set_fx<true, false, TargetFunctor>(L, fx); return 1; } return stack::push(L, lua_nil); @@ -18486,7 +20127,7 @@ namespace sol { static int push(lua_State* L, detail::yield_tag_t, std::function<Signature>&& fx) { if (fx) { - function_detail::select<true>(L, std::move(fx)); + function_detail::select_set_fx<true, false, TargetFunctor>(L, std::move(fx)); return 1; } return stack::push(L, lua_nil); @@ -18494,7 +20135,7 @@ namespace sol { static int push(lua_State* L, const std::function<Signature>& fx) { if (fx) { - function_detail::select<false>(L, fx); + function_detail::select_set_fx<false, false, TargetFunctor>(L, fx); return 1; } return stack::push(L, lua_nil); @@ -18502,7 +20143,7 @@ namespace sol { static int push(lua_State* L, std::function<Signature>&& fx) { if (fx) { - function_detail::select<false>(L, std::move(fx)); + function_detail::select_set_fx<false, false, TargetFunctor>(L, std::move(fx)); return 1; } return stack::push(L, lua_nil); @@ -18510,10 +20151,10 @@ namespace sol { }; template <typename Signature> - struct unqualified_pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> { + struct unqualified_pusher<Signature, std::enable_if_t<meta::is_member_object_or_function_v<Signature>>> { template <typename... Args> static int push(lua_State* L, Args&&... args) { - function_detail::select<false>(L, std::forward<Args>(args)...); + function_detail::select<false, false>(L, std::forward<Args>(args)...); return 1; } }; @@ -18522,7 +20163,7 @@ namespace sol { struct unqualified_pusher<Signature, std::enable_if_t<meta::all<std::is_function<std::remove_pointer_t<Signature>>, meta::neg<std::is_same<Signature, lua_CFunction>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>> -#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) , meta::neg<std::is_same<Signature, detail::lua_CFunction_noexcept>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<detail::lua_CFunction_noexcept>>> @@ -18530,7 +20171,7 @@ namespace sol { >::value>> { template <typename F> static int push(lua_State* L, F&& f) { - function_detail::select<false>(L, std::forward<F>(f)); + function_detail::select<false, true>(L, std::forward<F>(f)); return 1; } }; @@ -18652,8 +20293,9 @@ namespace sol { return stack::push(L, cf); } - static int push(lua_State* L, no_construction c, function_detail::call_indicator) { - return push(L, c); + static int push(lua_State* L, no_construction, function_detail::call_indicator) { + lua_CFunction cf = &function_detail::no_construction_error; + return stack::push(L, cf); } }; @@ -18724,7 +20366,7 @@ namespace sol { template <typename T> struct unqualified_pusher<detail::tagged<T, destructor_wrapper<void>>> { static int push(lua_State* L, destructor_wrapper<void>) { - lua_CFunction cf = detail::usertype_alloc_destruct<T>; + lua_CFunction cf = detail::usertype_alloc_destroy<T>; return stack::push(L, cf); } }; @@ -18834,7 +20476,7 @@ namespace sol { namespace stack_detail { template <typename Function, typename Handler> bool check_function_pointer(lua_State* L, int index, Handler&& handler, record& tracking) noexcept { -#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_) +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) tracking.use(1); bool success = lua_iscfunction(L, index) == 1; if (success) { @@ -18850,20 +20492,27 @@ namespace sol { } return success; #else + (void)L; + (void)index; + (void)handler; + (void)tracking; return false; #endif } template <typename Function> Function* get_function_pointer(lua_State* L, int index, record& tracking) noexcept { -#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_) +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) tracking.use(1); auto udata = stack::stack_detail::get_as_upvalues_using_function<Function*>(L, index); Function* fx = udata.first; return fx; #else + (void)L; + (void)index; + (void)tracking; static_assert(meta::meta_detail::always_true<Function>::value, -#if SOL_IS_DEFAULT_OFF(SOL_GET_FUNCTION_POINTER_UNSAFE_I_) +#if SOL_IS_DEFAULT_OFF(SOL_GET_FUNCTION_POINTER_UNSAFE) "You are attempting to retrieve a function pointer type. " "This is inherently unsafe in sol2. In order to do this, you must turn on the " "SOL_GET_FUNCTION_POINTER_UNSAFE configuration macro, as detailed in the documentation. " @@ -18893,40 +20542,40 @@ namespace sol { class dump_error : public error { private: - int ec_; + int m_ec; public: - dump_error(int error_code_) : error("dump returned non-zero error of " + std::to_string(error_code_)), ec_(error_code_) { + dump_error(int error_code_) : error("dump returned non-zero error of " + std::to_string(error_code_)), m_ec(error_code_) { } int error_code() const { - return ec_; + return m_ec; } }; - inline int dump_pass_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) { - (void)L; + inline int dump_pass_on_error(lua_State* L_, int result_code, lua_Writer writer_function, void* userdata_pointer_, bool strip) { + (void)L_; (void)writer_function; - (void)userdata; + (void)userdata_pointer_; (void)strip; return result_code; } - inline int dump_panic_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) { - (void)L; + inline int dump_panic_on_error(lua_State* L_, int result_code, lua_Writer writer_function, void* userdata_pointer_, bool strip) { + (void)L_; (void)writer_function; - (void)userdata; + (void)userdata_pointer_; (void)strip; - return luaL_error(L, "a non-zero error code (%d) was returned by the lua_Writer for the dump function", result_code); + return luaL_error(L_, "a non-zero error code (%d) was returned by the lua_Writer for the dump function", result_code); } - inline int dump_throw_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) { -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) - return dump_panic_on_error(L, result_code, writer_function, userdata, strip); + inline int dump_throw_on_error(lua_State* L_, int result_code, lua_Writer writer_function, void* userdata_pointer_, bool strip) { +#if SOL_IS_OFF(SOL_EXCEPTIONS) + return dump_panic_on_error(L_, result_code, writer_function, userdata_pointer_, strip); #else - (void)L; + (void)L_; (void)writer_function; - (void)userdata; + (void)userdata_pointer_; (void)strip; throw dump_error(result_code); #endif // no exceptions stuff @@ -18978,13 +20627,14 @@ namespace sol { using base_t::lua_state; basic_function() = default; - template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_function(T&& r) noexcept - : base_t(std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_function(T&& r) noexcept : base_t(std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) if (!is_function<meta::unqualified_t<T>>::value) { auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_function>(lua_state(), -1, handler); } #endif // Safety @@ -18993,36 +20643,30 @@ namespace sol { basic_function& operator=(const basic_function&) = default; basic_function(basic_function&&) = default; basic_function& operator=(basic_function&&) = default; - basic_function(const stack_reference& r) - : basic_function(r.lua_state(), r.stack_index()) { + basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) { } - basic_function(stack_reference&& r) - : basic_function(r.lua_state(), r.stack_index()) { + basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) { } - basic_function(lua_nil_t n) - : base_t(n) { + basic_function(lua_nil_t n) : base_t(n) { } template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_function(lua_State* L, T&& r) - : base_t(L, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_function(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_function>(lua_state(), -1, handler); #endif // Safety } - basic_function(lua_State* L, int index = -1) - : base_t(L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) - constructor_handler handler{}; + basic_function(lua_State* L, int index = -1) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; stack::check<basic_function>(L, index, handler); #endif // Safety } - basic_function(lua_State* L, ref_index index) - : base_t(L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_function(lua_State* L, ref_index index) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_function>(lua_state(), -1, handler); #endif // Safety } @@ -19085,85 +20729,80 @@ namespace sol { #include <cstdint> -namespace sol { - namespace detail { - inline const char(&default_handler_name())[9]{ - static const char name[9] = "sol.\xF0\x9F\x94\xA9"; - return name; - } +namespace sol { namespace detail { + inline const char (&default_handler_name())[9] { + static const char name[9] = "sol.\xF0\x9F\x94\xA9"; + return name; + } - template <bool b, typename target_t = reference> - struct protected_handler { - typedef is_stack_based<target_t> is_stack; - const target_t& target; - int stackindex; + template <bool ShouldPush, typename Target = reference> + struct protected_handler { + lua_State* m_L; + const Target& target; + int stack_index; - protected_handler(std::false_type, const target_t& target) - : target(target), stackindex(0) { - if (b) { - stackindex = lua_gettop(target.lua_state()) + 1; - target.push(); - } + protected_handler(std::false_type, lua_State* L_, const Target& target_) : m_L(L_), target(target_), stack_index(0) { + if (ShouldPush) { + stack_index = lua_gettop(L_) + 1; + target.push(L_); } + } - protected_handler(std::true_type, const target_t& target) - : target(target), stackindex(0) { - if (b) { - stackindex = target.stack_index(); - } + protected_handler(std::true_type, lua_State* L_, const Target& target_) : m_L(L_), target(target_), stack_index(0) { + if (ShouldPush) { + stack_index = target.stack_index(); } + } - protected_handler(const target_t& target) - : protected_handler(is_stack(), target) { - } + protected_handler(lua_State* L_, const Target& target_) : protected_handler(meta::boolean<is_stack_based_v<Target>>(), L_, target_) { + } - bool valid() const noexcept { - return b; - } + bool valid() const noexcept { + return ShouldPush; + } - ~protected_handler() { - if constexpr (!is_stack::value) { - if (stackindex != 0) { - lua_remove(target.lua_state(), stackindex); - } + ~protected_handler() { + if constexpr (!is_stack_based_v<Target>) { + if (stack_index != 0) { + lua_remove(m_L, stack_index); } } - }; - - template <typename base_t, typename T> - basic_function<base_t> force_cast(T& p) { - return p; } + }; - template <typename Reference, bool is_main_ref = false> - static Reference get_default_handler(lua_State* L) { - if (is_stack_based<Reference>::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 <typename Base, typename T> + inline basic_function<Base> force_cast(T& p) { + return p; + } - template <typename T> - static void set_default_handler(lua_State* L, const T& ref) { - if (L == nullptr) { - return; - } - if (!ref.valid()) { -#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); + template <typename Reference, bool IsMainReference = false> + inline Reference get_default_handler(lua_State* L_) { + if (is_stack_based_v<Reference> || L_ == nullptr) + return Reference(L_, lua_nil); + L_ = IsMainReference ? main_thread(L_, L_) : L_; + lua_getglobal(L_, default_handler_name()); + auto pp = stack::pop_n(L_, 1); + return Reference(L_, -1); + } + + template <typename T> + inline void set_default_handler(lua_State* L, const T& ref) { + if (L == nullptr) { + return; + } + if (!ref.valid()) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow - lua_pushnil(L); - lua_setglobal(L, default_handler_name()); - } - else { - ref.push(L); - lua_setglobal(L, default_handler_name()); - } + lua_pushnil(L); + lua_setglobal(L, default_handler_name()); } - } // namespace detail -} // namespace sol + else { + ref.push(L); + lua_setglobal(L, default_handler_name()); + } + } +}} // namespace sol::detail // end of sol/protected_handler.hpp @@ -19171,246 +20810,161 @@ namespace sol { #include <algorithm> namespace sol { - + namespace detail { - template <bool b, typename handler_t> - inline void handle_protected_exception(lua_State* L, optional<const std::exception&> maybe_ex, const char* error, detail::protected_handler<b, handler_t>& h) { - h.stackindex = 0; - if (b) { - h.target.push(); - detail::call_exception_handler(L, maybe_ex, error); - lua_call(L, 1, 1); + template <bool ShouldPush_, typename Handler_> + inline void handle_protected_exception( + lua_State* L_, optional<const std::exception&> maybe_ex, const char* error, detail::protected_handler<ShouldPush_, Handler_>& handler_) { + handler_.stack_index = 0; + if (ShouldPush_) { + handler_.target.push(L_); + detail::call_exception_handler(L_, maybe_ex, error); + lua_call(L_, 1, 1); } else { - detail::call_exception_handler(L, maybe_ex, error); + detail::call_exception_handler(L_, maybe_ex, error); } } - } - - template <typename ref_t, bool aligned = false, typename handler_t = reference> - class basic_protected_function : public basic_object<ref_t> { - private: - using base_t = basic_object<ref_t>; - - public: - using is_stack_handler = is_stack_based<handler_t>; - - static handler_t get_default_handler(lua_State* L) { - return detail::get_default_handler<handler_t, is_main_threaded<base_t>::value>(L); - } - - template <typename T> - static void set_default_handler(const T& ref) { - detail::set_default_handler(ref.lua_state(), ref); - } + } // namespace detail + template <typename Reference, bool Aligned = false, typename Handler = reference> + class basic_protected_function : public basic_object<Reference> { private: - template <bool b> - call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::protected_handler<b, handler_t>& h) const { - return static_cast<call_status>(lua_pcall(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex)); - } + using base_t = basic_object<Reference>; + using handler_t = Handler; + inline static constexpr bool is_stack_handler_v = is_stack_based_v<handler_t>; - template <std::size_t... I, bool b, typename... Ret> - auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { - luacall(n, sizeof...(Ret), h); - return stack::pop<std::tuple<Ret...>>(lua_state()); + basic_protected_function(std::true_type, const basic_protected_function& other_) noexcept + : base_t(other_), m_error_handler(other_.m_error_handler.copy(lua_state())) { } - template <std::size_t I, bool b, typename Ret> - Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { - luacall(n, 1, h); - return stack::pop<Ret>(lua_state()); - } - - template <std::size_t I, bool b> - void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { - luacall(n, 0, h); - } - - template <bool b> - protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { - int stacksize = lua_gettop(lua_state()); - int poststacksize = stacksize; - int firstreturn = 1; - int returncount = 0; - call_status code = call_status::ok; -#if !defined(SOL_NO_EXCEPTIONS) || !SOL_NO_EXCEPTIONS -#if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION) || (defined(SOL_LUAJIT) && SOL_LUAJIT) - try { -#endif // Safe Exception Propagation -#endif // No Exceptions - firstreturn = (std::max)(1, static_cast<int>(stacksize - n - static_cast<int>(h.valid() && !is_stack_handler::value))); - code = luacall(n, LUA_MULTRET, h); - poststacksize = lua_gettop(lua_state()) - static_cast<int>(h.valid() && !is_stack_handler::value); - returncount = poststacksize - (firstreturn - 1); -#ifndef SOL_NO_EXCEPTIONS -#if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION) || (defined(SOL_LUAJIT) && SOL_LUAJIT) - } - // Handle C++ errors thrown from C++ functions bound inside of lua - catch (const char* error) { - detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), error, h); - firstreturn = lua_gettop(lua_state()); - return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); - } - catch (const std::string& error) { - detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), error.c_str(), h); - firstreturn = lua_gettop(lua_state()); - return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); - } - catch (const std::exception& error) { - detail::handle_protected_exception(lua_state(), optional<const std::exception&>(error), error.what(), h); - firstreturn = lua_gettop(lua_state()); - return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); - } -#if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION) - // LuaJIT cannot have the catchall when the safe propagation is on - // but LuaJIT will swallow all C++ errors - // if we don't at least catch std::exception ones - catch (...) { - detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), detail::protected_function_error, h); - firstreturn = lua_gettop(lua_state()); - return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); - } -#endif // LuaJIT -#else - // do not handle exceptions: they can be propogated into C++ and keep all type information / rich information -#endif // Safe Exception Propagation -#endif // Exceptions vs. No Exceptions - return protected_function_result(lua_state(), firstreturn, returncount, returncount, code); + basic_protected_function(std::false_type, const basic_protected_function& other_) noexcept : base_t(other_), m_error_handler(other_.m_error_handler) { } public: - using base_t::lua_state; - - handler_t error_handler; - basic_protected_function() = default; - template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_protected_function(T&& r) noexcept - : base_t(std::forward<T>(r)), error_handler(get_default_handler(r.lua_state())) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, + meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_protected_function(T&& r) noexcept : base_t(std::forward<T>(r)), m_error_handler(get_default_handler(r.lua_state())) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) if (!is_function<meta::unqualified_t<T>>::value) { auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_protected_function>(lua_state(), -1, handler); } #endif // Safety } - basic_protected_function(const basic_protected_function&) = default; - basic_protected_function& operator=(const basic_protected_function&) = default; + basic_protected_function(const basic_protected_function& other_) noexcept + : basic_protected_function(meta::boolean<is_stateless_lua_reference_v<Handler>>(), other_) { + } + basic_protected_function& operator=(const basic_protected_function& other_) { + base_t::operator=(other_); + if constexpr (is_stateless_lua_reference_v<Handler>) { + m_error_handler.copy_assign(lua_state(), other_.m_error_handler); + } + else { + m_error_handler = other_.m_error_handler; + } + return *this; + } basic_protected_function(basic_protected_function&&) = default; basic_protected_function& operator=(basic_protected_function&&) = default; - basic_protected_function(const basic_function<base_t>& b) - : basic_protected_function(b, get_default_handler(b.lua_state())) { + basic_protected_function(const basic_function<base_t>& b) : basic_protected_function(b, get_default_handler(b.lua_state())) { } - basic_protected_function(basic_function<base_t>&& b) - : basic_protected_function(std::move(b), get_default_handler(b.lua_state())) { + basic_protected_function(basic_function<base_t>&& b) : basic_protected_function(std::move(b), get_default_handler(b.lua_state())) { } - basic_protected_function(const basic_function<base_t>& b, handler_t eh) - : base_t(b), error_handler(std::move(eh)) { + basic_protected_function(const basic_function<base_t>& b, handler_t eh) : base_t(b), m_error_handler(std::move(eh)) { } - basic_protected_function(basic_function<base_t>&& b, handler_t eh) - : base_t(std::move(b)), error_handler(std::move(eh)) { + basic_protected_function(basic_function<base_t>&& b, handler_t eh) : base_t(std::move(b)), m_error_handler(std::move(eh)) { } - basic_protected_function(const stack_reference& r) - : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) { + basic_protected_function(const stack_reference& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) { } - basic_protected_function(stack_reference&& r) - : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) { + basic_protected_function(stack_reference&& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) { } - basic_protected_function(const stack_reference& r, handler_t eh) - : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) { + basic_protected_function(const stack_reference& r, handler_t eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) { } - basic_protected_function(stack_reference&& r, handler_t eh) - : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) { + basic_protected_function(stack_reference&& r, handler_t eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) { } template <typename Super> - basic_protected_function(const proxy_base<Super>& p) - : basic_protected_function(p, get_default_handler(p.lua_state())) { + basic_protected_function(const proxy_base<Super>& p) : basic_protected_function(p, get_default_handler(p.lua_state())) { } template <typename Super> - basic_protected_function(proxy_base<Super>&& p) - : basic_protected_function(std::move(p), get_default_handler(p.lua_state())) { + basic_protected_function(proxy_base<Super>&& p) : basic_protected_function(std::move(p), get_default_handler(p.lua_state())) { } - template <typename Proxy, typename Handler, meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, meta::neg<is_lua_index<meta::unqualified_t<Handler>>>> = meta::enabler> - basic_protected_function(Proxy&& p, Handler&& eh) - : basic_protected_function(detail::force_cast<base_t>(p), std::forward<Handler>(eh)) { + template <typename Proxy, typename HandlerReference, + meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, + meta::neg<is_lua_index<meta::unqualified_t<HandlerReference>>>> = meta::enabler> + basic_protected_function(Proxy&& p, HandlerReference&& eh) + : basic_protected_function(detail::force_cast<base_t>(p), make_reference<handler_t>(p.lua_state(), std::forward<HandlerReference>(eh))) { } template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_protected_function(lua_State* L, T&& r) - : basic_protected_function(L, std::forward<T>(r), get_default_handler(L)) { + basic_protected_function(lua_State* L_, T&& r) : basic_protected_function(L_, std::forward<T>(r), get_default_handler(L_)) { } template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_protected_function(lua_State* L, T&& r, handler_t eh) - : base_t(L, std::forward<T>(r)), error_handler(std::move(eh)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_protected_function(lua_State* L_, T&& r, handler_t eh) : base_t(L_, std::forward<T>(r)), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_protected_function>(lua_state(), -1, handler); #endif // Safety } - - basic_protected_function(lua_nil_t n) - : base_t(n), error_handler(n) { + + basic_protected_function(lua_nil_t n) : base_t(n), m_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_ = -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)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) - constructor_handler handler{}; - stack::check<basic_protected_function>(L, index, handler); + basic_protected_function(lua_State* L_, int index_, handler_t eh) : base_t(L_, index_), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_protected_function>(L_, index_, handler); #endif // Safety } - basic_protected_function(lua_State* L, absolute_index index) - : basic_protected_function(L, index, get_default_handler(L)) { + basic_protected_function(lua_State* L_, absolute_index index_) : basic_protected_function(L_, index_, get_default_handler(L_)) { } - basic_protected_function(lua_State* L, absolute_index index, handler_t eh) - : base_t(L, index), error_handler(std::move(eh)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) - constructor_handler handler{}; - stack::check<basic_protected_function>(L, index, handler); + basic_protected_function(lua_State* L_, absolute_index index_, handler_t eh) : base_t(L_, index_), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_protected_function>(L_, index_, handler); #endif // Safety } - basic_protected_function(lua_State* L, raw_index index) - : basic_protected_function(L, index, get_default_handler(L)) { + basic_protected_function(lua_State* L_, raw_index index_) : basic_protected_function(L_, index_, get_default_handler(L_)) { } - basic_protected_function(lua_State* L, raw_index index, handler_t eh) - : base_t(L, index), error_handler(std::move(eh)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) - constructor_handler handler{}; - stack::check<basic_protected_function>(L, index, handler); + basic_protected_function(lua_State* L_, raw_index index_, handler_t eh) : base_t(L_, index_), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_protected_function>(L_, index_, handler); #endif // Safety } - basic_protected_function(lua_State* L, ref_index index) - : basic_protected_function(L, index, get_default_handler(L)) { + basic_protected_function(lua_State* L_, ref_index index_) : basic_protected_function(L_, index_, get_default_handler(L_)) { } - basic_protected_function(lua_State* L, ref_index index, handler_t eh) - : base_t(L, index), error_handler(std::move(eh)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_protected_function(lua_State* L_, ref_index index_, handler_t eh) : base_t(L_, index_), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_protected_function>(lua_state(), -1, handler); #endif // Safety } + using base_t::lua_state; + template <typename Fx> - int dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const { + int dump(lua_Writer writer, void* userdata_pointer_, bool strip, Fx&& on_error) const { this->push(); auto ppn = stack::push_popper_n<false>(this->lua_state(), 1); - int r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0); + int r = lua_dump(this->lua_state(), writer, userdata_pointer_, strip ? 1 : 0); if (r != 0) { - return on_error(this->lua_state(), r, writer, userdata, strip); + return on_error(this->lua_state(), r, writer, userdata_pointer_, strip); } return r; } - int dump(lua_Writer writer, void* userdata, bool strip = false) const { - return dump(writer, userdata, strip, &dump_pass_on_error); + int dump(lua_Writer writer, void* userdata_pointer_, bool strip = false) const { + return dump(writer, userdata_pointer_, strip, &dump_pass_on_error); } template <typename Container = bytecode> @@ -19439,16 +20993,16 @@ namespace sol { template <typename... Ret, typename... Args> decltype(auto) call(Args&&... args) const { - if constexpr (!aligned) { + if constexpr (!Aligned) { // we do not expect the function to already be on the stack: push it - if (error_handler.valid()) { - detail::protected_handler<true, handler_t> h(error_handler); + if (m_error_handler.valid(lua_state())) { + detail::protected_handler<true, handler_t> h(lua_state(), m_error_handler); base_t::push(); int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); } else { - detail::protected_handler<false, handler_t> h(error_handler); + detail::protected_handler<false, handler_t> h(lua_state(), m_error_handler); base_t::push(); int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); @@ -19456,29 +21010,148 @@ namespace sol { } else { // the function is already on the stack at the right location - if (error_handler.valid()) { + if (m_error_handler.valid()) { // the handler will be pushed onto the stack manually, // since it's not already on the stack this means we need to push our own // function on the stack too and swap things to be in-place - if constexpr (!is_stack_handler::value) { + if constexpr (!is_stack_handler_v) { // so, we need to remove the function at the top and then dump the handler out ourselves base_t::push(); } - detail::protected_handler<true, handler_t> h(error_handler); - if constexpr (!is_stack_handler::value) { + detail::protected_handler<true, handler_t> h(lua_state(), m_error_handler); + if constexpr (!is_stack_handler_v) { lua_replace(lua_state(), -3); - h.stackindex = lua_absindex(lua_state(), -2); + h.stack_index = lua_absindex(lua_state(), -2); } int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); } else { - detail::protected_handler<false, handler_t> h(error_handler); + detail::protected_handler<false, handler_t> h(lua_state(), m_error_handler); int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); } } } + + ~basic_protected_function() { + if constexpr (is_stateless_lua_reference_v<handler_t>) { + this->m_error_handler.reset(lua_state()); + } + } + + static handler_t get_default_handler(lua_State* L_) { + return detail::get_default_handler<handler_t, is_main_threaded_v<base_t>>(L_); + } + + template <typename T> + static void set_default_handler(const T& ref) { + detail::set_default_handler(ref.lua_state(), ref); + } + + auto get_error_handler() const noexcept { + if constexpr (is_stateless_lua_reference_v<handler_t>) { + if constexpr (is_stack_based_v<handler_t>) { + return stack_reference(lua_state(), m_error_handler.stack_index()); + } + else { + return basic_reference<is_main_threaded_v<base_t>>(lua_state(), ref_index(m_error_handler.registry_index())); + } + } + else { + return m_error_handler; + } + } + + template <typename ErrorHandler_> + void set_error_handler(ErrorHandler_&& error_handler_) noexcept { + static_assert(!is_stack_based_v<handler_t> || is_stack_based_v<ErrorHandler_>, + "A stack-based error handler can only be set from a parameter that is also stack-based."); + if constexpr (std::is_rvalue_reference_v<ErrorHandler_>) { + m_error_handler = std::forward<ErrorHandler_>(error_handler_); + } + else { + m_error_handler.copy_assign(lua_state(), std::forward<ErrorHandler_>(error_handler_)); + } + } + + void abandon () noexcept { + this->m_error_handler.abandon(); + base_t::abandon(); + } + + private: + handler_t m_error_handler; + + template <bool b> + call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t result_count_, detail::protected_handler<b, handler_t>& h) const { + return static_cast<call_status>(lua_pcall(lua_state(), static_cast<int>(argcount), static_cast<int>(result_count_), h.stack_index)); + } + + template <std::size_t... I, bool b, typename... Ret> + auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { + luacall(n, sizeof...(Ret), h); + return stack::pop<std::tuple<Ret...>>(lua_state()); + } + + template <std::size_t I, bool b, typename Ret> + Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { + luacall(n, 1, h); + return stack::pop<Ret>(lua_state()); + } + + template <std::size_t I, bool b> + void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { + luacall(n, 0, h); + } + + template <bool b> + protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { + int stacksize = lua_gettop(lua_state()); + int poststacksize = stacksize; + int firstreturn = 1; + int returncount = 0; + call_status code = call_status::ok; +#if SOL_IS_ON(SOL_EXCEPTIONS) && SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS) + try { +#endif // No Exceptions + firstreturn = (std::max)(1, static_cast<int>(stacksize - n - static_cast<int>(h.valid() && !is_stack_handler_v))); + code = luacall(n, LUA_MULTRET, h); + poststacksize = lua_gettop(lua_state()) - static_cast<int>(h.valid() && !is_stack_handler_v); + returncount = poststacksize - (firstreturn - 1); +#if SOL_IS_ON(SOL_EXCEPTIONS) && SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS) + } + // Handle C++ errors thrown from C++ functions bound inside of lua + catch (const char* error) { + detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), error, h); + firstreturn = lua_gettop(lua_state()); + return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + } + catch (const std::string& error) { + detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), error.c_str(), h); + firstreturn = lua_gettop(lua_state()); + return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + } + catch (const std::exception& error) { + detail::handle_protected_exception(lua_state(), optional<const std::exception&>(error), error.what(), h); + firstreturn = lua_gettop(lua_state()); + return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + } +#if SOL_IS_ON(SOL_EXCEPTIONS_CATCH_ALL) + // LuaJIT cannot have the catchall when the safe propagation is on + // but LuaJIT will swallow all C++ errors + // if we don't at least catch std::exception ones + catch (...) { + detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), detail::protected_function_error, h); + firstreturn = lua_gettop(lua_state()); + return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + } +#endif // Always catch edge case +#else + // do not handle exceptions: they can be propogated into C++ and keep all type information / rich information +#endif // Exceptions vs. No Exceptions + return protected_function_result(lua_state(), firstreturn, returncount, returncount, code); + } }; } // namespace sol @@ -19613,14 +21286,12 @@ namespace sol { #endif // compilers #endif // SOL_DEPRECATED -namespace sol { -namespace detail { +namespace sol { namespace detail { template <typename T> struct SOL_DEPRECATED deprecate_type { using type = T; }; -} -} // namespace sol::detail +}} // namespace sol::detail // end of sol/deprecate.hpp @@ -19955,10 +21626,10 @@ namespace sol { using has_traits_erase = meta::boolean<has_traits_erase_test<T>::value>; template <typename T> - struct is_forced_container : is_container<T> {}; + struct is_forced_container : is_container<T> { }; template <typename T> - struct is_forced_container<as_container_t<T>> : std::true_type {}; + struct is_forced_container<as_container_t<T>> : std::true_type { }; template <typename T> struct container_decay { @@ -20002,78 +21673,78 @@ namespace sol { typedef lua_nil_t iterator; typedef lua_nil_t value_type; - static int at(lua_State* L) { - return luaL_error(L, "sol: cannot call 'at(index)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int at(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'at(index)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int get(lua_State* L) { - return luaL_error(L, "sol: cannot call 'get(key)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int get(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'get(key)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int index_get(lua_State* L) { - return luaL_error(L, "sol: cannot call 'container[key]' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int index_get(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'container[key]' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int set(lua_State* L) { - return luaL_error(L, "sol: cannot call 'set(key, value)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int set(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'set(key, value)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int index_set(lua_State* L) { + static int index_set(lua_State* L_) { return luaL_error( - L, "sol: cannot call 'container[key] = value' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + L_, "sol: cannot call 'container[key] = value' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int add(lua_State* L) { - return luaL_error(L, "sol: cannot call 'add' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int add(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'add' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int insert(lua_State* L) { - return luaL_error(L, "sol: cannot call 'insert' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int insert(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'insert' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int find(lua_State* L) { - return luaL_error(L, "sol: cannot call 'find' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int find(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'find' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int index_of(lua_State* L) { - return luaL_error(L, "sol: cannot call 'index_of' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int index_of(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'index_of' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int size(lua_State* L) { - return luaL_error(L, "sol: cannot call 'end' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int size(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'end' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int clear(lua_State* L) { - return luaL_error(L, "sol: cannot call 'clear' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int clear(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'clear' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int empty(lua_State* L) { - return luaL_error(L, "sol: cannot call 'empty' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int empty(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'empty' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int erase(lua_State* L) { - return luaL_error(L, "sol: cannot call 'erase' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int erase(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'erase' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int next(lua_State* L) { - return luaL_error(L, "sol: cannot call 'next' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int next(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'next' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int pairs(lua_State* L) { - return luaL_error(L, "sol: cannot call '__pairs/pairs' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int pairs(lua_State* L_) { + return luaL_error(L_, "sol: cannot call '__pairs/pairs' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static int ipairs(lua_State* L) { - return luaL_error(L, "sol: cannot call '__ipairs' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static int ipairs(lua_State* L_) { + return luaL_error(L_, "sol: cannot call '__ipairs' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); } - static iterator begin(lua_State* L, T&) { - luaL_error(L, "sol: cannot call 'being' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static iterator begin(lua_State* L_, T&) { + luaL_error(L_, "sol: cannot call 'being' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); return lua_nil; } - static iterator end(lua_State* L, T&) { - luaL_error(L, "sol: cannot call 'end' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + static iterator end(lua_State* L_, T&) { + luaL_error(L_, "sol: cannot call 'end' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); return lua_nil; } }; @@ -20112,122 +21783,123 @@ namespace sol { typedef meta::all<std::is_integral<K>, meta::neg<meta::any<is_associative, is_lookup>>> is_linear_integral; struct iter { + reference keep_alive; T& source; iterator it; - std::size_t i; + std::size_t index; - iter(T& source, iterator it) : source(source), it(std::move(it)), i(0) { + iter(lua_State* L_, int stack_index, T& source_, iterator it_) : keep_alive(sol::main_thread(L_, L_), stack_index), source(source_), it(std::move(it_)), index(0) { } ~iter() { } }; - static auto& get_src(lua_State* L) { -#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_) - auto p = stack::unqualified_check_get<T*>(L, 1); + static auto& get_src(lua_State* L_) { +#if SOL_IS_ON(SOL_SAFE_USERTYPE) + auto p = stack::unqualified_check_get<T*>(L_, 1); if (!p) { - luaL_error(L, + luaL_error(L_, "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle<T>().c_str()); } if (p.value() == nullptr) { luaL_error( - L, "sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)", detail::demangle<T>().c_str()); + L_, "sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)", detail::demangle<T>().c_str()); } return *p.value(); #else - return stack::unqualified_get<T>(L, 1); + return stack::unqualified_get<T>(L_, 1); #endif // Safe getting with error } - static detail::error_result at_category(std::input_iterator_tag, lua_State* L, T& self, std::ptrdiff_t pos) { - pos += deferred_uc::index_adjustment(L, self); + static detail::error_result at_category(std::input_iterator_tag, lua_State* L_, T& self, std::ptrdiff_t pos) { + pos += deferred_uc::index_adjustment(L_, self); if (pos < 0) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } - auto it = deferred_uc::begin(L, self); - auto e = deferred_uc::end(L, self); + auto it = deferred_uc::begin(L_, self); + auto e = deferred_uc::end(L_, self); if (it == e) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } while (pos > 0) { --pos; ++it; if (it == e) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } } - return get_associative(is_associative(), L, it); + return get_associative(is_associative(), L_, it); } - static detail::error_result at_category(std::random_access_iterator_tag, lua_State* L, T& self, std::ptrdiff_t pos) { - std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self)); - pos += deferred_uc::index_adjustment(L, self); + static detail::error_result at_category(std::random_access_iterator_tag, lua_State* L_, T& self, std::ptrdiff_t pos) { + std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L_, self)); + pos += deferred_uc::index_adjustment(L_, self); if (pos < 0 || pos >= len) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } - auto it = std::next(deferred_uc::begin(L, self), pos); - return get_associative(is_associative(), L, it); + auto it = std::next(deferred_uc::begin(L_, self), pos); + return get_associative(is_associative(), L_, it); } - static detail::error_result at_start(lua_State* L, T& self, std::ptrdiff_t pos) { - return at_category(iterator_category(), L, self, pos); + static detail::error_result at_start(lua_State* L_, T& self, std::ptrdiff_t pos) { + return at_category(iterator_category(), L_, self, pos); } template <typename Iter> - static detail::error_result get_associative(std::true_type, lua_State* L, Iter& it) { + static detail::error_result get_associative(std::true_type, lua_State* L_, Iter& it) { decltype(auto) v = *it; - return stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(v.second)); + return stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(v.second)); } template <typename Iter> - static detail::error_result get_associative(std::false_type, lua_State* L, Iter& it) { - return stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(*it)); + static detail::error_result get_associative(std::false_type, lua_State* L_, Iter& it) { + return stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(*it)); } - static detail::error_result get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) { - key += deferred_uc::index_adjustment(L, self); + static detail::error_result get_category(std::input_iterator_tag, lua_State* L_, T& self, K& key) { + key = static_cast<K>(key + deferred_uc::index_adjustment(L_, self)); if (key < 0) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } - auto it = deferred_uc::begin(L, self); - auto e = deferred_uc::end(L, self); + auto it = deferred_uc::begin(L_, self); + auto e = deferred_uc::end(L_, self); if (it == e) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } while (key > 0) { --key; ++it; if (it == e) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } } - return get_associative(is_associative(), L, it); + return get_associative(is_associative(), L_, it); } - static detail::error_result get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) { - std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self)); - key += deferred_uc::index_adjustment(L, self); + static detail::error_result get_category(std::random_access_iterator_tag, lua_State* L_, T& self, K& key) { + std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L_, self)); + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); if (key < 0 || key >= len) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } - auto it = std::next(deferred_uc::begin(L, self), key); - return get_associative(is_associative(), L, it); + auto it = std::next(deferred_uc::begin(L_, self), key); + return get_associative(is_associative(), L_, it); } - static detail::error_result get_it(std::true_type, lua_State* L, T& self, K& key) { - return get_category(iterator_category(), L, self, key); + static detail::error_result get_it(std::true_type, lua_State* L_, T& self, K& key) { + return get_category(iterator_category(), L_, self, key); } - static detail::error_result get_comparative(std::true_type, lua_State* L, T& self, K& key) { + static detail::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 = deferred_uc::end(L, self); - auto it = std::find_if(deferred_uc::begin(L, self), e, std::ref(fx)); + auto e = deferred_uc::end(L_, self); + auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx)); if (it == e) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } - return get_associative(is_associative(), L, it); + return get_associative(is_associative(), L_, it); } static detail::error_result get_comparative(std::false_type, lua_State*, T&, K&) { @@ -20236,8 +21908,8 @@ namespace sol { detail::demangle<K>().data()); } - static detail::error_result get_it(std::false_type, lua_State* L, T& self, K& key) { - return get_comparative(meta::supports_op_equal<K, key_type>(), L, self, key); + static detail::error_result get_it(std::false_type, lua_State* L_, T& self, K& key) { + return get_comparative(meta::supports_op_equal<K, key_type>(), L_, self, key); } static detail::error_result set_associative(std::true_type, iterator& it, stack_object value) { @@ -20261,54 +21933,54 @@ namespace sol { "cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data()); } - static detail::error_result set_category(std::input_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) { + static detail::error_result set_category(std::input_iterator_tag, lua_State* L_, T& self, stack_object okey, stack_object value) { decltype(auto) key = okey.as<K>(); - key += deferred_uc::index_adjustment(L, self); - auto e = deferred_uc::end(L, self); - auto it = deferred_uc::begin(L, self); + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); + auto e = deferred_uc::end(L_, self); + auto it = deferred_uc::begin(L_, self); auto backit = it; for (; key > 0 && it != e; --key, ++it) { backit = it; } if (it == e) { if (key == 0) { - return add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after<T>::value ? backit : it); + return add_copyable(is_copyable(), L_, self, std::move(value), meta::has_insert_after<T>::value ? backit : it); } return detail::error_result("out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); } - return set_writable(is_writable(), L, self, it, std::move(value)); + return set_writable(is_writable(), L_, self, it, std::move(value)); } - static detail::error_result set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) { + static detail::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<K>(); - key += deferred_uc::index_adjustment(L, self); + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); if (key < 0) { return detail::error_result("sol: out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str()); } - std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self)); + std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L_, self)); if (key == len) { - return add_copyable(is_copyable(), L, self, std::move(value)); + return add_copyable(is_copyable(), L_, self, std::move(value)); } else if (key >= len) { return detail::error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); } - auto it = std::next(deferred_uc::begin(L, self), key); - return set_writable(is_writable(), L, self, it, std::move(value)); + auto it = std::next(deferred_uc::begin(L_, self), key); + return set_writable(is_writable(), L_, self, it, std::move(value)); } - static detail::error_result set_comparative(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) { + static detail::error_result set_comparative(std::true_type, lua_State* L_, T& self, stack_object okey, stack_object value) { decltype(auto) key = okey.as<K>(); if (!is_writable::value) { return detail::error_result( "cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data()); } auto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); }; - auto e = deferred_uc::end(L, self); - auto it = std::find_if(deferred_uc::begin(L, self), e, std::ref(fx)); + auto e = deferred_uc::end(L_, self); + auto it = std::find_if(deferred_uc::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 detail::error_result set_comparative(std::false_type, lua_State*, T&, stack_object, stack_object) { @@ -20319,10 +21991,14 @@ namespace sol { template <typename Iter> static detail::error_result set_associative_insert(std::true_type, lua_State*, T& self, Iter& it, K& key, stack_object value) { - if constexpr (meta::has_insert<T>::value) { + if constexpr (meta::has_insert_with_iterator<T>::value) { self.insert(it, value_type(key, value.as<V>())); return {}; } + else if constexpr (meta::has_insert<T>::value) { + self.insert(value_type(key, value.as<V>())); + return {}; + } else { (void)self; (void)it; @@ -20334,10 +22010,14 @@ namespace sol { template <typename Iter> static detail::error_result set_associative_insert(std::false_type, lua_State*, T& self, Iter& it, K& key, stack_object) { - if constexpr (meta::has_insert<T>::value) { + if constexpr (meta::has_insert_with_iterator<T>::value) { self.insert(it, key); return {}; } + else if constexpr (meta::has_insert<T>::value) { + self.insert(key); + return {}; + } else { (void)self; (void)it; @@ -20347,89 +22027,89 @@ namespace sol { } } - static detail::error_result set_associative_find(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) { + static detail::error_result set_associative_find(std::true_type, lua_State* L_, T& self, stack_object okey, stack_object value) { decltype(auto) key = okey.as<K>(); auto it = self.find(key); - if (it == deferred_uc::end(L, self)) { - return set_associative_insert(is_associative(), L, self, it, key, std::move(value)); + if (it == deferred_uc::end(L_, self)) { + return set_associative_insert(is_associative(), L_, self, it, key, std::move(value)); } - return set_writable(is_writable(), L, self, it, std::move(value)); + return set_writable(is_writable(), L_, self, it, std::move(value)); } - static detail::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<K, key_type>(), L, self, std::move(key), std::move(value)); + static detail::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<K, key_type>(), L_, self, std::move(key), std::move(value)); } - static detail::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 detail::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 detail::error_result set_it(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) { - return set_associative_find(meta::all<has_find<T>, meta::any<is_associative, is_lookup>>(), L, self, std::move(key), std::move(value)); + static detail::error_result set_it(std::false_type, lua_State* L_, T& self, stack_object key, stack_object value) { + return set_associative_find(meta::all<has_find<T>, meta::any<is_associative, is_lookup>>(), L_, self, std::move(key), std::move(value)); } template <bool idx_of = false> - static detail::error_result find_has_associative_lookup(std::true_type, lua_State* L, T& self) { + static detail::error_result find_has_associative_lookup(std::true_type, lua_State* L_, T& self) { if constexpr (!is_ordered::value && idx_of) { - (void)L; + (void)L_; (void)self; return detail::error_result("cannot perform an 'index_of': '%s's is not an ordered container", detail::demangle<T>().data()); } else { - decltype(auto) key = stack::unqualified_get<K>(L, 2); + decltype(auto) key = stack::unqualified_get<K>(L_, 2); auto it = self.find(key); - if (it == deferred_uc::end(L, self)) { - return stack::push(L, lua_nil); + if (it == deferred_uc::end(L_, self)) { + return stack::push(L_, lua_nil); } if constexpr (idx_of) { - auto dist = std::distance(deferred_uc::begin(L, self), it); - dist -= deferred_uc::index_adjustment(L, self); - return stack::push(L, dist); + auto dist = std::distance(deferred_uc::begin(L_, self), it); + dist -= deferred_uc::index_adjustment(L_, self); + return stack::push(L_, dist); } else { - return get_associative(is_associative(), L, it); + return get_associative(is_associative(), L_, it); } } } template <bool idx_of = false> - static detail::error_result find_has_associative_lookup(std::false_type, lua_State* L, T& self) { + static detail::error_result find_has_associative_lookup(std::false_type, lua_State* L_, T& self) { if constexpr (!is_ordered::value && idx_of) { - (void)L; + (void)L_; (void)self; return detail::error_result("cannot perform an 'index_of': '%s's is not an ordered container", detail::demangle<T>().data()); } else { - decltype(auto) value = stack::unqualified_get<V>(L, 2); + decltype(auto) value = stack::unqualified_get<V>(L_, 2); auto it = self.find(value); - if (it == deferred_uc::end(L, self)) { - return stack::push(L, lua_nil); + if (it == deferred_uc::end(L_, self)) { + return stack::push(L_, lua_nil); } if constexpr (idx_of) { - auto dist = std::distance(deferred_uc::begin(L, self), it); - dist -= deferred_uc::index_adjustment(L, self); - return stack::push(L, dist); + auto dist = std::distance(deferred_uc::begin(L_, self), it); + dist -= deferred_uc::index_adjustment(L_, self); + return stack::push(L_, dist); } else { - return get_associative(is_associative(), L, it); + return get_associative(is_associative(), L_, it); } } } template <bool idx_of = false> - static detail::error_result find_has(std::true_type, lua_State* L, T& self) { - return find_has_associative_lookup<idx_of>(meta::any<is_lookup, is_associative>(), L, self); + static detail::error_result find_has(std::true_type, lua_State* L_, T& self) { + return find_has_associative_lookup<idx_of>(meta::any<is_lookup, is_associative>(), L_, self); } template <typename Iter> - static detail::error_result find_associative_lookup(std::true_type, lua_State* L, T&, Iter& it, std::size_t) { - return get_associative(is_associative(), L, it); + static detail::error_result find_associative_lookup(std::true_type, lua_State* L_, T&, Iter& it, std::size_t) { + return get_associative(is_associative(), L_, it); } template <typename Iter> - static detail::error_result find_associative_lookup(std::false_type, lua_State* L, T& self, Iter&, std::size_t idx) { - idx -= deferred_uc::index_adjustment(L, self); - return stack::push(L, idx); + static detail::error_result find_associative_lookup(std::false_type, lua_State* L_, T& self, Iter&, std::size_t idx) { + idx = static_cast<std::size_t>(static_cast<std::ptrdiff_t>(idx) - deferred_uc::index_adjustment(L_, self)); + return stack::push(L_, idx); } template <bool = false> @@ -20439,30 +22119,30 @@ namespace sol { } template <bool idx_of = false> - static detail::error_result find_comparative(std::true_type, lua_State* L, T& self) { - decltype(auto) value = stack::unqualified_get<V>(L, 2); - auto it = deferred_uc::begin(L, self); - auto e = deferred_uc::end(L, self); + static detail::error_result find_comparative(std::true_type, lua_State* L_, T& self) { + decltype(auto) value = stack::unqualified_get<V>(L_, 2); + auto it = deferred_uc::begin(L_, self); + auto e = deferred_uc::end(L_, self); std::size_t idx = 0; for (;; ++it, ++idx) { if (it == e) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } if (value == get_value(is_associative(), *it)) { break; } } - return find_associative_lookup(meta::all<meta::boolean<!idx_of>, meta::any<is_lookup, is_associative>>(), L, self, it, idx); + return find_associative_lookup(meta::all<meta::boolean<!idx_of>, meta::any<is_lookup, is_associative>>(), L_, self, it, idx); } template <bool idx_of = false> - static detail::error_result find_has(std::false_type, lua_State* L, T& self) { - return find_comparative<idx_of>(meta::supports_op_equal<V>(), L, self); + static detail::error_result find_has(std::false_type, lua_State* L_, T& self) { + return find_comparative<idx_of>(meta::supports_op_equal<V>(), L_, self); } template <typename Iter> - static detail::error_result add_insert_after(std::false_type, lua_State* L, T& self, stack_object value, Iter&) { - return add_insert_after(std::false_type(), L, self, value); + static detail::error_result add_insert_after(std::false_type, lua_State* L_, T& self, stack_object value, Iter&) { + return add_insert_after(std::false_type(), L_, self, value); } static detail::error_result add_insert_after(std::false_type, lua_State*, T&, stack_object) { @@ -20475,14 +22155,13 @@ namespace sol { return {}; } - static detail::error_result add_insert_after(std::true_type, lua_State* L, T& self, stack_object value) { + static detail::error_result add_insert_after(std::true_type, lua_State* L_, T& self, stack_object value) { auto backit = self.before_begin(); { - auto e = deferred_uc::end(L, self); - for (auto it = deferred_uc::begin(L, self); it != e; ++backit, ++it) { - } + auto e = deferred_uc::end(L_, self); + for (auto it = deferred_uc::begin(L_, self); it != e; ++backit, ++it) { } } - return add_insert_after(std::true_type(), L, self, value, backit); + return add_insert_after(std::true_type(), L_, self, value, backit); } template <typename Iter> @@ -20491,18 +22170,18 @@ namespace sol { return {}; } - static detail::error_result add_insert(std::true_type, lua_State* L, T& self, stack_object value) { - auto pos = deferred_uc::end(L, self); - return add_insert(std::true_type(), L, self, value, pos); + static detail::error_result add_insert(std::true_type, lua_State* L_, T& self, stack_object value) { + auto pos = deferred_uc::end(L_, self); + return add_insert(std::true_type(), L_, self, value, pos); } template <typename Iter> - static detail::error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value, Iter& pos) { - return add_insert_after(meta::has_insert_after<T>(), L, self, std::move(value), pos); + static detail::error_result add_insert(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) { + return add_insert_after(meta::has_insert_after<T>(), L_, self, std::move(value), pos); } - static detail::error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value) { - return add_insert_after(meta::has_insert_after<T>(), L, self, std::move(value)); + static detail::error_result add_insert(std::false_type, lua_State* L_, T& self, stack_object value) { + return add_insert_after(meta::has_insert_after<T>(), L_, self, std::move(value)); } template <typename Iter> @@ -20517,22 +22196,28 @@ namespace sol { } template <typename Iter> - static detail::error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value, Iter& pos) { - return add_insert(meta::has_insert<T>(), L, self, value, pos); + static detail::error_result add_push_back(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) { + return add_insert( + std::integral_constant < bool, meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), L_, self, value, pos); } - static detail::error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value) { - return add_insert(meta::has_insert<T>(), L, self, value); + static detail::error_result add_push_back(std::false_type, lua_State* L_, T& self, stack_object value) { + return add_insert( + std::integral_constant < bool, meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), L_, self, value); } template <typename Iter> - static detail::error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key, Iter& pos) { - if constexpr (meta::has_insert<T>::value) { - self.insert(pos, value_type(key.as<K>(), stack::unqualified_get<V>(L, 3))); + static detail::error_result add_associative(std::true_type, lua_State* L_, T& self, stack_object key, Iter& pos) { + if constexpr (meta::has_insert_with_iterator<T>::value) { + self.insert(pos, value_type(key.as<K>(), stack::unqualified_get<V>(L_, 3))); + return {}; + } + else if constexpr (meta::has_insert<T>::value) { + self.insert(value_type(key.as<K>(), stack::unqualified_get<V>(L_, 3))); return {}; } else { - (void)L; + (void)L_; (void)self; (void)key; (void)pos; @@ -20541,59 +22226,59 @@ namespace sol { } } - static detail::error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key) { - auto pos = deferred_uc::end(L, self); - return add_associative(std::true_type(), L, self, std::move(key), pos); + static detail::error_result add_associative(std::true_type, lua_State* L_, T& self, stack_object key) { + auto pos = deferred_uc::end(L_, self); + return add_associative(std::true_type(), L_, self, std::move(key), pos); } template <typename Iter> - static detail::error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value, Iter& pos) { - return add_push_back(meta::has_push_back<T>(), L, self, value, pos); + static detail::error_result add_associative(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) { + return add_push_back(meta::has_push_back<T>(), L_, self, value, pos); } - static detail::error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value) { - return add_push_back(meta::has_push_back<T>(), L, self, value); + static detail::error_result add_associative(std::false_type, lua_State* L_, T& self, stack_object value) { + return add_push_back(meta::has_push_back<T>(), L_, self, value); } template <typename Iter> - static detail::error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value, Iter& pos) { - return add_associative(is_associative(), L, self, std::move(value), pos); + static detail::error_result add_copyable(std::true_type, lua_State* L_, T& self, stack_object value, Iter& pos) { + return add_associative(is_associative(), L_, self, std::move(value), pos); } - static detail::error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value) { - return add_associative(is_associative(), L, self, value); + static detail::error_result add_copyable(std::true_type, lua_State* L_, T& self, stack_object value) { + return add_associative(is_associative(), L_, self, value); } template <typename Iter> - static detail::error_result add_copyable(std::false_type, lua_State* L, T& self, stack_object value, Iter&) { - return add_copyable(std::false_type(), L, self, std::move(value)); + static detail::error_result add_copyable(std::false_type, lua_State* L_, T& self, stack_object value, Iter&) { + return add_copyable(std::false_type(), L_, self, std::move(value)); } static detail::error_result add_copyable(std::false_type, lua_State*, T&, stack_object) { return detail::error_result("cannot call 'add' on '%s': value_type is non-copyable", detail::demangle<T>().data()); } - static detail::error_result insert_lookup(std::true_type, lua_State* L, T& self, stack_object, stack_object value) { + static detail::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? - return add_copyable(std::true_type(), L, self, std::move(value)); + return add_copyable(std::true_type(), L_, self, std::move(value)); } - static detail::error_result insert_lookup(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) { - auto it = deferred_uc::begin(L, self); + static detail::error_result insert_lookup(std::false_type, lua_State* L_, T& self, stack_object where, stack_object value) { + auto it = deferred_uc::begin(L_, self); auto key = where.as<K>(); - key += deferred_uc::index_adjustment(L, self); + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); std::advance(it, key); self.insert(it, value.as<V>()); return {}; } - static detail::error_result insert_after_has(std::true_type, lua_State* L, T& self, stack_object where, stack_object value) { + static detail::error_result insert_after_has(std::true_type, lua_State* L_, T& self, stack_object where, stack_object value) { auto key = where.as<K>(); auto backit = self.before_begin(); { - key += deferred_uc::index_adjustment(L, self); - auto e = deferred_uc::end(L, self); - for (auto it = deferred_uc::begin(L, self); key > 0; ++backit, ++it, --key) { + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); + auto e = deferred_uc::end(L_, self); + for (auto it = deferred_uc::begin(L_, self); key > 0; ++backit, ++it, --key) { if (backit == e) { return detail::error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); } @@ -20608,35 +22293,40 @@ namespace sol { "cannot call 'insert' on '%s': no suitable or similar functionality detected on this container", detail::demangle<T>().data()); } - static detail::error_result insert_has(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { - return insert_lookup(meta::any<is_associative, is_lookup>(), L, self, std::move(key), std::move(value)); + static detail::error_result insert_has(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) { + return insert_lookup(meta::any<is_associative, is_lookup>(), L_, self, std::move(key), std::move(value)); } - static detail::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<T>(), L, self, where, value); + static detail::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<T>(), L_, self, where, value); } - static detail::error_result insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { - return insert_has(meta::has_insert<T>(), L, self, std::move(key), std::move(value)); + static detail::error_result insert_copyable(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) { + return insert_has(std::integral_constant < bool, + meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), + L_, + self, + std::move(key), + std::move(value)); } static detail::error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) { return detail::error_result("cannot call 'insert' on '%s': value_type is non-copyable", detail::demangle<T>().data()); } - static detail::error_result erase_integral(std::true_type, lua_State* L, T& self, K& key) { - auto it = deferred_uc::begin(L, self); - key += deferred_uc::index_adjustment(L, self); + static detail::error_result erase_integral(std::true_type, lua_State* L_, T& self, K& key) { + auto it = deferred_uc::begin(L_, self); + key = (static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); std::advance(it, key); self.erase(it); return {}; } - static detail::error_result erase_integral(std::false_type, lua_State* L, T& self, const K& key) { + static detail::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 = deferred_uc::end(L, self); - auto it = std::find_if(deferred_uc::begin(L, self), e, std::ref(fx)); + auto e = deferred_uc::end(L_, self); + auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx)); if (it == e) { return {}; } @@ -20650,16 +22340,16 @@ namespace sol { return {}; } - static detail::error_result erase_associative_lookup(std::false_type, lua_State* L, T& self, K& key) { - return erase_integral(std::is_integral<K>(), L, self, key); + static detail::error_result erase_associative_lookup(std::false_type, lua_State* L_, T& self, K& key) { + return erase_integral(std::is_integral<K>(), L_, self, key); } - static detail::error_result erase_after_has(std::true_type, lua_State* L, T& self, K& key) { + static detail::error_result erase_after_has(std::true_type, lua_State* L_, T& self, K& key) { auto backit = self.before_begin(); { - key += deferred_uc::index_adjustment(L, self); - auto e = deferred_uc::end(L, self); - for (auto it = deferred_uc::begin(L, self); key > 0; ++backit, ++it, --key) { + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); + auto e = deferred_uc::end(L_, self); + for (auto it = deferred_uc::begin(L_, self); key > 0; ++backit, ++it, --key) { if (backit == e) { return detail::error_result("sol: out of bounds for erase on '%s'", detail::demangle<T>().c_str()); } @@ -20673,24 +22363,24 @@ namespace sol { return detail::error_result("sol: cannot call erase on '%s'", detail::demangle<T>().c_str()); } - static detail::error_result erase_key_has(std::true_type, lua_State* L, T& self, K& key) { - return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L, self, key); + static detail::error_result erase_key_has(std::true_type, lua_State* L_, T& self, K& key) { + return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L_, self, key); } - static detail::error_result erase_key_has(std::false_type, lua_State* L, T& self, K& key) { - return erase_after_has(has_erase_after<T>(), L, self, key); + static detail::error_result erase_key_has(std::false_type, lua_State* L_, T& self, K& key) { + return erase_after_has(has_erase_after<T>(), L_, self, key); } - static detail::error_result erase_has(std::true_type, lua_State* L, T& self, K& key) { - return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L, self, key); + static detail::error_result erase_has(std::true_type, lua_State* L_, T& self, K& key) { + return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L_, self, key); } - static detail::error_result erase_has(std::false_type, lua_State* L, T& self, K& key) { - return erase_key_has(has_erase_key<T>(), L, self, key); + static detail::error_result erase_has(std::false_type, lua_State* L_, T& self, K& key) { + return erase_key_has(has_erase_key<T>(), L_, self, key); } - static auto size_has(std::false_type, lua_State* L, T& self) { - return std::distance(deferred_uc::begin(L, self), deferred_uc::end(L, self)); + static auto size_has(std::false_type, lua_State* L_, T& self) { + return std::distance(deferred_uc::begin(L_, self), deferred_uc::end(L_, self)); } static auto size_has(std::true_type, lua_State*, T& self) { @@ -20701,196 +22391,196 @@ namespace sol { self.clear(); } - static void clear_has(std::false_type, lua_State* L, T&) { - luaL_error(L, "sol: cannot call clear on '%s'", detail::demangle<T>().c_str()); + static void clear_has(std::false_type, lua_State* L_, T&) { + luaL_error(L_, "sol: cannot call clear on '%s'", detail::demangle<T>().c_str()); } static bool empty_has(std::true_type, lua_State*, T& self) { return self.empty(); } - static bool empty_has(std::false_type, lua_State* L, T& self) { - return deferred_uc::begin(L, self) == deferred_uc::end(L, self); + static bool empty_has(std::false_type, lua_State* L_, T& self) { + return deferred_uc::begin(L_, self) == deferred_uc::end(L_, self); } - static detail::error_result get_associative_find(std::true_type, lua_State* L, T& self, K& key) { + static detail::error_result get_associative_find(std::true_type, lua_State* L_, T& self, K& key) { auto it = self.find(key); - if (it == deferred_uc::end(L, self)) { - stack::push(L, lua_nil); + if (it == deferred_uc::end(L_, self)) { + stack::push(L_, lua_nil); return {}; } - return get_associative(std::true_type(), L, it); + return get_associative(std::true_type(), L_, it); } - static detail::error_result get_associative_find(std::false_type, lua_State* L, T& self, K& key) { - return get_it(is_linear_integral(), L, self, key); + static detail::error_result get_associative_find(std::false_type, lua_State* L_, T& self, K& key) { + return get_it(is_linear_integral(), L_, self, key); } - static detail::error_result get_start(lua_State* L, T& self, K& key) { - return get_associative_find(std::integral_constant < bool, is_associative::value&& has_find<T>::value > (), L, self, key); + static detail::error_result get_start(lua_State* L_, T& self, K& key) { + return get_associative_find(std::integral_constant < bool, is_associative::value&& has_find<T>::value > (), L_, self, key); } - static detail::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 detail::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) { - return size_has(meta::has_size<T>(), L, self); + static std::size_t size_start(lua_State* L_, T& self) { + return static_cast<std::size_t>(size_has(meta::has_size<T>(), L_, self)); } - static void clear_start(lua_State* L, T& self) { - clear_has(has_clear<T>(), L, self); + static void clear_start(lua_State* L_, T& self) { + clear_has(has_clear<T>(), L_, self); } - static bool empty_start(lua_State* L, T& self) { - return empty_has(has_empty<T>(), L, self); + static bool empty_start(lua_State* L_, T& self) { + return empty_has(has_empty<T>(), L_, self); } - static detail::error_result erase_start(lua_State* L, T& self, K& key) { - return erase_has(has_erase<T>(), L, self, key); + static detail::error_result erase_start(lua_State* L_, T& self, K& key) { + return erase_has(has_erase<T>(), L_, self, key); } template <bool ip> - static int next_associative(std::true_type, lua_State* L) { - iter& i = stack::unqualified_get<user<iter>>(L, 1); + static int next_associative(std::true_type, lua_State* L_) { + iter& i = stack::unqualified_get<user<iter>>(L_, 1); auto& source = i.source; auto& it = i.it; - if (it == deferred_uc::end(L, source)) { - return stack::push(L, lua_nil); + if (it == deferred_uc::end(L_, source)) { + return stack::push(L_, lua_nil); } int p; if constexpr (ip) { - ++i.i; - p = stack::push_reference(L, i.i); + ++i.index; + p = stack::push_reference(L_, i.index); } else { - p = stack::push_reference(L, it->first); + p = stack::push_reference(L_, it->first); } - p += stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(it->second)); + p += stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(it->second)); std::advance(it, 1); return p; } template <bool> - static int next_associative(std::false_type, lua_State* L) { - iter& i = stack::unqualified_get<user<iter>>(L, 1); + static int next_associative(std::false_type, lua_State* L_) { + iter& i = stack::unqualified_get<user<iter>>(L_, 1); auto& source = i.source; auto& it = i.it; - next_K k = stack::unqualified_get<next_K>(L, 2); - if (it == deferred_uc::end(L, source)) { - return stack::push(L, lua_nil); + next_K k = stack::unqualified_get<next_K>(L_, 2); + if (it == deferred_uc::end(L_, source)) { + return stack::push(L_, lua_nil); } int p; if constexpr (std::is_integral_v<next_K>) { - p = stack::push_reference(L, k + 1); + p = stack::push_reference(L_, k + 1); } else { - p = stack::stack_detail::push_reference(L, k + 1); + p = stack::stack_detail::push_reference(L_, k + 1); } - p += stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(*it)); + p += stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(*it)); std::advance(it, 1); return p; } template <bool ip> - static int next_iter(lua_State* L) { + static int next_iter(lua_State* L_) { typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc; - return next_associative<ip>(is_assoc(), L); + return next_associative<ip>(is_assoc(), L_); } template <bool ip> - static int pairs_associative(std::true_type, lua_State* L) { - auto& src = get_src(L); - stack::push(L, next_iter<ip>); - stack::push<user<iter>>(L, src, deferred_uc::begin(L, src)); - stack::push(L, lua_nil); + static int pairs_associative(std::true_type, lua_State* L_) { + auto& src = get_src(L_); + stack::push(L_, next_iter<ip>); + stack::push<user<iter>>(L_, L_, 1, src, deferred_uc::begin(L_, src)); + stack::push(L_, lua_nil); return 3; } template <bool ip> - static int pairs_associative(std::false_type, lua_State* L) { - auto& src = get_src(L); - stack::push(L, next_iter<ip>); - stack::push<user<iter>>(L, src, deferred_uc::begin(L, src)); - stack::push(L, 0); + static int pairs_associative(std::false_type, lua_State* L_) { + auto& src = get_src(L_); + stack::push(L_, next_iter<ip>); + stack::push<user<iter>>(L_, L_, 1, src, deferred_uc::begin(L_, src)); + stack::push(L_, 0); return 3; } public: - static int at(lua_State* L) { - auto& self = get_src(L); + static int at(lua_State* L_) { + auto& self = get_src(L_); detail::error_result er; { - std::ptrdiff_t pos = stack::unqualified_get<std::ptrdiff_t>(L, 2); - er = at_start(L, self, pos); + std::ptrdiff_t pos = stack::unqualified_get<std::ptrdiff_t>(L_, 2); + er = at_start(L_, self, pos); } - return handle_errors(L, er); + return handle_errors(L_, er); } - static int get(lua_State* L) { - auto& self = get_src(L); + static int get(lua_State* L_) { + auto& self = get_src(L_); detail::error_result er; { - decltype(auto) key = stack::unqualified_get<K>(L); - er = get_start(L, self, key); + decltype(auto) key = stack::unqualified_get<K>(L_); + er = get_start(L_, self, key); } - return handle_errors(L, er); + return handle_errors(L_, er); } - static int index_get(lua_State* L) { - return get(L); + static int index_get(lua_State* L_) { + return get(L_); } - static int set(lua_State* L) { - stack_object value = stack_object(L, raw_index(3)); + static int set(lua_State* L_) { + stack_object value = stack_object(L_, raw_index(3)); if constexpr (is_linear_integral::value) { // for non-associative containers, // erasure only happens if it is the // last index in the container - auto key = stack::get<K>(L, 2); - auto self_size = deferred_uc::size(L); + auto key = stack::get<K>(L_, 2); + auto self_size = deferred_uc::size(L_); if (key == static_cast<K>(self_size)) { - if (type_of(L, 3) == type::lua_nil) { - return erase(L); + if (type_of(L_, 3) == type::lua_nil) { + return erase(L_); } } } else { - if (type_of(L, 3) == type::lua_nil) { - return erase(L); + if (type_of(L_, 3) == type::lua_nil) { + return erase(L_); } } - auto& self = get_src(L); - detail::error_result er = set_start(L, self, stack_object(L, raw_index(2)), std::move(value)); - return handle_errors(L, er); + auto& self = get_src(L_); + detail::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) { - return set(L); + static int index_set(lua_State* L_) { + return set(L_); } - static int add(lua_State* L) { - auto& self = get_src(L); - detail::error_result er = add_copyable(is_copyable(), L, self, stack_object(L, raw_index(2))); - return handle_errors(L, er); + static int add(lua_State* L_) { + auto& self = get_src(L_); + detail::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); - detail::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 insert(lua_State* L_) { + auto& self = get_src(L_); + detail::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); - detail::error_result er = find_has(has_find<T>(), L, self); - return handle_errors(L, er); + static int find(lua_State* L_) { + auto& self = get_src(L_); + detail::error_result er = find_has(has_find<T>(), L_, self); + return handle_errors(L_, er); } - static int index_of(lua_State* L) { - auto& self = get_src(L); - detail::error_result er = find_has<true>(has_find<T>(), L, self); - return handle_errors(L, er); + static int index_of(lua_State* L_) { + auto& self = get_src(L_); + detail::error_result er = find_has<true>(has_find<T>(), L_, self); + return handle_errors(L_, er); } static iterator begin(lua_State*, T& self) { @@ -20913,49 +22603,49 @@ namespace sol { } } - static int size(lua_State* L) { - auto& self = get_src(L); - std::size_t r = size_start(L, self); - return stack::push(L, r); + static int size(lua_State* L_) { + auto& self = get_src(L_); + std::size_t r = size_start(L_, self); + return stack::push(L_, r); } - static int clear(lua_State* L) { - auto& self = get_src(L); - clear_start(L, self); + static int clear(lua_State* L_) { + auto& self = get_src(L_); + clear_start(L_, self); return 0; } - static int erase(lua_State* L) { - auto& self = get_src(L); + static int erase(lua_State* L_) { + auto& self = get_src(L_); detail::error_result er; { - decltype(auto) key = stack::unqualified_get<K>(L, 2); - er = erase_start(L, self, key); + decltype(auto) key = stack::unqualified_get<K>(L_, 2); + er = erase_start(L_, self, key); } - return handle_errors(L, er); + return handle_errors(L_, er); } - static int empty(lua_State* L) { - auto& self = get_src(L); - return stack::push(L, empty_start(L, self)); + static int empty(lua_State* L_) { + auto& self = get_src(L_); + return stack::push(L_, empty_start(L_, self)); } static std::ptrdiff_t index_adjustment(lua_State*, T&) { return static_cast<std::ptrdiff_t>((SOL_CONTAINER_START_INDEX_I_) == 0 ? 0 : -(SOL_CONTAINER_START_INDEX_I_)); } - static int pairs(lua_State* L) { + static int pairs(lua_State* L_) { typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc; - return pairs_associative<false>(is_assoc(), L); + return pairs_associative<false>(is_assoc(), L_); } - static int ipairs(lua_State* L) { + static int ipairs(lua_State* L_) { typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc; - return pairs_associative<true>(is_assoc(), L); + return pairs_associative<true>(is_assoc(), L_); } - static int next(lua_State* L) { - return stack::push(L, next_iter<false>); + static int next(lua_State* L_) { + return stack::push(L_, next_iter<false>); } }; @@ -20971,146 +22661,152 @@ namespace sol { private: struct iter { + reference keep_alive; T& source; iterator it; - iter(T& source, iterator it) : source(source), it(std::move(it)) { + iter(lua_State* L_, int stack_index, T& source, iterator it) noexcept + : keep_alive(sol::main_thread(L_, L_), stack_index), source(source), it(std::move(it)) { + } + + ~iter() { + } }; - static auto& get_src(lua_State* L) { - auto p = stack::unqualified_check_get<T*>(L, 1); -#if SOL_IS_ON(SOL_SAFE_USERTYPE_I_) + static auto& get_src(lua_State* L_) { + auto p = stack::unqualified_check_get<T*>(L_, 1); +#if SOL_IS_ON(SOL_SAFE_USERTYPE) if (!p) { - luaL_error(L, + luaL_error(L_, "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle<T>().c_str()); } if (p.value() == nullptr) { luaL_error( - L, "sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)", detail::demangle<T>().c_str()); + L_, "sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)", detail::demangle<T>().c_str()); } #endif // Safe getting with error return *p.value(); } - static int find(std::true_type, lua_State* L) { - T& self = get_src(L); - decltype(auto) value = stack::unqualified_get<value_type>(L, 2); + static int find(std::true_type, lua_State* L_) { + T& self = get_src(L_); + decltype(auto) value = stack::unqualified_get<value_type>(L_, 2); std::size_t N = std::extent<T>::value; for (std::size_t idx = 0; idx < N; ++idx) { using v_t = std::add_const_t<decltype(self[idx])>; v_t v = self[idx]; if (v == value) { - idx -= deferred_uc::index_adjustment(L, self); - return stack::push(L, idx); + idx = static_cast<std::size_t>(static_cast<std::ptrdiff_t>(idx) - deferred_uc::index_adjustment(L_, self)); + return stack::push(L_, idx); } } - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } - static int find(std::false_type, lua_State* L) { - return luaL_error(L, "sol: cannot call 'find' on '%s': no supported comparison operator for the value type", detail::demangle<T>().c_str()); + static int find(std::false_type, lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'find' on '%s': no supported comparison operator for the value type", detail::demangle<T>().c_str()); } - static int next_iter(lua_State* L) { - iter& i = stack::unqualified_get<user<iter>>(L, 1); + static int next_iter(lua_State* L_) { + iter& i = stack::unqualified_get<user<iter>>(L_, 1); auto& source = i.source; auto& it = i.it; - std::size_t k = stack::unqualified_get<std::size_t>(L, 2); - if (it == deferred_uc::end(L, source)) { + std::size_t k = stack::unqualified_get<std::size_t>(L_, 2); + if (it == deferred_uc::end(L_, source)) { return 0; } int p; - p = stack::push(L, k + 1); - p += stack::push_reference(L, detail::deref_move_only(*it)); + p = stack::push(L_, k + 1); + p += stack::push_reference(L_, detail::deref_move_only(*it)); std::advance(it, 1); return p; } public: - static int clear(lua_State* L) { - return luaL_error(L, "sol: cannot call 'clear' on type '%s': cannot remove all items from a fixed array", detail::demangle<T>().c_str()); + static int clear(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'clear' on type '%s': cannot remove all items from a fixed array", detail::demangle<T>().c_str()); } - static int erase(lua_State* L) { - return luaL_error(L, "sol: cannot call 'erase' on type '%s': cannot remove an item from fixed arrays", detail::demangle<T>().c_str()); + static int erase(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'erase' on type '%s': cannot remove an item from fixed arrays", detail::demangle<T>().c_str()); } - static int add(lua_State* L) { - return luaL_error(L, "sol: cannot call 'add' on type '%s': cannot add to fixed arrays", detail::demangle<T>().c_str()); + static int add(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'add' on type '%s': cannot add to fixed arrays", detail::demangle<T>().c_str()); } - static int insert(lua_State* L) { - return luaL_error(L, "sol: cannot call 'insert' on type '%s': cannot insert new entries into fixed arrays", detail::demangle<T>().c_str()); + static int insert(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'insert' on type '%s': cannot insert new entries into fixed arrays", detail::demangle<T>().c_str()); } - static int at(lua_State* L) { - return get(L); + static int at(lua_State* L_) { + return get(L_); } - static int get(lua_State* L) { - T& self = get_src(L); - std::ptrdiff_t idx = stack::unqualified_get<std::ptrdiff_t>(L, 2); - idx += deferred_uc::index_adjustment(L, self); + static int get(lua_State* L_) { + T& self = get_src(L_); + std::ptrdiff_t idx = stack::unqualified_get<std::ptrdiff_t>(L_, 2); + idx += deferred_uc::index_adjustment(L_, self); if (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value) || idx < 0) { - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } - return stack::push_reference(L, detail::deref_move_only(self[idx])); + return stack::push_reference(L_, detail::deref_move_only(self[idx])); } - static int index_get(lua_State* L) { - return get(L); + static int index_get(lua_State* L_) { + return get(L_); } - static int set(lua_State* L) { - T& self = get_src(L); - std::ptrdiff_t idx = stack::unqualified_get<std::ptrdiff_t>(L, 2); - idx += deferred_uc::index_adjustment(L, self); + static int set(lua_State* L_) { + T& self = get_src(L_); + std::ptrdiff_t idx = stack::unqualified_get<std::ptrdiff_t>(L_, 2); + idx += deferred_uc::index_adjustment(L_, self); if (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value)) { - return luaL_error(L, "sol: index out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); + return luaL_error(L_, "sol: index out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); } if (idx < 0) { - return luaL_error(L, "sol: index out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str()); + return luaL_error(L_, "sol: index out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str()); } - self[idx] = stack::unqualified_get<value_type>(L, 3); + self[idx] = stack::unqualified_get<value_type>(L_, 3); return 0; } - static int index_set(lua_State* L) { - return set(L); + static int index_set(lua_State* L_) { + return set(L_); } - static int index_of(lua_State* L) { - return find(L); + static int index_of(lua_State* L_) { + return find(L_); } - static int find(lua_State* L) { - return find(meta::supports_op_equal<value_type, value_type>(), L); + static int find(lua_State* L_) { + return find(meta::supports_op_equal<value_type, value_type>(), L_); } - static int size(lua_State* L) { - return stack::push(L, std::extent<T>::value); + static int size(lua_State* L_) { + return stack::push(L_, std::extent<T>::value); } - static int empty(lua_State* L) { - return stack::push(L, std::extent<T>::value > 0); + static int empty(lua_State* L_) { + return stack::push(L_, std::extent<T>::value > 0); } - static int pairs(lua_State* L) { - auto& src = get_src(L); - stack::push(L, next_iter); - stack::push<user<iter>>(L, src, deferred_uc::begin(L, src)); - stack::push(L, 0); + static int pairs(lua_State* L_) { + auto& src = get_src(L_); + stack::push(L_, next_iter); + stack::push<user<iter>>(L_, L_, 1, src, deferred_uc::begin(L_, src)); + stack::push(L_, 0); return 3; } - static int ipairs(lua_State* L) { - return pairs(L); + static int ipairs(lua_State* L_) { + return pairs(L_); } - static int next(lua_State* L) { - return stack::push(L, next_iter); + static int next(lua_State* L_) { + return stack::push(L_, next_iter); } static std::ptrdiff_t index_adjustment(lua_State*, T&) { @@ -21127,11 +22823,11 @@ namespace sol { }; template <typename X> - struct usertype_container_default<usertype_container<X>> : usertype_container_default<X> {}; + struct usertype_container_default<usertype_container<X>> : usertype_container_default<X> { }; } // namespace container_detail template <typename T> - struct usertype_container : container_detail::usertype_container_default<T> {}; + struct usertype_container : container_detail::usertype_container_default<T> { }; } // namespace sol @@ -21460,7 +23156,7 @@ namespace sol { { "find", &meta_usertype_container::find_call }, { "index_of", &meta_usertype_container::index_of_call }, { "erase", &meta_usertype_container::erase_call }, - std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct<T> }, + std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy<T> }, { nullptr, nullptr } // clang-format on } }; @@ -21576,6 +23272,12 @@ namespace sol { return s; } +#if SOL_IS_ON(SOL_CHAR8_T) + inline auto make_string_view(const char8_t* s) { + return string_view(reinterpret_cast<const char*>(s)); + } +#endif + inline auto make_string_view(call_construction) { return string_view(to_string(meta_function::call_function)); } @@ -21658,15 +23360,19 @@ namespace sol { } } if (fx(meta_function::to_string)) { - if constexpr (is_to_stringable<T>::value) { - auto f = &detail::static_trampoline<&default_to_string<T>>; - ifx(meta_function::to_string, f); + if constexpr (is_to_stringable_v<T>) { + if constexpr (!meta::is_probably_stateless_lambda_v<T> && !std::is_member_pointer_v<T>) { + auto f = &detail::static_trampoline<&default_to_string<T>>; + ifx(meta_function::to_string, f); + } } } if (fx(meta_function::call_function)) { - if constexpr (meta::has_deducible_signature<T>::value) { - auto f = &c_call<decltype(&T::operator()), &T::operator()>; - ifx(meta_function::call_function, f); + if constexpr (is_callable_v<T>) { + if constexpr (meta::call_operator_deducible_v<T>) { + auto f = &c_call<decltype(&T::operator()), &T::operator()>; + ifx(meta_function::call_function, f); + } } } } @@ -21682,12 +23388,12 @@ namespace sol { t.push(); - detail::lua_reg_table l{}; + detail::lua_reg_table l {}; int index = 0; detail::indexed_insert insert_fx(l, index); detail::insert_default_registrations<T>(insert_fx, detail::property_always_true); if constexpr (!std::is_pointer_v<X>) { - l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() }; + l[index] = luaL_Reg { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() }; } luaL_setfuncs(L, l, 0); @@ -21712,6 +23418,7 @@ namespace sol { #include <bitset> #include <unordered_map> +#include <memory> namespace sol { namespace u_detail { @@ -21719,16 +23426,16 @@ namespace sol { namespace u_detail { template <typename T> struct usertype_storage; - optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, int index); - usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey); + optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L_, int index); + usertype_storage_base& get_usertype_storage_base(lua_State* L_, const char* gcmetakey); template <typename T> - optional<usertype_storage<T>&> maybe_get_usertype_storage(lua_State* L); + optional<usertype_storage<T>&> maybe_get_usertype_storage(lua_State* L_); template <typename T> - usertype_storage<T>& get_usertype_storage(lua_State* L); + usertype_storage<T>& get_usertype_storage(lua_State* L_); using index_call_function = int(lua_State*, void*); - using change_indexing_mem_func - = void (usertype_storage_base::*)(lua_State*, submetatable_type, void*, stack_reference&, lua_CFunction, lua_CFunction, lua_CFunction, lua_CFunction); + using change_indexing_mem_func = void (usertype_storage_base::*)( + lua_State*, submetatable_type, void*, stateless_stack_reference&, lua_CFunction, lua_CFunction, lua_CFunction, lua_CFunction); struct index_call_storage { index_call_function* index; @@ -21750,7 +23457,7 @@ namespace sol { namespace u_detail { struct binding : binding_base { using uF = meta::unqualified_t<Fq>; using F = meta::conditional_t<meta::is_c_str_of_v<uF, char> -#ifdef __cpp_char8_t +#if SOL_IS_ON(SOL_CHAR8_T) || meta::is_c_str_of_v<uF, char8_t> #endif || meta::is_c_str_of_v<uF, char16_t> || meta::is_c_str_of_v<uF, char32_t> || meta::is_c_str_of_v<uF, wchar_t>, @@ -21766,23 +23473,23 @@ namespace sol { namespace u_detail { } template <bool is_index = true, bool is_variable = false> - static inline int call_with_(lua_State* L, void* target) { + static inline int call_with_(lua_State* L_, void* target) { constexpr int boost = !detail::is_non_factory_constructor<F>::value && std::is_same<K, call_construction>::value ? 1 : 0; auto& f = *static_cast<F*>(target); - return call_detail::call_wrapped<T, is_index, is_variable, boost>(L, f); + return call_detail::call_wrapped<T, is_index, is_variable, boost>(L_, f); } template <bool is_index = true, bool is_variable = false> - static inline int call_(lua_State* L) { - void* f = stack::get<void*>(L, upvalue_index(usertype_storage_index)); - return call_with_<is_index, is_variable>(L, f); + static inline int call_(lua_State* L_) { + void* f = stack::get<void*>(L_, upvalue_index(usertype_storage_index)); + return call_with_<is_index, is_variable>(L_, f); } template <bool is_index = true, bool is_variable = false> - static inline int call(lua_State* L) { - int r = detail::typed_static_trampoline<decltype(&call_<is_index, is_variable>), (&call_<is_index, is_variable>)>(L); + static inline int call(lua_State* L_) { + int r = detail::typed_static_trampoline<decltype(&call_<is_index, is_variable>), (&call_<is_index, is_variable>)>(L_); if constexpr (meta::is_specialization_of_v<uF, yielding_t>) { - return lua_yield(L, r); + return lua_yield(L_, r); } else { return r; @@ -21790,40 +23497,40 @@ namespace sol { namespace u_detail { } template <bool is_index = true, bool is_variable = false> - static inline int index_call_with_(lua_State* L, void* target) { + static inline int index_call_with_(lua_State* L_, void* target) { if constexpr (!is_variable) { if constexpr (is_lua_c_function_v<std::decay_t<F>>) { auto& f = *static_cast<std::decay_t<F>*>(target); - return stack::push(L, f); + return stack::push(L_, f); } else { // set up upvalues // for a chained call int upvalues = 0; - upvalues += stack::push(L, nullptr); - upvalues += stack::push(L, target); + upvalues += stack::push(L_, nullptr); + upvalues += stack::push(L_, target); auto cfunc = &call<is_index, is_variable>; - return stack::push(L, c_closure(cfunc, upvalues)); + return stack::push(L_, c_closure(cfunc, upvalues)); } } else { constexpr int boost = !detail::is_non_factory_constructor<F>::value && std::is_same<K, call_construction>::value ? 1 : 0; auto& f = *static_cast<F*>(target); - return call_detail::call_wrapped<T, is_index, is_variable, boost>(L, f); + return call_detail::call_wrapped<T, is_index, is_variable, boost>(L_, f); } } template <bool is_index = true, bool is_variable = false> - static inline int index_call_(lua_State* L) { - void* f = stack::get<void*>(L, upvalue_index(usertype_storage_index)); - return index_call_with_<is_index, is_variable>(L, f); + static inline int index_call_(lua_State* L_) { + void* f = stack::get<void*>(L_, upvalue_index(usertype_storage_index)); + return index_call_with_<is_index, is_variable>(L_, f); } template <bool is_index = true, bool is_variable = false> - static inline int index_call(lua_State* L) { - int r = detail::typed_static_trampoline<decltype(&index_call_<is_index, is_variable>), (&index_call_<is_index, is_variable>)>(L); + static inline int index_call(lua_State* L_) { + int r = detail::typed_static_trampoline<decltype(&index_call_<is_index, is_variable>), (&index_call_<is_index, is_variable>)>(L_); if constexpr (meta::is_specialization_of_v<uF, yielding_t>) { - return lua_yield(L, r); + return lua_yield(L_, r); } else { return r; @@ -21831,28 +23538,28 @@ namespace sol { namespace u_detail { } }; - inline int index_fail(lua_State* L) { - if (lua_getmetatable(L, 1) == 1) { - int metatarget = lua_gettop(L); - stack::get_field<false, true>(L, stack_reference(L, raw_index(2)), metatarget); + inline int index_fail(lua_State* L_) { + if (lua_getmetatable(L_, 1) == 1) { + int metatarget = lua_gettop(L_); + stack::get_field<false, true>(L_, stack_reference(L_, raw_index(2)), metatarget); return 1; } // With runtime extensibility, we can't // hard-error things. They have to // return nil, like regular table types - return stack::push(L, lua_nil); + return stack::push(L_, lua_nil); } - inline int index_target_fail(lua_State* L, void*) { - return index_fail(L); + inline int index_target_fail(lua_State* L_, void*) { + return index_fail(L_); } - inline int new_index_fail(lua_State* L) { - return luaL_error(L, "sol: cannot set (new_index) into this object: no defined new_index operation on usertype"); + inline int new_index_fail(lua_State* L_) { + return luaL_error(L_, "sol: cannot set (new_index) into this object: no defined new_index operation on usertype"); } - inline int new_index_target_fail(lua_State* L, void*) { - return new_index_fail(L); + inline int new_index_target_fail(lua_State* L_, void*) { + return new_index_fail(L_); } struct string_for_each_metatable_func { @@ -21873,50 +23580,50 @@ namespace sol { namespace u_detail { lua_CFunction idx_call = nullptr, new_idx_call = nullptr, meta_idx_call = nullptr, meta_new_idx_call = nullptr; change_indexing_mem_func change_indexing; - void operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) { + void operator()(lua_State* L_, submetatable_type smt_, stateless_reference& fast_index_table_) { std::string& key = *p_key; usertype_storage_base& usb = *p_usb; index_call_storage& ics = *p_ics; - if (smt == submetatable_type::named) { + if (smt_ == submetatable_type::named) { // do not override __call or // other specific meta functions on named metatable: // we need that for call construction // and other amenities return; } - int fast_index_table_push = fast_index_table.push(); - stack_reference t(L, -fast_index_table_push); + int fast_index_table_push = fast_index_table_.push(L_); + stateless_stack_reference t(L_, -fast_index_table_push); if (poison_indexing) { - (usb.*change_indexing)(L, smt, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call); + (usb.*change_indexing)(L_, smt_, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call); } if (is_destruction - && (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named - || smt == submetatable_type::unique)) { + && (smt_ == submetatable_type::reference || smt_ == submetatable_type::const_reference || smt_ == submetatable_type::named + || smt_ == submetatable_type::unique)) { // gc does not apply to us here // for reference types (raw T*, std::ref) // for the named metatable itself, - // or for unique_usertypes, which do their own custom destruction - t.pop(); + // or for unique_usertypes, which do their own custom destroyion + t.pop(L_); return; } if (is_index || is_new_index || is_static_index || is_static_new_index) { // do not serialize the new_index and index functions here directly // we control those... - t.pop(); + t.pop(L_); return; } if (is_unqualified_lua_CFunction) { - stack::set_field<false, true>(L, key, call_func, t.stack_index()); + stack::set_field<false, true>(L_, key, call_func, t.stack_index()); } else if (is_unqualified_lua_reference) { reference& binding_ref = *p_binding_ref; - stack::set_field<false, true>(L, key, binding_ref, t.stack_index()); + stack::set_field<false, true>(L_, key, binding_ref, t.stack_index()); } else { - stack::set_field<false, true>(L, key, make_closure(call_func, nullptr, ics.binding_data), t.stack_index()); + stack::set_field<false, true>(L_, key, make_closure(call_func, nullptr, ics.binding_data), t.stack_index()); } - t.pop(); + t.pop(L_); } }; @@ -21924,14 +23631,14 @@ namespace sol { namespace u_detail { reference key; reference value; - void operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) { - if (smt == submetatable_type::named) { + void operator()(lua_State* L_, submetatable_type smt_, stateless_reference& fast_index_table_) { + if (smt_ == submetatable_type::named) { return; } - int fast_index_table_push = fast_index_table.push(); - stack_reference t(L, -fast_index_table_push); - stack::set_field<false, true>(L, key, value, t.stack_index()); - t.pop(); + int fast_index_table_push = fast_index_table_.push(L_); + stateless_stack_reference t(L_, -fast_index_table_push); + stack::set_field<false, true>(L_, key, value, t.stack_index()); + t.pop(L_); } }; @@ -21943,14 +23650,14 @@ namespace sol { namespace u_detail { void* p_derived_usb; change_indexing_mem_func change_indexing; - void operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) { - int fast_index_table_push = fast_index_table.push(); - stack_reference t(L, -fast_index_table_push); - stack::set_field(L, detail::base_class_check_key(), reinterpret_cast<void*>(base_class_check_func), t.stack_index()); - stack::set_field(L, detail::base_class_cast_key(), reinterpret_cast<void*>(base_class_cast_func), t.stack_index()); + void operator()(lua_State* L_, submetatable_type smt_, stateless_reference& fast_index_table_) { + int fast_index_table_push = fast_index_table_.push(L_); + stateless_stack_reference t(L_, -fast_index_table_push); + stack::set_field(L_, detail::base_class_check_key(), reinterpret_cast<void*>(base_class_check_func), t.stack_index()); + stack::set_field(L_, detail::base_class_cast_key(), reinterpret_cast<void*>(base_class_cast_func), t.stack_index()); // change indexing, forcefully - (p_usb->*change_indexing)(L, smt, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call); - t.pop(); + (p_usb->*change_indexing)(L_, smt_, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call); + t.pop(L_); } }; @@ -21967,36 +23674,41 @@ namespace sol { namespace u_detail { struct usertype_storage_base { public: + lua_State* m_L; std::vector<std::unique_ptr<binding_base>> storage; std::vector<std::unique_ptr<char[]>> string_keys_storage; std::unordered_map<string_view, index_call_storage> string_keys; - std::unordered_map<reference, reference, reference_hash, reference_equals> auxiliary_keys; - reference value_index_table; - reference reference_index_table; - reference unique_index_table; - reference const_reference_index_table; - reference const_value_index_table; - reference named_index_table; - reference type_table; - reference gc_names_table; - reference named_metatable; + std::unordered_map<stateless_reference, stateless_reference, stateless_reference_hash, stateless_reference_equals> auxiliary_keys; + stateless_reference value_index_table; + stateless_reference reference_index_table; + stateless_reference unique_index_table; + stateless_reference const_reference_index_table; + stateless_reference const_value_index_table; + stateless_reference named_index_table; + stateless_reference type_table; + stateless_reference gc_names_table; + stateless_reference named_metatable; new_index_call_storage base_index; new_index_call_storage static_base_index; bool is_using_index; bool is_using_new_index; std::bitset<64> properties; - usertype_storage_base(lua_State* L) - : storage() + usertype_storage_base(lua_State* L_) + : m_L(L_) + , storage() + , string_keys_storage() , string_keys() - , auxiliary_keys() + , auxiliary_keys(0, stateless_reference_hash(L_), stateless_reference_equals(L_)) , value_index_table() , reference_index_table() , unique_index_table() , const_reference_index_table() - , type_table(make_reference(L, create)) - , gc_names_table(make_reference(L, create)) - , named_metatable(make_reference(L, create)) + , const_value_index_table() + , named_index_table() + , type_table(make_reference<stateless_reference>(L_, create)) + , gc_names_table(make_reference<stateless_reference>(L_, create)) + , named_metatable(make_reference<stateless_reference>(L_, create)) , base_index() , static_base_index() , is_using_index(false) @@ -22013,10 +23725,10 @@ namespace sol { namespace u_detail { } template <typename Fx> - void for_each_table(lua_State* L, Fx&& fx) { + void for_each_table(lua_State* L_, Fx&& fx) { for (int i = 0; i < 6; ++i) { submetatable_type smt = static_cast<submetatable_type>(i); - reference* p_fast_index_table = nullptr; + stateless_reference* p_fast_index_table = nullptr; switch (smt) { case submetatable_type::const_value: p_fast_index_table = &this->const_value_index_table; @@ -22038,7 +23750,7 @@ namespace sol { namespace u_detail { p_fast_index_table = &this->value_index_table; break; } - fx(L, smt, *p_fast_index_table); + fx(L_, smt, *p_fast_index_table); } } @@ -22051,7 +23763,7 @@ namespace sol { namespace u_detail { } template <typename T, typename... Bases> - void update_bases(lua_State* L, bases<Bases...>) { + void update_bases(lua_State* L_, bases<Bases...>) { 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."); @@ -22059,93 +23771,94 @@ namespace sol { namespace u_detail { "The size of this data pointer is too small to fit the inheritance checking function: Please file " "a bug report."); static_assert(!meta::any_same<T, Bases...>::value, "base classes cannot list the original class as part of the bases"); - if constexpr (sizeof...(Bases) < 1) { - return; + if constexpr (sizeof...(Bases) > 0) { + (void)detail::swallow { 0, ((weak_derive<Bases>::value = true), 0)... }; + + void* derived_this = static_cast<void*>(static_cast<usertype_storage<T>*>(this)); + + update_bases_func for_each_fx; + for_each_fx.base_class_check_func = &detail::inheritance<T>::template type_check_with<Bases...>; + for_each_fx.base_class_cast_func = &detail::inheritance<T>::template type_cast_with<Bases...>; + for_each_fx.idx_call = &usertype_storage<T>::template index_call_with_bases<false, Bases...>; + for_each_fx.new_idx_call = &usertype_storage<T>::template index_call_with_bases<true, Bases...>; + for_each_fx.meta_idx_call = &usertype_storage<T>::template meta_index_call_with_bases<false, Bases...>; + for_each_fx.meta_new_idx_call = &usertype_storage<T>::template meta_index_call_with_bases<true, Bases...>; + for_each_fx.p_usb = this; + for_each_fx.p_derived_usb = derived_this; + for_each_fx.change_indexing = &usertype_storage_base::change_indexing; + for_each_fx.p_derived_usb = derived_this; + this->for_each_table(L_, for_each_fx); + } + else { + (void)L_; } - - (void)detail::swallow { 0, ((weak_derive<Bases>::value = true), 0)... }; - - void* derived_this = static_cast<void*>(static_cast<usertype_storage<T>*>(this)); - - update_bases_func for_each_fx; - for_each_fx.base_class_check_func = &detail::inheritance<T>::template type_check_with<Bases...>; - for_each_fx.base_class_cast_func = &detail::inheritance<T>::template type_cast_with<Bases...>; - for_each_fx.idx_call = &usertype_storage<T>::template index_call_with_bases<false, Bases...>; - for_each_fx.new_idx_call = &usertype_storage<T>::template index_call_with_bases<true, Bases...>; - for_each_fx.meta_idx_call = &usertype_storage<T>::template meta_index_call_with_bases<false, Bases...>; - for_each_fx.meta_new_idx_call = &usertype_storage<T>::template meta_index_call_with_bases<true, Bases...>; - for_each_fx.p_usb = this; - for_each_fx.p_derived_usb = derived_this; - for_each_fx.change_indexing = &usertype_storage_base::change_indexing; - for_each_fx.p_derived_usb = derived_this; - this->for_each_table(L, for_each_fx); } void clear() { - if (value_index_table.valid()) { - stack::clear(value_index_table); + if (value_index_table.valid(m_L)) { + stack::clear(m_L, value_index_table); } - if (reference_index_table.valid()) { - stack::clear(reference_index_table); + if (reference_index_table.valid(m_L)) { + stack::clear(m_L, reference_index_table); } - if (unique_index_table.valid()) { - stack::clear(unique_index_table); + if (unique_index_table.valid(m_L)) { + stack::clear(m_L, unique_index_table); } - if (const_reference_index_table.valid()) { - stack::clear(const_reference_index_table); + if (const_reference_index_table.valid(m_L)) { + stack::clear(m_L, const_reference_index_table); } - if (const_value_index_table.valid()) { - stack::clear(const_value_index_table); + if (const_value_index_table.valid(m_L)) { + stack::clear(m_L, const_value_index_table); } - if (named_index_table.valid()) { - stack::clear(named_index_table); + if (named_index_table.valid(m_L)) { + stack::clear(m_L, named_index_table); } - if (type_table.valid()) { - stack::clear(type_table); + if (type_table.valid(m_L)) { + stack::clear(m_L, type_table); } - if (gc_names_table.valid()) { - stack::clear(gc_names_table); + if (gc_names_table.valid(m_L)) { + stack::clear(m_L, gc_names_table); } - if (named_metatable.valid()) { - lua_State* L = named_metatable.lua_state(); - auto pp = stack::push_pop(named_metatable); + if (named_metatable.valid(m_L)) { + auto pp = stack::push_pop(m_L, named_metatable); int named_metatable_index = pp.index_of(named_metatable); - if (lua_getmetatable(L, named_metatable_index) == 1) { - stack::clear(L, absolute_index(L, -1)); + if (lua_getmetatable(m_L, named_metatable_index) == 1) { + stack::clear(m_L, absolute_index(m_L, -1)); } - stack::clear(named_metatable); + stack::clear(m_L, named_metatable); } - value_index_table = lua_nil; - reference_index_table = lua_nil; - unique_index_table = lua_nil; - const_reference_index_table = lua_nil; - const_value_index_table = lua_nil; - named_index_table = lua_nil; - type_table = lua_nil; - gc_names_table = lua_nil; - named_metatable = lua_nil; + value_index_table.reset(m_L); + reference_index_table.reset(m_L); + unique_index_table.reset(m_L); + const_reference_index_table.reset(m_L); + const_value_index_table.reset(m_L); + named_index_table.reset(m_L); + type_table.reset(m_L); + gc_names_table.reset(m_L); + named_metatable.reset(m_L); storage.clear(); string_keys.clear(); auxiliary_keys.clear(); + string_keys_storage.clear(); } template <bool is_new_index, typename Base> - static void base_walk_index(lua_State* L, usertype_storage_base& self, bool& keep_going, int& base_result) { + static void base_walk_index(lua_State* L_, usertype_storage_base& self, bool& keep_going, int& base_result) { using bases = typename base<Base>::type; if (!keep_going) { return; } - (void)L; + (void)L_; (void)self; -#if SOL_IS_ON(SOL_USE_UNSAFE_BASE_LOOKUP_I_) - usertype_storage_base& base_storage = get_usertype_storage<Base>(L); - base_result = self_index_call<is_new_index, true>(bases(), L, base_storage); +#if SOL_IS_ON(SOL_USE_UNSAFE_BASE_LOOKUP) + usertype_storage_base& base_storage = get_usertype_storage<Base>(L_); + base_result = self_index_call<is_new_index, true>(bases(), L_, base_storage); #else - optional<usertype_storage<Base>&> maybe_base_storage = maybe_get_usertype_storage<Base>(L); + optional<usertype_storage<Base>&> maybe_base_storage = maybe_get_usertype_storage<Base>(L_); if (static_cast<bool>(maybe_base_storage)) { - base_result = self_index_call<is_new_index, true>(bases(), L, *maybe_base_storage); + base_result = self_index_call<is_new_index, true>(bases(), L_, *maybe_base_storage); keep_going = base_result == base_walking_failed_index; } #endif // Fast versus slow, safe base lookup @@ -22153,45 +23866,47 @@ namespace sol { namespace u_detail { template <bool is_new_index = false, bool base_walking = false, bool from_named_metatable = false, typename... Bases> static inline int self_index_call(types<Bases...>, lua_State* L, usertype_storage_base& self) { - type k_type = stack::get<type>(L, 2); - if (k_type == type::string) { - index_call_storage* target = nullptr; - { + if constexpr (!from_named_metatable || !is_new_index) { + type k_type = stack::get<type>(L, 2); + if (k_type == type::string) { + index_call_storage* target = nullptr; string_view k = stack::get<string_view>(L, 2); - auto it = self.string_keys.find(k); - if (it != self.string_keys.cend()) { - target = &it->second; - } - } - if (target != nullptr) { - // let the target decide what to do - if constexpr (is_new_index) { - return (target->new_index)(L, target->binding_data); - } - else { - return (target->index)(L, target->binding_data); + { + auto it = self.string_keys.find(k); + if (it != self.string_keys.cend()) { + target = &it->second; + } } - } - } - else if (k_type != type::lua_nil && k_type != type::none) { - reference* target = nullptr; - { - stack_reference k = stack::get<stack_reference>(L, 2); - auto it = self.auxiliary_keys.find(k); - if (it != self.auxiliary_keys.cend()) { - target = &it->second; + if (target != nullptr) { + // let the target decide what to do, unless it's named... + if constexpr (is_new_index) { + return (target->new_index)(L, target->binding_data); + } + else { + return (target->index)(L, target->binding_data); + } } } - if (target != nullptr) { - if constexpr (is_new_index) { - // set value and return - *target = reference(L, 3); - return 0; + else if (k_type != type::lua_nil && k_type != type::none) { + stateless_reference* target = nullptr; + { + stack_reference k = stack::get<stack_reference>(L, 2); + auto it = self.auxiliary_keys.find(k); + if (it != self.auxiliary_keys.cend()) { + target = &it->second; + } } - else { - // push target to return - // what we found - return stack::push(L, *target); + if (target != nullptr) { + if constexpr (is_new_index) { + // set value and return + target->reset(L, 3); + return 0; + } + else { + // push target to return + // what we found + return stack::push(L, *target); + } } } } @@ -22230,31 +23945,31 @@ namespace sol { namespace u_detail { } } - void change_indexing(lua_State* L, submetatable_type submetatable, void* derived_this, stack_reference& t, lua_CFunction index, - lua_CFunction new_index, lua_CFunction meta_index, lua_CFunction meta_new_index) { + void change_indexing(lua_State* L_, submetatable_type submetatable_, void* derived_this_, stateless_stack_reference& t_, lua_CFunction index_, + lua_CFunction new_index_, lua_CFunction meta_index_, lua_CFunction meta_new_index_) { usertype_storage_base& this_base = *this; void* base_this = static_cast<void*>(&this_base); this->is_using_index |= true; this->is_using_new_index |= true; - if (submetatable == submetatable_type::named) { - stack::set_field(L, metatable_key, named_index_table, t.stack_index()); - stack_reference stack_metametatable(L, -named_metatable.push()); - stack::set_field<false, true>(L, + if (submetatable_ == submetatable_type::named) { + stack::set_field(L_, metatable_key, named_index_table, t_.stack_index()); + stateless_stack_reference stack_metametatable(L_, -named_metatable.push(L_)); + stack::set_field<false, true>(L_, meta_function::index, - make_closure(meta_index, nullptr, derived_this, base_this, nullptr, toplevel_magic), + make_closure(meta_index_, nullptr, derived_this_, base_this, nullptr, toplevel_magic), stack_metametatable.stack_index()); - stack::set_field<false, true>(L, + stack::set_field<false, true>(L_, meta_function::new_index, - make_closure(meta_new_index, nullptr, derived_this, base_this, nullptr, toplevel_magic), + make_closure(meta_new_index_, nullptr, derived_this_, base_this, nullptr, toplevel_magic), stack_metametatable.stack_index()); - stack_metametatable.pop(); + stack_metametatable.pop(L_); } else { stack::set_field<false, true>( - L, meta_function::index, make_closure(index, nullptr, derived_this, base_this, nullptr, toplevel_magic), t.stack_index()); + L_, meta_function::index, make_closure(index_, nullptr, derived_this_, base_this, nullptr, toplevel_magic), t_.stack_index()); stack::set_field<false, true>( - L, meta_function::new_index, make_closure(new_index, nullptr, derived_this, base_this, nullptr, toplevel_magic), t.stack_index()); + L_, meta_function::new_index, make_closure(new_index_, nullptr, derived_this_, base_this, nullptr, toplevel_magic), t_.stack_index()); } } @@ -22266,6 +23981,32 @@ namespace sol { namespace u_detail { self.set(L, reference(L, raw_index(2)), reference(L, raw_index(3))); return 0; } + + ~usertype_storage_base() { + value_index_table.reset(m_L); + reference_index_table.reset(m_L); + unique_index_table.reset(m_L); + const_reference_index_table.reset(m_L); + const_value_index_table.reset(m_L); + named_index_table.reset(m_L); + type_table.reset(m_L); + gc_names_table.reset(m_L); + named_metatable.reset(m_L); + + auto auxiliary_first = auxiliary_keys.cbegin(); + auto auxiliary_last = auxiliary_keys.cend(); + while (auxiliary_first != auxiliary_last) { + // save a copy to what we're going to destroy + auto auxiliary_target = auxiliary_first; + // move the iterator up by 1 + ++auxiliary_first; + // extract the node and destroy the key + auto extracted_node = auxiliary_keys.extract(auxiliary_target); + extracted_node.key().reset(m_L); + extracted_node.mapped().reset(m_L); + // continue if auxiliary_first hasn't been exhausted + } + } }; template <typename T> @@ -22311,11 +24052,6 @@ namespace sol { namespace u_detail { inline void set(lua_State* L, Key&& key, Value&& value); }; - template <typename T> - inline int destruct_usertype_storage(lua_State* L) { - return detail::user_alloc_destruct<usertype_storage<T>>(L); - } - template <typename T, typename Key, typename Value> void usertype_storage_base::set(lua_State* L, Key&& key, Value&& value) { using ValueU = meta::unwrap_unqualified_t<Value>; @@ -22328,14 +24064,16 @@ namespace sol { namespace u_detail { Binding& b = *p_binding; this->storage.push_back(std::move(p_binding)); - this->named_index_table.push(); + this->named_index_table.push(L); absolute_index metametatable_index(L, -1); + std::string_view call_metamethod_name = to_string(meta_function::call); + lua_pushlstring(L, call_metamethod_name.data(), call_metamethod_name.size()); stack::push(L, nullptr); stack::push(L, b.data()); lua_CFunction target_func = &b.template call<false, false>; lua_pushcclosure(L, target_func, 2); - lua_setfield(L, metametatable_index, to_string(meta_function::call).c_str()); - this->named_index_table.pop(); + lua_rawset(L, metametatable_index); + this->named_index_table.pop(L); } else if constexpr (std::is_same_v<KeyU, base_classes_tag>) { (void)key; @@ -22441,7 +24179,7 @@ namespace sol { namespace u_detail { else { reference ref_key = make_reference(L, std::forward<Key>(key)); reference ref_value = make_reference(L, std::forward<Value>(value)); - lua_reference_func ref_additions_fx { key, value }; + lua_reference_func ref_additions_fx { ref_key, ref_value }; this->for_each_table(L, ref_additions_fx); this->auxiliary_keys.insert_or_assign(std::move(ref_key), std::move(ref_value)); @@ -22456,6 +24194,34 @@ namespace sol { namespace u_detail { } template <typename T> + inline void clear_usertype_registry_names(lua_State* L) { + using u_traits = usertype_traits<T>; + using u_const_traits = usertype_traits<const T>; + using u_unique_traits = usertype_traits<d::u<T>>; + using u_ref_traits = usertype_traits<T*>; + using u_const_ref_traits = usertype_traits<T const*>; + + stack_reference registry(L, raw_index(LUA_REGISTRYINDEX)); + registry.push(); + // eliminate all named entries for this usertype + // in the registry (luaL_newmetatable does + // [name] = new table + // in registry upon creation + stack::set_field(L, &u_traits::metatable()[0], lua_nil, registry.stack_index()); + stack::set_field(L, &u_const_traits::metatable()[0], lua_nil, registry.stack_index()); + stack::set_field(L, &u_const_ref_traits::metatable()[0], lua_nil, registry.stack_index()); + stack::set_field(L, &u_ref_traits::metatable()[0], lua_nil, registry.stack_index()); + stack::set_field(L, &u_unique_traits::metatable()[0], lua_nil, registry.stack_index()); + registry.pop(); + } + + template <typename T> + inline int destroy_usertype_storage(lua_State* L) noexcept { + clear_usertype_registry_names<T>(L); + return detail::user_alloc_destroy<usertype_storage<T>>(L); + } + + template <typename T> inline usertype_storage<T>& create_usertype_storage(lua_State* L) { const char* gcmetakey = &usertype_traits<T>::gc_table()[0]; @@ -22469,8 +24235,8 @@ namespace sol { namespace u_detail { // so that the destructor is called for the usertype storage int usertype_storage_metatabe_count = stack::push(L, new_table(0, 1)); stack_reference usertype_storage_metatable(L, -usertype_storage_metatabe_count); - // set the destruction routine on the metatable - stack::set_field(L, meta_function::garbage_collect, &destruct_usertype_storage<T>, usertype_storage_metatable.stack_index()); + // set the destroyion routine on the metatable + stack::set_field(L, meta_function::garbage_collect, &destroy_usertype_storage<T>, usertype_storage_metatable.stack_index()); // set the metatable on the usertype storage userdata stack::set_field(L, metatable_key, usertype_storage_metatable, usertype_storage_ref.stack_index()); usertype_storage_metatable.pop(); @@ -22487,18 +24253,37 @@ namespace sol { namespace u_detail { return target_umt; } - inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, int index) { - stack::record tracking; - if (!stack::check<user<usertype_storage_base>>(L, index)) { + inline optional<usertype_storage_base&> maybe_as_usertype_storage_base(lua_State* L, int index) { + if (type_of(L, index) != type::lightuserdata) { return nullopt; } - usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking); - return target_umt; + usertype_storage_base& base_storage = *static_cast<usertype_storage_base*>(stack::get<void*>(L, index)); + return base_storage; + } + + inline optional<usertype_storage_base&> maybe_get_usertype_storage_base_inside(lua_State* L, int index) { + // okay, maybe we're looking at a table that is nested? + if (type_of(L, index) != type::table) { + return nullopt; + } + stack::get_field(L, meta_function::storage, index); + auto maybe_storage_base = maybe_as_usertype_storage_base(L, -1); + lua_pop(L, 1); + return maybe_storage_base; + } + + inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, int index) { + // If we can get the index directly as this type, go for it + auto maybe_already_is_usertype_storage_base = maybe_as_usertype_storage_base(L, index); + if (maybe_already_is_usertype_storage_base) { + return maybe_already_is_usertype_storage_base; + } + return maybe_get_usertype_storage_base_inside(L, index); } inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) { stack::get_field<true>(L, gcmetakey); - auto maybe_storage = maybe_get_usertype_storage_base(L, lua_gettop(L)); + auto maybe_storage = maybe_as_usertype_storage_base(L, lua_gettop(L)); lua_pop(L, 1); return maybe_storage; } @@ -22532,49 +24317,28 @@ namespace sol { namespace u_detail { } template <typename T> - inline void delete_usertype_storage(lua_State* L) { + inline void clear_usertype_storage(lua_State* L) { using u_traits = usertype_traits<T>; -#if 0 - using u_const_traits = usertype_traits<const T>; - using u_unique_traits = usertype_traits<detail::unique_usertype<T>>; - using u_ref_traits = usertype_traits<T*>; - using u_const_ref_traits = usertype_traits<T const*>; -#endif - using uts = usertype_storage<T>; const char* gcmetakey = &u_traits::gc_table()[0]; stack::get_field<true>(L, gcmetakey); - if (!stack::check<user<uts>>(L)) { + if (!stack::check<user<usertype_storage<T>>>(L)) { lua_pop(L, 1); return; } usertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L); target_umt.clear(); - // get the registry -#if 0 - stack_reference registry(L, raw_index(LUA_REGISTRYINDEX)); - registry.push(); - // eliminate all named entries for this usertype - // in the registry (luaL_newmetatable does - // [name] = new table - // in registry upon creation - stack::set_field(L, &u_traits::metatable()[0], lua_nil, registry.stack_index()); - stack::set_field(L, &u_const_traits::metatable()[0], lua_nil, registry.stack_index()); - stack::set_field(L, &u_const_ref_traits::metatable()[0], lua_nil, registry.stack_index()); - stack::set_field(L, &u_ref_traits::metatable()[0], lua_nil, registry.stack_index()); - stack::set_field(L, &u_unique_traits::metatable()[0], lua_nil, registry.stack_index()); - registry.pop(); -#endif // Registry Cleanout + clear_usertype_registry_names<T>(L); stack::set_field<true>(L, gcmetakey, lua_nil); } - template <typename T> - inline int register_usertype(lua_State* L, automagic_enrollments enrollments = {}) { + template <typename T, automagic_flags enrollment_flags> + inline int register_usertype(lua_State* L_, automagic_enrollments enrollments_ = {}) { using u_traits = usertype_traits<T>; using u_const_traits = usertype_traits<const T>; - using u_unique_traits = usertype_traits<detail::unique_usertype<T>>; + using u_unique_traits = usertype_traits<d::u<T>>; using u_ref_traits = usertype_traits<T*>; using u_const_ref_traits = usertype_traits<T const*>; using uts = usertype_storage<T>; @@ -22609,47 +24373,47 @@ namespace sol { namespace u_detail { // we then let typical definitions potentially override these intrinsics // it's the user's fault if they override things or screw them up: - // these names have been reserved and documented since sol3 + // these names have been reserved and documented since sol2 // STEP 0: tell the old usertype (if it exists) // to fuck off - delete_usertype_storage<T>(L); + clear_usertype_storage<T>(L_); // STEP 1: Create backing store for usertype storage // Pretty much the most important step. // STEP 2: Create Lua tables used for fast method indexing. // This is done inside of the storage table's constructor - usertype_storage<T>& storage = create_usertype_storage<T>(L); + usertype_storage<T>& storage = create_usertype_storage<T>(L_); usertype_storage_base& base_storage = storage; void* light_storage = static_cast<void*>(&storage); void* light_base_storage = static_cast<void*>(&base_storage); // STEP 3: set up GC escape hatch table entirely - storage.gc_names_table.push(); - stack_reference gnt(L, -1); - stack::set_field(L, submetatable_type::named, &u_traits::gc_table()[0], gnt.stack_index()); - stack::set_field(L, submetatable_type::const_value, &u_const_traits::metatable()[0], gnt.stack_index()); - stack::set_field(L, submetatable_type::const_reference, &u_const_ref_traits::metatable()[0], gnt.stack_index()); - stack::set_field(L, submetatable_type::reference, &u_ref_traits::metatable()[0], gnt.stack_index()); - stack::set_field(L, submetatable_type::unique, &u_unique_traits::metatable()[0], gnt.stack_index()); - stack::set_field(L, submetatable_type::value, &u_traits::metatable()[0], gnt.stack_index()); - gnt.pop(); + storage.gc_names_table.push(L_); + stateless_stack_reference gnt(L_, -1); + stack::set_field(L_, submetatable_type::named, &u_traits::gc_table()[0], gnt.stack_index()); + stack::set_field(L_, submetatable_type::const_value, &u_const_traits::metatable()[0], gnt.stack_index()); + stack::set_field(L_, submetatable_type::const_reference, &u_const_ref_traits::metatable()[0], gnt.stack_index()); + stack::set_field(L_, submetatable_type::reference, &u_ref_traits::metatable()[0], gnt.stack_index()); + stack::set_field(L_, submetatable_type::unique, &u_unique_traits::metatable()[0], gnt.stack_index()); + stack::set_field(L_, submetatable_type::value, &u_traits::metatable()[0], gnt.stack_index()); + gnt.pop(L_); // STEP 4: add some useful information to the type table - stack_reference stacked_type_table(L, -storage.type_table.push()); - stack::set_field(L, "name", detail::demangle<T>(), stacked_type_table.stack_index()); - stack::set_field(L, "is", &detail::is_check<T>, stacked_type_table.stack_index()); - stacked_type_table.pop(); + stateless_stack_reference stacked_type_table(L_, -storage.type_table.push(L_)); + stack::set_field(L_, "name", detail::demangle<T>(), stacked_type_table.stack_index()); + stack::set_field(L_, "is", &detail::is_check<T>, stacked_type_table.stack_index()); + stacked_type_table.pop(L_); // STEP 5: create and hook up metatable, // add intrinsics // this one is the actual meta-handling table, // the next one will be the one for int for_each_backing_metatable_calls = 0; - auto for_each_backing_metatable = [&](lua_State* L, submetatable_type smt, reference& fast_index_table) { + auto for_each_backing_metatable = [&](lua_State* L_, submetatable_type smt_, stateless_reference& fast_index_table_) { // Pointer types, AKA "references" from C++ const char* metakey = nullptr; - switch (smt) { + switch (smt_) { case submetatable_type::const_value: metakey = &u_const_traits::metatable()[0]; break; @@ -22671,56 +24435,45 @@ namespace sol { namespace u_detail { break; } - luaL_newmetatable(L, metakey); - if (smt == submetatable_type::named) { + luaL_newmetatable(L_, metakey); + if (smt_ == submetatable_type::named) { // the named table itself // gets the associated name value - storage.named_metatable = reference(L, -1); - lua_pop(L, 1); + storage.named_metatable.reset(L_, -1); + lua_pop(L_, 1); // but the thing we perform the methods on // is still the metatable of the named // table - lua_createtable(L, 0, 6); - } - stack_reference t(L, -1); - fast_index_table = reference(t); - stack::set_field<false, true>(L, meta_function::type, storage.type_table, t.stack_index()); - if constexpr (std::is_destructible_v<T>) { - // destructible: serialize default - // destructor here - switch (smt) { - case submetatable_type::const_reference: - case submetatable_type::reference: - case submetatable_type::named: - break; - case submetatable_type::unique: - stack::set_field<false, true>(L, meta_function::garbage_collect, &detail::unique_destruct<T>, t.stack_index()); - break; - case submetatable_type::value: - case submetatable_type::const_value: - default: - stack::set_field<false, true>(L, meta_function::garbage_collect, detail::make_destructor<T>(), t.stack_index()); - break; + lua_createtable(L_, 0, 6); + } + stateless_stack_reference t(L_, -1); + fast_index_table_.reset(L_, t.stack_index()); + stack::set_field<false, true>(L_, meta_function::type, storage.type_table, t.stack_index()); + // destructible? serialize default destructor here + // otherwise, not destructible: serialize a "hey you messed up" + switch (smt_) { + case submetatable_type::const_reference: + case submetatable_type::reference: + case submetatable_type::named: + break; + case submetatable_type::unique: + if constexpr (std::is_destructible_v<T>) { + stack::set_field<false, true>(L_, meta_function::garbage_collect, &detail::unique_destroy<T>, t.stack_index()); } - } - else { - // not destructible: serialize a - // "hey you messed up" - // destructor - switch (smt) { - case submetatable_type::const_reference: - case submetatable_type::reference: - case submetatable_type::named: - break; - case submetatable_type::unique: - stack::set_field<false, true>(L, meta_function::garbage_collect, &detail::cannot_destruct<T>, t.stack_index()); - break; - case submetatable_type::value: - case submetatable_type::const_value: - default: - stack::set_field<false, true>(L, meta_function::garbage_collect, &detail::cannot_destruct<T>, t.stack_index()); - break; + else { + stack::set_field<false, true>(L_, meta_function::garbage_collect, &detail::cannot_destroy<T>, t.stack_index()); } + break; + case submetatable_type::value: + case submetatable_type::const_value: + default: + if constexpr (std::is_destructible_v<T>) { + stack::set_field<false, true>(L_, meta_function::garbage_collect, detail::make_destructor<T>(), t.stack_index()); + } + else { + stack::set_field<false, true>(L_, meta_function::garbage_collect, &detail::cannot_destroy<T>, t.stack_index()); + } + break; } static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), @@ -22729,36 +24482,36 @@ namespace sol { namespace u_detail { static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug " "report."); - stack::set_field<false, true>(L, detail::base_class_check_key(), reinterpret_cast<void*>(&detail::inheritance<T>::type_check), t.stack_index()); - stack::set_field<false, true>(L, detail::base_class_cast_key(), reinterpret_cast<void*>(&detail::inheritance<T>::type_cast), t.stack_index()); + stack::set_field<false, true>(L_, detail::base_class_check_key(), reinterpret_cast<void*>(&detail::inheritance<T>::type_check), t.stack_index()); + stack::set_field<false, true>(L_, detail::base_class_cast_key(), reinterpret_cast<void*>(&detail::inheritance<T>::type_cast), t.stack_index()); - auto prop_fx = detail::properties_enrollment_allowed(for_each_backing_metatable_calls, storage.properties, enrollments); - auto insert_fx = [&L, &t, &storage](meta_function mf, lua_CFunction reg) { - stack::set_field<false, true>(L, mf, reg, t.stack_index()); - storage.properties[static_cast<int>(mf)] = true; + auto prop_fx = detail::properties_enrollment_allowed(for_each_backing_metatable_calls, storage.properties, enrollments_); + auto insert_fx = [&L_, &t, &storage](meta_function mf, lua_CFunction reg) { + stack::set_field<false, true>(L_, mf, reg, t.stack_index()); + storage.properties[static_cast<std::size_t>(mf)] = true; }; detail::insert_default_registrations<T>(insert_fx, prop_fx); // There are no variables, so serialize the fast function stuff // be sure to reset the index stuff to the non-fast version // if the user ever adds something later! - if (smt == submetatable_type::named) { + if (smt_ == submetatable_type::named) { // add escape hatch storage pointer and gc names - stack::set_field<false, true>(L, meta_function::storage, light_base_storage, t.stack_index()); - stack::set_field<false, true>(L, meta_function::gc_names, storage.gc_names_table, t.stack_index()); + stack::set_field<false, true>(L_, meta_function::storage, light_base_storage, t.stack_index()); + stack::set_field<false, true>(L_, meta_function::gc_names, storage.gc_names_table, t.stack_index()); // fancy new_indexing when using the named table { - absolute_index named_metatable_index(L, -storage.named_metatable.push()); - stack::set_field<false, true>(L, metatable_key, t, named_metatable_index); - storage.named_metatable.pop(); + absolute_index named_metatable_index(L_, -storage.named_metatable.push(L_)); + stack::set_field<false, true>(L_, metatable_key, t, named_metatable_index); + storage.named_metatable.pop(L_); } - stack_reference stack_metametatable(L, -storage.named_index_table.push()); - stack::set_field<false, true>(L, + stack_reference stack_metametatable(L_, -storage.named_index_table.push(L_)); + stack::set_field<false, true>(L_, meta_function::index, make_closure(uts::template meta_index_call<false>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic), stack_metametatable.stack_index()); - stack::set_field<false, true>(L, + stack::set_field<false, true>(L_, meta_function::new_index, make_closure(uts::template meta_index_call<true>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic), stack_metametatable.stack_index()); @@ -22767,8 +24520,8 @@ namespace sol { namespace u_detail { else { // otherwise just plain for index, // and elaborated for new_index - stack::set_field<false, true>(L, meta_function::index, t, t.stack_index()); - stack::set_field<false, true>(L, + stack::set_field<false, true>(L_, meta_function::index, t, t.stack_index()); + stack::set_field<false, true>(L_, meta_function::new_index, make_closure(uts::template index_call<true>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic), t.stack_index()); @@ -22776,21 +24529,21 @@ namespace sol { namespace u_detail { } ++for_each_backing_metatable_calls; - fast_index_table = reference(L, t); - t.pop(); + fast_index_table_.reset(L_, t.stack_index()); + t.pop(L_); }; - storage.for_each_table(L, for_each_backing_metatable); + storage.for_each_table(L_, for_each_backing_metatable); // can only use set AFTER we initialize all the metatables - if constexpr (std::is_default_constructible_v<T>) { - if (enrollments.default_constructor) { - storage.set(L, meta_function::construct, constructors<T()>()); + if constexpr (std::is_default_constructible_v<T> && has_flag(enrollment_flags, automagic_flags::default_constructor)) { + if (enrollments_.default_constructor) { + storage.set(L_, meta_function::construct, constructors<T()>()); } } // return the named metatable we want names linked into - storage.named_metatable.push(); + storage.named_metatable.push(L_); return 1; } }} // namespace sol::u_detail @@ -22806,7 +24559,7 @@ namespace sol { using key_type = detail::proxy_key_t<Key>; template <typename T, std::size_t... I> - decltype(auto) tuple_get(std::index_sequence<I...>) const & { + decltype(auto) tuple_get(std::index_sequence<I...>) const& { return tbl.template traverse_get<T>(std::get<I>(key)...); } @@ -22840,8 +24593,7 @@ namespace sol { key_type key; template <typename T> - usertype_proxy(Table table, T&& k) - : tbl(table), key(std::forward<T>(k)) { + usertype_proxy(Table table, T&& k) : tbl(table), key(std::forward<T>(k)) { } template <typename T> @@ -23019,7 +24771,7 @@ namespace sol { template <typename T> table_proxy&& set(T&& item) && { - tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item)); + std::move(*this).tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item)); return std::move(*this); } @@ -23038,7 +24790,7 @@ namespace sol { template <typename T> table_proxy& operator=(T&& other) & { using Tu = meta::unwrap_unqualified_t<T>; - if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) { + if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_invocable_v<Tu>) { return set_function(std::forward<T>(other)); } else { @@ -23049,7 +24801,7 @@ namespace sol { template <typename T> table_proxy&& operator=(T&& other) && { using Tu = meta::unwrap_unqualified_t<T>; - if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) { + if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_invocable_v<Tu> && !detail::is_msvc_callable_rigged_v<T>) { return std::move(*this).set_function(std::forward<T>(other)); } else { @@ -23068,6 +24820,13 @@ namespace sol { } template <typename T> + bool is() const { + typedef decltype(get<T>()) U; + optional<U> option = this->get<optional<U>>(); + return option.has_value(); + } + + template <typename T> decltype(auto) get() const& { using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>; return tuple_get<T>(idx_seq()); @@ -23295,10 +25054,10 @@ namespace sol { std::ptrdiff_t idx = 0; public: - basic_table_iterator() : keyidx(-1), idx(-1) { + basic_table_iterator() noexcept : keyidx(-1), idx(-1) { } - basic_table_iterator(reference_type x) : ref(std::move(x)) { + basic_table_iterator(reference_type x) noexcept : ref(std::move(x)) { ref.push(); tableidx = lua_gettop(ref.lua_state()); stack::push(ref.lua_state(), lua_nil); @@ -23309,7 +25068,7 @@ namespace sol { --idx; } - basic_table_iterator& operator++() { + basic_table_iterator& operator++() noexcept { if (idx == -1) return *this; @@ -23327,25 +25086,21 @@ namespace sol { return *this; } - basic_table_iterator operator++(int) { + basic_table_iterator operator++(int) noexcept { auto saved = *this; this->operator++(); return saved; } - reference operator*() { - return kvp; + reference operator*() const noexcept { + return const_cast<reference>(kvp); } - const_reference operator*() const { - return kvp; - } - - bool operator==(const basic_table_iterator& right) const { + bool operator==(const basic_table_iterator& right) const noexcept { return idx == right.idx; } - bool operator!=(const basic_table_iterator& right) const { + bool operator!=(const basic_table_iterator& right) const noexcept { return idx != right.idx; } @@ -23363,6 +25118,317 @@ namespace sol { // end of sol/table_iterator.hpp +// beginning of sol/pairs_iterator.hpp + +// beginning of sol/stack/detail/pairs.hpp + +#include <optional> + +namespace sol { namespace stack { namespace stack_detail { + + inline bool maybe_push_lua_next_function(lua_State* L_) { + stack::get_field<true, false>(L_, "next"); + bool is_next = stack::check<protected_function>(L_); + if (is_next) { + return true; + } + stack::get_field<true, false>(L_, "table"); + stack::record tracking{}; + if (!stack::loose_table_check(L_, -1, &no_panic, tracking)) { + return false; + } + lua_getfield(L_, -1, "next"); + bool is_table_next_func = stack::check<protected_function>(L_, -1); + if (is_table_next_func) { + return true; + } + lua_pop(L_, 1); + return false; + } + + inline std::optional<protected_function> find_lua_next_function(lua_State* L_) { + if (maybe_push_lua_next_function(L_)) { + return stack::pop<protected_function>(L_); + } + return std::nullopt; + } + + inline int c_lua_next(lua_State* L_) noexcept { + stack_reference table_stack_ref(L_, raw_index(1)); + stateless_stack_reference key_stack_ref(L_, raw_index(2)); + int result = lua_next(table_stack_ref.lua_state(), table_stack_ref.stack_index()); + if (result == 0) { + stack::push(L_, lua_nil); + return 1; + } + return 2; + } + + inline int readonly_pairs(lua_State* L_) noexcept { + int pushed = 0; + if (!maybe_push_lua_next_function(L_)) { + // we do not have the "next" function in the global namespace + // from the "table" global entiry, use our own + pushed += stack::push(L_, &c_lua_next); + } + else { + pushed += 1; + } + int metatable_exists = lua_getmetatable(L_, 1); + sol_c_assert(metatable_exists == 1); + const auto& index_key = to_string(sol::meta_function::index); + lua_getfield(L_, lua_gettop(L_), index_key.c_str()); + lua_remove(L_, -2); + pushed += 1; + pushed += stack::push(L_, lua_nil); + return pushed; + } + +}}} // sol::stack::stack_detail + +// end of sol/stack/detail/pairs.hpp + +namespace sol { + + struct pairs_sentinel { }; + + class pairs_iterator { + private: + inline static constexpr int empty_key_index = -1; + + public: + using key_type = object; + using mapped_type = object; + using value_type = std::pair<object, object>; + using iterator_category = std::input_iterator_tag; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using const_pointer = value_type const*; + using reference = value_type&; + using const_reference = const value_type&; + + pairs_iterator() noexcept + : m_L(nullptr) + , m_next_function_ref(lua_nil) + , m_table_ref(lua_nil) + , m_cached_key_value_pair({ lua_nil, lua_nil }) + , m_key_index(empty_key_index) + , m_iteration_index(0) { + } + + pairs_iterator(const pairs_iterator&) = delete; + pairs_iterator& operator=(const pairs_iterator&) = delete; + + pairs_iterator(pairs_iterator&& right) noexcept + : m_L(right.m_L) + , m_next_function_ref(std::move(right.m_next_function_ref)) + , m_table_ref(std::move(right.m_table_ref)) + , m_cached_key_value_pair(std::move(right.m_cached_key_value_pair)) + , m_key_index(right.m_key_index) + , m_iteration_index(right.m_iteration_index) { + right.m_key_index = empty_key_index; + } + + pairs_iterator& operator=(pairs_iterator&& right) noexcept { + m_L = right.m_L; + m_next_function_ref = std::move(right.m_next_function_ref); + m_table_ref = std::move(right.m_table_ref); + m_cached_key_value_pair = std::move(right.m_cached_key_value_pair); + m_key_index = right.m_key_index; + m_iteration_index = right.m_iteration_index; + right.m_key_index = empty_key_index; + return *this; + } + + template <typename Source> + pairs_iterator(const Source& source_) noexcept : m_L(source_.lua_state()), m_key_index(empty_key_index), m_iteration_index(0) { + if (m_L == nullptr || !source_.valid()) { + m_key_index = empty_key_index; + return; + } + int source_index = -source_.push(m_L); + int abs_source_index = lua_absindex(m_L, source_index); + int metatable_exists = lua_getmetatable(m_L, abs_source_index); + lua_remove(m_L, abs_source_index); + if (metatable_exists == 1) { + // just has a metatable, but does it have __pairs ? + stack_reference metatable(m_L, raw_index(abs_source_index)); + stack::get_field<is_global_table_v<Source>, true>(m_L, meta_function::pairs, metatable.stack_index()); + optional<protected_function> maybe_pairs_function = stack::pop<optional<protected_function>>(m_L); + if (maybe_pairs_function.has_value()) { + protected_function& pairs_function = *maybe_pairs_function; + protected_function_result next_fn_and_table_and_first_key = pairs_function(source_); + if (next_fn_and_table_and_first_key.valid()) { + m_next_function_ref = next_fn_and_table_and_first_key.get<protected_function>(0); + m_table_ref = next_fn_and_table_and_first_key.get<sol::reference>(1); + m_key_index = next_fn_and_table_and_first_key.stack_index() - 1; + // remove next function and table + lua_remove(m_L, m_key_index); + lua_remove(m_L, m_key_index); + next_fn_and_table_and_first_key.abandon(); + lua_remove(m_L, abs_source_index); + this->operator++(); + m_iteration_index = 0; + return; + } + } + } + + { + auto maybe_next = stack::stack_detail::find_lua_next_function(m_L); + if (maybe_next.has_value()) { + m_next_function_ref = std::move(*maybe_next); + m_table_ref = source_; + + stack::push(m_L, lua_nil); + m_key_index = lua_gettop(m_L); + this->operator++(); + m_iteration_index = 0; + return; + } + } + + // okay, so none of the above worked and now we need to create + // a shim / polyfill instead + stack::push(m_L, &stack::stack_detail::c_lua_next); + m_next_function_ref = stack::pop<protected_function>(m_L); + m_table_ref = source_; + stack::push(m_L, lua_nil); + m_key_index = lua_gettop(m_L); + this->operator++(); + m_iteration_index = 0; + } + + pairs_iterator& operator++() { + if (m_key_index == empty_key_index) { + return *this; + } + { + sol::protected_function_result next_results = m_next_function_ref(m_table_ref, stack_reference(m_L, m_key_index)); + if (!next_results.valid()) { + // TODO: abort, or throw an error? + m_clear(); + m_key_index = empty_key_index; + return *this; + } + int next_results_count = next_results.return_count(); + if (next_results_count < 2) { + // iteration is over! + next_results.abandon(); + lua_settop(m_L, m_key_index - 1); + m_key_index = empty_key_index; + ++m_iteration_index; + return *this; + } + else { + lua_remove(m_L, m_key_index); + m_key_index = next_results.stack_index() - 1; + m_cached_key_value_pair.first = stack::get<object>(m_L, m_key_index); + m_cached_key_value_pair.second = stack::get<object>(m_L, m_key_index + 1); + lua_settop(m_L, m_key_index); + next_results.abandon(); + } + } + ++m_iteration_index; + return *this; + } + + std::ptrdiff_t index() const { + return static_cast<std::ptrdiff_t>(m_iteration_index); + } + + const_reference operator*() const noexcept { + return m_cached_key_value_pair; + } + + reference operator*() noexcept { + return m_cached_key_value_pair; + } + + friend bool operator==(const pairs_iterator& left, const pairs_iterator& right) noexcept { + return left.m_table_ref == right.m_table_ref && left.m_iteration_index == right.m_iteration_index; + } + + friend bool operator!=(const pairs_iterator& left, const pairs_iterator& right) noexcept { + return left.m_table_ref != right.m_table_ref || left.m_iteration_index != right.m_iteration_index; + } + + friend bool operator==(const pairs_iterator& left, const pairs_sentinel&) noexcept { + return left.m_key_index == empty_key_index; + } + + friend bool operator!=(const pairs_iterator& left, const pairs_sentinel&) noexcept { + return left.m_key_index != empty_key_index; + } + + friend bool operator==(const pairs_sentinel&, const pairs_iterator& left) noexcept { + return left.m_key_index == empty_key_index; + } + + friend bool operator!=(const pairs_sentinel&, const pairs_iterator& left) noexcept { + return left.m_key_index != empty_key_index; + } + + ~pairs_iterator() { + if (m_key_index != empty_key_index) { + m_clear(); + } + } + + private: + void m_clear() noexcept { + lua_remove(m_L, m_key_index); + } + + lua_State* m_L; + protected_function m_next_function_ref; + sol::reference m_table_ref; + std::pair<object, object> m_cached_key_value_pair; + int m_key_index; + int m_iteration_index; + }; + + template <typename Source> + class basic_pairs_range { + private: + using source_t = std::add_lvalue_reference_t<Source>; + source_t m_source; + + public: + using iterator = pairs_iterator; + using const_iterator = pairs_iterator; + + basic_pairs_range(source_t source_) noexcept : m_source(source_) { + } + + iterator begin() noexcept { + return iterator(m_source); + } + + iterator begin() const noexcept { + return iterator(m_source); + } + + const_iterator cbegin() const noexcept { + return const_iterator(m_source); + } + + pairs_sentinel end() noexcept { + return {}; + } + + pairs_sentinel end() const noexcept { + return {}; + } + + pairs_sentinel cend() const noexcept { + return {}; + } + }; +} // namespace sol + +// end of sol/pairs_iterator.hpp + namespace sol { namespace detail { template <std::size_t n> @@ -23377,16 +25443,17 @@ namespace sol { struct ref_clean { lua_State* L; - int& n; - ref_clean(lua_State* luastate, int& n) : L(luastate), n(n) { + int& pop_count; + + ref_clean(lua_State* L_, int& pop_count_) noexcept : L(L_), pop_count(pop_count_) { } ~ref_clean() { - lua_pop(L, static_cast<int>(n)); + lua_pop(L, static_cast<int>(pop_count)); } }; - inline int fail_on_newindex(lua_State* L) { - return luaL_error(L, "sol: cannot modify the elements of an enumeration table"); + inline int fail_on_newindex(lua_State* L_) { + return luaL_error(L_, "sol: cannot modify the elements of an enumeration table"); } } // namespace detail @@ -23403,6 +25470,18 @@ namespace sol { template <typename> friend class basic_metatable; + template <typename T> + using is_get_direct_tableless = meta::boolean<stack::stack_detail::is_get_direct_tableless_v<T, top_level, false>>; + + template <typename T> + using is_raw_get_direct_tableless = std::false_type; + + template <typename T> + using is_set_direct_tableless = meta::boolean<stack::stack_detail::is_set_direct_tableless_v<T, top_level, false>>; + + template <typename T> + using is_raw_set_direct_tableless = std::false_type; + template <bool raw, typename... Ret, typename... Keys> decltype(auto) tuple_get(int table_index, Keys&&... keys) const { if constexpr (sizeof...(Ret) < 2) { @@ -23432,7 +25511,7 @@ namespace sol { template <bool raw, typename Ret, typename... Keys> decltype(auto) traverse_get_single(int table_index, Keys&&... keys) const { - constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0); + constexpr static bool global = (meta::count_for_to_pack_v < 1, is_get_direct_tableless, meta::unqualified_t<Keys>... >> 0); if constexpr (meta::is_optional_v<meta::unqualified_t<Ret>>) { int popcount = 0; detail::ref_clean c(base_t::lua_state(), popcount); @@ -23446,8 +25525,8 @@ namespace sol { template <bool raw, typename Pairs, std::size_t... I> void tuple_set(std::index_sequence<I...>, Pairs&& pairs) { - constexpr static bool global = top_level - && (meta::count_even_for_pack_v<meta::is_c_str, meta::unqualified_t<decltype(std::get<I * 2>(std::forward<Pairs>(pairs)))>...> > 0); + constexpr static bool global = (meta::count_even_for_pack_v < is_set_direct_tableless, + meta::unqualified_t<decltype(std::get<I * 2>(std::forward<Pairs>(pairs)))>... >> 0); auto pp = stack::push_pop<global>(*this); int table_index = pp.index_of(*this); lua_State* L = base_t::lua_state(); @@ -23516,7 +25595,7 @@ namespace sol { if (!p.success) { if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { lua_pop(L, 1); - constexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0; + constexpr bool is_seq = meta::count_for_to_pack_v < 1, std::is_integral, Keys... >> 0; stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq))); stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index); } @@ -23537,7 +25616,7 @@ namespace sol { lua_pop(L, 1); stack::push(L, new_table(0, 0)); stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index); - if (stack::check<value_type>(L, lua_gettop(L), no_panic)) { + if (stack::check<value_type>(L, lua_gettop(L), &no_panic)) { return stack::get<T>(L); } } @@ -23587,7 +25666,7 @@ namespace sol { if constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty || (mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { if (vt == type::lua_nil || vt == type::none) { - constexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0; + constexpr bool is_seq = meta::count_for_to_pack_v < 1, std::is_integral, Keys... >> 0; lua_pop(L, 1); stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq))); stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index); @@ -23595,7 +25674,7 @@ namespace sol { } else { if (vt != type::table) { - constexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0; + constexpr bool is_seq = meta::count_for_to_pack_v < 1, std::is_integral, Keys... >> 0; lua_pop(L, 1); stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq))); stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index); @@ -23610,9 +25689,6 @@ namespace sol { } } - basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { - } - protected: basic_table_core(detail::no_safety_tag, lua_nil_t n) : base_t(n) { } @@ -23640,43 +25716,50 @@ namespace sol { basic_table_core(basic_table_core&&) = default; basic_table_core& operator=(const basic_table_core&) = default; basic_table_core& operator=(basic_table_core&&) = default; + basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) { } + basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) { } + template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_table_core(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); constructor_handler handler {}; stack::check<basic_table_core>(lua_state(), table_index, handler); #endif // Safety } + basic_table_core(lua_State* L, const new_table& nt) : base_t(L, -stack::push(L, nt)) { if (!is_stack_based<meta::unqualified_t<ref_t>>::value) { lua_pop(L, 1); } } + basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) constructor_handler handler {}; stack::check<basic_table_core>(L, index, handler); #endif // Safety } + basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); constructor_handler handler {}; stack::check<basic_table_core>(lua_state(), table_index, handler); #endif // Safety } + template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<ref_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) if (!is_table<meta::unqualified_t<T>>::value) { auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); @@ -23685,9 +25768,13 @@ namespace sol { } #endif // Safety } + basic_table_core(lua_nil_t r) noexcept : basic_table_core(detail::no_safety, r) { } + basic_table_core(lua_State* L, global_tag_t t) noexcept : base_t(L, t) { + } + iterator begin() const { if (this->get_type() == type::table) { return iterator(*this); @@ -23707,6 +25794,14 @@ namespace sol { return end(); } + basic_pairs_range<basic_table_core> pairs() noexcept { + return basic_pairs_range<basic_table_core>(*this); + } + + basic_pairs_range<const basic_table_core> pairs() const noexcept { + return basic_pairs_range<const basic_table_core>(*this); + } + void clear() { auto pp = stack::push_pop<false>(*this); int table_index = pp.index_of(*this); @@ -23716,7 +25811,7 @@ namespace sol { template <typename... Ret, typename... Keys> decltype(auto) get(Keys&&... keys) const { static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); - constexpr static bool global = meta::all<meta::boolean<top_level>, meta::is_c_str<meta::unqualified_t<Keys>>...>::value; + constexpr static bool global = meta::all<meta::boolean<top_level>, is_get_direct_tableless<meta::unqualified_t<Keys>>...>::value; auto pp = stack::push_pop<global>(*this); int table_index = pp.index_of(*this); return tuple_get<false, Ret...>(table_index, std::forward<Keys>(keys)...); @@ -23744,7 +25839,7 @@ namespace sol { template <typename T, typename... Keys> decltype(auto) traverse_get(Keys&&... keys) const { static_assert(sizeof...(Keys) > 0, "must pass at least 1 key to get"); - constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0); + constexpr static bool global = (meta::count_for_to_pack_v < 1, is_get_direct_tableless, meta::unqualified_t<Keys>... >> 0); auto pp = stack::push_pop<global>(*this); int table_index = pp.index_of(*this); return traverse_get_single<false, T>(table_index, std::forward<Keys>(keys)...); @@ -23754,7 +25849,7 @@ namespace sol { basic_table_core& traverse_set(Keys&&... keys) { static_assert(sizeof...(Keys) > 1, "must pass at least 1 key and 1 value to set"); constexpr static bool global - = top_level && (meta::count_when_for_to_pack_v<detail::is_not_insert_mode, 1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0); + = (meta::count_when_for_to_pack_v < detail::is_not_insert_mode, 1, is_set_direct_tableless, meta::unqualified_t<Keys>... >> 0); auto pp = stack::push_pop<global>(*this); int table_index = pp.index_of(*this); lua_State* L = base_t::lua_state(); @@ -23777,7 +25872,7 @@ namespace sol { template <typename... Ret, typename... Keys> decltype(auto) raw_get(Keys&&... keys) const { static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); - constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0); + constexpr static bool global = (meta::count_for_to_pack_v < 1, is_raw_get_direct_tableless, meta::unqualified_t<Keys>... >> 0); auto pp = stack::push_pop<global>(*this); int table_index = pp.index_of(*this); return tuple_get<true, Ret...>(table_index, std::forward<Keys>(keys)...); @@ -23804,7 +25899,7 @@ namespace sol { template <typename T, typename... Keys> decltype(auto) traverse_raw_get(Keys&&... keys) const { - constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0); + constexpr static bool global = (meta::count_for_to_pack_v < 1, is_raw_get_direct_tableless, meta::unqualified_t<Keys>... >> 0); auto pp = stack::push_pop<global>(*this); int table_index = pp.index_of(*this); return traverse_get_single<true, T>(table_index, std::forward<Keys>(keys)...); @@ -23812,7 +25907,7 @@ namespace sol { template <typename... Keys> basic_table_core& traverse_raw_set(Keys&&... keys) { - constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0); + constexpr static bool global = (meta::count_for_to_pack_v < 1, is_raw_set_direct_tableless, meta::unqualified_t<Keys>... >> 0); auto pp = stack::push_pop<global>(*this); lua_State* L = base_t::lua_state(); auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2 - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>)); @@ -23829,18 +25924,23 @@ namespace sol { template <typename Class, typename Key> usertype<Class> new_usertype(Key&& key); + template <typename Class, typename Key, automagic_flags enrollment_flags> + usertype<Class> new_usertype(Key&& key, constant_automagic_enrollments<enrollment_flags> enrollment); + template <typename Class, typename Key> usertype<Class> new_usertype(Key&& key, automagic_enrollments enrollment); template <typename Class, typename Key, typename Arg, typename... Args, - typename = std::enable_if_t<!std::is_same_v<meta::unqualified_t<Arg>, automagic_enrollments>>> + typename = std::enable_if_t<!std::is_base_of_v<automagic_enrollments, meta::unqualified_t<Arg>>>> usertype<Class> new_usertype(Key&& key, Arg&& arg, Args&&... args); template <bool read_only = true, typename... Args> table new_enum(const string_view& name, Args&&... args) { table target = create_with(std::forward<Args>(args)...); - if (read_only) { - table x = create_with(meta_function::new_index, detail::fail_on_newindex, meta_function::index, target); + if constexpr (read_only) { + // Need to create a special iterator to handle this + table x + = create_with(meta_function::new_index, detail::fail_on_newindex, meta_function::index, target, meta_function::pairs, stack::stack_detail::readonly_pairs); table shim = create_named(name, metatable_key, x); return shim; } @@ -23939,7 +26039,7 @@ namespace sol { auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); lua_State* L = base_t::lua_state(); - (void)detail::swallow { 0, (stack::set_ref(L, std::forward<Args>(args), table_index), 0)... }; + (void)detail::swallow { 0, (stack::stack_detail::raw_table_set(L, std::forward<Args>(args), table_index), 0)... }; return *this; } @@ -24051,6 +26151,27 @@ namespace sol { basic_metatable(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward<T>(r)) { } + template <typename R, typename... Args, typename Fx, typename Key, typename = std::invoke_result_t<Fx, Args...>> + void set_fx(types<R(Args...)>, Key&& key, Fx&& fx) { + set_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx)); + } + + template <typename Fx, typename Key, meta::enable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> + void set_fx(types<>, Key&& key, Fx&& fx) { + set(std::forward<Key>(key), std::forward<Fx>(fx)); + } + + template <typename Fx, typename Key, typename... Args, + meta::disable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> + void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) { + set(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...)); + } + + template <typename... Sig, typename... Args, typename Key> + void set_resolved_function(Key&& key, Args&&... args) { + set(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...)); + } + public: using base_t::lua_state; @@ -24065,22 +26186,22 @@ namespace sol { } template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_metatable(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_metatable>(lua_state(), -1, handler); #endif // Safety } basic_metatable(lua_State* L, int index = -1) : basic_metatable(detail::no_safety, L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) - constructor_handler handler{}; +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; stack::check<basic_metatable>(L, index, handler); #endif // Safety } basic_metatable(lua_State* L, ref_index index) : basic_metatable(detail::no_safety, L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_metatable>(lua_state(), -1, handler); #endif // Safety } @@ -24088,10 +26209,10 @@ namespace sol { meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_metatable>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_metatable(T&& r) noexcept : basic_metatable(detail::no_safety, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) if (!is_table<meta::unqualified_t<T>>::value) { auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_metatable>(base_t::lua_state(), -1, handler); } #endif // Safety @@ -24100,7 +26221,19 @@ namespace sol { } template <typename Key, typename Value> - void set(Key&& key, Value&& value); + basic_metatable<base_type>& set(Key&& key, Value&& value); + + template <typename Sig, typename Key, typename... Args> + basic_metatable& set_function(Key&& key, Args&&... args) { + set_fx(types<Sig>(), std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } + + template <typename Key, typename... Args> + basic_metatable& set_function(Key&& key, Args&&... args) { + set_fx(types<>(), std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } void unregister() { using ustorage_base = u_detail::usertype_storage_base; @@ -24113,11 +26246,13 @@ namespace sol { stack_reference mt(L, -1); stack::get_field(L, meta_function::gc_names, mt.stack_index()); if (type_of(L, -1) != type::table) { + lua_settop(L, top); return; } stack_reference gc_names_table(L, -1); stack::get_field(L, meta_function::storage, mt.stack_index()); if (type_of(L, -1) != type::lightuserdata) { + lua_settop(L, top); return; } ustorage_base& base_storage = *static_cast<ustorage_base*>(stack::get<void*>(L, -1)); @@ -24146,7 +26281,7 @@ namespace sol { else { // do not change the values in the registry: they need to be present // no matter what, for safety's sake - //stack::set_field(L, gcmetakey, lua_nil, registry.stack_index()); + // stack::set_field(L, gcmetakey, lua_nil, registry.stack_index()); } } @@ -24184,24 +26319,43 @@ namespace sol { template <std::size_t... I, typename... Args> void tuple_set(std::index_sequence<I...>, std::tuple<Args...>&& args) { (void)args; - (void)detail::swallow{ 0, - (this->set(std::get<I * 2>(std::move(args)), std::get<I * 2 + 1>(std::move(args))), 0)... }; + (void)detail::swallow { 0, (this->set(std::get<I * 2>(std::move(args)), std::get<I * 2 + 1>(std::move(args))), 0)... }; + } + + template <typename R, typename... Args, typename Fx, typename Key, typename = std::invoke_result_t<Fx, Args...>> + void set_fx(types<R(Args...)>, Key&& key, Fx&& fx) { + set_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx)); + } + + template <typename Fx, typename Key, meta::enable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> + void set_fx(types<>, Key&& key, Fx&& fx) { + set(std::forward<Key>(key), std::forward<Fx>(fx)); + } + + template <typename Fx, typename Key, typename... Args, + meta::disable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> + void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) { + set(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...)); + } + + template <typename... Sig, typename... Args, typename Key> + void set_resolved_function(Key&& key, Args&&... args) { + set(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...)); } public: using base_t::base_t; + using base_t::get; + using base_t::lua_state; using base_t::pop; using base_t::push; - using base_t::lua_state; - using base_t::get; - using base_t::set_function; - using base_t::traverse_set; using base_t::traverse_get; + using base_t::traverse_set; using base_t::unregister; template <typename Key, typename Value> - void set(Key&& key, Value&& value) { + basic_usertype& set(Key&& key, Value&& value) { optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(this->lua_state()); if (maybe_uts) { u_detail::usertype_storage<T>& uts = *maybe_uts; @@ -24218,6 +26372,19 @@ namespace sol { table_base_t::set(std::forward<Key>(key), std::forward<Value>(value)); } } + return *this; + } + + template <typename Sig, typename Key, typename... Args> + basic_usertype& set_function(Key&& key, Args&&... args) { + set_fx(types<Sig>(), std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } + + template <typename Key, typename... Args> + basic_usertype& set_function(Key&& key, Args&&... args) { + set_fx(types<>(), std::forward<Key>(key), std::forward<Args>(args)...); + return *this; } template <typename Key> @@ -24263,9 +26430,9 @@ namespace sol { } template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_lua_table(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_lua_table>(lua_state(), -1, handler); #endif // Safety } @@ -24275,15 +26442,15 @@ namespace sol { } } basic_lua_table(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) - constructor_handler handler{}; +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; stack::check<basic_lua_table>(L, index, handler); #endif // Safety } basic_lua_table(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_lua_table>(lua_state(), -1, handler); #endif // Safety } @@ -24291,10 +26458,10 @@ namespace sol { meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_lua_table>>, meta::neg<std::is_same<ref_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_lua_table(T&& r) noexcept : basic_lua_table(detail::no_safety, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) if (!is_table<meta::unqualified_t<T>>::value) { auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_lua_table>(lua_state(), -1, handler); } #endif // Safety @@ -24303,7 +26470,7 @@ namespace sol { } }; -} +} // namespace sol // end of sol/lua_table.hpp @@ -24313,14 +26480,24 @@ namespace sol { template <bool is_global, typename base_type> template <typename Class, typename Key> usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key) { - automagic_enrollments enrollments; + constant_automagic_enrollments<> enrollments {}; return this->new_usertype<Class>(std::forward<Key>(key), std::move(enrollments)); } template <bool is_global, typename base_type> + template <typename Class, typename Key, automagic_flags enrollment_flags> + usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, constant_automagic_enrollments<enrollment_flags> enrollments) { + int mt_index = u_detail::register_usertype<Class, enrollment_flags>(this->lua_state(), std::move(enrollments)); + usertype<Class> mt(this->lua_state(), -mt_index); + lua_pop(this->lua_state(), 1); + set(std::forward<Key>(key), mt); + return mt; + } + + template <bool is_global, typename base_type> template <typename Class, typename Key> usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, automagic_enrollments enrollments) { - int mt_index = u_detail::register_usertype<Class>(this->lua_state(), std::move(enrollments)); + int mt_index = u_detail::register_usertype<Class, automagic_flags::all>(this->lua_state(), std::move(enrollments)); usertype<Class> mt(this->lua_state(), -mt_index); lua_pop(this->lua_state(), 1); set(std::forward<Key>(key), mt); @@ -24330,12 +26507,15 @@ namespace sol { template <bool is_global, typename base_type> template <typename Class, typename Key, typename Arg, typename... Args, typename> usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, Arg&& arg, Args&&... args) { - automagic_enrollments enrollments; + constexpr automagic_flags enrollment_flags = meta::any_same_v<no_construction, meta::unqualified_t<Arg>, meta::unqualified_t<Args>...> + ? clear_flags(automagic_flags::all, automagic_flags::default_constructor) + : automagic_flags::all; + constant_automagic_enrollments<enrollment_flags> enrollments; enrollments.default_constructor = !detail::any_is_constructor_v<Arg, Args...>; enrollments.destructor = !detail::any_is_destructor_v<Arg, Args...>; usertype<Class> ut = this->new_usertype<Class>(std::forward<Key>(key), std::move(enrollments)); - static_assert(sizeof...(Args) % 2 == static_cast<std::size_t>(!detail::any_is_constructor_v<Arg>), - "you must pass an even number of arguments to new_usertype after first passing a constructor"); + static_assert(sizeof...(Args) % 2 == static_cast<std::size_t>(!detail::any_is_constructor_v<Arg>), + "you must pass an even number of arguments to new_usertype after first passing a constructor"); if constexpr (detail::any_is_constructor_v<Arg>) { ut.set(meta_function::construct, std::forward<Arg>(arg)); ut.tuple_set(std::make_index_sequence<(sizeof...(Args)) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...)); @@ -24348,29 +26528,32 @@ namespace sol { template <typename base_type> template <typename Key, typename Value> - void basic_metatable<base_type>::set(Key&& key, Value&& value) { + basic_metatable<base_type>& basic_metatable<base_type>::set(Key&& key, Value&& value) { this->push(); lua_State* L = this->lua_state(); int target = lua_gettop(L); - optional<u_detail::usertype_storage_base&> maybe_uts = u_detail::maybe_get_usertype_storage_base(L, target); - lua_pop(L, 1); + optional<u_detail::usertype_storage_base&> maybe_uts = nullopt; + maybe_uts = u_detail::maybe_get_usertype_storage_base(L, target); if (maybe_uts) { u_detail::usertype_storage_base& uts = *maybe_uts; uts.set(L, std::forward<Key>(key), std::forward<Value>(value)); + return *this; } else { base_t::set(std::forward<Key>(key), std::forward<Value>(value)); } + this->pop(); + return *this; } namespace stack { template <> struct unqualified_getter<metatable_key_t> { - static table get(lua_State* L, int index = -1) { + static metatable get(lua_State* L, int index = -1) { if (lua_getmetatable(L, index) == 0) { - return table(L, ref_index(LUA_REFNIL)); + return metatable(L, ref_index(LUA_REFNIL)); } - return table(L, -1); + return metatable(L, -1); } }; } // namespace stack @@ -24416,29 +26599,29 @@ namespace sol { basic_environment(env_key_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) constructor_handler handler {}; stack::check<env_key_t>(this->lua_state(), -1, handler); #endif // Safety - lua_pop(this->lua_state(), 2); + lua_pop(this->lua_state(), 1); } template <bool b> basic_environment(env_key_t, const basic_reference<b>& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) constructor_handler handler {}; stack::check<env_key_t>(this->lua_state(), -1, handler); #endif // Safety - lua_pop(this->lua_state(), 2); + lua_pop(this->lua_state(), 1); } basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) constructor_handler handler {}; stack::check<basic_environment>(L, index, handler); #endif // Safety } basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); constructor_handler handler {}; stack::check<basic_environment>(L, -1, handler); @@ -24448,7 +26631,7 @@ namespace sol { meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) if (!is_environment<meta::unqualified_t<T>>::value) { auto pp = stack::push_pop(*this); constructor_handler handler {}; @@ -24461,7 +26644,7 @@ namespace sol { template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_environment(lua_State* L, T&& r) noexcept : base_t(detail::no_safety, L, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) +#if SOL_IS_ON(SOL_SAFE_REFERENCES) if (!is_environment<meta::unqualified_t<T>>::value) { auto pp = stack::push_pop(*this); constructor_handler handler {}; @@ -24471,27 +26654,72 @@ namespace sol { } template <typename T> - void set_on(const T& target) const { + bool set_on(const T& target) const { lua_State* L = target.lua_state(); auto pp = stack::push_pop(target); -#if SOL_LUA_VESION_I_ < 502 + int target_index = pp.index_of(target); +#if SOL_LUA_VERSION_I_ < 502 // Use lua_setfenv this->push(); - lua_setfenv(L, -2); + int success_result = lua_setfenv(L, target_index); + return success_result != 0; #else - // Use upvalues as explained in Lua 5.2 and beyond's manual - this->push(); - const char* name = lua_setupvalue(L, -2, 1); - if (name == nullptr) { - this->pop(); + // If this is a C function, the environment is always placed in + // the first value, as is expected of sol2 (all upvalues have an empty name, "") + if (lua_iscfunction(L, target_index) != 0) { + const char* maybe_upvalue_name = lua_getupvalue(L, target_index, 1); + if (maybe_upvalue_name == nullptr) { + return false; + } + string_view upvalue_name(maybe_upvalue_name); + if (upvalue_name == "") { + this->push(); + const char* success = lua_setupvalue(L, target_index, 1); + if (success == nullptr) { + // left things alone on the stack, pop them off + lua_pop(L, 2); + return false; + } + lua_pop(L, 1); + return true; + } + lua_pop(L, 1); + return false; + } + else { + // Must search for the right upvalue target on index + for (int upvalue_index = 1;; ++upvalue_index) { + const char* maybe_upvalue_name = lua_getupvalue(L, target_index, upvalue_index); + if (maybe_upvalue_name == nullptr) { + break; + } + string_view upvalue_name(maybe_upvalue_name); + if (upvalue_name == "_ENV") { + lua_pop(L, 1); + this->push(); + const char* success = lua_setupvalue(L, target_index, upvalue_index); + if (success == nullptr) { + // left things alone on the stack, pop them off + lua_pop(L, 1); + break; + } + // whether or not we succeeded, we found _ENV + // so we need to break + return true; + } + lua_pop(L, 1); + } + // if we get here, + // we did not find an _ENV here... + return false; } #endif } }; template <typename T, typename E> - void set_environment(const basic_environment<E>& env, const T& target) { - env.set_on(target); + bool set_environment(const basic_environment<E>& env, const T& target) { + return env.set_on(target); } template <typename E = reference, typename T> @@ -24517,11 +26745,11 @@ namespace sol { return static_cast<bool>(env); } - operator optional<environment> &() { + operator optional<environment>&() { return env; } - operator const optional<environment> &() const { + operator const optional<environment>&() const { return env; } @@ -24590,7 +26818,7 @@ namespace sol { load_status err; public: - load_result() noexcept = default; + load_result() noexcept : load_result(nullptr) {} load_result(lua_State* Ls, int stackindex = -1, int retnum = 0, int popnum = 0, load_status lerr = load_status::ok) noexcept : L(Ls), index(stackindex), returncount(retnum), popcount(popnum), err(lerr) { } @@ -24657,7 +26885,7 @@ namespace sol { } else { if constexpr (std::is_same_v<T, error>) { -#if SOL_IS_ON(SOL_SAFE_PROXIES_I_) +#if SOL_IS_ON(SOL_SAFE_PROXIES) if (valid()) { type_panic_c_str(L, index, type_of(L, index), type::none, "expecting an error type (a string, from Lua)"); } @@ -24665,7 +26893,7 @@ namespace sol { return error(detail::direct_error, stack::get<std::string>(L, index)); } else { -#if SOL_IS_ON(SOL_SAFE_PROXIES_I_) +#if SOL_IS_ON(SOL_SAFE_PROXIES) if (!valid()) { type_panic_c_str(L, index, type_of(L, index), type::none); } @@ -24677,12 +26905,7 @@ namespace sol { template <typename... Ret, typename... Args> decltype(auto) call(Args&&... args) { -#if !defined(__clang__) && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000 - // MSVC is ass sometimes - return get<protected_function>().call<Ret...>(std::forward<Args>(args)...); -#else return get<protected_function>().template call<Ret...>(std::forward<Args>(args)...); -#endif } template <typename... Args> @@ -24698,7 +26921,9 @@ namespace sol { }; ~load_result() { - stack::remove(L, index, popcount); + if (L != nullptr) { + stack::remove(L, index, popcount); + } } }; } // namespace sol @@ -24729,7 +26954,7 @@ namespace sol { using is_lua_value_single_constructible = meta::any<std::is_same<T, lua_value>, is_reference_or_lua_value_init_list<T>>; static lua_State*& thread_local_lua_state() { -#if SOL_IS_ON(SOL_USE_THREAD_LOCAL_I_) +#if SOL_IS_ON(SOL_USE_THREAD_LOCAL) static thread_local lua_State* L = nullptr; #else static lua_State* L = nullptr; @@ -24813,7 +27038,7 @@ namespace sol { if (r == LUA_NOREF) return false; auto pp = stack::push_pop(ref_value); - return stack::check<T>(ref_value.lua_state(), -1, no_panic); + return stack::check<T>(ref_value.lua_state(), -1, &no_panic); } }; @@ -24842,13 +27067,13 @@ namespace sol { // end of sol/lua_value.hpp -#if SOL_IS_ON(SOL_PRINT_ERRORS_I_) +#if SOL_IS_ON(SOL_PRINT_ERRORS) #include <iostream> #endif namespace sol { inline void register_main_thread(lua_State* L) { -#if SOL_LUA_VESION_I_ < 502 +#if SOL_LUA_VERSION_I_ < 502 if (L == nullptr) { lua_pushnil(L); lua_setglobal(L, detail::default_main_thread_name()); @@ -24862,7 +27087,7 @@ namespace sol { } inline int default_at_panic(lua_State* L) { -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) +#if SOL_IS_OFF(SOL_EXCEPTIONS) (void)L; return -1; #else @@ -24871,8 +27096,8 @@ namespace sol { if (message) { std::string err(message, messagesize); lua_settop(L, 0); -#if SOL_IS_ON(SOL_PRINT_ERRORS_I_) - std::cerr << "[sol3] An error occurred and panic has been invoked: "; +#if SOL_IS_ON(SOL_PRINT_ERRORS) + std::cerr << "[sol2] An error occurred and panic has been invoked: "; std::cerr << err; std::cerr << std::endl; #endif @@ -24885,19 +27110,19 @@ namespace sol { inline int default_traceback_error_handler(lua_State* L) { std::string msg = "An unknown error has triggered the default error handler"; - optional<string_view> maybetopmsg = stack::unqualified_check_get<string_view>(L, 1, no_panic); + optional<string_view> maybetopmsg = stack::unqualified_check_get<string_view>(L, 1, &no_panic); if (maybetopmsg) { const string_view& topmsg = maybetopmsg.value(); msg.assign(topmsg.data(), topmsg.size()); } luaL_traceback(L, L, msg.c_str(), 1); - optional<string_view> maybetraceback = stack::unqualified_check_get<string_view>(L, -1, no_panic); + optional<string_view> maybetraceback = stack::unqualified_check_get<string_view>(L, -1, &no_panic); if (maybetraceback) { const string_view& traceback = maybetraceback.value(); msg.assign(traceback.data(), traceback.size()); } -#if SOL_IS_ON(SOL_PRINT_ERRORS_I_) - // std::cerr << "[sol3] An error occurred and was caught in traceback: "; +#if SOL_IS_ON(SOL_PRINT_ERRORS) + // std::cerr << "[sol2] An error occurred and was caught in traceback: "; // std::cerr << msg; // std::cerr << std::endl; #endif // Printing @@ -24916,9 +27141,9 @@ namespace sol { } inline std::size_t total_memory_used(lua_State* L) { - std::size_t kb = lua_gc(L, LUA_GCCOUNT, 0); + std::size_t kb = static_cast<std::size_t>(lua_gc(L, LUA_GCCOUNT, 0)); kb *= 1024; - kb += lua_gc(L, LUA_GCCOUNTB, 0); + kb += static_cast<std::size_t>(lua_gc(L, LUA_GCCOUNTB, 0)); return kb; } @@ -24931,7 +27156,7 @@ namespace sol { std::string err = "sol: "; err += to_string(result.status()); err += " error"; -#if SOL_IS_ON(SOL_EXCEPTIONS_I_) +#if SOL_IS_ON(SOL_EXCEPTIONS) std::exception_ptr eptr = std::current_exception(); if (eptr) { err += " with a "; @@ -24960,8 +27185,8 @@ namespace sol { string_view serr = stack::unqualified_get<string_view>(L, result.stack_index()); err.append(serr.data(), serr.size()); } -#if SOL_IS_ON(SOL_PRINT_ERRORS_I_) - std::cerr << "[sol3] An error occurred and has been passed to an error handler: "; +#if SOL_IS_ON(SOL_PRINT_ERRORS) + std::cerr << "[sol2] An error occurred and has been passed to an error handler: "; std::cerr << err; std::cerr << std::endl; #endif @@ -24976,7 +27201,7 @@ namespace sol { if (towards != 0) { lua_rotate(L, top, towards); } -#if SOL_IS_OFF(SOL_EXCEPTIONS_I_) +#if SOL_IS_OFF(SOL_EXCEPTIONS) return result; #else // just throw our error @@ -24985,7 +27210,7 @@ namespace sol { } inline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) { -#if SOL_IS_ON(SOL_DEFAULT_PASS_ON_ERROR_I_) +#if SOL_IS_ON(SOL_DEFAULT_PASS_ON_ERROR) return script_pass_on_error(L, std::move(pfr)); #else return script_throw_on_error(L, std::move(pfr)); @@ -25020,7 +27245,7 @@ namespace sol { bool is53mod = loaded && !(loaded->is<bool>() && !loaded->as<bool>()); if (is53mod) return loaded; -#if SOL_LUA_VESION_I_ <= 501 +#if SOL_LUA_VERSION_I_ <= 501 auto loaded51 = global.traverse_get<optional<object>>("package", "loaded", key); bool is51mod = loaded51 && !(loaded51->is<bool>() && !loaded51->as<bool>()); if (is51mod) @@ -25031,7 +27256,7 @@ namespace sol { template <typename T> void ensure_package(const std::string& key, T&& sr) { -#if SOL_LUA_VESION_I_ <= 501 +#if SOL_LUA_VERSION_I_ <= 501 auto pkg = global["package"]; if (!pkg.valid()) { pkg = create_table_with("loaded", create_table_with(key, sr)); @@ -25060,7 +27285,16 @@ namespace sol { optional<object> loaded = is_loaded_package(key); if (loaded && loaded->valid()) return std::move(*loaded); + int before = lua_gettop(L); action(); + int after = lua_gettop(L); + if (before == after) { + // I mean, you were supposed to return + // something, ANYTHING, from your requires script. I guess I'll just + // but some trash in here, it's on you after that? + ensure_package(key, static_cast<void*>(L)); + return object(L, lua_nil); + } stack_reference sr(L, -1); if (create_global) set(key, sr); @@ -25072,7 +27306,7 @@ namespace sol { using iterator = typename global_table::iterator; using const_iterator = typename global_table::const_iterator; - state_view(lua_State* Ls) : L(Ls), reg(Ls, LUA_REGISTRYINDEX), global(Ls, detail::global_) { + state_view(lua_State* Ls) : L(Ls), reg(Ls, LUA_REGISTRYINDEX), global(Ls, global_tag) { } state_view(this_state Ls) : state_view(Ls.L) { @@ -25094,7 +27328,7 @@ namespace sol { for (auto&& library : libraries) { switch (library) { -#if SOL_LUA_VESION_I_ <= 501 && defined(SOL_LUAJIT) +#if SOL_LUA_VERSION_I_ <= 501 && SOL_IS_ON(SOL_USE_LUAJIT) case lib::coroutine: #endif // luajit opens coroutine base stuff case lib::base: @@ -25105,9 +27339,9 @@ namespace sol { luaL_requiref(L, "package", luaopen_package, 1); lua_pop(L, 1); break; -#if !defined(SOL_LUAJIT) +#if SOL_IS_OFF(SOL_USE_LUAJIT) case lib::coroutine: -#if SOL_LUA_VESION_I_ > 501 +#if SOL_LUA_VERSION_I_ > 501 luaL_requiref(L, "coroutine", luaopen_coroutine, 1); lua_pop(L, 1); #endif // Lua 5.2+ only @@ -25126,14 +27360,14 @@ namespace sol { lua_pop(L, 1); break; case lib::bit32: -#ifdef SOL_LUAJIT +#if SOL_IS_ON(SOL_USE_LUAJIT) luaL_requiref(L, "bit32", luaopen_bit, 1); lua_pop(L, 1); -#elif (SOL_LUA_VESION_I_ == 502) || defined(LUA_COMPAT_BITLIB) || defined(LUA_COMPAT_5_2) +#elif SOL_IS_ON(SOL_LUA_BIT32_LIB) luaL_requiref(L, "bit32", luaopen_bit32, 1); lua_pop(L, 1); #else -#endif // Lua 5.2 only (deprecated in 5.3 (503)) (Can be turned on with Compat flags) +#endif break; case lib::io: luaL_requiref(L, "io", luaopen_io, 1); @@ -25148,19 +27382,19 @@ namespace sol { lua_pop(L, 1); break; case lib::utf8: -#if SOL_LUA_VESION_I_ > 502 && !defined(SOL_LUAJIT) +#if SOL_LUA_VERSION_I_ > 502 && SOL_IS_OFF(SOL_USE_LUAJIT) luaL_requiref(L, "utf8", luaopen_utf8, 1); lua_pop(L, 1); #endif // Lua 5.3+ only break; case lib::ffi: -#ifdef SOL_LUAJIT +#if SOL_IS_ON(SOL_USE_LUAJIT) && SOL_IS_OFF(SOL_LUAJIT_FFI_DISABLED) luaL_requiref(L, "ffi", luaopen_ffi, 1); lua_pop(L, 1); #endif // LuaJIT only break; case lib::jit: -#ifdef SOL_LUAJIT +#if SOL_IS_ON(SOL_USE_LUAJIT) luaL_requiref(L, "jit", luaopen_jit, 0); lua_pop(L, 1); #endif // LuaJIT Only @@ -25201,7 +27435,7 @@ namespace sol { // one day Lua 5.1 will die a peaceful death // and its old bones will find blissful rest auto loaders_proxy = package -#if SOL_LUA_VESION_I_ < 502 +#if SOL_LUA_VERSION_I_ < 502 ["loaders"] #else ["searchers"] @@ -25229,7 +27463,7 @@ namespace sol { // one day Lua 5.1 will die a peaceful death // and its old bones will find blissful rest auto loaders_proxy = package -#if SOL_LUA_VESION_I_ < 502 +#if SOL_LUA_VERSION_I_ < 502 ["loaders"] #else ["searchers"] @@ -25516,7 +27750,7 @@ namespace sol { return safe_script_file(filename, env, script_default_on_error, mode); } -#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS_I_) +#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS) protected_function_result script( lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { return safe_script(reader, data, chunkname, mode); @@ -25612,7 +27846,7 @@ namespace sol { } bool supports_gc_mode(gc_mode mode) const noexcept { -#if SOL_LUA_VESION_I_ >= 504 +#if SOL_LUA_VERSION_I_ >= 504 // supports all modes (void)mode; return true; @@ -25621,7 +27855,7 @@ namespace sol { } bool is_gc_on() const { -#if SOL_LUA_VESION_I_ >= 502 +#if SOL_LUA_VERSION_I_ >= 502 return lua_gc(lua_state(), LUA_GCISRUNNING, 0) == 1; #else // You cannot turn it off in Lua 5.1 @@ -25641,7 +27875,7 @@ namespace sol { // THOUGHT: std::chrono-alikes to map "kilobyte size" here...? // Make it harder to give MB or KB to a B parameter...? // Probably overkill for now. -#if SOL_LUA_VESION_I_ >= 504 +#if SOL_LUA_VERSION_I_ >= 504 // The manual implies that this function is almost always successful... // is it?? It could depend on the GC mode... return lua_gc(lua_state(), LUA_GCSTEP, step_size_kilobytes) != 0; @@ -25666,7 +27900,7 @@ namespace sol { // THOUGHT: std::chrono-alikes to map "byte size" here...? // Make it harder to give MB or KB to a B parameter...? // Probably overkill for now. -#if SOL_LUA_VESION_I_ >= 504 +#if SOL_LUA_VERSION_I_ >= 504 int old_mode = lua_gc(lua_state(), LUA_GCINC, pause, step_multiplier, step_byte_size); if (old_mode == LUA_GCGEN) { return gc_mode::generational; @@ -25684,7 +27918,7 @@ namespace sol { // Returns the old GC mode. Check support using the supports_gc_mode function. gc_mode change_gc_mode_generational(int minor_multiplier, int major_multiplier) { -#if SOL_LUA_VESION_I_ >= 504 +#if SOL_LUA_VERSION_I_ >= 504 // "What does this shit mean?" // http://www.lua.org/manual/5.4/manual.html#2.5.2 int old_mode = lua_gc(lua_state(), LUA_GCGEN, minor_multiplier, major_multiplier); @@ -25694,6 +27928,9 @@ namespace sol { else if (old_mode == LUA_GCINC) { return gc_mode::incremental; } +#else + (void)minor_multiplier; + (void)major_multiplier; #endif return gc_mode::default_value; } @@ -25743,8 +27980,8 @@ namespace sol { } template <typename Class, typename... Args> - usertype<Class> new_usertype(const std::string& name, Args&&... args) { - return global.new_usertype<Class>(name, std::forward<Args>(args)...); + usertype<Class> new_usertype(Args&&... args) { + return global.new_usertype<Class>(std::forward<Args>(args)...); } template <bool read_only = true, typename... Args> @@ -25841,8 +28078,7 @@ namespace sol { struct lua_thread_state { lua_State* L; - lua_thread_state(lua_State* Ls) - : L(Ls) { + lua_thread_state(lua_State* Ls) : L(Ls) { } lua_State* lua_state() const noexcept { @@ -25869,7 +28105,7 @@ namespace sol { struct unqualified_getter<lua_thread_state> { lua_thread_state get(lua_State* L, int index, record& tracking) { tracking.use(1); - lua_thread_state lts( lua_tothread(L, index) ); + lua_thread_state lts(lua_tothread(L, index)); return lts; } }; @@ -25878,7 +28114,7 @@ namespace sol { struct unqualified_check_getter<lua_thread_state> { template <typename Handler> optional<lua_thread_state> get(lua_State* L, int index, Handler&& handler, record& tracking) { - lua_thread_state lts( lua_tothread(L, index) ); + lua_thread_state lts(lua_tothread(L, index)); if (lts.lua_state() == nullptr) { handler(L, index, type::thread, type_of(L, index), "value is not a valid thread type"); return nullopt; @@ -25900,55 +28136,47 @@ namespace sol { basic_thread() noexcept = default; basic_thread(const basic_thread&) = default; basic_thread(basic_thread&&) = default; - template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_thread>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_thread(T&& r) - : base_t(std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_thread>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_thread(T&& r) : base_t(std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_thread>(lua_state(), -1, handler); #endif // Safety } - basic_thread(const stack_reference& r) - : basic_thread(r.lua_state(), r.stack_index()){}; - basic_thread(stack_reference&& r) - : basic_thread(r.lua_state(), r.stack_index()){}; + basic_thread(const stack_reference& r) : basic_thread(r.lua_state(), r.stack_index()) {}; + basic_thread(stack_reference&& r) : basic_thread(r.lua_state(), r.stack_index()) {}; basic_thread& operator=(const basic_thread&) = default; basic_thread& operator=(basic_thread&&) = default; template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_thread(lua_State* L, T&& r) - : base_t(L, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_thread(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_thread>(lua_state(), -1, handler); #endif // Safety } - basic_thread(lua_State* L, int index = -1) - : base_t(L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) - constructor_handler handler{}; + basic_thread(lua_State* L, int index = -1) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; stack::check<basic_thread>(L, index, handler); #endif // Safety } - basic_thread(lua_State* L, ref_index index) - : base_t(L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_thread(lua_State* L, ref_index index) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_thread>(lua_state(), -1, handler); #endif // Safety } - basic_thread(lua_State* L, lua_State* actualthread) - : basic_thread(L, lua_thread_state{ actualthread }) { + basic_thread(lua_State* L, lua_State* actualthread) : basic_thread(L, lua_thread_state { actualthread }) { } - basic_thread(lua_State* L, this_state actualthread) - : basic_thread(L, lua_thread_state{ actualthread.L }) { + basic_thread(lua_State* L, this_state actualthread) : basic_thread(L, lua_thread_state { actualthread.L }) { } - basic_thread(lua_State* L, lua_thread_state actualthread) - : base_t(L, -stack::push(L, actualthread)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) - constructor_handler handler{}; + basic_thread(lua_State* L, lua_thread_state actualthread) : base_t(L, -stack::push(L, actualthread)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; stack::check<basic_thread>(lua_state(), -1, handler); #endif // Safety if (!is_stack_based<base_t>::value) { @@ -26012,8 +28240,7 @@ namespace sol { typedef std::unique_ptr<lua_State, detail::state_deleter> unique_base; public: - state(lua_CFunction panic = default_at_panic) - : unique_base(luaL_newstate()), state_view(unique_base::get()) { + state(lua_CFunction panic = default_at_panic) : unique_base(luaL_newstate()), state_view(unique_base::get()) { set_default_state(unique_base::get(), panic); } @@ -26043,20 +28270,17 @@ namespace sol { // beginning of sol/coroutine.hpp namespace sol { - template <typename ref_t> - class basic_coroutine : public basic_object<ref_t> { + template <typename Reference> + class basic_coroutine : public basic_object<Reference> { private: - using base_t = basic_object<ref_t>; - - public: - typedef reference handler_t; - handler_t error_handler; + using base_t = basic_object<Reference>; + using handler_t = reference; private: call_status stats = call_status::yielded; void luacall(std::ptrdiff_t argcount, std::ptrdiff_t) { -#if SOL_LUA_VESION_I_ >= 504 +#if SOL_LUA_VERSION_I_ >= 504 int nresults; stats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount), &nresults)); #else @@ -26087,9 +28311,9 @@ namespace sol { int poststacksize = lua_gettop(this->lua_state()); int returncount = poststacksize - (firstreturn - 1); if (error()) { - if (error_handler.valid()) { + if (m_error_handler.valid()) { string_view err = stack::get<string_view>(this->lua_state(), poststacksize); - error_handler.push(); + m_error_handler.push(); stack::push(this->lua_state(), err); lua_call(lua_state(), 1, 1); } @@ -26107,8 +28331,8 @@ namespace sol { meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_coroutine(T&& r) noexcept - : base_t(std::forward<T>(r)), error_handler(detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + : base_t(std::forward<T>(r)), m_error_handler(detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) if (!is_function<meta::unqualified_t<T>>::value) { auto pp = stack::push_pop(*this); constructor_handler handler {}; @@ -26116,29 +28340,39 @@ namespace sol { } #endif // Safety } - basic_coroutine(const basic_coroutine&) = default; + + basic_coroutine(const basic_coroutine& other) = default; basic_coroutine& operator=(const basic_coroutine&) = default; - basic_coroutine(basic_coroutine&&) = default; - basic_coroutine& operator=(basic_coroutine&&) = default; - basic_coroutine(const basic_function<base_t>& b) + + basic_coroutine(basic_coroutine&& other) noexcept : base_t(std::move(other)), m_error_handler(this->lua_state(), std::move(other.m_error_handler)) { + } + + basic_coroutine& operator=(basic_coroutine&& other) noexcept { + base_t::operator=(std::move(other)); + // must change the state, since it could change on the coroutine type + m_error_handler = handler_t(this->lua_state(), std::move(other.m_error_handler)); + return *this; + } + + basic_coroutine(const basic_function<base_t>& b) noexcept : basic_coroutine(b, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(b.lua_state())) { } - basic_coroutine(basic_function<base_t>&& b) + basic_coroutine(basic_function<base_t>&& b) noexcept : basic_coroutine(std::move(b), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(b.lua_state())) { } - basic_coroutine(const basic_function<base_t>& b, handler_t eh) : base_t(b), error_handler(std::move(eh)) { + basic_coroutine(const basic_function<base_t>& b, handler_t eh) noexcept : base_t(b), m_error_handler(std::move(eh)) { } - basic_coroutine(basic_function<base_t>&& b, handler_t eh) : base_t(std::move(b)), error_handler(std::move(eh)) { + basic_coroutine(basic_function<base_t>&& b, handler_t eh) noexcept : base_t(std::move(b)), m_error_handler(std::move(eh)) { } - basic_coroutine(const stack_reference& r) + basic_coroutine(const stack_reference& r) noexcept : basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) { } - basic_coroutine(stack_reference&& r) + basic_coroutine(stack_reference&& r) noexcept : basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler<reference, is_main_threaded<base_t>::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(const stack_reference& r, handler_t eh) noexcept : 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)) { + basic_coroutine(stack_reference&& r, handler_t eh) noexcept : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) { } template <typename Super> @@ -26149,31 +28383,32 @@ namespace sol { basic_coroutine(proxy_base<Super>&& p) : basic_coroutine(std::move(p), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(p.lua_state())) { } - template <typename Proxy, typename Handler, - meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, meta::neg<is_lua_index<meta::unqualified_t<Handler>>>> = meta::enabler> - basic_coroutine(Proxy&& p, Handler&& eh) : basic_coroutine(detail::force_cast<base_t>(p), std::forward<Handler>(eh)) { + template <typename Proxy, typename HandlerReference, + meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, + meta::neg<is_lua_index<meta::unqualified_t<HandlerReference>>>> = meta::enabler> + basic_coroutine(Proxy&& p, HandlerReference&& eh) : basic_coroutine(detail::force_cast<base_t>(p), std::forward<HandlerReference>(eh)) { } template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_coroutine(lua_State* L, T&& r) + basic_coroutine(lua_State* L, T&& r) noexcept : basic_coroutine(L, std::forward<T>(r), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { } template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_coroutine(lua_State* L, T&& r, handler_t eh) : base_t(L, std::forward<T>(r)), error_handler(std::move(eh)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_coroutine(lua_State* L, T&& r, handler_t eh) : base_t(L, std::forward<T>(r)), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); constructor_handler handler {}; stack::check<basic_coroutine>(lua_state(), -1, handler); #endif // Safety } - basic_coroutine(lua_nil_t n) : base_t(n), error_handler(n) { + basic_coroutine(lua_nil_t n) : base_t(n), m_error_handler(n) { } basic_coroutine(lua_State* L, int index = -1) : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { } - basic_coroutine(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { + basic_coroutine(lua_State* L, int index, handler_t eh) : base_t(L, index), m_error_handler(std::move(eh)) { #ifdef SOL_SAFE_REFERENCES constructor_handler handler {}; stack::check<basic_coroutine>(L, index, handler); @@ -26182,8 +28417,8 @@ namespace sol { basic_coroutine(lua_State* L, absolute_index index) : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { } - basic_coroutine(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_coroutine(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) constructor_handler handler {}; stack::check<basic_coroutine>(L, index, handler); #endif // Safety @@ -26191,8 +28426,8 @@ namespace sol { basic_coroutine(lua_State* L, raw_index index) : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { } - basic_coroutine(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_coroutine(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) constructor_handler handler {}; stack::check<basic_coroutine>(L, index, handler); #endif // Safety @@ -26200,8 +28435,8 @@ namespace sol { basic_coroutine(lua_State* L, ref_index index) : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { } - basic_coroutine(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_coroutine(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); constructor_handler handler {}; stack::check<basic_coroutine>(lua_state(), -1, handler); @@ -26245,6 +28480,9 @@ namespace sol { int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount); } + + private: + handler_t m_error_handler; }; } // namespace sol @@ -26262,10 +28500,11 @@ namespace sol { using base_t::lua_state; basic_userdata() noexcept = default; - template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_userdata>>, meta::neg<std::is_same<base_t, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_userdata(T&& r) noexcept - : base_t(std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_userdata>>, meta::neg<std::is_same<base_t, stack_reference>>, + is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_userdata(T&& r) noexcept : base_t(std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) if (!is_userdata<meta::unqualified_t<T>>::value) { auto pp = stack::push_pop(*this); type_assert(lua_state(), -1, type::userdata); @@ -26276,33 +28515,28 @@ namespace sol { basic_userdata(basic_userdata&&) = default; basic_userdata& operator=(const basic_userdata&) = default; basic_userdata& operator=(basic_userdata&&) = default; - basic_userdata(const stack_reference& r) - : basic_userdata(r.lua_state(), r.stack_index()) { + basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) { } - basic_userdata(stack_reference&& r) - : basic_userdata(r.lua_state(), r.stack_index()) { + basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) { } template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_userdata(lua_State* L, T&& r) - : base_t(L, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_userdata(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_userdata>(L, -1, handler); #endif // Safety } - basic_userdata(lua_State* L, int index = -1) - : base_t(detail::no_safety, L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) - constructor_handler handler{}; + basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; stack::check<basic_userdata>(L, index, handler); #endif // Safety } - basic_userdata(lua_State* L, ref_index index) - : base_t(detail::no_safety, L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_userdata>(L, -1, handler); #endif // Safety } @@ -26316,10 +28550,11 @@ namespace sol { using base_t::lua_state; basic_lightuserdata() noexcept = default; - template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_lightuserdata>>, meta::neg<std::is_same<base_t, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_lightuserdata(T&& r) noexcept - : base_t(std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_lightuserdata>>, meta::neg<std::is_same<base_t, stack_reference>>, + is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_lightuserdata(T&& r) noexcept : base_t(std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) if (!is_lightuserdata<meta::unqualified_t<T>>::value) { auto pp = stack::push_pop(*this); type_assert(lua_state(), -1, type::lightuserdata); @@ -26330,33 +28565,28 @@ namespace sol { basic_lightuserdata(basic_lightuserdata&&) = default; basic_lightuserdata& operator=(const basic_lightuserdata&) = default; basic_lightuserdata& operator=(basic_lightuserdata&&) = default; - basic_lightuserdata(const stack_reference& r) - : basic_lightuserdata(r.lua_state(), r.stack_index()) { + basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) { } - basic_lightuserdata(stack_reference&& r) - : basic_lightuserdata(r.lua_state(), r.stack_index()) { + basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) { } template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> - basic_lightuserdata(lua_State* L, T&& r) - : basic_lightuserdata(L, std::forward<T>(r)) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_lightuserdata>(lua_state(), -1, handler); #endif // Safety } - basic_lightuserdata(lua_State* L, int index = -1) - : base_t(L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) - constructor_handler handler{}; + basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; stack::check<basic_lightuserdata>(L, index, handler); #endif // Safety } - basic_lightuserdata(lua_State* L, ref_index index) - : base_t(L, index) { -#if SOL_IS_ON(SOL_SAFE_REFERENCES_I_) + basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) auto pp = stack::push_pop(*this); - constructor_handler handler{}; + constructor_handler handler {}; stack::check<basic_lightuserdata>(lua_state(), index, handler); #endif // Safety } @@ -26419,16 +28649,13 @@ namespace sol { typedef std::reverse_iterator<const_iterator> const_reverse_iterator; variadic_args() = default; - variadic_args(lua_State* luastate, int stackindex = -1) - : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) { + variadic_args(lua_State* luastate, int stackindex = -1) : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) { } - variadic_args(lua_State* luastate, int stackindex, int lastindex) - : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) { + variadic_args(lua_State* luastate, int stackindex, int lastindex) : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) { } variadic_args(const variadic_args&) = default; variadic_args& operator=(const variadic_args&) = default; - variadic_args(variadic_args&& o) - : L(o.L), index(o.index), stacktop(o.stacktop) { + variadic_args(variadic_args&& o) : L(o.L), index(o.index), stacktop(o.stacktop) { // Must be manual, otherwise destructor will screw us // return count being 0 is enough to keep things clean // but will be thorough @@ -26559,20 +28786,25 @@ namespace sol { namespace sol { template <typename T> - struct as_returns_t { - T src; + struct as_returns_t : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using base_t::base_t; + using base_t::value; }; template <typename Source> auto as_returns(Source&& source) { - return as_returns_t<std::decay_t<Source>>{ std::forward<Source>(source) }; + return as_returns_t<std::decay_t<Source>> { std::forward<Source>(source) }; } namespace stack { template <typename T> struct unqualified_pusher<as_returns_t<T>> { int push(lua_State* L, const as_returns_t<T>& e) { - auto& src = detail::unwrap(e.src); + auto& src = detail::unwrap(e.value()); int p = 0; for (const auto& i : src) { p += stack::push(L, i); @@ -26657,13 +28889,14 @@ namespace sol { // end of sol/variadic_results.hpp -#if SOL_IS_ON(SOL_COMPILER_GCC_I_) +#if SOL_IS_ON(SOL_COMPILER_GCC) #pragma GCC diagnostic pop -#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_) +#elif SOL_IS_ON(SOL_COMPILER_CLANG) +#elif SOL_IS_ON(SOL_COMPILER_VCXX) #pragma warning(pop) #endif // g++ -#if SOL_IS_ON(SOL_INSIDE_UNREAL_ENGINE_I_) +#if SOL_IS_ON(SOL_INSIDE_UNREAL_ENGINE) #undef check #pragma pop_macro("check") #endif // Unreal Engine 4 Bullshit |