diff --git a/third_party/sol2/sol2/sol.hpp b/third_party/sol2/sol2/sol.hpp index ff868d73c..335c7852b 100644 --- a/third_party/sol2/sol2/sol.hpp +++ b/third_party/sol2/sol2/sol.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors +// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2017-02-19 09:59:38.638408 UTC -// This header was generated with sol v2.15.8 (revision 0c8ec82) +// Generated 2017-07-09 23:05:15.984374 UTC +// This header was generated with sol v2.18.0 (revision 2d65f6c) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -47,11 +47,175 @@ #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 defined _MSC_VER #pragma warning( push ) #pragma warning( disable : 4324 ) // structure was padded due to alignment specifier +#pragma warning( disable : 4503 ) // decorated name horse shit +#pragma warning( disable : 4702 ) // unreachable code #endif // g++ +// beginning of sol/forward.hpp + +// beginning of sol/feature_test.hpp + +#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && (defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (_MSVC_LANG > 201402)) +#ifndef SOL_CXX17_FEATURES +#define SOL_CXX17_FEATURES 1 +#endif // C++17 features macro +#endif // C++17 features check + +#if defined(__cpp_noexcept_function_type) +#ifndef SOL_NOEXCEPT_FUNCTION_TYPE +#define SOL_NOEXCEPT_FUNCTION_TYPE 1 +#endif // noexcept is part of a function's type +#endif + +#if defined(_WIN32) || defined(_MSC_VER) +#ifndef SOL_CODECVT_SUPPORT +#define SOL_CODECVT_SUPPORT 1 +#endif // sol codecvt support +#elif defined(__GNUC__) +#if __GNUC__ >= 5 +#ifndef SOL_CODECVT_SUPPORT +#define SOL_CODECVT_SUPPORT 1 +#endif // codecvt support +#endif // g++ 5.x.x (MinGW too) +#else +#endif // Windows/VC++ vs. g++ vs Others + +#ifdef _MSC_VER +#ifdef _DEBUG +#ifndef NDEBUG +#ifndef SOL_CHECK_ARGUMENTS +#endif // Check Arguments +#ifndef SOL_SAFE_USERTYPE +#define SOL_SAFE_USERTYPE +#endif // Safe Usertypes +#endif // NDEBUG +#endif // Debug + +#ifndef _CPPUNWIND +#ifndef SOL_NO_EXCEPTIONS +#define SOL_NO_EXCEPTIONS 1 +#endif +#endif // Automatic Exceptions + +#ifndef _CPPRTTI +#ifndef SOL_NO_RTTI +#define SOL_NO_RTTI 1 +#endif +#endif // Automatic RTTI + +#elif defined(__GNUC__) || defined(__clang__) + +#ifndef NDEBUG +#ifndef __OPTIMIZE__ +#ifndef SOL_CHECK_ARGUMENTS +#endif // Check Arguments +#ifndef SOL_SAFE_USERTYPE +#define SOL_SAFE_USERTYPE +#endif // Safe Usertypes +#endif // g++ optimizer flag +#endif // Not Debug + +#ifndef __EXCEPTIONS +#ifndef SOL_NO_EXCEPTIONS +#define SOL_NO_EXCEPTIONS 1 +#endif +#endif // No Exceptions + +#ifndef __GXX_RTTI +#ifndef SOL_NO_RTII +#define SOL_NO_RTTI 1 +#endif +#endif // No RTTI + +#endif // vc++ || clang++/g++ + +#ifndef SOL_SAFE_USERTYPE +#ifdef SOL_CHECK_ARGUMENTS +#define SOL_SAFE_USERTYPE +#endif // Turn on Safety for all +#endif // Safe Usertypes + +// end of sol/feature_test.hpp + +namespace sol { + + class reference; + class stack_reference; + template + struct proxy; + template + class usertype; + template + class simple_usertype; + template + class basic_table_core; + template + using table_core = basic_table_core; + template + using stack_table_core = basic_table_core; + template + using basic_table = basic_table_core; + typedef table_core table; + typedef table_core global_table; + typedef stack_table_core stack_table; + typedef stack_table_core stack_global_table; + template + struct basic_environment; + using environment = basic_environment; + using stack_environment = basic_environment; + template + class basic_function; + template + class basic_protected_function; + using protected_function = basic_protected_function; + using stack_protected_function = basic_protected_function; + using unsafe_function = basic_function; + using safe_function = basic_protected_function; + using stack_unsafe_function = basic_function; + using stack_safe_function = basic_protected_function; +#ifdef SOL_SAFE_FUNCTIONS + using function = protected_function; + using stack_function = stack_protected_function; +#else + using function = unsafe_function; + using stack_function = stack_unsafe_function; +#endif + template + class basic_object; + template + class basic_userdata; + template + class basic_lightuserdata; + struct variadic_args; + using object = basic_object; + using stack_object = basic_object; + using userdata = basic_userdata; + using stack_userdata = basic_userdata; + using lightuserdata = basic_lightuserdata; + using stack_lightuserdata = basic_lightuserdata; + class coroutine; + class thread; + struct variadic_args; + struct variadic_results; + struct this_state; + struct this_environment; + template + struct light; + template + struct user; + template + struct as_args_t; + +} // sol + +// end of sol/forward.hpp + // beginning of sol/state.hpp // beginning of sol/state_view.hpp @@ -190,12 +354,13 @@ namespace sol { template using void_tuple_element_t = typename void_tuple_element::type; - template + template struct basic_traits { private: typedef std::conditional_t::value, int, T>& first_type; public: + static const bool is_noexcept = it_is_noexcept; static const bool is_member_function = std::is_void::value; static const bool has_c_var_arg = has_c_variadic; static const std::size_t arity = sizeof...(Args); @@ -215,123 +380,238 @@ namespace sol { }; template::value> - struct fx_traits : basic_traits {}; + struct fx_traits : basic_traits {}; // Free Functions template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(*function_pointer_type)(Args...); }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(*function_pointer_type)(Args...); }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(*function_pointer_type)(Args..., ...); }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(*function_pointer_type)(Args..., ...); }; // Member Functions /* C-Style Variadics */ template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args...); }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args..., ...); }; /* Const Volatile */ template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args...) const; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args..., ...) const; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args...) const volatile; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args..., ...) const volatile; }; /* Member Function Qualifiers */ template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args...) &; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args..., ...) &; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args...) const &; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args..., ...) const &; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args...) const volatile &; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args..., ...) const volatile &; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args...) && ; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args..., ...) && ; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args...) const &&; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args..., ...) const &&; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args...) const volatile &&; }; template - struct fx_traits : basic_traits { + struct fx_traits : basic_traits { typedef R(T::* function_pointer_type)(Args..., ...) const volatile &&; }; +#ifdef SOL_NOEXCEPT_FUNCTION_TYPE + + template + struct fx_traits : basic_traits { + typedef R(*function_pointer_type)(Args...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(*function_pointer_type)(Args...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(*function_pointer_type)(Args..., ...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(*function_pointer_type)(Args..., ...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) noexcept; + }; + + /* Const Volatile */ + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const volatile noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const volatile noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) & noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) & noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const & noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const & noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const volatile & noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const volatile & noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) && noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) && noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const && noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const && noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const volatile && noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const volatile && noexcept; + }; + +#endif // noexcept is part of a function's type + template struct fx_traits : fx_traits::function_type, false> {}; @@ -345,6 +625,7 @@ namespace sol { typedef R Arg; typedef T object_type; using signature_type = R(T::*); + static const bool is_noexcept = false; static const bool is_member_function = false; static const std::size_t arity = 1; static const std::size_t free_arity = 2; @@ -359,6 +640,7 @@ namespace sol { template using arg_at = void_tuple_element_t; }; + } // meta_detail template @@ -381,6 +663,10 @@ namespace sol { #include #include #include +#include +#ifdef SOL_CXX17_FEATURES +#include +#endif namespace sol { template @@ -629,6 +915,42 @@ namespace sol { static std::false_type test(...); }; + struct has_key_type_impl { + template, + typename V = typename U::key_type> + static std::true_type test(int); + + template + static std::false_type test(...); + }; + + struct has_mapped_type_impl { + template, + typename V = typename U::mapped_type> + static std::true_type test(int); + + template + static std::false_type test(...); + }; + + struct has_value_type_impl { + template, + typename V = typename U::value_type> + static std::true_type test(int); + + template + static std::false_type test(...); + }; + + struct has_iterator_impl { + template, + typename V = typename U::iterator> + static std::true_type test(int); + + template + static std::false_type test(...); + }; + struct has_key_value_pair_impl { template, typename V = typename U::value_type, @@ -668,8 +990,37 @@ namespace sol { template struct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test(0)) {}; + template + struct has_key_type : decltype(meta_detail::has_key_type_impl::test(0)) {}; + + template + struct has_mapped_type : decltype(meta_detail::has_mapped_type_impl::test(0)) {}; + + template + struct has_iterator : decltype(meta_detail::has_iterator_impl::test(0)) {}; + + template + struct has_value_type : decltype(meta_detail::has_value_type_impl::test(0)) {}; + template - using is_string_constructible = any, const char*>, std::is_same, char>, std::is_same, std::string>, std::is_same, std::initializer_list>>; + struct is_associative : meta::all, has_mapped_type> {}; + + template + using is_string_constructible = any< + std::is_same, const char*> + , std::is_same, char> + , std::is_same, std::string> + , std::is_same, std::initializer_list> +#ifdef SOL_CXX17_FEATURES + , std::is_same, std::string_view> +#endif + >; + + template + struct is_pair : std::false_type {}; + + template + struct is_pair> : std::true_type {}; template using is_c_str = any< @@ -704,7 +1055,19 @@ namespace sol { decltype(auto) tuplefy(X&&... x) { return std::tuple_cat(meta_detail::force_tuple(std::forward(x))...); } + + template + struct iterator_tag { + using type = std::input_iterator_tag; + }; + + template + struct iterator_tag> { + using type = typename T::iterator_category; + }; + } // meta + namespace detail { template decltype(auto) forward_get(Tuple&& tuple) { @@ -781,7 +1144,9 @@ namespace sol { // end of sol/traits.hpp -// beginning of sol/object.hpp +// beginning of sol/function.hpp + +// beginning of sol/unsafe_function.hpp // beginning of sol/reference.hpp @@ -797,22 +1162,12 @@ namespace sol { #include #include #include +#ifdef SOL_USING_CXX_LUAJIT +#include +#endif // C++ LuaJIT ... whatever that means #else #include -#endif // C++-compiler Lua - -#if defined(_WIN32) || defined(_MSC_VER) -#ifndef SOL_CODECVT_SUPPORT -#define SOL_CODECVT_SUPPORT 1 -#endif // sol codecvt support -#elif defined(__GNUC__) -#if __GNUC__ >= 5 -#ifndef SOL_CODECVT_SUPPORT -#define SOL_CODECVT_SUPPORT 1 -#endif // codecvt support -#endif // g++ 5.x.x (MinGW too) -#else -#endif // Windows/VC++ vs. g++ vs Others +#endif // C++ Mangling for Lua #ifdef LUAJIT_VERSION #ifndef SOL_LUAJIT @@ -831,68 +1186,38 @@ namespace sol { #define SOL_LUA_VERSION 502 #endif // Lua Version 502, 501 || luajit, 500 -#ifdef _MSC_VER -#ifdef _DEBUG -#ifndef NDEBUG -#ifndef SOL_CHECK_ARGUMENTS -#endif // Check Arguments -#ifndef SOL_SAFE_USERTYPE -#define SOL_SAFE_USERTYPE -#endif // Safe Usertypes -#endif // NDEBUG -#endif // Debug - -#ifndef _CPPUNWIND -#ifndef SOL_NO_EXCEPTIONS -#define SOL_NO_EXCEPTIONS 1 -#endif -#endif // Automatic Exceptions - -#ifndef _CPPRTTI -#ifndef SOL_NO_RTTI -#define SOL_NO_RTTI 1 -#endif -#endif // Automatic RTTI - -#elif defined(__GNUC__) || defined(__clang__) - -#ifndef NDEBUG -#ifndef __OPTIMIZE__ -#ifndef SOL_CHECK_ARGUMENTS -#endif // Check Arguments -#ifndef SOL_SAFE_USERTYPE -#define SOL_SAFE_USERTYPE -#endif // Safe Usertypes -#endif // g++ optimizer flag -#endif // Not Debug - -#ifndef __EXCEPTIONS -#ifndef SOL_NO_EXCEPTIONS -#define SOL_NO_EXCEPTIONS 1 -#endif -#endif // No Exceptions - -#ifndef __GXX_RTTI -#ifndef SOL_NO_RTII -#define SOL_NO_RTTI 1 -#endif -#endif // No RTTI - -#endif // vc++ || clang++/g++ - -#ifndef SOL_SAFE_USERTYPE -#ifdef SOL_CHECK_ARGUMENTS -#define SOL_SAFE_USERTYPE -#endif // Turn on Safety for all -#endif // Safe Usertypes - // end of sol/compatibility/version.hpp #ifndef SOL_NO_COMPAT -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(SOL_USING_CXX_LUA) extern "C" { #endif +// beginning of sol/compatibility/5.2.0.h + +#ifndef SOL_5_2_0_H +#define SOL_5_2_0_H + +#if SOL_LUA_VERSION < 503 + +inline int lua_isinteger(lua_State* L, int idx) { + if (lua_type(L, idx) != LUA_TNUMBER) + return 0; + // This is a very slipshod way to do the testing + // but lua_totingerx doesn't play ball nicely + // on older versions... + lua_Number n = lua_tonumber(L, idx); + lua_Integer i = lua_tointeger(L, idx); + if (i != n) + return 0; + // it's DEFINITELY an integer + return 1; +} + +#endif // SOL_LUA_VERSION == 502 +#endif // SOL_5_2_0_H +// end of sol/compatibility/5.2.0.h + // beginning of sol/compatibility/5.1.0.h #ifndef SOL_5_1_0_H @@ -921,7 +1246,7 @@ extern "C" { /* LuaJIT does not have the updated error codes for thread status/function returns */ #ifndef LUA_ERRGCMM -#define LUA_ERRGCMM (LUA_ERRERR + 1) +#define LUA_ERRGCMM (LUA_ERRERR + 2) #endif // LUA_ERRGCMM /* LuaJIT does not support continuation contexts / return error codes? */ @@ -1086,21 +1411,25 @@ inline int luaL_loadbufferx(lua_State* L, const char* buff, size_t size, const c #define lua_pushglobaltable(L) \ lua_pushvalue(L, LUA_GLOBALSINDEX) -#define luaL_newlib(L, l) \ - (lua_newtable((L)),luaL_setfuncs((L), (l), 0)) - void luaL_checkversion(lua_State *L); -int lua_absindex(lua_State *L, int i); +#if !defined(SOL_LUAJIT_VERSION) || SOL_LUAJIT_VERSION < 20100 void lua_copy(lua_State *L, int from, int to); -void lua_rawgetp(lua_State *L, int i, const void *p); -void lua_rawsetp(lua_State *L, int i, const void *p); -void *luaL_testudata(lua_State *L, int i, const char *tname); +lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum); lua_Number lua_tonumberx(lua_State *L, int i, int *isnum); -void lua_getuservalue(lua_State *L, int i); -void lua_setuservalue(lua_State *L, int i); +const lua_Number *lua_version(lua_State *L); void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup); void luaL_setmetatable(lua_State *L, const char *tname); +void *luaL_testudata(lua_State *L, int i, const char *tname); +#define luaL_newlib(L, l) \ + (lua_newtable((L)),luaL_setfuncs((L), (l), 0)) +#endif // LuaJIT-2.1.0-beta3 added these compatibility functions + +int lua_absindex(lua_State *L, int i); +void lua_rawgetp(lua_State *L, int i, const void *p); +void lua_rawsetp(lua_State *L, int i, const void *p); +void lua_getuservalue(lua_State *L, int i); +void lua_setuservalue(lua_State *L, int i); int luaL_getsubtable(lua_State *L, int i, const char *name); void luaL_traceback(lua_State *L, lua_State *L1, const char *msg, int level); int luaL_fileresult(lua_State *L, int stat, const char *fname); @@ -1115,32 +1444,7 @@ int luaL_fileresult(lua_State *L, int stat, const char *fname); #ifndef SOL_5_X_X_INL #define SOL_5_X_X_INL -// beginning of sol/compatibility/5.2.0.h - -#ifndef SOL_5_2_0_H -#define SOL_5_2_0_H - -#if SOL_LUA_VERSION < 503 - -inline int lua_isinteger(lua_State* L, int idx) { - if (lua_type(L, idx) != LUA_TNUMBER) - return 0; - // This is a very slipshod way to do the testing - // but lua_totingerx doesn't play ball nicely - // on older versions... - lua_Number n = lua_tonumber(L, idx); - lua_Integer i = lua_tointeger(L, idx); - if (i != n) - return 0; - // it's DEFINITELY an integer - return 1; -} - -#endif // SOL_LUA_VERSION == 502 -#endif // SOL_5_2_0_H -// end of sol/compatibility/5.2.0.h - -#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501 +#if SOL_LUA_VERSION < 502 #include @@ -1152,6 +1456,7 @@ inline int lua_absindex(lua_State *L, int i) { return i; } +#if !defined(SOL_LUAJIT_VERSION) || SOL_LUAJIT_VERSION < 20100 inline void lua_copy(lua_State *L, int from, int to) { int abs_to = lua_absindex(L, to); luaL_checkstack(L, 1, "not enough stack slots"); @@ -1159,6 +1464,69 @@ inline void lua_copy(lua_State *L, int from, int to) { lua_replace(L, abs_to); } +inline lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum) { + lua_Integer n = lua_tointeger(L, i); + if (isnum != NULL) { + *isnum = (n != 0 || lua_isnumber(L, i)); + } + return n; +} + +inline lua_Number lua_tonumberx(lua_State *L, int i, int *isnum) { + lua_Number n = lua_tonumber(L, i); + if (isnum != NULL) { + *isnum = (n != 0 || lua_isnumber(L, i)); + } + return n; +} + +inline const lua_Number *lua_version(lua_State *L) { + static const lua_Number version = LUA_VERSION_NUM; + if (L == NULL) return &version; + // TODO: wonky hacks to get at the inside of the incomplete type lua_State? + //else return L->l_G->version; + else return &version; +} + +/* +** Adapted from Lua 5.2.0 +*/ +inline void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { + luaL_checkstack(L, nup + 1, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + int i; + lua_pushstring(L, l->name); + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -(nup + 1)); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ + } + lua_pop(L, nup); /* remove upvalues */ +} + +inline void luaL_setmetatable(lua_State *L, const char *tname) { + luaL_checkstack(L, 1, "not enough stack slots"); + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); +} + +inline void *luaL_testudata(lua_State *L, int i, const char *tname) { + void *p = lua_touserdata(L, i); + luaL_checkstack(L, 2, "not enough stack slots"); + if (p == NULL || !lua_getmetatable(L, i)) + return NULL; + else { + int res = 0; + luaL_getmetatable(L, tname); + res = lua_rawequal(L, -1, -2); + lua_pop(L, 2); + if (!res) + p = NULL; + } + return p; +} +#endif + inline void lua_rawgetp(lua_State *L, int i, const void *p) { int abs_i = lua_absindex(L, i); lua_pushlightuserdata(L, (void*)p); @@ -1173,30 +1541,6 @@ inline void lua_rawsetp(lua_State *L, int i, const void *p) { lua_rawset(L, abs_i); } -inline void *luaL_testudata(lua_State *L, int i, const char *tname) { - void *p = lua_touserdata(L, i); - luaL_checkstack(L, 2, "not enough stack slots"); - if (p == NULL || !lua_getmetatable(L, i)) - return NULL; - else { - int res = 0; - luaL_getmetatable(L, tname); - res = lua_rawequal(L, -1, -2); - lua_pop(L, 2); - if (!res) - p = NULL; - } - return p; -} - -inline lua_Number lua_tonumberx(lua_State *L, int i, int *isnum) { - lua_Number n = lua_tonumber(L, i); - if (isnum != NULL) { - *isnum = (n != 0 || lua_isnumber(L, i)); - } - return n; -} - inline static void push_package_table(lua_State *L) { lua_pushliteral(L, PACKAGE_KEY); lua_rawget(L, LUA_REGISTRYINDEX); @@ -1246,28 +1590,6 @@ inline void lua_setuservalue(lua_State *L, int i) { lua_setfenv(L, i); } -/* -** Adapted from Lua 5.2.0 -*/ -inline void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { - luaL_checkstack(L, nup + 1, "too many upvalues"); - for (; l->name != NULL; l++) { /* fill the table with given functions */ - int i; - lua_pushstring(L, l->name); - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -(nup + 1)); - lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ - lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ - } - lua_pop(L, nup); /* remove upvalues */ -} - -inline void luaL_setmetatable(lua_State *L, const char *tname) { - luaL_checkstack(L, 1, "not enough stack slots"); - luaL_getmetatable(L, tname); - lua_setmetatable(L, -2); -} - inline int luaL_getsubtable(lua_State *L, int i, const char *name) { int abs_i = lua_absindex(L, i); luaL_checkstack(L, 3, "not enough stack slots"); @@ -1383,14 +1705,6 @@ inline void luaL_traceback(lua_State *L, lua_State *L1, } #endif -inline const lua_Number *lua_version(lua_State *L) { - static const lua_Number version = LUA_VERSION_NUM; - if (L == NULL) return &version; - // TODO: wonky hacks to get at the inside of the incomplete type lua_State? - //else return L->l_G->version; - else return &version; -} - inline static void luaL_checkversion_(lua_State *L, lua_Number ver) { const lua_Number* v = lua_version(L); if (v != lua_version(NULL)) @@ -1420,7 +1734,7 @@ inline int luaL_fileresult(lua_State *L, int stat, const char *fname) { } else { char buf[1024]; -#if defined(__GLIBC__) || defined(_POSIX_VERSION) +#if defined(__GLIBC__) || defined(_POSIX_VERSION) || defined(__APPLE__) strerror_r(en, buf, 1024); #else strerror_s(buf, 1024, en); @@ -1663,14 +1977,6 @@ inline lua_Unsigned luaL_optunsigned(lua_State *L, int i, lua_Unsigned def) { return luaL_opt(L, luaL_checkunsigned, i, def); } -inline lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum) { - lua_Integer n = lua_tointeger(L, i); - if (isnum != NULL) { - *isnum = (n != 0 || lua_isnumber(L, i)); - } - return n; -} - inline void lua_len(lua_State *L, int i) { switch (lua_type(L, i)) { case LUA_TSTRING: /* fall through */ @@ -1812,7 +2118,7 @@ inline void luaL_pushresult(luaL_Buffer_52 *B) { #endif // SOL_5_X_X_INL // end of sol/compatibility/5.x.x.inl -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(SOL_USING_CXX_LUA) } #endif @@ -1822,28 +2128,51 @@ inline void luaL_pushresult(luaL_Buffer_52 *B) { // beginning of sol/in_place.hpp +#include + namespace sol { +#ifdef SOL_CXX17_FEATURES + using in_place_t = std::in_place_t; + constexpr std::in_place_t in_place{}; + constexpr std::in_place_t in_place_of{}; + + template using in_place_type_t = std::in_place_type_t; + template + constexpr std::in_place_type_t in_place_type{}; + + template using in_place_index_t = std::in_place_index_t; + template + constexpr in_place_index_t in_place_index{}; +#else namespace detail { - struct in_place_of {}; + struct in_place_of_tag {}; template struct in_place_of_i {}; template struct in_place_of_t {}; } // detail - struct in_place_tag { struct init {}; constexpr in_place_tag(init) {} in_place_tag() = delete; }; - constexpr inline in_place_tag in_place(detail::in_place_of) { return in_place_tag(in_place_tag::init()); } + struct in_place_tag { constexpr in_place_tag() = default; }; + + constexpr inline in_place_tag in_place (detail::in_place_of_tag) { return in_place_tag(); } template - constexpr inline in_place_tag in_place(detail::in_place_of_t) { return in_place_tag(in_place_tag::init()); } + constexpr inline in_place_tag in_place (detail::in_place_of_t) { return in_place_tag(); } template - constexpr inline in_place_tag in_place(detail::in_place_of_i) { return in_place_tag(in_place_tag::init()); } + constexpr inline in_place_tag in_place (detail::in_place_of_i) { return in_place_tag(); } - using in_place_t = in_place_tag(&)(detail::in_place_of); + constexpr inline in_place_tag in_place_of(detail::in_place_of_tag) { return in_place_tag(); } + template + constexpr inline in_place_tag in_place_type (detail::in_place_of_t) { return in_place_tag(); } + template + constexpr inline in_place_tag in_place_index (detail::in_place_of_i) { return in_place_tag(); } + + using in_place_t = in_place_tag(&)(detail::in_place_of_tag); template using in_place_type_t = in_place_tag(&)(detail::in_place_of_t); template using in_place_index_t = in_place_tag(&)(detail::in_place_of_i); +#endif } // sol @@ -2576,15 +2905,12 @@ namespace sol { } constexpr T& value() const { - return ref ? - *ref #ifdef SOL_NO_EXCEPTIONS - // we can't abort here - // because there's no constexpr abort - : *(T*)nullptr; + return *ref; #else - : throw bad_optional_access("bad optional access"); -#endif + return ref ? *ref + : (throw bad_optional_access("bad optional access"), *ref); +#endif // Exceptions } explicit constexpr operator bool() const noexcept { @@ -2941,14 +3267,26 @@ namespace sol { const nullopt_t nullopt = boost::none; #endif // Boost vs. Better optional + namespace meta { + template + struct is_optional : std::false_type {}; + template + struct is_optional> : std::true_type {}; + } // meta } // sol // end of sol/optional.hpp // beginning of sol/string_shim.hpp +#ifdef SOL_CXX17_FEATURES +#endif // C++17 features + namespace sol { namespace string_detail { +#ifdef SOL_CXX17_FEATURES + typedef std::string_view string_shim; +#else struct string_shim { std::size_t s; const char* p; @@ -3004,27 +3342,42 @@ namespace sol { return !(*this == r); } }; +#endif // C++17 } } // end of sol/string_shim.hpp #include +#ifdef SOL_CXX17_FEATURES +#include +#endif // C++17 namespace sol { namespace detail { +#ifdef SOL_NOEXCEPT_FUNCTION_TYPE + typedef int(*lua_CFunction_noexcept) (lua_State *L) noexcept; +#endif // noexcept function type for lua_CFunction + #ifdef SOL_NO_EXCEPTIONS template - int static_trampoline(lua_State* L) { + int static_trampoline(lua_State* L) noexcept { return f(L); } +#ifdef SOL_NOEXCEPT_FUNCTION_TYPE + template + int static_trampoline_noexcept(lua_State* L) noexcept { + return f(L); + } +#endif + template - int trampoline(lua_State* L, Fx&& f, Args&&... args) { + int trampoline(lua_State* L, Fx&& f, Args&&... args) noexcept { return f(L, std::forward(args)...); } - inline int c_trampoline(lua_State* L, lua_CFunction f) { + inline int c_trampoline(lua_State* L, lua_CFunction f) noexcept { return trampoline(L, f); } #else @@ -3047,8 +3400,29 @@ namespace sol { return lua_error(L); } +#ifdef SOL_NOEXCEPT_FUNCTION_TYPE +#if 0 + template + int static_trampoline(lua_State* L) noexcept { +#else + template + int static_trampoline_noexcept(lua_State* L) noexcept { +#endif // impossible + return f(L); + } + +#else + template + int static_trampoline_noexcept(lua_State* L) noexcept { + return f(L); + } +#endif // noexcept lua_CFunction type + template int trampoline(lua_State* L, Fx&& f, Args&&... args) { + if (meta::bind_traits>::is_noexcept) { + return f(L, std::forward(args)...); + } try { return f(L, std::forward(args)...); } @@ -3071,6 +3445,21 @@ namespace sol { } #endif // Exceptions vs. No Exceptions + template + inline int typed_static_trampoline_raw(std::true_type, lua_State* L) { + return static_trampoline_noexcept(L); + } + + template + inline int typed_static_trampoline_raw(std::false_type, lua_State* L) { + return static_trampoline(L); + } + + template + inline int typed_static_trampoline(lua_State* L) { + return typed_static_trampoline_raw(std::integral_constant::is_noexcept>(), L); + } + template struct unique_usertype {}; @@ -3086,6 +3475,9 @@ namespace sol { return std::addressof(item); } }; + + struct unchecked_t {}; + const unchecked_t unchecked = unchecked_t{}; } // detail struct lua_nil_t {}; @@ -3097,8 +3489,11 @@ namespace sol { const nil_t nil{}; #endif - struct metatable_key_t {}; - const metatable_key_t metatable_key = {}; + struct metatable_t {}; + const metatable_t metatable_key = {}; + + struct env_t {}; + const env_t env_key = {}; struct no_metatable_t {}; const no_metatable_t no_metatable = {}; @@ -3160,26 +3555,46 @@ namespace sol { struct upvalue_index { int index; - upvalue_index(int idx) : index(lua_upvalueindex(idx)) {} - operator int() const { return index; } + upvalue_index(int idx) : index(lua_upvalueindex(idx)) { + + } + + operator int() const { + return index; + } }; struct raw_index { int index; - raw_index(int i) : index(i) {} - operator int() const { return index; } + raw_index(int i) : index(i) { + + } + + operator int() const { + return index; + } }; struct absolute_index { int index; - absolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) {} - operator int() const { return index; } + absolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) { + + } + + operator int() const { + return index; + } }; struct ref_index { int index; - ref_index(int idx) : index(idx) {} - operator int() const { return index; } + ref_index(int idx) : index(idx) { + + } + + operator int() const { + return index; + } }; struct lightuserdata_value { @@ -3289,11 +3704,28 @@ namespace sol { } }; + template + struct nested { + T source; + + template + nested(Args&&... args) : source(std::forward(args)...) {} + + operator std::add_lvalue_reference_t() { + return source; + } + }; + template as_table_t as_table(T&& container) { return as_table_t(std::forward(container)); } + template + nested as_nested(T&& container) { + return as_nested(std::forward(container)); + } + struct this_state { lua_State* L; operator lua_State* () const { @@ -3304,6 +3736,19 @@ namespace sol { } }; + struct new_table { + int sequence_hint = 0; + int map_hint = 0; + + new_table() = default; + new_table(const new_table&) = default; + new_table(new_table&&) = default; + 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) {} + }; + enum class call_syntax { dot = 0, colon = 1 @@ -3315,7 +3760,9 @@ namespace sol { runtime = LUA_ERRRUN, memory = LUA_ERRMEM, handler = LUA_ERRERR, - gc = LUA_ERRGCMM + gc = LUA_ERRGCMM, + syntax = LUA_ERRSYNTAX, + file = LUA_ERRFILE, }; enum class thread_status : int { @@ -3354,6 +3801,61 @@ namespace sol { table | boolean | function | userdata | lightuserdata }; + inline const std::string& to_string(call_status c) { + static const std::array names{{ + "ok", + "yielded", + "runtime", + "memory", + "handler", + "gc", + "syntax", + "file", + }}; + switch (c) { + case call_status::ok: + return names[0]; + case call_status::yielded: + return names[1]; + case call_status::runtime: + return names[2]; + case call_status::memory: + return names[3]; + case call_status::handler: + return names[4]; + case call_status::gc: + return names[5]; + case call_status::syntax: + return names[6]; + case call_status::file: + return names[7]; + } + return names[0]; + } + + inline const std::string& to_string(load_status c) { + static const std::array names{ { + "ok", + "memory", + "gc", + "syntax", + "file", + } }; + switch (c) { + case load_status::ok: + return names[0]; + case load_status::memory: + return names[1]; + case load_status::gc: + return names[2]; + case load_status::syntax: + return names[3]; + case load_status::file: + return names[4]; + } + return names[0]; + } + enum class meta_function { construct, index, @@ -3390,54 +3892,52 @@ namespace sol { typedef meta_function meta_method; - const std::array meta_variable_names = { { - "__index", - "__newindex", - } }; + inline const std::array& meta_function_names() { + static const std::array names = { { + "new", + "__index", + "__newindex", + "__mode", + "__call", + "__mt", + "__tostring", + "__len", + "__unm", + "__add", + "__sub", + "__mul", + "__div", + "__mod", + "__pow", + "__concat", + "__eq", + "__lt", + "__le", + "__gc", - const std::array meta_function_names = { { - "new", - "__index", - "__newindex", - "__mode", - "__call", - "__mt", - "__tostring", - "__len", - "__unm", - "__add", - "__sub", - "__mul", - "__div", - "__mod", - "__pow", - "__concat", - "__eq", - "__lt", - "__le", - "__gc", - - "__idiv", - "__shl", - "__shr", - "__bnot", - "__band", - "__bor", - "__bxor", + "__idiv", + "__shl", + "__shr", + "__bnot", + "__band", + "__bor", + "__bxor", - "__pairs", - "__next" - } }; + "__pairs", + "__next" + } }; + return names; + } - inline const std::string& name_of(meta_function mf) { - return meta_function_names[static_cast(mf)]; + inline const std::string& to_string(meta_function mf) { + return meta_function_names()[static_cast(mf)]; } inline type type_of(lua_State* L, int index) { return static_cast(lua_type(L, index)); } - inline int type_panic(lua_State* L, int index, type expected, type actual) { + inline int type_panic(lua_State* L, int index, type expected, type actual) noexcept(false) { return luaL_error(L, "stack index %d, expected %s, received %s", index, expected == type::poly ? "anything" : lua_typename(L, static_cast(expected)), expected == type::poly ? "anything" : lua_typename(L, static_cast(actual)) @@ -3449,15 +3949,15 @@ namespace sol { return 0; } - inline void type_error(lua_State* L, int expected, int actual) { + inline void type_error(lua_State* L, int expected, int actual) noexcept(false) { luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual)); } - inline void type_error(lua_State* L, type expected, type actual) { + inline void type_error(lua_State* L, type expected, type actual) noexcept(false) { type_error(L, static_cast(expected), static_cast(actual)); } - inline void type_assert(lua_State* L, int index, type expected, type actual) { + inline void type_assert(lua_State* L, int index, type expected, type actual) noexcept(false) { if (expected != type::poly && expected != actual) { type_panic(L, index, expected, actual); } @@ -3472,52 +3972,6 @@ namespace sol { return lua_typename(L, static_cast(t)); } - class reference; - class stack_reference; - template - struct proxy; - template - class usertype; - template - class basic_table_core; - template - using table_core = basic_table_core; - template - using stack_table_core = basic_table_core; - typedef table_core table; - typedef table_core global_table; - typedef stack_table_core stack_table; - typedef stack_table_core stack_global_table; - template - class basic_function; - template - class basic_protected_function; - using function = basic_function; - using protected_function = basic_protected_function; - using stack_function = basic_function; - using stack_protected_function = basic_protected_function; - using unsafe_function = basic_function; - using safe_function = basic_protected_function; - using stack_unsafe_function = basic_function; - using stack_safe_function = basic_protected_function; - template - class basic_object; - template - class basic_userdata; - template - class basic_lightuserdata; - struct variadic_args; - using object = basic_object; - using stack_object = basic_object; - using userdata = basic_userdata; - using stack_userdata = basic_userdata; - using lightuserdata = basic_lightuserdata; - using stack_lightuserdata = basic_lightuserdata; - class coroutine; - class thread; - struct variadic_args; - struct this_state; - namespace detail { template struct lua_type_of : std::integral_constant {}; @@ -3567,9 +4021,6 @@ namespace sol { template <> struct lua_type_of : std::integral_constant {}; - template <> - struct lua_type_of : std::integral_constant {}; - template <> struct lua_type_of : std::integral_constant {}; @@ -3588,6 +4039,21 @@ namespace sol { template struct lua_type_of> : std::integral_constant { }; + template <> + struct lua_type_of : std::integral_constant { }; + + template + struct lua_type_of> : std::integral_constant { }; + + template <> + struct lua_type_of : std::integral_constant { }; + + template <> + struct lua_type_of : std::integral_constant { }; + + template + struct lua_type_of> : std::integral_constant {}; + template <> struct lua_type_of : std::integral_constant {}; @@ -3654,6 +4120,9 @@ namespace sol { template <> struct lua_type_of : std::integral_constant {}; + template <> + struct lua_type_of : std::integral_constant {}; + template <> struct lua_type_of : std::integral_constant {}; @@ -3666,14 +4135,61 @@ namespace sol { template struct lua_type_of::value>> : std::integral_constant {}; + template <> + struct lua_type_of : std::integral_constant {}; + +#ifdef SOL_CXX17_FEATURES + template <> + struct lua_type_of : std::integral_constant {}; + + template <> + struct lua_type_of : std::integral_constant {}; + + template <> + struct lua_type_of : std::integral_constant {}; + + template <> + struct lua_type_of : std::integral_constant {}; + + template + struct lua_type_of> : std::integral_constant {}; +#else + template <> + struct lua_type_of : std::integral_constant {}; +#endif // C++ 17 (or not) features + template struct is_container : std::false_type {}; - template - struct is_container>::value>> : std::true_type {}; + template <> + struct is_container : std::false_type {}; template <> - struct lua_type_of : std::integral_constant {}; + struct is_container : std::false_type {}; + + template <> + struct is_container : std::false_type {}; + + template <> + struct is_container : std::false_type {}; + +#ifdef SOL_CXX17_FEATURES + template <> + struct is_container : std::false_type {}; + + template <> + struct is_container : std::false_type {}; + + template <> + struct is_container : std::false_type {}; + + template <> + struct is_container : std::false_type {}; + +#endif // C++ 17 + + template + struct is_container>::value>> : std::true_type {}; template class V, typename... Args> struct accumulate : std::integral_constant {}; @@ -3686,10 +4202,14 @@ namespace sol { struct is_unique_usertype : std::integral_constant::value> {}; template - struct lua_type_of : detail::lua_type_of {}; + struct lua_type_of : detail::lua_type_of { + typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; + }; template - struct lua_size : std::integral_constant { }; + struct lua_size : std::integral_constant { + typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; + }; template struct lua_size> : std::integral_constant::value + lua_size::value> { }; @@ -3697,10 +4217,24 @@ namespace sol { template struct lua_size> : std::integral_constant::value> { }; + namespace detail { + template + struct void_ { typedef void type; }; + template + struct has_internal_marker_impl : std::false_type {}; + template + struct has_internal_marker_impl::type> : std::true_type {}; + + template + struct has_internal_marker : has_internal_marker_impl {}; + } + template struct is_lua_primitive : std::integral_constant>::value - || (lua_size::value > 1) + || ((type::userdata == lua_type_of>::value) + && detail::has_internal_marker>>::value + && !detail::has_internal_marker>>::value) || std::is_base_of>::value || std::is_base_of>::value || meta::is_specialization_of>::value @@ -3740,6 +4274,9 @@ namespace sol { template <> struct is_transparent_argument : std::true_type {}; + template <> + struct is_transparent_argument : std::true_type {}; + template <> struct is_transparent_argument : std::true_type {}; @@ -3780,6 +4317,9 @@ namespace sol { template struct is_userdata> : std::true_type {}; + template + struct is_environment : std::integral_constant::value || is_table::value> {}; + template struct is_container : detail::is_container{}; @@ -3787,6 +4327,14 @@ namespace sol { inline type type_of() { return lua_type_of>::value; } + + namespace detail { + template + struct lua_type_of, std::enable_if_t<::sol::is_container::value>> : std::integral_constant {}; + + template + struct lua_type_of, std::enable_if_t::value>> : lua_type_of {}; + } // detail } // sol // end of sol/types.hpp @@ -3862,12 +4410,59 @@ namespace sol { inline bool operator!= (const stack_reference& l, const stack_reference& r) { return !operator==(l, r); } + + inline bool operator==(const stack_reference& lhs, const lua_nil_t&) { + return !lhs.valid(); + } + + inline bool operator==(const lua_nil_t&, const stack_reference& rhs) { + return !rhs.valid(); + } + + inline bool operator!=(const stack_reference& lhs, const lua_nil_t&) { + return lhs.valid(); + } + + inline bool operator!=(const lua_nil_t&, const stack_reference& rhs) { + return rhs.valid(); + } } // sol // end of sol/stack_reference.hpp namespace sol { namespace stack { + inline void remove(lua_State* L, int rawindex, int count) { + if (count < 1) + return; + int top = lua_gettop(L); + if (rawindex == -count || top == rawindex) { + // Slice them right off the top + lua_pop(L, static_cast(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); + if (index < 0) { + index = lua_gettop(L) + (index + 1); + } + int last = index + count; + for (int i = index; i < last; ++i) { + lua_remove(L, index); + } + } + + struct push_popper_at { + 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() { remove(L, index, count); } + }; + template struct push_popper_n { lua_State* L; @@ -3894,6 +4489,12 @@ namespace sol { push_popper push_pop(T&& x) { return push_popper(std::forward(x)); } + template + 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); + } template push_popper_n pop_n(lua_State* L, int x) { return push_popper_n(L, x); @@ -3902,6 +4503,7 @@ namespace sol { namespace detail { struct global_tag { } const global_{}; + struct no_safety_tag {} const no_safety{}; } // detail class reference { @@ -4030,6 +4632,22 @@ namespace sol { inline bool operator!= (const reference& l, const reference& r) { return !operator==(l, r); } + + inline bool operator==(const reference& lhs, const lua_nil_t&) { + return !lhs.valid(); + } + + inline bool operator==(const lua_nil_t&, const reference& rhs) { + return !rhs.valid(); + } + + inline bool operator!=(const reference& lhs, const lua_nil_t&) { + return lhs.valid(); + } + + inline bool operator!=(const lua_nil_t&, const reference& rhs) { + return rhs.valid(); + } } // sol // end of sol/reference.hpp @@ -4038,81 +4656,6 @@ namespace sol { // beginning of sol/stack_core.hpp -// beginning of sol/userdata.hpp - -namespace sol { - template - class basic_userdata : public base_t { - public: - basic_userdata() noexcept = default; - template , basic_userdata>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_userdata(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_userdata>::value) { - auto pp = stack::push_pop(*this); - type_assert(base_t::lua_state(), -1, type::userdata); - } -#endif // Safety - } - basic_userdata(const basic_userdata&) = default; - 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(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} - template >>, meta::neg>> = meta::enabler> - basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {} - basic_userdata(lua_State* L, int index = -1) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - type_assert(L, index, type::userdata); -#endif // Safety - } - basic_userdata(lua_State* L, ref_index index) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - type_assert(L, -1, type::userdata); -#endif // Safety - } - }; - - template - class basic_lightuserdata : public base_t { - public: - basic_lightuserdata() noexcept = default; - template , basic_lightuserdata>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_lightuserdata(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_userdata>::value) { - auto pp = stack::push_pop(*this); - type_assert(base_t::lua_state(), -1, type::lightuserdata); - } -#endif // Safety - } - basic_lightuserdata(const basic_lightuserdata&) = default; - 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(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} - template >>, meta::neg>> = meta::enabler> - basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {} - basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - type_assert(L, index, type::lightuserdata); -#endif // Safety - } - basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - type_assert(L, -1, type::lightuserdata); -#endif // Safety - } - }; - -} // sol - -// end of sol/userdata.hpp - // beginning of sol/tie.hpp namespace sol { @@ -4239,25 +4782,26 @@ namespace sol { template struct as_value_tag {}; - using special_destruct_func = void(*)(void*); - - template - inline void special_destruct(void* memory) { - T** pointerpointer = static_cast(memory); - special_destruct_func* dx = static_cast(static_cast(pointerpointer + 1)); - Real* target = static_cast(static_cast(dx + 1)); - target->~Real(); - } + using unique_destructor = void(*)(void*); template inline int unique_destruct(lua_State* L) { void* memory = lua_touserdata(L, 1); T** pointerpointer = static_cast(memory); - special_destruct_func& dx = *static_cast(static_cast(pointerpointer + 1)); + unique_destructor& dx = *static_cast(static_cast(pointerpointer + 1)); (dx)(memory); return 0; } + template + inline void usertype_unique_alloc_destroy(void* memory) { + T** pointerpointer = static_cast(memory); + unique_destructor* dx = static_cast(static_cast(pointerpointer + 1)); + Real* target = static_cast(static_cast(dx + 1)); + std::allocator alloc; + alloc.destroy(target); + } + template inline int user_alloc_destroy(lua_State* L) { void* rawdata = lua_touserdata(L, 1); @@ -4349,6 +4893,7 @@ namespace sol { }; template using strip_t = typename strip::type; + const bool default_check_arguments = #ifdef SOL_CHECK_ARGUMENTS true; @@ -4359,6 +4904,17 @@ namespace sol { inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) { return getter>{}.get(L, index, tracking); } + + template + inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) { + typedef meta::all< + std::is_lvalue_reference, + meta::neg>, + meta::neg>>, + meta::neg>> + > use_reference_tag; + return pusher>>{}.push(L, std::forward(arg), std::forward(args)...); + } } // stack_detail inline bool maybe_indexable(lua_State* L, int index = -1) { @@ -4379,13 +4935,12 @@ namespace sol { template inline int push_reference(lua_State* L, T&& t, Args&&... args) { - typedef meta::all< - std::is_lvalue_reference, - meta::neg>, - meta::neg>>, - meta::neg>> - > use_reference_tag; - return pusher>>{}.push(L, std::forward(t), std::forward(args)...); + return stack_detail::push_reference(L, std::forward(t), std::forward(args)...); + } + + template + inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) { + return stack_detail::push_reference(L, std::forward(arg), std::forward(args)...); } inline int multi_push(lua_State*) { @@ -4614,6 +5169,7 @@ namespace sol { // beginning of sol/demangle.hpp #include +#include namespace sol { namespace detail { @@ -4875,7 +5431,8 @@ namespace sol { // end of sol/inheritance.hpp -#include +#ifdef SOL_CXX17_FEATURES +#endif // C++17 namespace sol { namespace stack { @@ -4984,6 +5541,15 @@ namespace sol { } }; + template + struct checker { + template + static bool check(lua_State*, int, Handler&&, record& tracking) { + tracking.use(0); + return true; + } + }; + template struct checker { template @@ -5046,6 +5612,14 @@ namespace sol { } }; + template + struct checker, type::userdata, C> { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + return stack::check(L, index, std::forward(handler), tracking); + } + }; + template struct checker, type::userdata, C> : checker, type::lightuserdata, C> {}; @@ -5074,7 +5648,7 @@ namespace sol { return false; } // Do advanced check for call-style userdata? - static const auto& callkey = name_of(meta_function::call); + static const auto& callkey = to_string(meta_function::call); if (lua_getmetatable(L, index) == 0) { // No metatable, no __call key possible handler(L, index, type::function, t); @@ -5107,7 +5681,73 @@ namespace sol { return true; } if (t != type::userdata) { - handler(L, index, type::function, t); + handler(L, index, type::table, t); + return false; + } + return true; + } + }; + + template + struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::nil) { + lua_pop(L, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L, 1); + handler(L, index, expected, t); + return false; + } + return true; + } + }; + + template + struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::nil) { + lua_pop(L, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L, 1); + handler(L, index, type::table, t); + return false; + } + return true; + } + }; + + template + struct checker, type::poly, C> { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::nil) { + lua_pop(L, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L, 1); + handler(L, index, type::table, t); return false; } return true; @@ -5179,11 +5819,34 @@ namespace sol { } }; - template - struct checker::value>> { + template + struct checker::value>> { + typedef typename unique_usertype_traits::type T; template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return checker::type, type::userdata>{}.check(L, index, std::forward(handler), tracking); + const type indextype = type_of(L, index); + tracking.use(1); + if (indextype != type::userdata) { + handler(L, index, type::userdata, indextype); + return false; + } + if (lua_getmetatable(L, index) == 0) { + return true; + } + int metatableindex = lua_gettop(L); + if (stack_detail::check_metatable>(L, metatableindex)) { + void* memory = lua_touserdata(L, index); + T** pointerpointer = static_cast(memory); + detail::unique_destructor& pdx = *static_cast(static_cast(pointerpointer + 1)); + bool success = &detail::usertype_unique_alloc_destroy == pdx; + if (!success) { + handler(L, index, type::userdata, indextype); + } + return success; + } + lua_pop(L, 1); + handler(L, index, type::userdata, indextype); + return false; } }; @@ -5227,6 +5890,40 @@ namespace sol { return stack::check(L, index, no_panic, tracking); } }; + +#ifdef SOL_CXX17_FEATURES + template + struct checker, type::poly, C> { + typedef std::variant V; + typedef std::variant_size V_size; + typedef std::integral_constant V_is_empty; + + template + static bool is_one(std::integral_constant, lua_State* L, int index, Handler&& handler, record& tracking) { + if (V_is_empty::value && lua_isnone(L, index)) { + return true; + } + tracking.use(1); + handler(L, index, type::poly, type_of(L, index)); + return false; + } + + template + static bool is_one(std::integral_constant, lua_State* L, int index, Handler&& handler, record& tracking) { + typedef std::variant_alternative_t T; + if (stack::check(L, index, no_panic, tracking)) { + return true; + } + return is_one(std::integral_constant(), L, index, std::forward(handler), tracking); + } + + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + return is_one(std::integral_constant(), L, index, std::forward(handler), tracking); + } + }; +#endif // C++17 + } // stack } // sol @@ -5258,8 +5955,9 @@ namespace sol { #ifdef SOL_CODECVT_SUPPORT #include -#include -#endif +#endif // codecvt header support +#ifdef SOL_CXX17_FEATURES +#endif // C++17 namespace sol { namespace stack { @@ -5305,53 +6003,55 @@ namespace sol { template struct getter, std::enable_if_t>::value>> { - static T get(lua_State* L, int index, record& tracking) { + static T get(lua_State* L, int relindex, record& tracking) { typedef typename T::value_type V; + return get(types(), L, relindex, tracking); + } + + template + static T get(types, lua_State* L, int relindex, record& tracking) { tracking.use(1); - index = lua_absindex(L, index); + int index = lua_absindex(L, relindex); T arr; - get_field(L, static_cast(-1), index); - int isnum; - std::size_t sizehint = static_cast(lua_tointegerx(L, -1, &isnum)); - if (isnum != 0) { - detail::reserve(arr, sizehint); - } - lua_pop(L, 1); #if SOL_LUA_VERSION >= 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::value, lua_pop(L, lua_size::value)) { + bool isnil = false; for (int vi = 0; vi < lua_size::value; ++vi) { type t = static_cast(lua_geti(L, index, i + vi)); - if (t == type::lua_nil) { + isnil = t == type::lua_nil; + if (isnil) { if (i == 0) { - continue; - } - else { - lua_pop(L, (vi + 1)); - return arr; + break; } + lua_pop(L, (vi + 1)); + return arr; } } + if (isnil) + continue; arr.push_back(stack::get(L, -lua_size::value)); } #else // Zzzz slower but necessary thanks to the lower version API and missing functions qq for (lua_Integer i = 0; ; i += lua_size::value, lua_pop(L, lua_size::value)) { + bool isnil = false; for (int vi = 0; vi < lua_size::value; ++vi) { lua_pushinteger(L, i); lua_gettable(L, index); type t = type_of(L, -1); - if (t == type::lua_nil) { + isnil = t == type::lua_nil; + if (isnil) { if (i == 0) { - continue; - } - else { - lua_pop(L, (vi + 1)); - return arr; + break; } + lua_pop(L, (vi + 1)); + return arr; } } + if (isnil) + continue; arr.push_back(stack::get(L, -1)); } #endif @@ -5365,10 +6065,15 @@ namespace sol { typedef typename T::value_type P; typedef typename P::first_type K; typedef typename P::second_type V; + return get(types(), L, index, tracking); + } + + template + static T get(types, lua_State* L, int relindex, record& tracking) { tracking.use(1); T associative; - index = lua_absindex(L, index); + int index = lua_absindex(L, relindex); lua_pushnil(L); while (lua_next(L, index) != 0) { decltype(auto) key = stack::check_get(L, -2); @@ -5383,6 +6088,40 @@ namespace sol { } }; + template + struct getter, std::enable_if_t::value>> { + static T get(lua_State* L, int index, record& tracking) { + getter g; + // VC++ has a bad warning here: shut it up + (void)g; + return g.get(L, index, tracking); + } + }; + + template + struct getter, std::enable_if_t, meta::neg>>>::value>> { + static T get(lua_State* L, int index, record& tracking) { + typedef typename T::value_type V; + getter> g; + // VC++ has a bad warning here: shut it up + (void)g; + return g.get(types>(), L, index, tracking); + } + }; + + template + struct getter, std::enable_if_t, meta::has_key_value_pair>>::value>> { + static T get(lua_State* L, int index, record& tracking) { + typedef typename T::value_type P; + typedef typename P::first_type K; + typedef typename P::second_type V; + getter> g; + // VC++ has a bad warning here: shut it up + (void)g; + return g.get(types>(), L, index, tracking); + } + }; + template struct getter::value || std::is_base_of::value>> { static T get(lua_State* L, int index, record& tracking) { @@ -5453,17 +6192,7 @@ namespace sol { tracking.use(1); std::size_t len; auto str = lua_tolstring(L, index, &len); - return std::string( str, len ); - } - }; - - template <> - struct getter { - string_detail::string_shim get(lua_State* L, int index, record& tracking) { - tracking.use(1); - size_t len; - const char* p = lua_tolstring(L, index, &len); - return string_detail::string_shim(p, len); + return std::string(str, len); } }; @@ -5471,10 +6200,11 @@ namespace sol { struct getter { static const char* get(lua_State* L, int index, record& tracking) { tracking.use(1); - return lua_tostring(L, index); + size_t sz; + return lua_tolstring(L, index, &sz); } }; - + template<> struct getter { static char get(lua_State* L, int index, record& tracking) { @@ -5497,12 +6227,12 @@ namespace sol { if (sizeof(wchar_t) == 2) { static std::wstring_convert> convert; std::wstring r = convert.from_bytes(str, str + len); -#ifdef __MINGW32__ +#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 7 // Fuck you, MinGW, and fuck you libstdc++ for introducing this absolutely asinine bug // https://sourceforge.net/p/mingw-w64/bugs/538/ // http://chat.stackoverflow.com/transcript/message/32271369#32271369 for (auto& c : r) { - uint8_t* b = reinterpret_cast(&c); + uint8_t* b = reinterpret_cast(&c); std::swap(b[0], b[1]); } #endif @@ -5586,8 +6316,9 @@ namespace sol { static meta_function get(lua_State *L, int index, record& tracking) { tracking.use(1); const char* name = getter{}.get(L, index, tracking); - for (std::size_t i = 0; i < meta_function_names.size(); ++i) - if (meta_function_names[i] == name) + const auto& mfnames = meta_function_names(); + for (std::size_t i = 0; i < mfnames.size(); ++i) + if (mfnames[i] == name) return static_cast(i); return meta_function::construct; } @@ -5682,7 +6413,7 @@ namespace sol { T* obj = static_cast(udata); return obj; } - + static T& get(lua_State* L, int index, record& tracking) { return *get_no_lua_nil(L, index, tracking); } @@ -5696,35 +6427,50 @@ namespace sol { tracking.use(1); return nullptr; } - return getter>::get_no_lua_nil(L, index, tracking); + getter> g; + // Avoid VC++ warning + (void)g; + return g.get_no_lua_nil(L, index, tracking); } }; template struct getter> { static T* get(lua_State* L, int index, record& tracking) { - return getter>::get_no_lua_nil(L, index, tracking); + getter> g; + // Avoid VC++ warning + (void)g; + return g.get_no_lua_nil(L, index, tracking); } }; template struct getter { static T& get(lua_State* L, int index, record& tracking) { - return getter>::get(L, index, tracking); + getter> g; + // Avoid VC++ warning + (void)g; + return g.get(L, index, tracking); } }; template struct getter> { static T& get(lua_State* L, int index, record& tracking) { - return getter{}.get(L, index, tracking); + getter g; + // Avoid VC++ warning + (void)g; + return g.get(L, index, tracking); } }; template struct getter { static T* get(lua_State* L, int index, record& tracking) { - return getter>::get(L, index, tracking); + getter> g; + // Avoid VC++ warning + (void)g; + return g.get(L, index, tracking); } }; @@ -5736,31 +6482,31 @@ namespace sol { static Real& get(lua_State* L, int index, record& tracking) { tracking.use(1); P** pref = static_cast(lua_touserdata(L, index)); - detail::special_destruct_func* fx = static_cast(static_cast(pref + 1)); + detail::unique_destructor* fx = static_cast(static_cast(pref + 1)); Real* mem = static_cast(static_cast(fx + 1)); return *mem; } }; - template - struct getter> { - typedef std::tuple(nullptr, 0))...> R; - - template - static R apply(std::index_sequence<>, lua_State*, int, record&, TArgs&&... args) { + template + struct getter> { + typedef std::tuple(nullptr, 0))...> R; + + template + static R apply(std::index_sequence<>, lua_State*, int, record&, Args&&... args) { // Fuck you too, VC++ - return R{std::forward(args)...}; + return R{ std::forward(args)... }; } - - template - static R apply(std::index_sequence, lua_State* L, int index, record& tracking, TArgs&&... args) { + + template + static R apply(std::index_sequence, lua_State* L, int index, record& tracking, Args&&... args) { // Fuck you too, VC++ - typedef std::tuple_element_t> T; - return apply(std::index_sequence(), L, index, tracking, std::forward(args)..., stack::get(L, index + tracking.used, tracking)); + typedef std::tuple_element_t> T; + return apply(std::index_sequence(), L, index, tracking, std::forward(args)..., stack::get(L, index + tracking.used, tracking)); } static R get(lua_State* L, int index, record& tracking) { - return apply(std::make_index_sequence(), L, index, tracking); + return apply(std::make_index_sequence(), L, index, tracking); } }; @@ -5771,6 +6517,64 @@ namespace sol { } }; +#ifdef SOL_CXX17_FEATURES + template<> + struct getter { + static std::string_view get(lua_State* L, int index, record& tracking) { + tracking.use(1); + size_t sz; + const char* str = lua_tolstring(L, index, &sz); + return std::string_view(str, sz); + } + }; + + template + struct getter> { + typedef std::variant V; + typedef std::variant_size V_size; + typedef std::integral_constant V_is_empty; + + static V get_empty(std::true_type, lua_State* L, int index, record& tracking) { + return V(); + } + + static V get_empty(std::false_type, lua_State* L, int index, record& tracking) { + typedef std::variant_alternative_t<0, V> T; + // This should never be reached... + // please check your code and understand what you did to bring yourself here + std::abort(); + return V(std::in_place_index<0>, stack::get(L, index)); + } + + static V get_one(std::integral_constant, lua_State* L, int index, record& tracking) { + return get_empty(V_is_empty(), L, index, tracking); + } + + template + static V get_one(std::integral_constant, lua_State* L, int index, record& tracking) { + typedef std::variant_alternative_t T; + if (stack::check(L, index, no_panic, tracking)) { + return V(std::in_place_index, stack::get(L, index)); + } + return get_one(std::integral_constant(), L, index, tracking); + } + + static V get(lua_State* L, int index, record& tracking) { + return get_one(std::integral_constant(), L, index, tracking); + } + }; +#else + template <> + struct getter { + string_detail::string_shim get(lua_State* L, int index, record& tracking) { + tracking.use(1); + size_t len; + const char* p = lua_tolstring(L, index, &len); + return string_detail::string_shim(p, len); + } + }; +#endif // C++17-wave + } // stack } // sol @@ -5859,6 +6663,48 @@ namespace sol { return check_get(L, index, no_panic, tracking); } }; + +#ifdef SOL_CXX17_FEATURES + template + struct check_getter> { + typedef std::variant V; + typedef std::variant_size V_size; + typedef std::integral_constant V_is_empty; + + template + static optional get_empty(std::true_type, lua_State* L, int index, Handler&& handler, record& tracking) { + return nullopt; + } + + template + static optional get_empty(std::false_type, lua_State* L, int index, Handler&& handler, record& tracking) { + typedef std::variant_alternative_t<0, V> T; + // This should never be reached... + // please check your code and understand what you did to bring yourself here + handler(L, index, type::poly, type_of(L, index)); + return nullopt; + } + + template + static optional get_one(std::integral_constant, lua_State* L, int index, Handler&& handler, record& tracking) { + return get_empty(V_is_empty(), L, index, std::forward(handler), tracking); + } + + template + static optional get_one(std::integral_constant, lua_State* L, int index, Handler&& handler, record& tracking) { + typedef std::variant_alternative_t T; + if (stack::check(L, index, no_panic, tracking)) { + return V(std::in_place_index, stack::get(L, index)); + } + return get_one(std::integral_constant(), L, index, std::forward(handler), tracking); + } + + template + static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { + return get_one(std::integral_constant(), L, index, std::forward(handler), tracking); + } + }; +#endif // C++17 } // stack } // sol @@ -5976,9 +6822,32 @@ namespace sol { #ifdef SOL_CODECVT_SUPPORT #endif +#ifdef SOL_CXX17_FEATURES +#endif // C++17 namespace sol { namespace stack { + inline int push_environment_of(lua_State* L, int index = -1) { +#if SOL_LUA_VERSION < 502 + // Use lua_setfenv + lua_getfenv(L, index); + return 1; +#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; + } +#endif + return 1; + } + + template + int push_environment_of(const T& target) { + target.push(); + return push_environment_of(target.lua_state(), -1) + 1; + } + template struct pusher> { template @@ -6068,8 +6937,9 @@ namespace sol { template >> = meta::enabler> static int push(lua_State* L, Arg&& arg) { - if (unique_usertype_traits::is_null(arg)) + if (unique_usertype_traits::is_null(arg)) { return stack::push(L, lua_nil); + } return push_deep(L, std::forward(arg)); } @@ -6080,10 +6950,10 @@ namespace sol { template static int push_deep(lua_State* L, Args&&... args) { - P** pref = static_cast(lua_newuserdata(L, sizeof(P*) + sizeof(detail::special_destruct_func) + sizeof(Real))); - detail::special_destruct_func* fx = static_cast(static_cast(pref + 1)); + P** pref = static_cast(lua_newuserdata(L, sizeof(P*) + sizeof(detail::unique_destructor) + sizeof(Real))); + detail::unique_destructor* fx = static_cast(static_cast(pref + 1)); Real* mem = static_cast(static_cast(fx + 1)); - *fx = detail::special_destruct; + *fx = detail::usertype_unique_alloc_destroy; detail::default_construct::construct(mem, std::forward(args)...); *pref = unique_usertype_traits::get(*mem); if (luaL_newmetatable(L, &usertype_traits>::metatable()[0]) == 1) { @@ -6215,8 +7085,8 @@ namespace sol { }; template<> - struct pusher { - static int push(lua_State* L, metatable_key_t) { + struct pusher { + static int push(lua_State* L, metatable_t) { lua_pushlstring(L, "__mt", 4); return 1; } @@ -6237,6 +7107,23 @@ namespace sol { return 1; } }; +#ifdef SOL_NOEXCEPT_FUNCTION_TYPE + template<> + struct pusher> { + static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { + lua_pushcclosure(L, func, n); + return 1; + } + }; + + template<> + struct pusher { + static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { + lua_pushcclosure(L, func, n); + return 1; + } + }; +#endif // noexcept function type template<> struct pusher { @@ -6305,7 +7192,7 @@ namespace sol { return 1; } - template , no_metatable_t, metatable_key_t>> = meta::enabler> + template , no_metatable_t, metatable_t>> = meta::enabler> static int push(lua_State* L, Arg&& arg, Args&&... args) { const auto name = &usertype_traits>::user_gc_metatable()[0]; return push_with(L, name, std::forward(arg), std::forward(args)...); @@ -6318,7 +7205,7 @@ namespace sol { } template - static int push(lua_State* L, metatable_key_t, Key&& key, Args&&... args) { + static int push(lua_State* L, metatable_t, Key&& key, Args&&... args) { const auto name = &key[0]; return push_with(L, name, std::forward(args)...); } @@ -6412,7 +7299,7 @@ namespace sol { template<> struct pusher { static int push(lua_State* L, meta_function m) { - const std::string& str = name_of(m); + const std::string& str = to_string(m); lua_pushlstring(L, str.c_str(), str.size()); return 1; } @@ -6610,7 +7497,7 @@ namespace sol { if (t == nullopt) { return stack::push(L, nullopt); } - return stack::push(L, t.value()); + return stack::push(L, static_cast::value, O&, O&&>>(t.value())); } }; @@ -6634,6 +7521,71 @@ namespace sol { return 0; } }; + + template<> + struct pusher { + static int push(lua_State* L, const new_table& nt) { + lua_createtable(L, nt.sequence_hint, nt.map_hint); + return 1; + } + }; + +#ifdef SOL_CXX17_FEATURES + template <> + struct pusher { + static int push(lua_State* L, const std::string_view& sv) { + return stack::push(L, sv.data(), sv.length()); + } + }; +#ifdef SOL_CODECVT_SUPPORT + template <> + struct pusher { + static int push(lua_State* L, const std::wstring_view& sv) { + return stack::push(L, sv.data(), sv.length()); + } + }; + + template <> + struct pusher { + static int push(lua_State* L, const std::u16string_view& sv) { + return stack::push(L, sv.data(), sv.length()); + } + }; + + template <> + struct pusher { + static int push(lua_State* L, const std::u32string_view& sv) { + return stack::push(L, sv.data(), sv.length()); + } + }; +#endif // codecvt header support + + namespace stack_detail { + + struct push_function { + lua_State* L; + + push_function(lua_State* L) : L(L) {} + + template + int operator()(T&& value) const { + return stack::push(L, std::forward(value)); + } + }; + + } // stack_detail + + template + struct pusher> { + static int push(lua_State* L, const std::variant& v) { + return std::visit(stack_detail::push_function(L), v); + } + + static int push(lua_State* L, std::variant&& v) { + return std::visit(stack_detail::push_function(L), std::move(v)); + } + }; +#endif } // stack } // sol @@ -6685,13 +7637,28 @@ namespace sol { }; template - struct field_getter { - void get(lua_State* L, metatable_key_t, int tableindex = -1) { + struct field_getter { + void get(lua_State* L, metatable_t, int tableindex = -1) { if (lua_getmetatable(L, tableindex) == 0) push(L, lua_nil); } }; + template + struct field_getter { + void get(lua_State* L, env_t, int tableindex = -1) { +#if SOL_LUA_VERSION < 502 + // Use lua_setfenv + lua_getfenv(L, tableindex); +#else + // Use upvalues as explained in Lua 5.2 and beyond's manual + if (lua_getupvalue(L, tableindex, 1) == nullptr) { + push(L, lua_nil); + } +#endif + } + }; + template struct field_getter::value>> { template @@ -6710,7 +7677,7 @@ namespace sol { #if SOL_LUA_VERSION >= 503 template - struct field_getter::value>> { + struct field_getter::value && !std::is_same::value>> { template void get(lua_State* L, Key&& key, int tableindex = -1) { lua_geti(L, tableindex, static_cast(key)); @@ -6728,7 +7695,7 @@ namespace sol { #endif // Lua 5.3.x template - struct field_getter::value>> { + struct field_getter::value && !std::is_same::value>> { template void get(lua_State* L, Key&& key, int tableindex = -1) { lua_rawgeti(L, tableindex, static_cast(key)); @@ -6799,9 +7766,9 @@ namespace sol { }; template - struct field_setter { + struct field_setter { template - void set(lua_State* L, metatable_key_t, Value&& value, int tableindex = -2) { + void set(lua_State* L, metatable_t, Value&& value, int tableindex = -2) { push(L, std::forward(value)); lua_setmetatable(L, tableindex); } @@ -6827,7 +7794,7 @@ namespace sol { #if SOL_LUA_VERSION >= 503 template - struct field_setter::value>> { + struct field_setter::value && !std::is_same::value>> { template void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) { push(L, std::forward(value)); @@ -6837,7 +7804,7 @@ namespace sol { #endif // Lua 5.3.x template - struct field_setter::value>> { + struct field_setter::value && !std::is_same::value>> { template void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) { push(L, std::forward(value)); @@ -6983,7 +7950,7 @@ namespace sol { } template - inline std::pair get_as_upvalues(lua_State* L, int index = 1) { + inline std::pair get_as_upvalues(lua_State* L, int index = 2) { const static std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); typedef std::array data_t; data_t voiddata{ {} }; @@ -7032,28 +7999,6 @@ namespace sol { return luaL_ref(L, tableindex); } - inline void remove(lua_State* L, int index, int count) { - if (count < 1) - return; - int top = lua_gettop(L); - if (index == -1 || top == index) { - // Slice them right off the top - lua_pop(L, static_cast(count)); - return; - } - - // Remove each item one at a time using stack operations - // Probably slower, maybe, haven't benchmarked, - // but necessary - if (index < 0) { - index = lua_gettop(L) + (index + 1); - } - int last = index + count; - for (int i = index; i < last; ++i) { - lua_remove(L, index); - } - } - template ::value>> inline decltype(auto) call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { typedef std::make_index_sequence args_indices; @@ -7155,48 +8100,15 @@ namespace sol { // end of sol/stack.hpp -// beginning of sol/as_args.hpp - -namespace sol { - template - struct to_args_t { - T src; - }; - - template - auto as_args(Source&& source) { - return to_args_t{ std::forward(source) }; - } - - namespace stack { - template - struct pusher> { - int push(lua_State* L, const to_args_t& e) { - int p = 0; - for (const auto& i : e.src) { - p += stack::push(L, i); - } - return p; - } - }; - } -} // sol - -// end of sol/as_args.hpp - -// beginning of sol/variadic_args.hpp - -// beginning of sol/stack_proxy.hpp - -// beginning of sol/function.hpp - // beginning of sol/function_result.hpp // beginning of sol/proxy_base.hpp namespace sol { + struct proxy_base_tag {}; + template - struct proxy_base { + struct proxy_base : proxy_base_tag { operator std::string() const { const Super& super = *static_cast(static_cast(this)); return super.template get(); @@ -7289,7 +8201,7 @@ namespace sol { template struct wrapper { - typedef lua_bind_traits traits_type; + typedef lua_bind_traits> traits_type; typedef typename traits_type::args_list args_list; typedef typename traits_type::args_list free_args_list; typedef typename traits_type::returns_list returns_list; @@ -7308,8 +8220,8 @@ namespace sol { }; template - struct wrapper>>::value>> { - typedef lua_bind_traits traits_type; + struct wrapper>>::value>> { + typedef lua_bind_traits>> traits_type; typedef typename traits_type::args_list args_list; typedef typename traits_type::args_list free_args_list; typedef typename traits_type::returns_list returns_list; @@ -7342,16 +8254,21 @@ namespace sol { template struct wrapper>::value>> { - typedef lua_bind_traits traits_type; + typedef lua_bind_traits> traits_type; typedef typename traits_type::object_type object_type; typedef typename traits_type::return_type return_type; typedef typename traits_type::args_list args_list; typedef types free_args_list; typedef typename traits_type::returns_list returns_list; - template - static decltype(auto) invoke(object_type& mem, Args&&... args) { - return (mem.*fx)(std::forward(args)...); + template + static decltype(auto) invoke(object_type& mem) { + return mem.*fx; + } + + template + static decltype(auto) invoke(object_type& mem, Arg&& arg, Args&&...) { + return mem.*fx = std::forward(arg); } template @@ -7489,15 +8406,94 @@ namespace sol { }; +#ifdef SOL_NOEXCEPT_FUNCTION_TYPE //noexcept has become a part of a function's type + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + +#endif // noexcept is part of a function's type + } // sol // end of sol/wrapper.hpp namespace sol { namespace function_detail { - template + template inline int call(lua_State* L) { - Fx& fx = stack::get>(L, upvalue_index(1)); + Fx& fx = stack::get>(L, upvalue_index(start)); return fx(L); } } // function_detail @@ -7592,11 +8588,29 @@ namespace sol { return property_detail::property(std::true_type(), std::forward(f)); } + template + inline decltype(auto) writeonly_property(F&& f) { + return property_detail::property(std::false_type(), std::forward(f)); + } + + template + struct readonly_wrapper { + T v; + + readonly_wrapper(T v) : v(std::move(v)) {} + + operator T& () { + return v; + } + operator const T& () const { + return v; + } + }; + // Allow someone to make a member variable readonly (const) template inline auto readonly(R T::* v) { - typedef const R C; - return static_cast(v); + return readonly_wrapper>(v); } template @@ -7616,11 +8630,25 @@ namespace sol { return var_wrapper(std::forward(v)); } + namespace meta { + template + struct is_member_object : std::is_member_object_pointer {}; + + template + struct is_member_object> : std::true_type {}; + } + } // sol // end of sol/property.hpp namespace sol { + namespace function_detail { + inline int no_construction_error(lua_State* L) { + return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); + } + } + namespace call_detail { template @@ -7634,7 +8662,7 @@ namespace sol { } template - struct void_call; + struct void_call : void_call> {}; template struct void_call> { @@ -7662,7 +8690,7 @@ namespace sol { template inline int overload_match_arity(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - typedef lua_bind_traits> traits; + typedef lua_bind_traits> traits; typedef meta::tuple_types return_types; typedef typename traits::free_args_list args_list; // compile-time eliminate any functions that we know ahead of time are of improper arity @@ -7686,7 +8714,7 @@ namespace sol { template inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - typedef lua_bind_traits> traits; + typedef lua_bind_traits> traits; typedef meta::tuple_types return_types; typedef typename traits::free_args_list args_list; // compile-time eliminate any functions that we know ahead of time are of improper arity @@ -7701,7 +8729,7 @@ namespace sol { template inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - typedef lua_bind_traits> traits; + typedef lua_bind_traits> traits; typedef meta::tuple_types return_types; typedef typename traits::free_args_list args_list; // compile-time eliminate any functions that we know ahead of time are of improper arity @@ -7826,6 +8854,14 @@ namespace sol { return f(L); } }; +#ifdef SOL_NOEXCEPT_FUNCTION_TYPE + template + struct agnostic_lua_call_wrapper { + static int call(lua_State* L, detail::lua_CFunction_noexcept f) { + return f(L); + } + }; +#endif // noexcept function types template struct agnostic_lua_call_wrapper { @@ -7837,7 +8873,7 @@ namespace sol { template struct agnostic_lua_call_wrapper { static int call(lua_State* L, const no_construction&) { - return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); + return function_detail::no_construction_error(L); } }; @@ -7849,6 +8885,13 @@ namespace sol { } }; + template + struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, C> { + static int call(lua_State* L, std::reference_wrapper f) { + return agnostic_lua_call_wrapper{}.call(L, f.get()); + } + }; + template struct lua_call_wrapper : agnostic_lua_call_wrapper {}; @@ -7922,7 +8965,7 @@ namespace sol { template static int call_const(std::false_type, lua_State* L, Args&&... args) { typedef typename traits_type::return_type R; - return call_assign(std::is_assignable>, R>(), L, std::forward(args)...); + return call_assign(std::is_copy_assignable>(), L, std::forward(args)...); } template @@ -7932,12 +8975,12 @@ namespace sol { template static int call(lua_State* L, V&& f) { - return call_const(std::is_const(), L, f); + return call_const(std::is_const(), L, std::forward(f)); } template static int call(lua_State* L, V&& f, object_type& o) { - return call_const(std::is_const(), L, f, o); + return call_const(std::is_const(), L, std::forward(f), o); } }; @@ -7948,9 +8991,10 @@ namespace sol { typedef typename wrap::object_type object_type; template - static int call(lua_State* L, V&& f, object_type& o) { + static int call(lua_State* L, V&& v, object_type& o) { typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; + F f(std::forward(v)); return stack::call_into_lua(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); } @@ -7974,6 +9018,28 @@ namespace sol { } }; + template + struct lua_call_wrapper, false, is_variable, checked, boost, C> { + typedef lua_bind_traits traits_type; + typedef wrapper> wrap; + typedef typename wrap::object_type object_type; + + template + static int call(lua_State* L, V&&) { + return luaL_error(L, "sol: cannot write to a sol::readonly variable"); + } + + template + static int call(lua_State* L, V&&, object_type&) { + return luaL_error(L, "sol: cannot write to a sol::readonly variable"); + } + }; + + template + struct lua_call_wrapper, true, is_variable, checked, boost, C> : lua_call_wrapper { + + }; + template struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { typedef constructor_list F; @@ -8102,12 +9168,21 @@ namespace sol { struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { typedef std::conditional_t P; typedef meta::unqualified_t

