diff options
author | 2023-03-07 01:39:42 +1100 | |
---|---|---|
committer | 2023-03-07 01:39:42 +1100 | |
commit | b5475eb38b8b79a13a0a9e8a6cb68755b84f0c7b (patch) | |
tree | 005b70ffe81cab56d55873ac6ee68725e5ba9d36 /3rdparty/sol2/sol/sol.hpp | |
parent | 2102c32d2f3f94e69e3baf60294be3c04ca8b09f (diff) |
Various updates, mostly around Lua:
Compile Lua as C++. When Lua is compiled as C, it uses setjmp/longjmp
for error handling, resulting in failure to unwind intermediate stack
frames. Trying to ensure no objects with non-trivial destructors are in
scope when raising a Lua error is error-prone. In particular,
converting an exception to a Lua error becomes convoluted, and raising a
Lua error from a constructor is effectively impossible.
Updated Lua to 5.4.4 - this includes a brand-new garbage collector
implementation with better performance. The main thing removed is the
deprecated bitlib.
Updated sol2 to version 3.3.0 - this adds support for Lua 5.4 and fixes
a number of issues, including not correctly handling errors when Lua is
built as C++.
Updated LuaFileSystem to version 1.8.0 - this adds support for symbolic
links on Windows, as well as Lua 5.4 compatibility.
Updated LuaSQLite3 to version 0.9.5 - this fixes issues in
multi-threaded environments, as well as Lua 5.4 compatibility.
Fixed double-free after attempting to construct a debugger expression
from Lua with an invalid string, and exposed expression error to Lua in
a better way.
Added warning level print function to Lua.
Fixed saving cheats with shift operators in expressions, although this
code isn't actually used as there's no cheat editor.
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 |