U; + typedef wrapper wrap; typedef lua_bind_traits traits_type; + typedef meta::unqualified_t> object_type; template - static int self_call(lua_State* L, F&& f) { - typedef wrapper wrap; - typedef meta::unqualified_t> object_type; + static int self_call(std::true_type, lua_State* L, F&& f) { + // The type being void means we don't have any arguments, so it might be a free functions? + typedef typename traits_type::free_args_list args_list; + typedef typename wrap::returns_list returns_list; + typedef typename wrap::caller caller; + return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f); + } + + template + static int self_call(std::false_type, lua_State* L, F&& f) { typedef meta::pop_front_type_t args_list; typedef T Ta; #ifdef SOL_SAFE_USERTYPE @@ -8129,7 +9204,7 @@ namespace sol { template static int defer_call(std::false_type, lua_State* L, F&& f, Args&&... args) { - return self_call(L, pick(meta::boolean(), f), std::forward(args)...); + return self_call(meta::any, meta::boolean>::value != type::userdata>>(), L, pick(meta::boolean(), f), std::forward(args)...); } template @@ -8175,9 +9250,9 @@ namespace sol { return lua_call_wrapper, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward(fx), std::forward(args)...); } - template + template inline int call_user(lua_State* L) { - auto& fx = stack::get>(L, upvalue_index(1)); + auto& fx = stack::get>(L, upvalue_index(start)); return call_wrapped(L, fx); } @@ -8195,6 +9270,9 @@ namespace sol { template struct is_var_bind> : std::true_type {}; + + template + struct is_var_bind> : is_var_bind {}; } // call_detail template @@ -8267,7 +9345,7 @@ namespace sol { } template - int call_wrapper_entry(lua_State* L) { + int call_wrapper_entry(lua_State* L) noexcept(meta::bind_traits::is_noexcept) { return call_wrapper_function(std::is_member_function_pointer>(), L); } @@ -8280,15 +9358,30 @@ namespace sol { } }; + template + inline int c_call_raw(std::true_type, lua_State* L) { + return fx(L); + } + + template + inline int c_call_raw(std::false_type, lua_State* L) { +#ifdef __clang__ + return detail::trampoline(L, function_detail::call_wrapper_entry); +#else + return detail::typed_static_trampoline), (&function_detail::call_wrapper_entry)>(L); +#endif // fuck you clang :c + } + } // function_detail template inline int c_call(lua_State* L) { -#ifdef __clang__ - return detail::trampoline(L, function_detail::call_wrapper_entry); -#else - return detail::static_trampoline<(&function_detail::call_wrapper_entry)>(L); -#endif // fuck you clang :c + typedef meta::unqualified_t Fu; + return function_detail::c_call_raw(std::integral_constant::value +#ifdef SOL_NOEXCEPT_FUNCTION_TYPE + || std::is_same::value +#endif + >(), L); } template @@ -8321,16 +9414,16 @@ namespace sol { template struct upvalue_free_function { typedef std::remove_pointer_t> function_type; - typedef lua_bind_traits traits_type; + typedef meta::bind_traits traits_type; - static int real_call(lua_State* L) { + static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { auto udata = stack::stack_detail::get_as_upvalues(L); function_type* fx = udata.first; return call_detail::call_wrapped(L, fx); } static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); + return detail::typed_static_trampoline(L); } int operator()(lua_State* L) { @@ -8343,13 +9436,13 @@ namespace sol { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; - static int real_call(lua_State* L) { + static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { // Layout: // idx 1...n: verbatim data of member function pointer // idx n + 1: is the object's void pointer // We don't need to store the size, because the other side is templated // with the same member function pointer type - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); + auto memberdata = stack::stack_detail::get_as_upvalues(L); auto objdata = stack::stack_detail::get_as_upvalues(L, memberdata.second); function_type& memfx = memberdata.first; auto& item = *objdata.first; @@ -8357,7 +9450,7 @@ namespace sol { } static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); + return detail::typed_static_trampoline(L); } int operator()(lua_State* L) { @@ -8370,13 +9463,13 @@ namespace sol { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; - static int real_call(lua_State* L) { + static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { // Layout: // idx 1...n: verbatim data of member variable pointer // idx n + 1: is the object's void pointer // We don't need to store the size, because the other side is templated // with the same member function pointer type - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); + auto memberdata = stack::stack_detail::get_as_upvalues(L); auto objdata = stack::stack_detail::get_as_upvalues(L, memberdata.second); auto& mem = *objdata.first; function_type& var = memberdata.first; @@ -8391,7 +9484,39 @@ namespace sol { } static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); + return detail::typed_static_trampoline(L); + } + + int operator()(lua_State* L) { + return call(L); + } + }; + + template + struct upvalue_member_variable> { + typedef std::remove_pointer_t> function_type; + typedef lua_bind_traits traits_type; + + static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { + // Layout: + // idx 1...n: verbatim data of member variable pointer + // idx n + 1: is the object's void pointer + // We don't need to store the size, because the other side is templated + // with the same member function pointer type + auto memberdata = stack::stack_detail::get_as_upvalues(L); + auto objdata = stack::stack_detail::get_as_upvalues(L, memberdata.second); + auto& mem = *objdata.first; + function_type& var = memberdata.first; + switch (lua_gettop(L)) { + case 0: + return call_detail::call_wrapped(L, var, mem); + default: + return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + } + } + + static int call(lua_State* L) { + return detail::typed_static_trampoline(L); } int operator()(lua_State* L) { @@ -8404,16 +9529,16 @@ namespace sol { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; - static int real_call(lua_State* L) { + static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { // Layout: // idx 1...n: verbatim data of member variable pointer - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); + auto memberdata = stack::stack_detail::get_as_upvalues(L); function_type& memfx = memberdata.first; return call_detail::call_wrapped(L, memfx); } static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); + return detail::typed_static_trampoline(L); } int operator()(lua_State* L) { @@ -8424,12 +9549,11 @@ namespace sol { template struct upvalue_this_member_variable { typedef std::remove_pointer_t> function_type; - typedef lua_bind_traits traits_type; - static int real_call(lua_State* L) { + static int real_call(lua_State* L) noexcept(false) { // Layout: // idx 1...n: verbatim data of member variable pointer - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); + auto memberdata = stack::stack_detail::get_as_upvalues(L); function_type& var = memberdata.first; switch (lua_gettop(L)) { case 1: @@ -8442,7 +9566,34 @@ namespace sol { } static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); + return detail::typed_static_trampoline(L); + } + + int operator()(lua_State* L) { + return call(L); + } + }; + + template + struct upvalue_this_member_variable> { + typedef std::remove_pointer_t> function_type; + typedef lua_bind_traits traits_type; + + static int real_call(lua_State* L) noexcept(false) { + // Layout: + // idx 1...n: verbatim data of member variable pointer + auto memberdata = stack::stack_detail::get_as_upvalues(L); + function_type& var = memberdata.first; + switch (lua_gettop(L)) { + case 1: + return call_detail::call_wrapped(L, var); + default: + return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + } + } + + static int call(lua_State* L) { + return detail::typed_static_trampoline(L); } int operator()(lua_State* L) { @@ -8460,11 +9611,11 @@ namespace sol { namespace function_detail { template struct functor_function { - typedef meta::unwrapped_t> Function; - Function fx; + typedef std::decay_t> function_type; + function_type fx; template - functor_function(Function f, Args&&... args) : fx(std::move(f), std::forward(args)...) {} + functor_function(function_type f, Args&&... args) : fx(std::move(f), std::forward(args)...) {} int call(lua_State* L) { return call_detail::call_wrapped(L, fx); @@ -8766,7 +9917,9 @@ namespace sol { auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); lua_CFunction freefunc = &function_detail::upvalue_member_variable, meta::unqualified_t>::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr); upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8785,7 +9938,9 @@ namespace sol { template static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8793,7 +9948,9 @@ namespace sol { static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { typedef typename meta::bind_traits>::object_type C; lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8811,14 +9968,16 @@ namespace sol { auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); lua_CFunction freefunc = &function_detail::upvalue_member_function, meta::unqualified_t>::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr); upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); stack::push(L, c_closure(freefunc, upvalues)); } template static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_variable(std::is_member_object_pointer>(), L, std::forward(fx), std::forward(args)...); + select_member_variable(meta::is_member_object>(), L, std::forward(fx), std::forward(args)...); } template >> = meta::enabler> @@ -8830,7 +9989,9 @@ namespace sol { template static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8838,7 +9999,9 @@ namespace sol { static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { typedef typename meta::bind_traits>::object_type C; lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8852,7 +10015,9 @@ namespace sol { std::decay_t target(std::forward(fx), std::forward(args)...); lua_CFunction freefunc = &function_detail::upvalue_free_function::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, target); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, target); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8860,17 +10025,30 @@ namespace sol { stack::push(L, f); } - template +#ifdef SOL_NOEXCEPT_FUNCTION_TYPE + static void select_function(std::true_type, lua_State* L, detail::lua_CFunction_noexcept f) { + stack::push(L, f); + } +#endif // noexcept function type + + template >, std::is_base_of>>> = meta::enabler> static void select(lua_State* L, Fx&& fx, Args&&... args) { - select_function(std::is_function>(), L, std::forward(fx), std::forward(args)...); + select_function(std::is_function>>(), L, std::forward(fx), std::forward(args)...); + } + + template >, std::is_base_of>>> = meta::enabler> + static void select(lua_State* L, Fx&& fx) { + stack::push(L, std::forward(fx)); } template static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = function_detail::call>; + lua_CFunction freefunc = function_detail::call, 2>; - stack::push>(L, std::forward(args)...); - stack::push(L, c_closure(freefunc, 1)); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(L, std::forward(args)...); + stack::push(L, c_closure(freefunc, upvalues)); } template @@ -8899,7 +10077,11 @@ namespace sol { template struct pusher> { - static int push(lua_State* L, std::function fx) { + static int push(lua_State* L, const std::function& fx) { + return pusher>{}.push(L, fx); + } + + static int push(lua_State* L, std::function&& fx) { return pusher>{}.push(L, std::move(fx)); } }; @@ -8913,7 +10095,15 @@ namespace sol { }; template - struct pusher, meta::neg>, meta::neg>>>::value>> { + struct pusher, + meta::neg>, + meta::neg>> +#ifdef SOL_NOEXCEPT_FUNCTION_TYPE + , meta::neg>, + meta::neg>> +#endif // noexcept function types + >::value>> { template static int push(lua_State* L, F&& f) { return pusher>{}.push(L, std::forward(f)); @@ -8938,15 +10128,19 @@ namespace sol { template struct pusher> { static int push(lua_State* L, protect_t&& pw) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>>(L, std::move(pw.value)); - return stack::push(L, c_closure(cf, closures)); + lua_CFunction cf = call_detail::call_user, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>>(L, std::move(pw.value)); + return stack::push(L, c_closure(cf, upvalues)); } static int push(lua_State* L, const protect_t& pw) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>>(L, pw.value); - return stack::push(L, c_closure(cf, closures)); + lua_CFunction cf = call_detail::call_user, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>>(L, pw.value); + return stack::push(L, c_closure(cf, upvalues)); } }; @@ -9017,6 +10211,18 @@ namespace sol { } }; + template <> + struct pusher { + static int push(lua_State* L, no_construction) { + lua_CFunction cf = &function_detail::no_construction_error; + return stack::push(L, cf); + } + + static int push(lua_State* L, no_construction c, function_detail::call_indicator) { + return push(L, c); + } + }; + template struct pusher>> { static int push(lua_State* L, detail::tagged>) { @@ -9029,9 +10235,11 @@ namespace sol { struct pusher>> { template static int push(lua_State* L, C&& c) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>>(L, std::forward(c)); - return stack::push(L, c_closure(cf, closures)); + lua_CFunction cf = call_detail::call_user, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>>(L, std::forward(c)); + return stack::push(L, c_closure(cf, upvalues)); } }; @@ -9046,9 +10254,11 @@ namespace sol { template struct pusher>> { static int push(lua_State* L, destructor_wrapper c) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>(L, std::move(c)); - return stack::push(L, c_closure(cf, closures)); + lua_CFunction cf = call_detail::call_user, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(L, std::move(c)); + return stack::push(L, c_closure(cf, upvalues)); } }; @@ -9139,51 +10349,9 @@ namespace sol { return invoke(types(), std::make_index_sequence(), pushcount); } }; - - namespace stack { - template - struct getter> { - typedef meta::bind_traits fx_t; - typedef typename fx_t::args_list args_lists; - typedef meta::tuple_types return_types; - - template - static std::function get_std_func(types, types, lua_State* L, int index) { - sol::function f(L, index); - auto fx = [f, L, index](Args&&... args) -> meta::return_type_t { - return f.call(std::forward(args)...); - }; - return std::move(fx); - } - - template - static std::function get_std_func(types, types, lua_State* L, int index) { - sol::function f(L, index); - auto fx = [f, L, index](FxArgs&&... args) -> void { - f(std::forward(args)...); - }; - return std::move(fx); - } - - template - static std::function get_std_func(types<>, types t, lua_State* L, int index) { - return get_std_func(types(), t, L, index); - } - - static std::function get(lua_State* L, int index, record& tracking) { - tracking.last = 1; - tracking.used += 1; - type t = type_of(L, index); - if (t == type::none || t == type::lua_nil) { - return nullptr; - } - return get_std_func(return_types(), args_lists(), L, index); - } - }; - } // stack } // sol -// end of sol/function.hpp +// end of sol/unsafe_function.hpp // beginning of sol/protected_function.hpp @@ -9199,11 +10367,11 @@ namespace sol { call_status err; template - decltype(auto) tagged_get(types>) const { + decltype(auto) tagged_get(types>) const { if (!valid()) { - return sol::optional(nullopt); + return optional(nullopt); } - return stack::get>(L, index); + return stack::get>(L, index); } template @@ -9424,7 +10592,7 @@ namespace sol { template basic_protected_function(proxy_base&& p, reference eh = get_default_handler()) : basic_protected_function(p.operator basic_function(), std::move(eh)) {} template - basic_protected_function(const proxy_base& p, reference eh = get_default_handler()) : basic_protected_function(static_cast>(p), std::move(eh)) {} + basic_protected_function(const proxy_base& p, reference eh = get_default_handler()) : basic_protected_function(p.operator basic_function(), std::move(eh)) {} template >>, meta::neg>> = meta::enabler> basic_protected_function(lua_State* L, T&& r, reference eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {} basic_protected_function(lua_State* L, int index = -1, reference eh = get_default_handler()) : base_t(L, index), error_handler(std::move(eh)) { @@ -9461,6 +10629,411 @@ namespace sol { // end of sol/protected_function.hpp +namespace sol { + + namespace stack { + template + struct getter> { + typedef meta::bind_traits fx_t; + typedef typename fx_t::args_list args_lists; + typedef meta::tuple_types return_types; + + template + static std::function get_std_func(types, types, lua_State* L, int index) { + sol::function f(L, index); + auto fx = [f, L, index](Args&&... args) -> meta::return_type_t { + return f.call(std::forward(args)...); + }; + return std::move(fx); + } + + template + static std::function get_std_func(types, types, lua_State* L, int index) { + sol::function f(L, index); + auto fx = [f, L, index](FxArgs&&... args) -> void { + f(std::forward(args)...); + }; + return std::move(fx); + } + + template + static std::function get_std_func(types<>, types t, lua_State* L, int index) { + return get_std_func(types(), t, L, index); + } + + static std::function get(lua_State* L, int index, record& tracking) { + tracking.last = 1; + tracking.used += 1; + type t = type_of(L, index); + if (t == type::none || t == type::lua_nil) { + return nullptr; + } + return get_std_func(return_types(), args_lists(), L, index); + } + }; + } // stack + +} // sol + +// end of sol/function.hpp + +namespace sol { + template + struct proxy : public proxy_base> { + private: + typedef meta::condition, Key, std::tuple>, Key&, meta::unqualified_t>>> key_type; + + template + decltype(auto) tuple_get(std::index_sequence) const { + return tbl.template traverse_get(std::get(key)...); + } + + template + void tuple_set(std::index_sequence, T&& value) { + tbl.traverse_set(std::get(key)..., std::forward(value)); + } + + public: + Table tbl; + key_type key; + + template + proxy(Table table, T&& k) : tbl(table), key(std::forward(k)) {} + + template + proxy& set(T&& item) { + tuple_set(std::make_index_sequence>::value>(), std::forward(item)); + return *this; + } + + template + proxy& set_function(Args&&... args) { + tbl.set_function(key, std::forward(args)...); + return *this; + } + + template>>, meta::is_callable>> = meta::enabler> + proxy& operator=(U&& other) { + return set_function(std::forward(other)); + } + + template>>, meta::is_callable>> = meta::enabler> + proxy& operator=(U&& other) { + return set(std::forward(other)); + } + + template + decltype(auto) get() const { + return tuple_get(std::make_index_sequence>::value>()); + } + + template + decltype(auto) get_or(T&& otherwise) const { + typedef decltype(get()) U; + optional option = get>(); + if (option) { + return static_cast(option.value()); + } + return static_cast(std::forward(otherwise)); + } + + template + decltype(auto) get_or(D&& otherwise) const { + optional option = get>(); + if (option) { + return static_cast(option.value()); + } + return static_cast(std::forward(otherwise)); + } + + template + decltype(auto) operator[](K&& k) const { + auto keys = meta::tuplefy(key, std::forward(k)); + return proxy(tbl, std::move(keys)); + } + + template + decltype(auto) call(Args&&... args) { + return get().template call(std::forward(args)...); + } + + template + decltype(auto) operator()(Args&&... args) { + return call<>(std::forward(args)...); + } + + bool valid() const { + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field, global_table>::value>(tbl.lua_state(), key, lua_gettop(tbl.lua_state())); + lua_pop(tbl.lua_state(), p.levels); + return p; + } + + type get_type() const { + type t = type::none; + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field, global_table>::value>(tbl.lua_state(), key, lua_gettop(tbl.lua_state())); + if (p) { + t = type_of(tbl.lua_state(), -1); + } + lua_pop(tbl.lua_state(), p.levels); + return t; + } + }; + + template + inline bool operator==(T&& left, const proxy& right) { + typedef decltype(stack::get(nullptr, 0)) U; + return right.template get>() == left; + } + + template + inline bool operator==(const proxy& right, T&& left) { + typedef decltype(stack::get(nullptr, 0)) U; + return right.template get>() == left; + } + + template + inline bool operator!=(T&& left, const proxy& right) { + typedef decltype(stack::get(nullptr, 0)) U; + return right.template get>() == left; + } + + template + inline bool operator!=(const proxy& right, T&& left) { + typedef decltype(stack::get(nullptr, 0)) U; + return right.template get>() == left; + } + + template + inline bool operator==(lua_nil_t, const proxy& right) { + return !right.valid(); + } + + template + inline bool operator==(const proxy& right, lua_nil_t) { + return !right.valid(); + } + + template + inline bool operator!=(lua_nil_t, const proxy& right) { + return right.valid(); + } + + template + inline bool operator!=(const proxy& right, lua_nil_t) { + return right.valid(); + } + + namespace stack { + template + struct pusher> { + static int push(lua_State* L, const proxy& p) { + sol::reference r = p; + return r.push(L); + } + }; + } // stack +} // sol + +// end of sol/proxy.hpp + +// beginning of sol/usertype.hpp + +// beginning of sol/usertype_metatable.hpp + +// beginning of sol/deprecate.hpp + +#ifndef SOL_DEPRECATED + #ifdef _MSC_VER + #define SOL_DEPRECATED __declspec(deprecated) + #elif __GNUC__ + #define SOL_DEPRECATED __attribute__((deprecated)) + #else + #define SOL_DEPRECATED [[deprecated]] + #endif // compilers +#endif // SOL_DEPRECATED + +namespace sol { + namespace detail { + template + struct SOL_DEPRECATED deprecate_type { + using type = T; + }; + } // detail +} // sol + +// end of sol/deprecate.hpp + +// beginning of sol/object.hpp + +// beginning of sol/object_base.hpp + +namespace sol { + + template + class basic_object_base : public base_t { + private: + template + decltype(auto) as_stack(std::true_type) const { + return stack::get(base_t::lua_state(), base_t::stack_index()); + } + + template + decltype(auto) as_stack(std::false_type) const { + base_t::push(); + return stack::pop(base_t::lua_state()); + } + + template + bool is_stack(std::true_type) const { + return stack::check(base_t::lua_state(), base_t::stack_index(), no_panic); + } + + template + bool is_stack(std::false_type) const { + int r = base_t::registry_index(); + if (r == LUA_REFNIL) + return meta::any_same, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false; + if (r == LUA_NOREF) + return false; + auto pp = stack::push_pop(*this); + return stack::check(base_t::lua_state(), -1, no_panic); + } + + public: + basic_object_base() noexcept = default; + basic_object_base(const basic_object_base&) = default; + basic_object_base(basic_object_base&&) = default; + basic_object_base& operator=(const basic_object_base&) = default; + basic_object_base& operator=(basic_object_base&&) = default; + template , basic_object_base>>> = meta::enabler> + basic_object_base(T&& arg, Args&&... args) : base_t(std::forward(arg), std::forward(args)...) { } + + template + decltype(auto) as() const { + return as_stack(std::is_same()); + } + + template + bool is() const { + return is_stack(std::is_same()); + } + }; +} // sol + +// end of sol/object_base.hpp + +// beginning of sol/userdata.hpp + +namespace sol { + template + class basic_userdata : public basic_table { + typedef basic_table base_t; + public: + basic_userdata() noexcept = default; + template , basic_userdata>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_userdata(T&& r) noexcept : base_t(std::forward(r)) { +#ifdef SOL_CHECK_ARGUMENTS + if (!is_userdata>::value) { + auto pp = stack::push_pop(*this); + type_assert(base_t::lua_state(), -1, type::userdata); + } +#endif // Safety + } + basic_userdata(const basic_userdata&) = default; + 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(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} + template >>, meta::neg, ref_index>>> = meta::enabler> + basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {} + basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(L, index, type_panic); +#endif // Safety + } + basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + auto pp = stack::push_pop(*this); + stack::check(L, index, type_panic); +#endif // Safety + } + }; + + template + class basic_lightuserdata : public basic_object_base { + typedef basic_object_base base_t; + public: + basic_lightuserdata() noexcept = default; + template , basic_lightuserdata>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_lightuserdata(T&& r) noexcept : base_t(std::forward(r)) { +#ifdef SOL_CHECK_ARGUMENTS + if (!is_lightuserdata>::value) { + auto pp = stack::push_pop(*this); + type_assert(base_t::lua_state(), -1, type::lightuserdata); + } +#endif // Safety + } + basic_lightuserdata(const basic_lightuserdata&) = default; + 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(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} + template >>, meta::neg, ref_index>>> = meta::enabler> + basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {} + basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(L, index, type_panic); +#endif // Safety + } + basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { +#ifdef SOL_CHECK_ARGUMENTS + auto pp = stack::push_pop(*this); + stack::check(L, index, type_panic); +#endif // Safety + } + }; + +} // sol + +// end of sol/userdata.hpp + +// beginning of sol/as_args.hpp + +namespace sol { + template + struct as_args_t { + T src; + }; + + template + auto as_args(Source&& source) { + return as_args_t{ std::forward(source) }; + } + + namespace stack { + template + struct pusher> { + int push(lua_State* L, const as_args_t& e) { + int p = 0; + for (const auto& i : e.src) { + p += stack::push(L, i); + } + return p; + } + }; + } // stack +} // sol + +// end of sol/as_args.hpp + +// beginning of sol/variadic_args.hpp + +// beginning of sol/stack_proxy.hpp + namespace sol { struct stack_proxy : public proxy_base { private: @@ -9476,6 +11049,10 @@ namespace sol { return stack::get(L, stack_index()); } + type get_type() const noexcept { + return type_of(lua_state(), stack_index()); + } + int push() const { return push(L); } @@ -9562,7 +11139,6 @@ namespace sol { // end of sol/stack_proxy.hpp #include -#include namespace sol { template @@ -9579,17 +11155,27 @@ namespace sol { stack_proxy sp; va_iterator() : L(nullptr), index((std::numeric_limits::max)()), stacktop((std::numeric_limits::max)()) {} + va_iterator(const va_iterator& r) : L(r.L), index(r.index), stacktop(r.stacktop) {} va_iterator(lua_State* luastate, int idx, int topidx) : L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) {} reference operator*() { return stack_proxy(L, index); } + reference operator*() const { + return stack_proxy(L, index); + } + pointer operator->() { sp = stack_proxy(L, index); return &sp; } + pointer operator->() const { + const_cast(sp) = stack_proxy(L, index); + return &sp; + } + va_iterator& operator++ () { ++index; return *this; @@ -9632,7 +11218,7 @@ namespace sol { return r; } - reference operator[](difference_type idx) { + reference operator[](difference_type idx) const { return stack_proxy(L, index + static_cast(idx)); } @@ -9691,6 +11277,7 @@ namespace sol { 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, 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) { @@ -9749,6 +11336,10 @@ namespace sol { return stack::get(L, index + static_cast(start)); } + type get_type(difference_type start = 0) const noexcept { + return type_of(L, index + static_cast(start)); + } + stack_proxy operator[](difference_type start) const { return stack_proxy(L, index + static_cast(start)); } @@ -9756,6 +11347,7 @@ namespace sol { lua_State* lua_state() const { return L; }; int stack_index() const { return index; }; int leftover_count() const { return stacktop - (index - 1); } + std::size_t size() const { return static_cast(leftover_count()); } int top() const { return stacktop; } }; @@ -9801,30 +11393,10 @@ namespace sol { return r; } - template - class basic_object : public base_t { + template + class basic_object : public basic_object_base { private: - template - decltype(auto) as_stack(std::true_type) const { - return stack::get(base_t::lua_state(), base_t::stack_index()); - } - - template - decltype(auto) as_stack(std::false_type) const { - base_t::push(); - return stack::pop(base_t::lua_state()); - } - - template - bool is_stack(std::true_type) const { - return stack::check(base_t::lua_state(), base_t::stack_index(), no_panic); - } - - template - bool is_stack(std::false_type) const { - auto pp = stack::push_pop(*this); - return stack::check(base_t::lua_state(), -1, no_panic); - } + typedef basic_object_base base_t; template basic_object(std::integral_constant, lua_State* L, int index = -1) noexcept : base_t(L, index) { @@ -9835,7 +11407,7 @@ namespace sol { public: basic_object() noexcept = default; - template , basic_object>>, meta::neg>, std::is_base_of>> = meta::enabler> + template , basic_object>>, meta::neg>, std::is_base_of>> = meta::enabler> basic_object(T&& r) : base_t(std::forward(r)) {} basic_object(lua_nil_t r) : base_t(r) {} basic_object(const basic_object&) = default; @@ -9849,29 +11421,19 @@ namespace sol { basic_object(lua_State* L, int index = -1) noexcept : base_t(L, index) {} basic_object(lua_State* L, ref_index index) noexcept : base_t(L, index) {} template - basic_object(lua_State* L, in_place_type_t, Args&&... args) noexcept : basic_object(std::integral_constant::value>(), L, -stack::push(L, std::forward(args)...)) {} + basic_object(lua_State* L, in_place_type_t, Args&&... args) noexcept + : basic_object(std::integral_constant::value>(), L, -stack::push(L, std::forward(args)...)) {} template - basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept : basic_object(L, in_place, std::forward(arg), std::forward(args)...) {} + basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept + : basic_object(L, in_place_type, std::forward(arg), std::forward(args)...) {} basic_object& operator=(const basic_object&) = default; basic_object& operator=(basic_object&&) = default; - basic_object& operator=(const base_t& b) { base_t::operator=(b); return *this; } - basic_object& operator=(base_t&& b) { base_t::operator=(std::move(b)); return *this; } + basic_object& operator=(const base_type& b) { base_t::operator=(b); return *this; } + basic_object& operator=(base_type&& b) { base_t::operator=(std::move(b)); return *this; } template basic_object& operator=(const proxy_base& r) { this->operator=(r.operator basic_object()); return *this; } template basic_object& operator=(proxy_base&& r) { this->operator=(r.operator basic_object()); return *this; } - - template - decltype(auto) as() const { - return as_stack(std::is_same()); - } - - template - bool is() const { - if (!base_t::valid()) - return false; - return is_stack(std::is_same()); - } }; template @@ -9883,208 +11445,137 @@ namespace sol { object make_object(lua_State* L, Args&&... args) { return make_reference(L, std::forward(args)...); } - - inline bool operator==(const object& lhs, const lua_nil_t&) { - return !lhs.valid(); - } - - inline bool operator==(const lua_nil_t&, const object& rhs) { - return !rhs.valid(); - } - - inline bool operator!=(const object& lhs, const lua_nil_t&) { - return lhs.valid(); - } - - inline bool operator!=(const lua_nil_t&, const object& rhs) { - return rhs.valid(); - } } // sol // end of sol/object.hpp -namespace sol { - template - struct proxy : public proxy_base> { - private: - typedef meta::condition, Key, std::tuple>, Key&, meta::unqualified_t>>> key_type; - - template - decltype(auto) tuple_get(std::index_sequence) const { - return tbl.template traverse_get(std::get(key)...); - } - - template - void tuple_set(std::index_sequence, T&& value) { - tbl.traverse_set(std::get(key)..., std::forward(value)); - } - - public: - Table tbl; - key_type key; - - template - proxy(Table table, T&& k) : tbl(table), key(std::forward(k)) {} - - template - proxy& set(T&& item) { - tuple_set(std::make_index_sequence>::value>(), std::forward(item)); - return *this; - } - - template - proxy& set_function(Args&&... args) { - tbl.set_function(key, std::forward(args)...); - return *this; - } - - template>>, meta::is_callable>> = meta::enabler> - proxy& operator=(U&& other) { - return set_function(std::forward(other)); - } - - template>>, meta::is_callable>> = meta::enabler> - proxy& operator=(U&& other) { - return set(std::forward(other)); - } - - template - decltype(auto) get() const { - return tuple_get(std::make_index_sequence>::value>()); - } - - template - decltype(auto) get_or(T&& otherwise) const { - typedef decltype(get()) U; - sol::optional option = get>(); - if (option) { - return static_cast(option.value()); - } - return static_cast(std::forward(otherwise)); - } - - template - decltype(auto) get_or(D&& otherwise) const { - sol::optional option = get>(); - if (option) { - return static_cast(option.value()); - } - return static_cast(std::forward(otherwise)); - } - - template - decltype(auto) operator[](K&& k) const { - auto keys = meta::tuplefy(key, std::forward(k)); - return proxy(tbl, std::move(keys)); - } - - template - decltype(auto) call(Args&&... args) { - return get().template call(std::forward(args)...); - } - - template - decltype(auto) operator()(Args&&... args) { - return call<>(std::forward(args)...); - } - - bool valid() const { - auto pp = stack::push_pop(tbl); - auto p = stack::probe_get_field, global_table>::value>(tbl.lua_state(), key, lua_gettop(tbl.lua_state())); - lua_pop(tbl.lua_state(), p.levels); - return p; - } - }; - - template - inline bool operator==(T&& left, const proxy& right) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() == left; - } - - template - inline bool operator==(const proxy& right, T&& left) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() == left; - } - - template - inline bool operator!=(T&& left, const proxy& right) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() == left; - } - - template - inline bool operator!=(const proxy& right, T&& left) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() == left; - } - - template - inline bool operator==(lua_nil_t, const proxy& right) { - return !right.valid(); - } - - template - inline bool operator==(const proxy& right, lua_nil_t) { - return !right.valid(); - } - - template - inline bool operator!=(lua_nil_t, const proxy& right) { - return right.valid(); - } - - template - inline bool operator!=(const proxy& right, lua_nil_t) { - return right.valid(); - } - - namespace stack { - template - struct pusher> { - static int push(lua_State* L, const proxy& p) { - sol::reference r = p; - return r.push(L); - } - }; - } // stack -} // sol - -// end of sol/proxy.hpp - -// beginning of sol/usertype.hpp - -// beginning of sol/usertype_metatable.hpp - -// beginning of sol/deprecate.hpp - -#ifndef SOL_DEPRECATED - #ifdef _MSC_VER - #define SOL_DEPRECATED __declspec(deprecated) - #elif __GNUC__ - #define SOL_DEPRECATED __attribute__((deprecated)) - #else - #define SOL_DEPRECATED [[deprecated]] - #endif // compilers -#endif // SOL_DEPRECATED - -namespace sol { - namespace detail { - template - struct SOL_DEPRECATED deprecate_type { - using type = T; - }; - } // detail -} // sol - -// end of sol/deprecate.hpp - #include #include namespace sol { namespace usertype_detail { + const int metatable_index = 2; + const int metatable_core_index = 3; + const int filler_index = 4; + const int magic_index = 5; + + const int simple_metatable_index = 2; + const int index_function_index = 3; + const int newindex_function_index = 4; + + typedef void(*base_walk)(lua_State*, bool&, int&, string_detail::string_shim&); + typedef int(*member_search)(lua_State*, void*, int); + + struct call_information { + member_search index; + member_search new_index; + int runtime_target; + + call_information(member_search index, member_search newindex) : call_information(index, newindex, -1) {} + call_information(member_search index, member_search newindex, int runtimetarget) : index(index), new_index(newindex), runtime_target(runtimetarget) {} + }; + + typedef std::unordered_map mapping_t; + + struct variable_wrapper { + virtual int index(lua_State* L) = 0; + virtual int new_index(lua_State* L) = 0; + virtual ~variable_wrapper() {}; + }; + + template + struct callable_binding : variable_wrapper { + F fx; + + template + callable_binding(Arg&& arg) : fx(std::forward(arg)) {} + + virtual int index(lua_State* L) override { + return call_detail::call_wrapped(L, fx); + } + + virtual int new_index(lua_State* L) override { + return call_detail::call_wrapped(L, fx); + } + }; + + typedef std::unordered_map> variable_map; + typedef std::unordered_map function_map; + + struct simple_map { + const char* metakey; + variable_map variables; + function_map functions; + object index; + object newindex; + base_walk indexbaseclasspropogation; + base_walk newindexbaseclasspropogation; + + simple_map(const char* mkey, base_walk index, base_walk newindex, object i, object ni, variable_map&& vars, function_map&& funcs) + : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), + index(std::move(i)), newindex(std::move(ni)), + indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {} + }; + } + + struct usertype_metatable_core { + usertype_detail::mapping_t mapping; + lua_CFunction indexfunc; + lua_CFunction newindexfunc; + std::vector runtime; + bool mustindex; + + usertype_metatable_core(lua_CFunction ifx, lua_CFunction nifx) : + mapping(), indexfunc(ifx), + newindexfunc(nifx), runtime(), mustindex(false) + { + + } + + usertype_metatable_core(const usertype_metatable_core&) = default; + usertype_metatable_core(usertype_metatable_core&&) = default; + usertype_metatable_core& operator=(const usertype_metatable_core&) = default; + usertype_metatable_core& operator=(usertype_metatable_core&&) = default; + + }; + + namespace usertype_detail { + const lua_Integer toplevel_magic = static_cast(0xCCC2CCC1); + + struct add_destructor_tag {}; + struct check_destructor_tag {}; + struct verified_tag {} const verified{}; + + template + struct is_non_factory_constructor : std::false_type {}; + + template + struct is_non_factory_constructor> : std::true_type {}; + + template + struct is_non_factory_constructor> : std::true_type {}; + + template <> + struct is_non_factory_constructor : std::true_type {}; + + template + struct is_constructor : is_non_factory_constructor {}; + + template + struct is_constructor> : std::true_type {}; + + template + using has_constructor = meta::any>...>; + + template + struct is_destructor : std::false_type {}; + + template + struct is_destructor> : std::true_type {}; + + template + using has_destructor = meta::any>...>; + struct no_comp { template bool operator()(A&&, B&&) const { @@ -10092,30 +11583,32 @@ namespace sol { } }; - typedef void(*base_walk)(lua_State*, bool&, int&, string_detail::string_shim&); - typedef int(*member_search)(lua_State*, void*); - - struct find_call_pair { - member_search first; - member_search second; - - find_call_pair(member_search first, member_search second) : first(first), second(second) {} - }; - - inline bool is_indexer(string_detail::string_shim s) { - return s == name_of(meta_function::index) || s == name_of(meta_function::new_index); + inline int is_indexer(string_detail::string_shim s) { + if (s == to_string(meta_function::index)) { + return 1; + } + else if (s == to_string(meta_function::new_index)) { + return 2; + } + return 0; } - inline bool is_indexer(meta_function mf) { - return mf == meta_function::index || mf == meta_function::new_index; + inline int is_indexer(meta_function mf) { + if (mf == meta_function::index) { + return 1; + } + else if (mf == meta_function::new_index) { + return 2; + } + return 0; } - inline bool is_indexer(call_construction) { - return false; + inline int is_indexer(call_construction) { + return 0; } - inline bool is_indexer(base_classes_tag) { - return false; + inline int is_indexer(base_classes_tag) { + return 0; } inline auto make_shim(string_detail::string_shim s) { @@ -10123,11 +11616,11 @@ namespace sol { } inline auto make_shim(call_construction) { - return string_detail::string_shim(name_of(meta_function::call_function)); + return string_detail::string_shim(to_string(meta_function::call_function)); } inline auto make_shim(meta_function mf) { - return string_detail::string_shim(name_of(mf)); + return string_detail::string_shim(to_string(mf)); } inline auto make_shim(base_classes_tag) { @@ -10137,28 +11630,153 @@ namespace sol { template inline std::string make_string(Arg&& arg) { string_detail::string_shim s = make_shim(arg); - return std::string(s.c_str(), s.size()); + return std::string(s.data(), s.size()); } template inline luaL_Reg make_reg(N&& n, lua_CFunction f) { - luaL_Reg l{ make_shim(std::forward(n)).c_str(), f }; + luaL_Reg l{ make_shim(std::forward(n)).data(), f }; return l; } struct registrar { + registrar() = default; + registrar(const registrar&) = default; + registrar(registrar&&) = default; + registrar& operator=(const registrar&) = default; + registrar& operator=(registrar&&) = default; virtual int push_um(lua_State* L) = 0; virtual ~registrar() {} }; - template + inline bool is_toplevel(lua_State* L, int index = magic_index) { + int isnum = 0; + lua_Integer magic = lua_tointegerx(L, upvalue_index(index), &isnum); + return isnum != 0 && magic == toplevel_magic; + } + + inline int runtime_object_call(lua_State* L, void*, int runtimetarget) { + usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + std::vector& runtime = umc.runtime; + object& runtimeobj = runtime[runtimetarget]; + return stack::push(L, runtimeobj); + } + + template inline int indexing_fail(lua_State* L) { - auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); - string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); - if (is_index) - return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str()); - else - return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str()); + if (is_index) { +#if 0//def SOL_SAFE_USERTYPE + auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); + string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); + return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); +#else + if (is_toplevel(L)) { + if (lua_getmetatable(L, 1) == 1) { + int metatarget = lua_gettop(L); + stack::get_field(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, unfortunately... + return stack::push(L, lua_nil); +#endif + } + else { + auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); + string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); + return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); + } + } + + int runtime_new_index(lua_State* L, void*, int runtimetarget); + + template + inline int metatable_newindex(lua_State* L) { + if (is_toplevel(L)) { + auto non_indexable = [&L]() { + if (is_simple) { + simple_map& sm = stack::get>(L, upvalue_index(simple_metatable_index)); + function_map& functions = sm.functions; + optional maybeaccessor = stack::get>(L, 2); + if (!maybeaccessor) { + return; + } + std::string& accessor = maybeaccessor.value(); + auto preexistingit = functions.find(accessor); + if (preexistingit == functions.cend()) { + functions.emplace_hint(preexistingit, std::move(accessor), sol::object(L, 3)); + } + else { + preexistingit->second = sol::object(L, 3); + } + return; + } + usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + bool mustindex = umc.mustindex; + if (!mustindex) + return; + optional maybeaccessor = stack::get>(L, 2); + if (!maybeaccessor) { + return; + } + std::string& accessor = maybeaccessor.value(); + mapping_t& mapping = umc.mapping; + std::vector& runtime = umc.runtime; + int target = static_cast(runtime.size()); + auto preexistingit = mapping.find(accessor); + if (preexistingit == mapping.cend()) { + runtime.emplace_back(L, 3); + mapping.emplace_hint(mapping.cend(), accessor, call_information(&runtime_object_call, &runtime_new_index, target)); + } + else { + target = preexistingit->second.runtime_target; + runtime[target] = sol::object(L, 3); + preexistingit->second = call_information(&runtime_object_call, &runtime_new_index, target); + } + }; + non_indexable(); + for (std::size_t i = 0; i < 4; lua_settop(L, 3), ++i) { + const char* metakey = nullptr; + switch (i) { + case 0: + metakey = &usertype_traits::metatable()[0]; + luaL_getmetatable(L, metakey); + break; + case 1: + metakey = &usertype_traits>::metatable()[0]; + luaL_getmetatable(L, metakey); + break; + case 2: + metakey = &usertype_traits::metatable()[0]; + luaL_getmetatable(L, metakey); + break; + case 3: + default: + metakey = &usertype_traits::user_metatable()[0]; + { + luaL_getmetatable(L, metakey); + lua_getmetatable(L, -1); + } + break; + } + int tableindex = lua_gettop(L); + if (type_of(L, tableindex) == type::lua_nil) { + continue; + } + stack::set_field(L, stack_reference(L, raw_index(2)), stack_reference(L, raw_index(3)), tableindex); + } + lua_settop(L, 0); + return 0; + } + return indexing_fail(L); + } + + inline int runtime_new_index(lua_State* L, void*, int runtimetarget) { + usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + std::vector& runtime = umc.runtime; + object& runtimeobj = runtime[runtimetarget]; + runtimeobj = object(L, 3); + return 0; } template @@ -10230,41 +11848,6 @@ namespace sol { inline void make_reg_op(Regs&, int&, const char*) { // Do nothing if there's no support } - - struct add_destructor_tag {}; - struct check_destructor_tag {}; - struct verified_tag {} const verified{}; - - template - struct is_non_factory_constructor : std::false_type {}; - - template - struct is_non_factory_constructor> : std::true_type {}; - - template - struct is_non_factory_constructor> : std::true_type {}; - - template <> - struct is_non_factory_constructor : std::true_type {}; - - template - struct is_constructor : is_non_factory_constructor {}; - - template - struct is_constructor> : std::true_type {}; - - template - using has_constructor = meta::any>...>; - - template - struct is_destructor : std::false_type {}; - - template - struct is_destructor> : std::true_type {}; - - template - using has_destructor = meta::any>...>; - } // usertype_detail template @@ -10279,7 +11862,7 @@ namespace sol { struct usertype_metatable : usertype_detail::registrar {}; template - struct usertype_metatable, Tn...> : usertype_detail::registrar { + struct usertype_metatable, Tn...> : usertype_metatable_core, usertype_detail::registrar { typedef std::make_index_sequence indices; typedef std::index_sequence half_indices; typedef std::array regs_t; @@ -10287,11 +11870,7 @@ namespace sol { typedef std::tuple ...> Tuple; template struct check_binding : is_variable_binding> {}; - typedef std::unordered_map mapping_t; Tuple functions; - mapping_t mapping; - lua_CFunction indexfunc; - lua_CFunction newindexfunc; lua_CFunction destructfunc; lua_CFunction callconstructfunc; lua_CFunction indexbase; @@ -10300,20 +11879,20 @@ namespace sol { usertype_detail::base_walk newindexbaseclasspropogation; void* baseclasscheck; void* baseclasscast; - bool mustindex; bool secondarymeta; bool hasequals; bool hasless; bool haslessequals; template >> = meta::enabler> - inline lua_CFunction make_func() { + lua_CFunction make_func() const { return std::get(functions); } template >> = meta::enabler> - inline lua_CFunction make_func() { - return call; + lua_CFunction make_func() const { + const auto& name = std::get(functions); + return (usertype_detail::make_shim(name) == "__newindex") ? &call : &call; } static bool contains_variable() { @@ -10323,25 +11902,25 @@ namespace sol { bool contains_index() const { bool idx = false; - (void)detail::swallow{ 0, ((idx |= usertype_detail::is_indexer(std::get(functions))), 0) ... }; + (void)detail::swallow{ 0, ((idx |= (usertype_detail::is_indexer(std::get(functions)) != 0)), 0) ... }; return idx; } int finish_regs(regs_t& l, int& index) { if (!hasless) { - const char* name = name_of(meta_function::less_than).c_str(); + const char* name = to_string(meta_function::less_than).c_str(); usertype_detail::make_reg_op, meta::supports_op_less>(l, index, name); } if (!haslessequals) { - const char* name = name_of(meta_function::less_than_or_equal_to).c_str(); + const char* name = to_string(meta_function::less_than_or_equal_to).c_str(); usertype_detail::make_reg_op, meta::supports_op_less_equal>(l, index, name); } if (!hasequals) { - const char* name = name_of(meta_function::equal_to).c_str(); + const char* name = to_string(meta_function::equal_to).c_str(); usertype_detail::make_reg_op::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name); } if (destructfunc != nullptr) { - l[index] = { name_of(meta_function::garbage_collect).c_str(), destructfunc }; + l[index] = { to_string(meta_function::garbage_collect).c_str(), destructfunc }; ++index; } return index; @@ -10355,6 +11934,7 @@ namespace sol { template void make_regs(regs_t&, int&, base_classes_tag, bases) { + static_assert(!meta::any_same::value, "base classes cannot list the original class as part of the bases"); if (sizeof...(Bases) < 1) { return; } @@ -10378,25 +11958,25 @@ namespace sol { // Returnable scope // That would be a neat keyword for C++ // returnable { ... }; - if (reg.name == name_of(meta_function::equal_to)) { + if (reg.name == to_string(meta_function::equal_to)) { hasequals = true; } - if (reg.name == name_of(meta_function::less_than)) { + if (reg.name == to_string(meta_function::less_than)) { hasless = true; } - if (reg.name == name_of(meta_function::less_than_or_equal_to)) { + if (reg.name == to_string(meta_function::less_than_or_equal_to)) { haslessequals = true; } - if (reg.name == name_of(meta_function::garbage_collect)) { + if (reg.name == to_string(meta_function::garbage_collect)) { destructfunc = reg.func; return; } - else if (reg.name == name_of(meta_function::index)) { + else if (reg.name == to_string(meta_function::index)) { indexfunc = reg.func; mustindex = true; return; } - else if (reg.name == name_of(meta_function::new_index)) { + else if (reg.name == to_string(meta_function::new_index)) { newindexfunc = reg.func; mustindex = true; return; @@ -10406,37 +11986,58 @@ namespace sol { } template > - usertype_metatable(Args&&... args) : functions(std::forward(args)...), - mapping(), - indexfunc(usertype_detail::indexing_fail), newindexfunc(usertype_detail::indexing_fail), + usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail, &usertype_detail::metatable_newindex), usertype_detail::registrar(), + functions(std::forward(args)...), destructfunc(nullptr), callconstructfunc(nullptr), indexbase(&core_indexing_call), newindexbase(&core_indexing_call), indexbaseclasspropogation(usertype_detail::walk_all_bases), newindexbaseclasspropogation(usertype_detail::walk_all_bases), baseclasscheck(nullptr), baseclasscast(nullptr), - mustindex(contains_variable() || contains_index()), secondarymeta(contains_variable()), + secondarymeta(contains_variable()), hasequals(false), hasless(false), haslessequals(false) { - std::initializer_list ilist{ { - std::pair( - usertype_detail::make_string(std::get(functions)), - usertype_detail::find_call_pair(&usertype_metatable::real_find_call, - &usertype_metatable::real_find_call) + std::initializer_list ilist{ { + std::pair( usertype_detail::make_string(std::get(functions)), + usertype_detail::call_information(&usertype_metatable::real_find_call, + &usertype_metatable::real_find_call) ) }... }; - mapping.insert(ilist); + this->mapping.insert(ilist); + for (const auto& n : meta_function_names()) { + this->mapping.erase(n); + } + this->mustindex = contains_variable() || contains_index(); } + usertype_metatable(const usertype_metatable&) = default; + usertype_metatable(usertype_metatable&&) = default; + usertype_metatable& operator=(const usertype_metatable&) = default; + usertype_metatable& operator=(usertype_metatable&&) = default; + template - static int real_find_call(lua_State* L, void* um) { + static int real_find_call(lua_State* L, void* um, int) { auto& f = *static_cast(um); if (is_variable_binding(f.functions))>::value) { return real_call_with(L, f); } - return stack::push(L, c_closure(call, stack::push(L, light(f)))); + // set up upvalues + // for a chained call + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, light(f)); + auto cfunc = &call; + return stack::push(L, c_closure(cfunc, upvalues)); + } + + template + static int real_meta_call(lua_State* L, void* um, int) { + auto& f = *static_cast(um); + return is_index ? f.indexfunc(L) : f.newindexfunc(L); } template static int core_indexing_call(lua_State* L) { - usertype_metatable& f = toplevel ? stack::get>(L, upvalue_index(1)) : stack::pop>(L); + usertype_metatable& f = toplevel + ? stack::get>(L, upvalue_index(usertype_detail::metatable_index)) + : stack::pop>(L); static const int keyidx = -2 + static_cast(is_index); if (toplevel && stack::get(L, keyidx) != type::string) { return is_index ? f.indexfunc(L) : f.newindexfunc(L); @@ -10444,8 +12045,9 @@ namespace sol { std::string name = stack::get(L, keyidx); auto memberit = f.mapping.find(name); if (memberit != f.mapping.cend()) { - auto& member = is_index ? memberit->second.second : memberit->second.first; - return (member)(L, static_cast(&f)); + const usertype_detail::call_information& ci = memberit->second; + const usertype_detail::member_search& member = is_index ? ci.index: ci.new_index; + return (member)(L, static_cast(&f), ci.runtime_target); } string_detail::string_shim accessor = name; int ret = 0; @@ -10471,7 +12073,7 @@ namespace sol { template static int real_call(lua_State* L) { - usertype_metatable& f = stack::get>(L, upvalue_index(1)); + usertype_metatable& f = stack::get>(L, upvalue_index(usertype_detail::metatable_index)); return real_call_with(L, f); } @@ -10489,20 +12091,20 @@ namespace sol { template static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); + return detail::typed_static_trampoline), (&real_call)>(L); } template static int call_with(lua_State* L) { - return detail::static_trampoline<(&real_call_with)>(L); + return detail::typed_static_trampoline), (&real_call_with)>(L); } static int index_call(lua_State* L) { - return detail::static_trampoline<(&real_index_call)>(L); + return detail::typed_static_trampoline(L); } static int new_index_call(lua_State* L) { - return detail::static_trampoline<(&real_new_index_call)>(L); + return detail::typed_static_trampoline(L); } virtual int push_um(lua_State* L) override { @@ -10551,6 +12153,7 @@ namespace sol { static int push(lua_State* L, umt_t&& umx) { umt_t& um = make_cleanup(L, std::move(umx)); + usertype_metatable_core& umc = um; regs_t value_table{ {} }; int lastreg = 0; (void)detail::swallow{ 0, (um.template make_regs<(I * 2)>(value_table, lastreg, std::get<(I * 2)>(um.functions), std::get<(I * 2 + 1)>(um.functions)), 0)... }; @@ -10558,14 +12161,14 @@ namespace sol { value_table[lastreg] = { nullptr, nullptr }; regs_t ref_table = value_table; regs_t unique_table = value_table; - bool hasdestructor = !value_table.empty() && name_of(meta_function::garbage_collect) == value_table[lastreg - 1].name; + bool hasdestructor = !value_table.empty() && to_string(meta_function::garbage_collect) == value_table[lastreg - 1].name; if (hasdestructor) { ref_table[lastreg - 1] = { nullptr, nullptr }; - unique_table[lastreg - 1] = { value_table[lastreg - 1].name, detail::unique_destruct }; } + unique_table[lastreg - 1] = { value_table[lastreg - 1].name, detail::unique_destruct }; // Now use um - const bool& mustindex = um.mustindex; + const bool& mustindex = umc.mustindex; for (std::size_t i = 0; i < 3; ++i) { // Pointer types, AKA "references" from C++ const char* metakey = nullptr; @@ -10587,8 +12190,10 @@ namespace sol { } luaL_newmetatable(L, metakey); stack_reference t(L, -1); - stack::push(L, make_light(um)); - luaL_setfuncs(L, metaregs, 1); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, make_light(um)); + luaL_setfuncs(L, metaregs, upvalues); if (um.baseclasscheck != nullptr) { stack::set_field(L, detail::base_class_check_key(), um.baseclasscheck, t.stack_index()); @@ -10597,14 +12202,14 @@ namespace sol { stack::set_field(L, detail::base_class_cast_key(), um.baseclasscast, t.stack_index()); } - stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, make_light(um)), t.stack_index()); - stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, make_light(um)), t.stack_index()); + stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, nullptr, make_light(um), make_light(umc)), t.stack_index()); + stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, nullptr, make_light(um), make_light(umc)), t.stack_index()); if (mustindex) { // Basic index pushing: specialize // index and newindex to give variables and stuff - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um)), t.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um)), t.stack_index()); + stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc)), t.stack_index()); + stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc)), t.stack_index()); } else { // If there's only functions, we can use the fast index version @@ -10615,11 +12220,11 @@ namespace sol { lua_createtable(L, 0, 3); stack_reference metabehind(L, -1); if (um.callconstructfunc != nullptr) { - stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um)), metabehind.stack_index()); + stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); } if (um.secondarymeta) { - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um)), metabehind.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um)), metabehind.stack_index()); + stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); + stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); } stack::set_field(L, metatable_key, metabehind, t.stack_index()); metabehind.pop(); @@ -10631,18 +12236,20 @@ namespace sol { // Now for the shim-table that actually gets assigned to the name luaL_newmetatable(L, &usertype_traits::user_metatable()[0]); stack_reference t(L, -1); - stack::push(L, make_light(um)); - luaL_setfuncs(L, value_table.data(), 1); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, make_light(um)); + luaL_setfuncs(L, value_table.data(), upvalues); { lua_createtable(L, 0, 3); stack_reference metabehind(L, -1); if (um.callconstructfunc != nullptr) { - stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um)), metabehind.stack_index()); - } - if (um.secondarymeta) { - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um)), metabehind.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um)), metabehind.stack_index()); + stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); } + + stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index()); + stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index()); + stack::set_field(L, metatable_key, metabehind, t.stack_index()); metabehind.pop(); } @@ -10662,94 +12269,42 @@ namespace sol { namespace sol { namespace usertype_detail { - const lua_Integer toplevel_magic = static_cast(0x00000001); - - struct variable_wrapper { - virtual int index(lua_State* L) = 0; - virtual int new_index(lua_State* L) = 0; - virtual ~variable_wrapper() {}; - }; - - template - struct callable_binding : variable_wrapper { - F fx; - - template - callable_binding(Arg&& arg) : fx(std::forward(arg)) {} - - virtual int index(lua_State* L) override { - return call_detail::call_wrapped(L, fx); + inline int call_indexing_object(lua_State* L, object& f) { + int before = lua_gettop(L); + f.push(); + for (int i = 1; i <= before; ++i) { + lua_pushvalue(L, i); } - - virtual int new_index(lua_State* L) override { - return call_detail::call_wrapped(L, fx); - } - }; - - typedef std::unordered_map> variable_map; - typedef std::unordered_map function_map; - - struct simple_map { - const char* metakey; - variable_map variables; - function_map functions; - base_walk indexbaseclasspropogation; - base_walk newindexbaseclasspropogation; - - simple_map(const char* mkey, base_walk index, base_walk newindex, variable_map&& vars, function_map&& funcs) : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {} - }; - - template - inline int simple_metatable_newindex(lua_State* L) { - int isnum = 0; - lua_Integer magic = lua_tointegerx(L, lua_upvalueindex(4), &isnum); - if (isnum != 0 && magic == toplevel_magic) { - for (std::size_t i = 0; i < 3; lua_pop(L, 1), ++i) { - // Pointer types, AKA "references" from C++ - const char* metakey = nullptr; - switch (i) { - case 0: - metakey = &usertype_traits::metatable()[0]; - break; - case 1: - metakey = &usertype_traits>::metatable()[0]; - break; - case 2: - default: - metakey = &usertype_traits::metatable()[0]; - break; - } - luaL_getmetatable(L, metakey); - int tableindex = lua_gettop(L); - if (type_of(L, tableindex) == type::lua_nil) { - continue; - } - stack::set_field(L, stack_reference(L, 2), stack_reference(L, 3), tableindex); - } - lua_settop(L, 0); - return 0; - } - return indexing_fail(L); + lua_callk(L, before, LUA_MULTRET, 0, nullptr); + int after = lua_gettop(L); + return after - before; } - inline int simple_indexing_fail(lua_State* L) { - return stack::push(L, sol::lua_nil); - } - - template + template inline int simple_core_indexing_call(lua_State* L) { - simple_map& sm = toplevel ? stack::get>(L, upvalue_index(1)) : stack::pop>(L); + simple_map& sm = toplevel + ? stack::get>(L, upvalue_index(simple_metatable_index)) + : stack::pop>(L); variable_map& variables = sm.variables; function_map& functions = sm.functions; static const int keyidx = -2 + static_cast(is_index); if (toplevel) { if (stack::get(L, keyidx) != type::string) { - lua_CFunction indexingfunc = is_index ? stack::get(L, upvalue_index(2)) : stack::get(L, upvalue_index(3)); - return indexingfunc(L); + if (has_indexing) { + object& indexingfunc = is_index + ? sm.index + : sm.newindex; + return call_indexing_object(L, indexingfunc); + } + else { + return is_index + ? indexing_fail(L) + : metatable_newindex(L); + } } } string_detail::string_shim accessor = stack::get(L, keyidx); - std::string accessorkey = accessor.c_str(); + std::string accessorkey = accessor.data(); auto vit = variables.find(accessorkey); if (vit != variables.cend()) { auto& varwrap = *(vit->second); @@ -10760,10 +12315,25 @@ namespace sol { } auto fit = functions.find(accessorkey); if (fit != functions.cend()) { - auto& func = (fit->second); - return stack::push(L, func); + sol::object& func = fit->second; + if (is_index) { + return stack::push(L, func); + } + else { + if (has_indexing && !is_toplevel(L)) { + object& indexingfunc = is_index + ? sm.index + : sm.newindex; + return call_indexing_object(L, indexingfunc); + } + else { + return is_index + ? indexing_fail(L) + : metatable_newindex(L); + } + } } - // Check table storage first for a method that works + /* Check table storage first for a method that works luaL_getmetatable(L, sm.metakey); if (type_of(L, -1) != type::lua_nil) { stack::get_field(L, accessor.c_str(), lua_gettop(L)); @@ -10775,7 +12345,8 @@ namespace sol { lua_pop(L, 1); } lua_pop(L, 1); - + */ + int ret = 0; bool found = false; // Otherwise, we need to do propagating calls through the bases @@ -10789,26 +12360,47 @@ namespace sol { return ret; } if (toplevel) { - lua_CFunction indexingfunc = is_index ? stack::get(L, upvalue_index(2)) : stack::get(L, upvalue_index(3)); - return indexingfunc(L); + if (has_indexing && !is_toplevel(L)) { + object& indexingfunc = is_index + ? sm.index + : sm.newindex; + return call_indexing_object(L, indexingfunc); + } + else { + return is_index + ? indexing_fail(L) + : metatable_newindex(L); + } } return -1; } + template inline int simple_real_index_call(lua_State* L) { - return simple_core_indexing_call(L); + return simple_core_indexing_call(L); } + template inline int simple_real_new_index_call(lua_State* L) { - return simple_core_indexing_call(L); + return simple_core_indexing_call(L); } + template inline int simple_index_call(lua_State* L) { - return detail::static_trampoline<(&simple_real_index_call)>(L); +#if defined(__clang__) + return detail::trampoline(L, &simple_real_index_call); +#else + return detail::typed_static_trampoline), (&simple_real_index_call)>(L); +#endif } + template inline int simple_new_index_call(lua_State* L) { - return detail::static_trampoline<(&simple_real_new_index_call)>(L); +#if defined(__clang__) + return detail::trampoline(L, &simple_real_new_index_call); +#else + return detail::typed_static_trampoline), (&simple_real_new_index_call)>(L); +#endif } } @@ -10820,8 +12412,8 @@ namespace sol { usertype_detail::function_map registrations; usertype_detail::variable_map varmap; object callconstructfunc; - lua_CFunction indexfunc; - lua_CFunction newindexfunc; + object indexfunc; + object newindexfunc; lua_CFunction indexbase; lua_CFunction newindexbase; usertype_detail::base_walk indexbaseclasspropogation; @@ -10834,6 +12426,15 @@ namespace sol { template void insert(N&& n, object&& o) { std::string key = usertype_detail::make_string(std::forward(n)); + int is_indexer = static_cast(usertype_detail::is_indexer(n)); + if (is_indexer == 1) { + indexfunc = o; + mustindex = true; + } + else if (is_indexer == 2) { + newindexfunc = o; + mustindex = true; + } auto hint = registrations.find(key); if (hint == registrations.cend()) { registrations.emplace_hint(hint, std::move(key), std::move(o)); @@ -10900,7 +12501,7 @@ namespace sol { template void add(lua_State* L, N&& n, constructor_wrapper c) { - object o(L, in_place>>, std::move(c)); + object o(L, in_place_type>>, std::move(c)); if (std::is_same, call_construction>::value) { callconstructfunc = std::move(o); return; @@ -10910,7 +12511,7 @@ namespace sol { template void add(lua_State* L, N&& n, constructor_list c) { - object o(L, in_place>>, std::move(c)); + object o(L, in_place_type>>, std::move(c)); if (std::is_same, call_construction>::value) { callconstructfunc = std::move(o); return; @@ -10920,7 +12521,7 @@ namespace sol { template void add(lua_State* L, N&& n, destructor_wrapper c) { - object o(L, in_place>>, std::move(c)); + object o(L, in_place_type>>, std::move(c)); if (std::is_same, call_construction>::value) { callconstructfunc = std::move(o); return; @@ -10930,7 +12531,7 @@ namespace sol { template void add(lua_State* L, N&& n, destructor_wrapper c) { - object o(L, in_place>>, std::move(c)); + object o(L, in_place_type>>, std::move(c)); if (std::is_same, call_construction>::value) { callconstructfunc = std::move(o); return; @@ -10941,6 +12542,7 @@ namespace sol { template void add(lua_State*, base_classes_tag, bases) { static_assert(sizeof(usertype_detail::base_walk) <= sizeof(void*), "size of function pointer is greater than sizeof(void*); cannot work on this platform. Please file a bug report."); + static_assert(!meta::any_same::value, "base classes cannot list the original class as part of the bases"); if (sizeof...(Bases) < 1) { return; } @@ -10959,8 +12561,8 @@ namespace sol { template simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence, lua_State* L, Tuple&& args) : callconstructfunc(lua_nil), - indexfunc(&usertype_detail::simple_indexing_fail), newindexfunc(&usertype_detail::simple_metatable_newindex), - indexbase(&usertype_detail::simple_core_indexing_call), newindexbase(&usertype_detail::simple_core_indexing_call), + indexfunc(lua_nil), newindexfunc(lua_nil), + indexbase(&usertype_detail::simple_core_indexing_call), newindexbase(&usertype_detail::simple_core_indexing_call), indexbaseclasspropogation(usertype_detail::walk_all_bases), newindexbaseclasspropogation(&usertype_detail::walk_all_bases), baseclasscheck(nullptr), baseclasscast(nullptr), mustindex(false), secondarymeta(false) { @@ -10998,6 +12600,11 @@ namespace sol { template simple_usertype_metatable(lua_State* L, constructor_wrapper constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} + simple_usertype_metatable(const simple_usertype_metatable&) = default; + simple_usertype_metatable(simple_usertype_metatable&&) = default; + simple_usertype_metatable& operator=(const simple_usertype_metatable&) = default; + simple_usertype_metatable& operator=(simple_usertype_metatable&&) = default; + virtual int push_um(lua_State* L) override { return stack::push(L, std::move(*this)); } @@ -11024,6 +12631,7 @@ namespace sol { const char* gcmetakey = &usertype_traits::gc_table()[0]; stack::push>(L, metatable_key, uniquegcmetakey, &usertype_traits::metatable()[0], umx.indexbaseclasspropogation, umx.newindexbaseclasspropogation, + std::move(umx.indexfunc), std::move(umx.newindexfunc), std::move(umx.varmap), std::move(umx.registrations) ); stack_reference stackvarmap(L, -1); @@ -11036,34 +12644,38 @@ namespace sol { } static int push(lua_State* L, umt_t&& umx) { + bool hasindex = umx.indexfunc.valid(); + bool hasnewindex = umx.newindexfunc.valid(); auto& varmap = make_cleanup(L, umx); + auto sic = hasindex ? &usertype_detail::simple_index_call : &usertype_detail::simple_index_call; + auto snic = hasnewindex ? &usertype_detail::simple_new_index_call : &usertype_detail::simple_new_index_call; bool hasequals = false; bool hasless = false; bool haslessequals = false; auto register_kvp = [&](std::size_t i, stack_reference& t, const std::string& first, object& second) { - if (first == name_of(meta_function::equal_to)) { + if (first == to_string(meta_function::equal_to)) { hasequals = true; } - else if (first == name_of(meta_function::less_than)) { + else if (first == to_string(meta_function::less_than)) { hasless = true; } - else if (first == name_of(meta_function::less_than_or_equal_to)) { + else if (first == to_string(meta_function::less_than_or_equal_to)) { haslessequals = true; } - else if (first == name_of(meta_function::index)) { - umx.indexfunc = second.template as(); + else if (first == to_string(meta_function::index)) { + umx.indexfunc = second; } - else if (first == name_of(meta_function::new_index)) { - umx.newindexfunc = second.template as(); + else if (first == to_string(meta_function::new_index)) { + umx.newindexfunc = second; } switch (i) { case 0: - if (first == name_of(meta_function::garbage_collect)) { + if (first == to_string(meta_function::garbage_collect)) { return; } break; case 1: - if (first == name_of(meta_function::garbage_collect)) { + if (first == to_string(meta_function::garbage_collect)) { stack::set_field(L, first, detail::unique_destruct, t.stack_index()); return; } @@ -11075,7 +12687,6 @@ namespace sol { stack::set_field(L, first, second, t.stack_index()); }; for (std::size_t i = 0; i < 3; ++i) { - // Pointer types, AKA "references" from C++ const char* metakey = nullptr; switch (i) { case 0: @@ -11099,15 +12710,15 @@ namespace sol { luaL_Reg opregs[4]{}; int opregsindex = 0; if (!hasless) { - const char* name = name_of(meta_function::less_than).c_str(); + const char* name = to_string(meta_function::less_than).c_str(); usertype_detail::make_reg_op, meta::supports_op_less>(opregs, opregsindex, name); } if (!haslessequals) { - const char* name = name_of(meta_function::less_than_or_equal_to).c_str(); + const char* name = to_string(meta_function::less_than_or_equal_to).c_str(); usertype_detail::make_reg_op, meta::supports_op_less_equal>(opregs, opregsindex, name); } if (!hasequals) { - const char* name = name_of(meta_function::equal_to).c_str(); + const char* name = to_string(meta_function::equal_to).c_str(); usertype_detail::make_reg_op::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(opregs, opregsindex, name); } t.push(); @@ -11128,16 +12739,14 @@ namespace sol { if (umx.mustindex) { // use indexing function stack::set_field(L, meta_function::index, - make_closure(&usertype_detail::simple_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc + make_closure(sic, + nullptr, + make_light(varmap) ), t.stack_index()); stack::set_field(L, meta_function::new_index, - make_closure(&usertype_detail::simple_new_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc + make_closure(snic, + nullptr, + make_light(varmap) ), t.stack_index()); } else { @@ -11153,16 +12762,14 @@ namespace sol { } if (umx.secondarymeta) { stack::set_field(L, meta_function::index, - make_closure(&usertype_detail::simple_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc + make_closure(sic, + nullptr, + make_light(varmap) ), metabehind.stack_index()); stack::set_field(L, meta_function::new_index, - make_closure(&usertype_detail::simple_new_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc + make_closure(snic, + nullptr, + make_light(varmap) ), metabehind.stack_index()); } stack::set_field(L, metatable_key, metabehind, t.stack_index()); @@ -11187,17 +12794,19 @@ namespace sol { } // use indexing function stack::set_field(L, meta_function::index, - make_closure(&usertype_detail::simple_index_call, + make_closure(sic, + nullptr, make_light(varmap), - umx.indexfunc, - umx.newindexfunc, + nullptr, + nullptr, usertype_detail::toplevel_magic ), metabehind.stack_index()); stack::set_field(L, meta_function::new_index, - make_closure(&usertype_detail::simple_new_index_call, + make_closure(snic, + nullptr, make_light(varmap), - umx.indexfunc, - umx.newindexfunc, + nullptr, + nullptr, usertype_detail::toplevel_magic ), metabehind.stack_index()); stack::set_field(L, metatable_key, metabehind, t.stack_index()); @@ -11226,7 +12835,7 @@ namespace sol { typedef std::array one; typedef std::array two; - template static one test(decltype(&C::find)); + template static one test(decltype(std::declval().find(std::declval>()))*); template static two test(...); public: @@ -11300,13 +12909,21 @@ namespace sol { template struct container_usertype_metatable { - typedef meta::has_key_value_pair> is_associative; + typedef meta::is_associative>> is_associative; typedef meta::unqualified_t T; typedef typename T::iterator I; typedef std::conditional_t> KV; typedef typename KV::first_type K; typedef typename KV::second_type V; typedef std::remove_reference_t())> IR; + typedef typename meta::iterator_tag::type tag_t; + typedef std::conditional_t::value, + V, + std::conditional_t()) + > + > push_type; struct iter { T& source; @@ -11324,7 +12941,26 @@ namespace sol { return *p.value(); #else return stack::get(L, 1); -#endif +#endif // Safe getting with error + } + + static int delegate_call(lua_State* L) { + static std::unordered_map calls{ + { "add", &real_add_call }, + { "insert", &real_insert_call }, + { "clear", &real_clear_call }, + { "find", &real_find_call }, + { "get", &real_get_call } + }; + auto maybename = stack::check_get(L, 2); + if (maybename) { + auto& name = *maybename; + auto it = calls.find(name); + if (it != calls.cend()) { + return stack::push(L, it->second); + } + } + return stack::push(L, lua_nil); } static int real_index_call_associative(std::true_type, lua_State* L) { @@ -11335,25 +12971,10 @@ namespace sol { auto it = detail::find(src, *k); if (it != end(src)) { auto& v = *it; - return stack::push_reference(L, v.second); + return stack::stack_detail::push_reference(L, v.second); } } - else { - auto maybename = stack::check_get(L, 2); - if (maybename) { - auto& name = *maybename; - if (name == "add") { - return stack::push(L, &add_call); - } - else if (name == "insert") { - return stack::push(L, &insert_call); - } - else if (name == "clear") { - return stack::push(L, &clear_call); - } - } - } - return stack::push(L, lua_nil); + return delegate_call(L); } static int real_index_call_associative(std::false_type, lua_State* L) { @@ -11363,39 +12984,24 @@ namespace sol { using std::begin; auto it = begin(src); K k = *maybek; -#ifdef SOL_SAFE_USERTYPE if (k > src.size() || k < 1) { return stack::push(L, lua_nil); } -#else -#endif // Safety --k; std::advance(it, k); - return stack::push_reference(L, *it); + return stack::stack_detail::push_reference(L, *it); } - else { - auto maybename = stack::check_get(L, 2); - if (maybename) { - auto& name = *maybename; - if (name == "add") { - return stack::push(L, &add_call); - } - else if (name == "insert") { - return stack::push(L, &insert_call); - } - else if (name == "clear") { - return stack::push(L, &clear_call); - } - } - } - - return stack::push(L, lua_nil); + return delegate_call(L); } static int real_index_call(lua_State* L) { return real_index_call_associative(is_associative(), L); } + static int real_get_call(lua_State* L) { + return real_index_call_associative(is_associative(), L); + } + static int real_new_index_call_const(std::false_type, std::false_type, lua_State* L) { return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)"); } @@ -11404,48 +13010,91 @@ namespace sol { return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)"); } - static int real_new_index_call_const(std::true_type, std::true_type, lua_State* L) { + static int real_new_index_call_fixed(std::true_type, lua_State* L) { auto& src = get_src(L); - auto k = stack::check_get(L, 2); - if (k) { - using std::end; - auto it = detail::find(src, *k); - if (it != end(src)) { - auto& v = *it; - v.second = stack::get(L, 3); - } - else { - src.insert(it, { std::move(*k), stack::get(L, 3) }); - } +#ifdef SOL_CHECK_ARGUMENTS + auto maybek = stack::check_get(L, 2); + if (!maybek) { + return luaL_error(L, "sol: improper key of type %s for %s", lua_typename(L, static_cast(type_of(L, 2))), detail::demangle().c_str()); + } + K& k = *maybek; +#else + K k = stack::get(L, 2); +#endif + using std::end; + auto it = detail::find(src, k); + if (it != end(src)) { + auto& v = *it; + v.second = stack::get(L, 3); + } + else { + src.insert(it, { std::move(k), stack::get(L, 3) }); } return 0; } - static int real_new_index_call_const(std::true_type, std::false_type, lua_State* L) { + static int real_new_index_call_fixed(std::false_type, lua_State* L) { auto& src = get_src(L); -#ifdef SOL_SAFE_USERTYPE +#ifdef SOL_CHECK_ARGUMENTS auto maybek = stack::check_get(L, 2); if (!maybek) { - return stack::push(L, lua_nil); + return luaL_error(L, "sol: improper key of type %s for %s", lua_typename(L, static_cast(type_of(L, 2))), detail::demangle().c_str()); } - K k = *maybek; + K& k = *maybek; +#else + K k = stack::get(L, 2); +#endif + using std::end; + auto it = detail::find(src, k); + if (it != end(src)) { + auto& v = *it; + v.second = stack::get(L, 3); + } + else { + return luaL_error(L, "sol: cannot insert key of type %s to into %s", lua_typename(L, static_cast(type_of(L, 2))), detail::demangle().c_str()); + } + return 0; + } + + static int real_new_index_call_const(std::true_type, std::true_type, lua_State* L) { + return real_new_index_call_fixed(std::integral_constant::value>(), L); + } + + static int real_new_index_call_const(std::true_type, std::false_type, lua_State* L) { + auto& src = get_src(L); +#ifdef SOL_CHECK_ARGUMENTS + auto maybek = stack::check_get(L, 2); + if (!maybek) { + return luaL_error(L, "sol: improper index of type %s to a %s", lua_typename(L, static_cast(type_of(L, 2))), detail::demangle().c_str()); + } + K& k = *maybek; #else K k = stack::get(L, 2); #endif using std::begin; auto it = begin(src); +#ifdef SOL_CHECK_ARGUMENTS + if (k < 1) { + return luaL_error(L, "sol: out of bounds index to a %s", detail::demangle().c_str()); + } +#endif + --k; if (k == src.size()) { - real_add_call_push(std::integral_constant::value>(), L, src, 1); + real_add_call_push(std::integral_constant::value && std::is_copy_constructible::value>(), L, src, 1); return 0; } - --k; +#ifdef SOL_CHECK_ARGUMENTS + if (k > src.size()) { + return luaL_error(L, "sol: out of bounds index to a %s", detail::demangle().c_str()); + } +#endif std::advance(it, k); *it = stack::get(L, 3); return 0; } static int real_new_index_call(lua_State* L) { - return real_new_index_call_const(meta::neg, std::is_const>>(), is_associative(), L); + return real_new_index_call_const(meta::neg, std::is_const, meta::neg>>>(), meta::all>(), L); } static int real_pairs_next_call_assoc(std::true_type, lua_State* L) { @@ -11456,7 +13105,9 @@ namespace sol { if (it == end(source)) { return 0; } - int p = stack::multi_push_reference(L, it->first, it->second); + int p; + p = stack::push_reference(L, it->first); + p += stack::stack_detail::push_reference(L, it->second); std::advance(it, 1); return p; } @@ -11479,7 +13130,9 @@ namespace sol { if (it == end(source)) { return 0; } - int p = stack::multi_push_reference(L, k + 1, *it); + int p; + p = stack::push_reference(L, k + 1); + p += stack::stack_detail::push_reference(L, *it); std::advance(it, 1); return p; } @@ -11523,7 +13176,7 @@ namespace sol { } static int real_add_call_push(std::false_type, lua_State*L, T& src, int boost = 0) { - return real_add_call_insert(std::integral_constant::value>(), L, src, boost); + return real_add_call_insert(std::integral_constant::value && std::is_copy_constructible::value>(), L, src, boost); } static int real_add_call_associative(std::true_type, lua_State* L) { @@ -11532,7 +13185,7 @@ namespace sol { static int real_add_call_associative(std::false_type, lua_State* L) { auto& src = get_src(L); - return real_add_call_push(std::integral_constant::value>(), L, src); + return real_add_call_push(std::integral_constant::value && std::is_copy_constructible::value>(), L, src); } static int real_add_call_capable(std::true_type, lua_State* L) { @@ -11545,7 +13198,7 @@ namespace sol { } static int real_add_call(lua_State* L) { - return real_add_call_capable(std::integral_constant::value || detail::has_insert::value>(), L); + return real_add_call_capable(std::integral_constant::value || detail::has_insert::value) && std::is_copy_constructible::value>(), L); } static int real_insert_call_capable(std::false_type, std::false_type, lua_State*L) { @@ -11569,7 +13222,7 @@ namespace sol { } static int real_insert_call(lua_State*L) { - return real_insert_call_capable(std::integral_constant::value>(), is_associative(), L); + return real_insert_call_capable(std::integral_constant::value && std::is_copy_assignable::value>(), is_associative(), L); } static int real_clear_call_capable(std::false_type, lua_State* L) { @@ -11587,36 +13240,74 @@ namespace sol { return real_clear_call_capable(std::integral_constant::value>(), L); } + static int real_find_call_capable(std::false_type, std::false_type, lua_State*L) { + static const std::string& s = detail::demangle(); + return luaL_error(L, "sol: cannot call find on type %s", s.c_str()); + } + + static int real_find_call_capable(std::false_type, std::true_type, lua_State*L) { + return real_index_call(L); + } + + static int real_find_call_capable(std::true_type, std::false_type, lua_State* L) { + auto k = stack::check_get(L, 2); + if (k) { + auto& src = get_src(L); + auto it = src.find(*k); + if (it != src.end()) { + auto& v = *it; + return stack::stack_detail::push_reference(L, v); + } + } + return stack::push(L, lua_nil); + } + + static int real_find_call_capable(std::true_type, std::true_type, lua_State* L) { + return real_index_call(L); + } + + static int real_find_call(lua_State*L) { + return real_find_call_capable(std::integral_constant::value>(), is_associative(), L); + } + static int add_call(lua_State*L) { - return detail::static_trampoline<(&real_add_call)>(L); + return detail::typed_static_trampoline(L); } static int insert_call(lua_State*L) { - return detail::static_trampoline<(&real_insert_call)>(L); + return detail::typed_static_trampoline(L); } static int clear_call(lua_State*L) { - return detail::static_trampoline<(&real_clear_call)>(L); + return detail::typed_static_trampoline(L); + } + + static int find_call(lua_State*L) { + return detail::typed_static_trampoline(L); } static int length_call(lua_State*L) { - return detail::static_trampoline<(&real_length_call)>(L); + return detail::typed_static_trampoline(L); } static int pairs_next_call(lua_State*L) { - return detail::static_trampoline<(&real_pairs_next_call)>(L); + return detail::typed_static_trampoline(L); } static int pairs_call(lua_State*L) { - return detail::static_trampoline<(&real_pairs_call)>(L); + return detail::typed_static_trampoline(L); + } + + static int get_call(lua_State*L) { + return detail::typed_static_trampoline(L); } static int index_call(lua_State*L) { - return detail::static_trampoline<(&real_index_call)>(L); + return detail::typed_static_trampoline(L); } static int new_index_call(lua_State*L) { - return detail::static_trampoline<(&real_new_index_call)>(L); + return detail::typed_static_trampoline(L); } }; @@ -11625,15 +13316,17 @@ namespace sol { template inline auto container_metatable() { typedef container_usertype_metatable> meta_cumt; - std::array reg = { { + std::array reg = { { { "__index", &meta_cumt::index_call }, { "__newindex", &meta_cumt::new_index_call }, { "__pairs", &meta_cumt::pairs_call }, { "__ipairs", &meta_cumt::pairs_call }, { "__len", &meta_cumt::length_call }, + { "get", &meta_cumt::get_call }, { "clear", &meta_cumt::clear_call }, { "insert", &meta_cumt::insert_call }, { "add", &meta_cumt::add_call }, + { "find", &meta_cumt::find_call }, std::is_pointer::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy }, { nullptr, nullptr } } }; @@ -11739,7 +13432,9 @@ namespace sol { } int push(lua_State* L) { - return metatableregister->push_um(L); + int r = metatableregister->push_um(L); + metatableregister = nullptr; + return r; } }; @@ -11756,7 +13451,7 @@ namespace sol { template void set(N&& n, F&& f) { auto meta = static_cast*>(base_t::registrar_data()); - meta->add(state, n, f); + meta->add(state, std::forward(n), std::forward(f)); } }; @@ -11878,8 +13573,11 @@ namespace sol { } } - template - class basic_table_core : public base_t { + const new_table create = new_table{}; + + template + class basic_table_core : public basic_object_base { + typedef basic_object_base base_t; friend class state; friend class state_view; @@ -11916,15 +13614,15 @@ namespace sol { -> decltype(stack::pop>(nullptr)) { typedef decltype(stack::pop>(nullptr)) Tup; return Tup( - traverse_get_optional(meta::is_specialization_of>(), detail::forward_get<0>(keys)), - traverse_get_optional(meta::is_specialization_of>(), detail::forward_get<1>(keys)), - traverse_get_optional(meta::is_specialization_of>(), detail::forward_get(keys))... + traverse_get_optional(meta::is_optional>(), detail::forward_get<0>(keys)), + traverse_get_optional(meta::is_optional>(), detail::forward_get<1>(keys)), + traverse_get_optional(meta::is_optional>(), detail::forward_get(keys))... ); } template decltype(auto) tuple_get(types, std::index_sequence, Keys&& keys) const { - return traverse_get_optional(meta::is_specialization_of>(), detail::forward_get(keys)); + return traverse_get_optional(meta::is_optional>(), detail::forward_get(keys)); } template @@ -11992,41 +13690,52 @@ namespace sol { traverse_set_deep(std::forward(keys)...); } - basic_table_core(lua_State* L, detail::global_tag t) noexcept : reference(L, t) { } - + basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { } + + protected: + basic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {} + basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {} + template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward(r)) {} + public: - typedef basic_table_iterator iterator; + typedef basic_table_iterator iterator; typedef iterator const_iterator; - basic_table_core() noexcept : base_t() { } - template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_table_core(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_table>::value) { - auto pp = stack::push_pop(*this); - stack::check(base_t::lua_state(), -1, type_panic); - } -#endif // Safety - } + basic_table_core() noexcept = default; basic_table_core(const basic_table_core&) = default; 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 >>, meta::neg>> = meta::enabler> + template >>, meta::neg, ref_index>>> = meta::enabler> basic_table_core(lua_State* L, T&& r) : basic_table_core(L, sol::ref_index(r.registry_index())) {} - basic_table_core(lua_State* L, int index = -1) : base_t(L, index) { + basic_table_core(lua_State* L, new_table nt) : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) { + if (!std::is_base_of::value) { + lua_pop(L, 1); + } + } + basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS stack::check(L, index, type_panic); #endif // Safety } - basic_table_core(lua_State* L, ref_index index) : base_t(L, index) { + basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); stack::check(L, -1, type_panic); #endif // Safety } + template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward(r)) { +#ifdef SOL_CHECK_ARGUMENTS + if (!is_table>::value) { + auto pp = stack::push_pop(*this); + stack::check(base_t::lua_state(), -1, type_panic); + } +#endif // Safety + } iterator begin() const { return iterator(*this); @@ -12054,7 +13763,7 @@ namespace sol { template decltype(auto) get_or(Key&& key, T&& otherwise) const { typedef decltype(get("")) U; - sol::optional option = get>(std::forward(key)); + optional option = get>(std::forward(key)); if (option) { return static_cast(option.value()); } @@ -12063,7 +13772,7 @@ namespace sol { template decltype(auto) get_or(Key&& key, D&& otherwise) const { - sol::optional option = get>(std::forward(key)); + optional option = get>(std::forward(key)); if (option) { return static_cast(option.value()); } @@ -12073,7 +13782,7 @@ namespace sol { template decltype(auto) traverse_get(Keys&&... keys) const { auto pp = stack::push_pop::value>(*this); - return traverse_get_optional(meta::is_specialization_of>(), std::forward(keys)...); + return traverse_get_optional(meta::is_optional>(), std::forward(keys)...); } template @@ -12316,10 +14025,185 @@ namespace sol { namespace sol { typedef table_core table; + + namespace stack { + template <> + struct getter { + static table get(lua_State* L, int index = -1) { + if (lua_getmetatable(L, index) == 0) { + return table(L, ref_index(LUA_REFNIL)); + } + return table(L, -1); + } + }; + } // stack } // sol // end of sol/table.hpp +// beginning of sol/environment.hpp + +namespace sol { + + template + struct basic_environment : basic_table { + private: + typedef basic_table base_t; + + public: + basic_environment() noexcept = default; + basic_environment(const basic_environment&) = default; + basic_environment(basic_environment&&) = default; + basic_environment& operator=(const basic_environment&) = default; + basic_environment& operator=(basic_environment&&) = default; + basic_environment(const stack_reference& r) : basic_environment(r.lua_state(), r.stack_index()) {} + basic_environment(stack_reference&& r) : basic_environment(r.lua_state(), r.stack_index()) {} + + basic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) {} + basic_environment(lua_State* L, new_table t, const reference& fallback) : basic_environment(L, std::move(t)) { + sol::stack_table mt(L, sol::new_table(0, 1)); + mt.set(sol::meta_function::index, fallback); + this->set(metatable_key, mt); + mt.pop(); + } + + basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(this->lua_state(), -1, type_panic); +#endif // Safety + lua_pop(this->lua_state(), 2); + } + basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(this->lua_state(), -1, type_panic); +#endif // Safety + lua_pop(this->lua_state(), 2); + } + basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(L, index, type_panic); +#endif // Safety + } + basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + auto pp = stack::push_pop(*this); + stack::check(L, -1, type_panic); +#endif // Safety + } + template , basic_environment>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward(r)) { +#ifdef SOL_CHECK_ARGUMENTS + if (!is_environment>::value) { + auto pp = stack::push_pop(*this); + stack::check(base_t::lua_state(), -1, type_panic); + } +#endif // Safety + } + + template + void set_on(const T& target) const { + lua_State* L = target.lua_state(); + auto pp = stack::push_pop(target); +#if SOL_LUA_VERSION < 502 + // Use lua_setfenv + this->push(); + lua_setfenv(L, -2); +#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(); + } +#endif + } + }; + + template + void set_environment(const basic_environment& env, const T& target) { + env.set_on(target); + } + + template + basic_environment get_environment(const T& target) { + lua_State* L = target.lua_state(); + auto pp = stack::pop_n(L, stack::push_environment_of(target)); + return basic_environment(L, -1); + } + + struct this_environment { + optional env; + + this_environment() : env(nullopt) {} + this_environment(sol::environment e) : env(std::move(e)) {} + this_environment(const this_environment&) = default; + this_environment(this_environment&&) = default; + this_environment& operator=(const this_environment&) = default; + this_environment& operator=(this_environment&&) = default; + + explicit operator bool() const { + return static_cast(env); + } + + operator optional& () { + return env; + } + + operator const optional& () const { + return env; + } + + operator environment& () { + return env.value(); + } + + operator const environment& () const { + return env.value(); + } + }; + + namespace stack { + template <> + struct getter { + static environment get(lua_State* L, int index, record& tracking) { + tracking.use(1); + return get_environment(stack_reference(L, raw_index(index))); + } + }; + + template <> + struct getter { + static this_environment get(lua_State* L, int, record& tracking) { + tracking.use(0); + lua_Debug info; + // Level 0 means current function (this C function, which may or may not be useful for us?) + // Level 1 means next call frame up the stack. (Can be nothing if function called directly from C++ with lua_p/call) + int pre_stack_size = lua_gettop(L); + if (lua_getstack(L, 1, &info) != 1) { + if (lua_getstack(L, 0, &info) != 1) { + lua_settop(L, pre_stack_size); + return this_environment(); + } + } + if (lua_getinfo(L, "f", &info) == 0) { + lua_settop(L, pre_stack_size); + return this_environment(); + } + + sol::stack_reference f(L, -1); + sol::environment env(sol::env_key, f); + if (!env.valid()) { + lua_settop(L, pre_stack_size); + return this_environment(); + } + return this_environment(std::move(env)); + } + }; + } // stack +} // sol + +// end of sol/environment.hpp + // beginning of sol/load_result.hpp namespace sol { @@ -12332,11 +14216,11 @@ namespace sol { load_status err; template - decltype(auto) tagged_get(types>) const { + decltype(auto) tagged_get(types>) const { if (!valid()) { - return sol::optional(nullopt); + return optional(nullopt); } - return stack::get>(L, index); + return stack::get>(L, index); } template @@ -12349,20 +14233,20 @@ namespace sol { return stack::get(L, index); } - sol::optional tagged_get(types>) const { + optional tagged_get(types>) const { if (valid()) { return nullopt; } - return sol::error(detail::direct_error, stack::get(L, index)); + return error(detail::direct_error, stack::get(L, index)); } - sol::error tagged_get(types) const { + error tagged_get(types) const { #ifdef SOL_CHECK_ARGUMENTS if (valid()) { type_panic(L, index, type_of(L, index), type::none); } #endif // Check Argument Safety - return sol::error(detail::direct_error, stack::get(L, index)); + return error(detail::direct_error, stack::get(L, index)); } public: @@ -12458,6 +14342,29 @@ namespace sol { return kb; } + inline protected_function_result simple_on_error(lua_State*, sol::protected_function_result result) { + return result; + } + + inline protected_function_result default_on_error( lua_State* L, protected_function_result pfr ) { + type t = type_of(L, pfr.stack_index()); + std::string err = to_string(pfr.status()) + " error"; + if (t == type::string) { + err += " "; + err += stack::get(L, pfr.stack_index()); + } +#ifdef SOL_NO_EXCEPTIONS + if (t != type::nil) { + lua_pop(L, 1); + } + stack::push(L, err); + lua_error(L); +#else + throw error(detail::direct_error, err); +#endif + return pfr; + } + class state_view { private: lua_State* L; @@ -12639,16 +14546,94 @@ namespace sol { return require_core(key, [this, &filename]() {stack::script_file(L, filename); }, create_global); } + template + protected_function_result do_string(const std::string& code, const basic_environment& env) { + load_status x = static_cast(luaL_loadstring(L, code.c_str())); + if (x != load_status::ok) { + return protected_function_result(L, -1, 0, 1, static_cast(x)); + } + protected_function pf(L, -1); + pf.pop(); + set_environment(env, pf); + return pf(); + } + + template + protected_function_result do_file(const std::string& filename, const basic_environment& env) { + load_status x = static_cast(luaL_loadfile(L, filename.c_str())); + if (x != load_status::ok) { + return protected_function_result(L, -1, 0, 1, static_cast(x)); + } + protected_function pf(L, -1); + pf.pop(); + set_environment(env, pf); + return pf(); + } + protected_function_result do_string(const std::string& code) { - sol::protected_function pf = load(code); + load_status x = static_cast(luaL_loadstring(L, code.c_str())); + if (x != load_status::ok) { + return protected_function_result(L, -1, 0, 1, static_cast(x)); + } + protected_function pf(L, -1); + pf.pop(); return pf(); } protected_function_result do_file(const std::string& filename) { - sol::protected_function pf = load_file(filename); + load_status x = static_cast(luaL_loadfile(L, filename.c_str())); + if (x != load_status::ok) { + return protected_function_result(L, -1, 0, 1, static_cast(x)); + } + protected_function pf(L, -1); + pf.pop(); return pf(); } + protected_function_result script(const std::string& code, const environment& env) { + return script(code, env, sol::default_on_error); + } + + protected_function_result script_file(const std::string& filename, const environment& env) { + return script_file(filename, env, sol::default_on_error); + } + + template >> = meta::enabler> + protected_function_result script(const std::string& code, Fx&& on_error) { + protected_function_result pfr = do_string(code); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + template >> = meta::enabler> + protected_function_result script_file(const std::string& filename, Fx&& on_error) { + protected_function_result pfr = do_file(filename); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + template + protected_function_result script(const std::string& code, const basic_environment& env, Fx&& on_error) { + protected_function_result pfr = do_string(code, env); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + template + protected_function_result script_file(const std::string& filename, const basic_environment& env, Fx&& on_error) { + protected_function_result pfr = do_file(filename, env); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + function_result script(const std::string& code) { int index = lua_gettop(L); stack::script(L, code); @@ -12905,9 +14890,10 @@ namespace sol { const char* message = lua_tostring(L, -1); if (message) { std::string err = message; - lua_pop(L, 1); + lua_settop(L, 0); throw error(err); } + lua_settop(L, 0); throw error(std::string("An unexpected error occurred and forced the lua state to call atpanic")); #endif } @@ -12918,13 +14904,13 @@ namespace sol { optional maybetopmsg = stack::check_get(L, 1); if (maybetopmsg) { const string_detail::string_shim& topmsg = maybetopmsg.value(); - msg.assign(topmsg.c_str(), topmsg.size()); + msg.assign(topmsg.data(), topmsg.size()); } luaL_traceback(L, L, msg.c_str(), 1); optional maybetraceback = stack::check_get(L, -1); if (maybetraceback) { const string_detail::string_shim& traceback = maybetraceback.value(); - msg.assign(traceback.c_str(), traceback.size()); + msg.assign(traceback.data(), traceback.size()); } return stack::push(L, msg); } @@ -12936,6 +14922,7 @@ namespace sol { state(lua_CFunction panic = default_at_panic) : unique_base(luaL_newstate(), lua_close), state_view(unique_base::get()) { set_panic(panic); + sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, default_error_handler)); stack::luajit_exception_handler(unique_base::get()); } @@ -13210,6 +15197,61 @@ namespace sol { // end of sol/coroutine.hpp +// beginning of sol/variadic_results.hpp + +// beginning of sol/as_returns.hpp + +namespace sol { + template + struct as_returns_t { + T src; + }; + + template + auto as_returns(Source&& source) { + return as_returns_t>{ std::forward(source) }; + } + + namespace stack { + template + struct pusher> { + int push(lua_State* L, const as_returns_t& e) { + auto& src = detail::unwrap(e.src); + int p = 0; + for (const auto& i : src) { + p += stack::push(L, i); + } + return p; + } + }; + } // stack +} // sol + +// end of sol/as_returns.hpp + +namespace sol { + + struct variadic_results : public std::vector { + using std::vector::vector; + }; + + namespace stack { + template <> + struct pusher { + int push(lua_State* L, const variadic_results& e) { + int p = 0; + for (const auto& i : e) { + p += stack::push(L, i); + } + return p; + } + }; + } // stack + +} // sol + +// end of sol/variadic_results.hpp + #ifdef __GNUC__ #pragma GCC diagnostic pop #elif defined _MSC_VER @@ -13218,7 +15260,11 @@ namespace sol { #ifdef SOL_INSIDE_UNREAL #ifdef SOL_INSIDE_UNREAL_REMOVED_CHECK -#define check(expr) { if(UNLIKELY(!(expr))) { FDebug::LogAssertFailedMessage( #expr, __FILE__, __LINE__ ); _DebugBreakAndPromptForRemote(); FDebug::AssertFailed( #expr, __FILE__, __LINE__ ); CA_ASSUME(false); } }} +#if DO_CHECK +#define check(expr) { if(UNLIKELY(!(expr))) { FDebug::LogAssertFailedMessage( #expr, __FILE__, __LINE__ ); _DebugBreakAndPromptForRemote(); FDebug::AssertFailed( #expr, __FILE__, __LINE__ ); CA_ASSUME(false); } } +#else +#define check(expr) { CA_ASSUME(expr); } +#endif #endif #endif // Unreal Engine 4 Bullshit