Merge branch 'develop' into feature/meson

This commit is contained in:
The Phantom Derpstorm 2018-06-15 13:30:39 -04:00 committed by GitHub
commit 278d59f31e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 24448 additions and 23764 deletions

4
.gitignore vendored
View File

@ -82,6 +82,10 @@ main2.cpp
main.cpp
# Local Lua Testbeds
lua-5.4.0-cxx/
lua-5.4.0/
lua-5.4.0-work1-cxx/
lua-5.4.0-work1/
lua-5.3.4-cxx/
lua-5.3.4/
lua-5.3.2/

9
CONTRIBUTORS.md Normal file
View File

@ -0,0 +1,9 @@
# Donators! ♥
Thank you to all patrons, donators and contributors who help keep sol2 amazing.
Robert Salvet
Ορφέας Ζαφείρης - 2x Donations!
Michael Wallar
Johannes Schultz
Dailidzionak Ilya

View File

@ -47,6 +47,17 @@ int main() {
More examples are given in the examples directory [here](https://github.com/ThePhD/sol2/tree/develop/examples).
## Supporting
You can [donate to support Sol and the project](https://www.paypal.me/LMeneide), which is always appreciated! This is a time-consuming effort, so individuals who donate get to:
- steer the direction and time spent on sol
- get a role on the Discord server
- get their name put up in the CONTRIBUTORS list
- put something of their choice on sol2's README or the documentation's front page
You can also help out the library by submitting pull requests to fix anything or add anything you think would be helpful! This includes making small, useful examples of something you haven't seen, or fixing typos and bad code in the documentation.
## Presentations
"A Sun For the Moon - A Zero-Overhead Lua Abstraction using C++"
@ -118,12 +129,6 @@ Testing on Travis-CI and Appveyor use CMake. You can generate the tests by runni
You will need any flavor of python3 and an available compiler. The testing suite will build its own version of Lua and LuaJIT, so you do not have to.
## Supporting
You can help out the library by submitting pull requests to fix anything or add anything you think would be helpful! This includes making small, useful examples of something you haven't seen, or fixing typos and bad code in the documentation.
You can also [donate to support me and my family](https://www.paypal.me/LMeneide), which is always appreciated!
## License
Sol is distributed with an MIT License. You can see LICENSE.txt for more info.

View File

@ -19,6 +19,9 @@ The actual class produced by ``sol::overload`` is essentially a type-wrapper aro
Please note that default parameters in a function (e.g., ``int func(int a = 20)``) do not exist beyond C++'s compile-time fun. When that function gets bound or serialized into Lua's framework, it is bound as a function taking 1 argument, not 2 functions taking either 0 or 1 argument. If you want to achieve the same effect, then you need to use overloading and explicitly call the version of the function you want. There is no magic in C++ that allows me to retrieve default parameters and set this up automatically.
.. note::
Overload resolution can be affected by configuration defines in the :doc:`safety pages<../safety>`. For example, it is impossible to differentiate between integers (uint8_t, in32_t, etc.) versus floating-point types (float, double, half) when ``SOL_SAFE_NUMERICS`` is not turned on.
Its use is simple: wherever you can pass a function type to Lua, whether its on a :doc:`usertype<usertype>` or if you are just setting any kind of function with ``set`` or ``set_function`` (for :doc:`table<table>` or :doc:`state(_view)<state>`), simply wrap up the functions you wish to be considered for overload resolution on one function like so:

View File

@ -63,3 +63,7 @@ It can also be used with :doc:`sol::c_call<c_call>`:
lua.script("f(1, 2)");
.. note::
You cannot use ``sol::resolve<...>(...)`` when one function is templated and it has a non-templated overload: it will always fail in this case. To resolve this, please use a manual ``static_cast<R(Args...)>( &func )`` or ``static_cast<R (T::*)(Args...)>( &T::overloaded_member_func )`` (with the right const-ness and volatile-ness and r-value/l-value qualifiers if necessary).

View File

@ -110,7 +110,7 @@ Below are the many container operations and their override points for ``containe
+-----------+-------------------------------------------+--------------------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| at | ``v = c:at(key)`` | ``static int at(lua_State*);`` | 1 self | - can return multiple values |
| | | | 2 index | - default implementation increments iterators linearly for non-random-access |
| | | | 2 index | - if the type does not have random-access iterators, **do not use this in a for loop** ! |
| | | | | - if the type does not have random-access iterators, **do not use this in a for loop** ! |
+-----------+-------------------------------------------+--------------------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| get | ``v = c:get(key)`` | ``static int get(lua_State*);`` | 1 self | - can return multiple values |
| | | | 2 key | - default implementation increments iterators linearly for non-random-access |
@ -142,9 +142,11 @@ Below are the many container operations and their override points for ``containe
+-----------+-------------------------------------------+--------------------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| offset | n/a | ``static int index_adjustment(lua_State*, T&);`` | n/a | - returns an index that adds to the passed-in numeric index for array acces (default implementation is ``return -1`` to simulate 1-based indexing from Lua) |
+-----------+-------------------------------------------+--------------------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| begin | n/a | ``static int begin(lua_State*, T&);`` | n/a | - called by default implementation |
| begin | n/a | ``static iterator begin(lua_State*, T&);`` | n/a | - called by default implementation |
| | | | | - is not the regular raw function: must return an iterator from second "T&" argument, which is self |
+-----------+-------------------------------------------+--------------------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| end | n/a | ``static int end(lua_State*, T&);`` | n/a | - called by default implementation |
| end | n/a | ``static iterator end(lua_State*, T&);`` | n/a | - called by default implementation |
| | | | | - is not the regular raw function: must return an iterator from second "T&" argument, which is self |
+-----------+-------------------------------------------+--------------------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| next | | ``static int next(lua_State*);`` | 1 self | - implement if advanced user only that understands caveats |
| | | | | - is used as 'iteration function' dispatched with pairs() call |

View File

@ -13,6 +13,7 @@ There are a number of examples dealing with functions and how they can be bound
- using :doc:`sol::variadic_results<api/variadic_results>`
* :doc:`Overload function calls with different argument types and count on a single name<api/overload>` (first-bound, first-serve overloading)
- Note: because of this feature, automatic number to string conversion from Lua is not permitted for overloads and does not work when safeties are turned on
- int/float overloads must have ``SOL_SAFE_NUMERICS`` turned on to differentiate between the two
- Use C++ captures and lambdas to bind member functions tied to a single object /
* You can work with **transparent arguments** that provide you with special information, such as
- :doc:`sol::variadic_args<api/variadic_args>`, for handling variable number of arguments at runtime

View File

@ -69,12 +69,16 @@ the basics:
helping out
-----------
You can support the library by submitting pull requests to fix anything (the code, typos, even contribute your own examples).
You can support sol2 development by `donating here`_. This is a time-consuming effort, so individuals who donate get to:
You can support me and my family by `donating a little something here`_.
- steer the direction and time spent on sol
- get a role on the Discord server
- get their name put up in the CONTRIBUTORS list
- put something of their choice on sol2's README or the documentation's front page
Thank you for using sol2!
You can also help out the library by submitting pull requests to fix anything or add anything you think would be helpful! This includes making small, useful examples of something you haven't seen, or fixing typos and bad code in the documentation.
Finally, `come join in Discord`_!
Indices and tables
==================
@ -85,4 +89,5 @@ Indices and tables
.. _Sol: https://github.com/ThePhD/sol2
.. _issues: https://github.com/ThePhD/sol2/issues
.. _examples directory: https://github.com/ThePhD/sol2/tree/develop/examples
.. _donating a little something here: https://www.paypal.me/LMeneide
.. _donating here: https://www.paypal.me/LMeneide
.. _come join in Discord: https://discord.gg/buxkYNT

View File

@ -39,6 +39,7 @@ Safety Config
``SOL_SAFE_NUMERICS`` triggers the following changes:
* Numbers will also be checked to see if they fit within a ``lua_Number`` if there is no ``lua_Integer`` type available that can fit your signed or unsigned number
* You can opt-out of this behavior with ``SOL_NO_CHECK_NUMBER_PRECISION``
* **This option is required to differentiate between floats/ints in overloads**
* **Not** turned on by default under any settings: *this MUST be turned on manually*
``SOL_SAFE_GETTER`` triggers the following changes:

File diff suppressed because it is too large Load Diff

View File

@ -1,357 +1,357 @@
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2018-05-22 19:42:19.843589 UTC
// This header was generated with sol v2.20.2 (revision d67c5b7)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
#define SOL_SINGLE_INCLUDE_FORWARD_HPP
// 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) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L))))
#ifndef SOL_CXX17_FEATURES
#define SOL_CXX17_FEATURES 1
#endif // C++17 features macro
#endif // C++17 features check
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && (defined(_MSVC_LANG) && ((_MSVC_LANG >= 201403L))))
#ifndef SOL_NOEXCEPT_FUNCTION_TYPE
#define SOL_NOEXCEPT_FUNCTION_TYPE 1
#endif // noexcept is part of a function's type
#endif // compiler-specific checks
#if defined(__clang__) && defined(__APPLE__)
#if defined(__has_include)
#if __has_include(<variant>)
#define SOL_STD_VARIANT 1
#endif // has include nonsense
#endif // __has_include
#else
#define SOL_STD_VARIANT 1
#endif // Clang screws up variant
#endif // C++17 only
// beginning of sol/config.hpp
#ifdef _MSC_VER
#if defined(_DEBUG) && !defined(NDEBUG)
#ifndef SOL_IN_DEBUG_DETECTED
#define SOL_IN_DEBUG_DETECTED 1
#endif
#endif // VC++ Debug macros
#ifndef _CPPUNWIND
#ifndef SOL_NO_EXCEPTIONS
#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__)
#if !defined(NDEBUG) && !defined(__OPTIMIZE__)
#ifndef SOL_IN_DEBUG_DETECTED
#define SOL_IN_DEBUG_DETECTED 1
#endif
#endif // Not Debug && g++ optimizer flag
#ifndef __EXCEPTIONS
#ifndef SOL_NO_EXCEPTIONS
#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++
#if defined(SOL_CHECK_ARGUMENTS) && SOL_CHECK_ARGUMENTS
// Checks low-level getter function
// (and thusly, affects nearly entire framework)
#if !defined(SOL_SAFE_GETTER)
#define SOL_SAFE_GETTER 1
#endif
// Checks access on usertype functions
// local my_obj = my_type.new()
// my_obj.my_member_function()
// -- bad syntax and crash
#if !defined(SOL_SAFE_USERTYPE)
#define SOL_SAFE_USERTYPE 1
#endif
// Checks sol::reference derived boundaries
// sol::function ref(L, 1);
// sol::userdata sref(L, 2);
#if !defined(SOL_SAFE_REFERENCES)
#define SOL_SAFE_REFERENCES 1
#endif
// Changes all typedefs of sol::function to point to the
// protected_function version, instead of unsafe_function
#if !defined(SOL_SAFE_FUNCTION)
#define SOL_SAFE_FUNCTION 1
#endif
// Checks function parameters and
// returns upon call into/from Lua
// local a = 1
// local b = "woof"
// my_c_function(a, b)
#if !defined(SOL_SAFE_FUNCTION_CALLS)
#define SOL_SAFE_FUNCTION_CALLS 1
#endif
// Checks conversions
// int v = lua["bark"];
// int v2 = my_sol_function();
#if !defined(SOL_SAFE_PROXIES)
#define SOL_SAFE_PROXIES 1
#endif
// Check overflowing number conversions
// for things like 64 bit integers that don't fit in a typical lua_Number
// for Lua 5.1 and 5.2
#if !defined(SOL_SAFE_NUMERICS)
#define SOL_SAFE_NUMERICS 1
#endif
// Turn off Number Precision Checks
// if this is defined, we do not do range
// checks on integers / unsigned integers that might
// be bigger than what Lua can represent
#if !defined(SOL_NO_CHECK_NUMBER_PRECISION)
// off by default
#define SOL_NO_CHECK_NUMBER_PRECISION 0
#endif
#endif // Turn on Safety for all if top-level macro is defined
#if defined(SOL_IN_DEBUG_DETECTED) && SOL_IN_DEBUG_DETECTED
#if !defined(SOL_SAFE_REFERENCES)
// Ensure that references are forcefully type-checked upon construction
#define SOL_SAFE_REFERENCES 1
#endif
// Safe usertypes checks for errors such as
// obj = my_type.new()
// obj.f() -- note the '.' instead of ':'
// usertypes should be safe no matter what
#if !defined(SOL_SAFE_USERTYPE)
#define SOL_SAFE_USERTYPE 1
#endif
#if !defined(SOL_SAFE_FUNCTION_CALLS)
// Function calls from Lua should be automatically safe in debug mode
#define SOL_SAFE_FUNCTION_CALLS 1
#endif
// Print any exceptions / errors that occur
// in debug mode to the default error stream / console
#if !defined(SOL_PRINT_ERRORS)
#define SOL_PRINT_ERRORS 1
#endif
#endif // DEBUG: Turn on all debug safety features for VC++ / g++ / clang++ and similar
#if !defined(SOL_PRINT_ERRORS)
#define SOL_PRINT_ERRORS 0
#endif
#if !defined(SOL_DEFAULT_PASS_ON_ERROR)
#define SOL_DEFAULT_PASS_ON_ERROR 0
#endif
#if !defined(SOL_ENABLE_INTEROP)
#define SOL_ENABLE_INTEROP 0
#endif
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil)
#if !defined(SOL_NO_NIL)
#define SOL_NO_NIL 1
#endif
#endif // avoiding nil defines / keywords
#if defined(SOL_USE_BOOST) && SOL_USE_BOOST
#ifndef SOL_UNORDERED_MAP_COMPATIBLE_HASH
#define SOL_UNORDERED_MAP_COMPATIBLE_HASH 1
#endif // SOL_UNORDERED_MAP_COMPATIBLE_HASH
#endif
#ifndef SOL_STACK_STRING_OPTIMIZATION_SIZE
#define SOL_STACK_STRING_OPTIMIZATION_SIZE 1024
#endif // Optimized conversion routines using a KB or so off the stack
// end of sol/config.hpp
// end of sol/feature_test.hpp
namespace sol {
template <bool b>
class basic_reference;
using reference = basic_reference<false>;
using main_reference = basic_reference<true>;
class stack_reference;
struct proxy_base_tag;
template <typename Super>
struct proxy_base;
template <typename Table, typename Key>
struct proxy;
template <typename T>
class usertype;
template <typename T>
class simple_usertype;
template <bool, typename T>
class basic_table_core;
template <bool b>
using table_core = basic_table_core<b, reference>;
template <bool b>
using main_table_core = basic_table_core<b, main_reference>;
template <bool b>
using stack_table_core = basic_table_core<b, stack_reference>;
template <typename T>
using basic_table = basic_table_core<false, T>;
typedef table_core<false> table;
typedef table_core<true> global_table;
typedef main_table_core<false> main_table;
typedef main_table_core<true> main_global_table;
typedef stack_table_core<false> stack_table;
typedef stack_table_core<true> stack_global_table;
template <typename base_t>
struct basic_environment;
using environment = basic_environment<reference>;
using main_environment = basic_environment<main_reference>;
using stack_environment = basic_environment<stack_reference>;
template <typename T, bool>
class basic_function;
template <typename T, bool, typename H>
class basic_protected_function;
using unsafe_function = basic_function<reference, false>;
using safe_function = basic_protected_function<reference, false, reference>;
using main_unsafe_function = basic_function<main_reference, false>;
using main_safe_function = basic_protected_function<main_reference, false, reference>;
using stack_unsafe_function = basic_function<stack_reference, false>;
using stack_safe_function = basic_protected_function<stack_reference, false, reference>;
using stack_aligned_unsafe_function = basic_function<stack_reference, true>;
using stack_aligned_safe_function = basic_protected_function<stack_reference, true, reference>;
using protected_function = safe_function;
using main_protected_function = main_safe_function;
using stack_protected_function = stack_safe_function;
using stack_aligned_protected_function = stack_aligned_safe_function;
#if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION
using function = protected_function;
using main_function = main_protected_function;
using stack_function = stack_protected_function;
#else
using function = unsafe_function;
using main_function = main_unsafe_function;
using stack_function = stack_unsafe_function;
#endif
using stack_aligned_function = stack_aligned_unsafe_function;
using stack_aligned_stack_handler_function = basic_protected_function<stack_reference, true, stack_reference>;
struct unsafe_function_result;
struct protected_function_result;
using safe_function_result = protected_function_result;
#if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION
using function_result = safe_function_result;
#else
using function_result = unsafe_function_result;
#endif
template <typename base_t>
class basic_object;
template <typename base_t>
class basic_userdata;
template <typename base_t>
class basic_lightuserdata;
template <typename base_t>
class basic_coroutine;
template <typename base_t>
class basic_thread;
using object = basic_object<reference>;
using userdata = basic_userdata<reference>;
using lightuserdata = basic_lightuserdata<reference>;
using thread = basic_thread<reference>;
using coroutine = basic_coroutine<reference>;
using main_object = basic_object<main_reference>;
using main_userdata = basic_userdata<main_reference>;
using main_lightuserdata = basic_lightuserdata<main_reference>;
using main_coroutine = basic_coroutine<main_reference>;
using stack_object = basic_object<stack_reference>;
using stack_userdata = basic_userdata<stack_reference>;
using stack_lightuserdata = basic_lightuserdata<stack_reference>;
using stack_thread = basic_thread<stack_reference>;
using stack_coroutine = basic_coroutine<stack_reference>;
struct stack_proxy_base;
struct stack_proxy;
struct variadic_args;
struct variadic_results;
struct stack_count;
struct this_state;
struct this_main_state;
struct this_environment;
template <typename T>
struct as_table_t;
template <typename T>
struct as_container_t;
template <typename T>
struct nested;
template <typename T>
struct light;
template <typename T>
struct user;
template <typename T>
struct as_args_t;
template <typename T>
struct protect_t;
template <typename F, typename... Filters>
struct filter_wrapper;
} // namespace sol
// end of sol/forward.hpp
#endif // SOL_SINGLE_INCLUDE_FORWARD_HPP
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2018-06-11 18:42:24.829810 UTC
// This header was generated with sol v2.20.2 (revision ac70911)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
#define SOL_SINGLE_INCLUDE_FORWARD_HPP
// 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) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L))))
#ifndef SOL_CXX17_FEATURES
#define SOL_CXX17_FEATURES 1
#endif // C++17 features macro
#endif // C++17 features check
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && (defined(_MSVC_LANG) && ((_MSVC_LANG >= 201403L))))
#ifndef SOL_NOEXCEPT_FUNCTION_TYPE
#define SOL_NOEXCEPT_FUNCTION_TYPE 1
#endif // noexcept is part of a function's type
#endif // compiler-specific checks
#if defined(__clang__) && defined(__APPLE__)
#if defined(__has_include)
#if __has_include(<variant>)
#define SOL_STD_VARIANT 1
#endif // has include nonsense
#endif // __has_include
#else
#define SOL_STD_VARIANT 1
#endif // Clang screws up variant
#endif // C++17 only
// beginning of sol/config.hpp
#ifdef _MSC_VER
#if defined(_DEBUG) && !defined(NDEBUG)
#ifndef SOL_IN_DEBUG_DETECTED
#define SOL_IN_DEBUG_DETECTED 1
#endif
#endif // VC++ Debug macros
#ifndef _CPPUNWIND
#ifndef SOL_NO_EXCEPTIONS
#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__)
#if !defined(NDEBUG) && !defined(__OPTIMIZE__)
#ifndef SOL_IN_DEBUG_DETECTED
#define SOL_IN_DEBUG_DETECTED 1
#endif
#endif // Not Debug && g++ optimizer flag
#ifndef __EXCEPTIONS
#ifndef SOL_NO_EXCEPTIONS
#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++
#if defined(SOL_CHECK_ARGUMENTS) && SOL_CHECK_ARGUMENTS
// Checks low-level getter function
// (and thusly, affects nearly entire framework)
#if !defined(SOL_SAFE_GETTER)
#define SOL_SAFE_GETTER 1
#endif
// Checks access on usertype functions
// local my_obj = my_type.new()
// my_obj.my_member_function()
// -- bad syntax and crash
#if !defined(SOL_SAFE_USERTYPE)
#define SOL_SAFE_USERTYPE 1
#endif
// Checks sol::reference derived boundaries
// sol::function ref(L, 1);
// sol::userdata sref(L, 2);
#if !defined(SOL_SAFE_REFERENCES)
#define SOL_SAFE_REFERENCES 1
#endif
// Changes all typedefs of sol::function to point to the
// protected_function version, instead of unsafe_function
#if !defined(SOL_SAFE_FUNCTION)
#define SOL_SAFE_FUNCTION 1
#endif
// Checks function parameters and
// returns upon call into/from Lua
// local a = 1
// local b = "woof"
// my_c_function(a, b)
#if !defined(SOL_SAFE_FUNCTION_CALLS)
#define SOL_SAFE_FUNCTION_CALLS 1
#endif
// Checks conversions
// int v = lua["bark"];
// int v2 = my_sol_function();
#if !defined(SOL_SAFE_PROXIES)
#define SOL_SAFE_PROXIES 1
#endif
// Check overflowing number conversions
// for things like 64 bit integers that don't fit in a typical lua_Number
// for Lua 5.1 and 5.2
#if !defined(SOL_SAFE_NUMERICS)
#define SOL_SAFE_NUMERICS 1
#endif
// Turn off Number Precision Checks
// if this is defined, we do not do range
// checks on integers / unsigned integers that might
// be bigger than what Lua can represent
#if !defined(SOL_NO_CHECK_NUMBER_PRECISION)
// off by default
#define SOL_NO_CHECK_NUMBER_PRECISION 0
#endif
#endif // Turn on Safety for all if top-level macro is defined
#if defined(SOL_IN_DEBUG_DETECTED) && SOL_IN_DEBUG_DETECTED
#if !defined(SOL_SAFE_REFERENCES)
// Ensure that references are forcefully type-checked upon construction
#define SOL_SAFE_REFERENCES 1
#endif
// Safe usertypes checks for errors such as
// obj = my_type.new()
// obj.f() -- note the '.' instead of ':'
// usertypes should be safe no matter what
#if !defined(SOL_SAFE_USERTYPE)
#define SOL_SAFE_USERTYPE 1
#endif
#if !defined(SOL_SAFE_FUNCTION_CALLS)
// Function calls from Lua should be automatically safe in debug mode
#define SOL_SAFE_FUNCTION_CALLS 1
#endif
// Print any exceptions / errors that occur
// in debug mode to the default error stream / console
#if !defined(SOL_PRINT_ERRORS)
#define SOL_PRINT_ERRORS 1
#endif
#endif // DEBUG: Turn on all debug safety features for VC++ / g++ / clang++ and similar
#if !defined(SOL_PRINT_ERRORS)
#define SOL_PRINT_ERRORS 0
#endif
#if !defined(SOL_DEFAULT_PASS_ON_ERROR)
#define SOL_DEFAULT_PASS_ON_ERROR 0
#endif
#if !defined(SOL_ENABLE_INTEROP)
#define SOL_ENABLE_INTEROP 0
#endif
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil)
#if !defined(SOL_NO_NIL)
#define SOL_NO_NIL 1
#endif
#endif // avoiding nil defines / keywords
#if defined(SOL_USE_BOOST) && SOL_USE_BOOST
#ifndef SOL_UNORDERED_MAP_COMPATIBLE_HASH
#define SOL_UNORDERED_MAP_COMPATIBLE_HASH 1
#endif // SOL_UNORDERED_MAP_COMPATIBLE_HASH
#endif
#ifndef SOL_STACK_STRING_OPTIMIZATION_SIZE
#define SOL_STACK_STRING_OPTIMIZATION_SIZE 1024
#endif // Optimized conversion routines using a KB or so off the stack
// end of sol/config.hpp
// end of sol/feature_test.hpp
namespace sol {
template <bool b>
class basic_reference;
using reference = basic_reference<false>;
using main_reference = basic_reference<true>;
class stack_reference;
struct proxy_base_tag;
template <typename Super>
struct proxy_base;
template <typename Table, typename Key>
struct proxy;
template <typename T>
class usertype;
template <typename T>
class simple_usertype;
template <bool, typename T>
class basic_table_core;
template <bool b>
using table_core = basic_table_core<b, reference>;
template <bool b>
using main_table_core = basic_table_core<b, main_reference>;
template <bool b>
using stack_table_core = basic_table_core<b, stack_reference>;
template <typename T>
using basic_table = basic_table_core<false, T>;
typedef table_core<false> table;
typedef table_core<true> global_table;
typedef main_table_core<false> main_table;
typedef main_table_core<true> main_global_table;
typedef stack_table_core<false> stack_table;
typedef stack_table_core<true> stack_global_table;
template <typename base_t>
struct basic_environment;
using environment = basic_environment<reference>;
using main_environment = basic_environment<main_reference>;
using stack_environment = basic_environment<stack_reference>;
template <typename T, bool>
class basic_function;
template <typename T, bool, typename H>
class basic_protected_function;
using unsafe_function = basic_function<reference, false>;
using safe_function = basic_protected_function<reference, false, reference>;
using main_unsafe_function = basic_function<main_reference, false>;
using main_safe_function = basic_protected_function<main_reference, false, reference>;
using stack_unsafe_function = basic_function<stack_reference, false>;
using stack_safe_function = basic_protected_function<stack_reference, false, reference>;
using stack_aligned_unsafe_function = basic_function<stack_reference, true>;
using stack_aligned_safe_function = basic_protected_function<stack_reference, true, reference>;
using protected_function = safe_function;
using main_protected_function = main_safe_function;
using stack_protected_function = stack_safe_function;
using stack_aligned_protected_function = stack_aligned_safe_function;
#if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION
using function = protected_function;
using main_function = main_protected_function;
using stack_function = stack_protected_function;
#else
using function = unsafe_function;
using main_function = main_unsafe_function;
using stack_function = stack_unsafe_function;
#endif
using stack_aligned_function = stack_aligned_unsafe_function;
using stack_aligned_stack_handler_function = basic_protected_function<stack_reference, true, stack_reference>;
struct unsafe_function_result;
struct protected_function_result;
using safe_function_result = protected_function_result;
#if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION
using function_result = safe_function_result;
#else
using function_result = unsafe_function_result;
#endif
template <typename base_t>
class basic_object;
template <typename base_t>
class basic_userdata;
template <typename base_t>
class basic_lightuserdata;
template <typename base_t>
class basic_coroutine;
template <typename base_t>
class basic_thread;
using object = basic_object<reference>;
using userdata = basic_userdata<reference>;
using lightuserdata = basic_lightuserdata<reference>;
using thread = basic_thread<reference>;
using coroutine = basic_coroutine<reference>;
using main_object = basic_object<main_reference>;
using main_userdata = basic_userdata<main_reference>;
using main_lightuserdata = basic_lightuserdata<main_reference>;
using main_coroutine = basic_coroutine<main_reference>;
using stack_object = basic_object<stack_reference>;
using stack_userdata = basic_userdata<stack_reference>;
using stack_lightuserdata = basic_lightuserdata<stack_reference>;
using stack_thread = basic_thread<stack_reference>;
using stack_coroutine = basic_coroutine<stack_reference>;
struct stack_proxy_base;
struct stack_proxy;
struct variadic_args;
struct variadic_results;
struct stack_count;
struct this_state;
struct this_main_state;
struct this_environment;
template <typename T>
struct as_table_t;
template <typename T>
struct as_container_t;
template <typename T>
struct nested;
template <typename T>
struct light;
template <typename T>
struct user;
template <typename T>
struct as_args_t;
template <typename T>
struct protect_t;
template <typename F, typename... Filters>
struct filter_wrapper;
} // namespace sol
// end of sol/forward.hpp
#endif // SOL_SINGLE_INCLUDE_FORWARD_HPP

View File

@ -28,7 +28,7 @@
#if defined(SOL_INSIDE_UNREAL) && SOL_INSIDE_UNREAL
#ifdef check
#define SOL_INSIDE_UNREAL_REMOVED_CHECK
#define SOL_INSIDE_UNREAL_REMOVED_CHECK 1
#undef check
#endif
#endif // Unreal Engine 4 Bullshit
@ -69,7 +69,7 @@
#if defined(SOL_INSIDE_UNREAL) && SOL_INSIDE_UNREAL
#if defined(SOL_INSIDE_UNREAL_REMOVED_CHECK) && SOL_INSIDE_UNREAL_REMOVED_CHECK
#if DO_CHECK
#if defined(DO_CHECK) && 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); }

View File

@ -271,7 +271,7 @@ namespace sol {
struct agnostic_lua_call_wrapper<var_wrapper<T>, false, is_variable, checked, boost, clean_stack, C> {
template <typename V>
static int call_assign(std::true_type, lua_State* L, V&& f) {
detail::unwrap(f.value) = stack::get<meta::unwrapped_t<T>>(L, boost + (is_variable ? 3 : 1));
detail::unwrap(f.value) = stack::unqualified_get<meta::unwrapped_t<T>>(L, boost + (is_variable ? 3 : 1));
if (clean_stack) {
lua_settop(L, 0);
}
@ -372,14 +372,14 @@ namespace sol {
static int call(lua_State* L, Fx&& f) {
typedef std::conditional_t<std::is_void<T>::value, object_type, T> Ta;
#if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE
auto maybeo = stack::check_get<Ta*>(L, 1);
auto maybeo = stack::unqualified_check_get<Ta*>(L, 1);
if (!maybeo || maybeo.value() == nullptr) {
return luaL_error(L, "sol: received nil for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)");
}
object_type* o = static_cast<object_type*>(maybeo.value());
return call(L, std::forward<Fx>(f), *o);
#else
object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1));
object_type& o = static_cast<object_type&>(*stack::unqualified_get<non_null<Ta*>>(L, 1));
return call(L, std::forward<Fx>(f), o);
#endif // Safety
}
@ -726,7 +726,7 @@ namespace sol {
template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls, bool clean_stack = true>
inline int call_user(lua_State* L) {
auto& fx = stack::get<user<F>>(L, upvalue_index(start));
auto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start));
return call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx);
}

View File

@ -396,7 +396,7 @@ COMPAT53_API void luaL_requiref(lua_State *L, const char *modname,
/* other Lua versions */
#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 503
#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 504
# error "unsupported Lua version (i.e. not Lua 5.1, 5.2, or 5.3)"

29
sol/config_setup.hpp Normal file
View File

@ -0,0 +1,29 @@
// sol2
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_CONFIG_SETUP_HPP
#define SOL_CONFIG_SETUP_HPP
#endif // SOL_CONFIG_SETUP_HPP

View File

@ -597,7 +597,7 @@ namespace sol {
static auto& get_src(lua_State* L) {
#if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE
auto p = stack::check_get<T*>(L, 1);
auto p = stack::unqualified_check_get<T*>(L, 1);
if (!p) {
luaL_error(L, "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle<T>().c_str());
}
@ -606,7 +606,7 @@ namespace sol {
}
return *p.value();
#else
return stack::get<T>(L, 1);
return stack::unqualified_get<T>(L, 1);
#endif // Safe getting with error
}
@ -814,7 +814,7 @@ namespace sol {
}
static error_result find_has_associative_lookup(std::true_type, lua_State* L, T& self) {
decltype(auto) key = stack::get<K>(L, 2);
decltype(auto) key = stack::unqualified_get<K>(L, 2);
auto it = self.find(key);
if (it == deferred_traits::end(L, self)) {
return stack::push(L, lua_nil);
@ -823,7 +823,7 @@ namespace sol {
}
static error_result find_has_associative_lookup(std::false_type, lua_State* L, T& self) {
decltype(auto) value = stack::get<V>(L, 2);
decltype(auto) value = stack::unqualified_get<V>(L, 2);
auto it = self.find(value);
if (it == deferred_traits::end(L, self)) {
return stack::push(L, lua_nil);
@ -848,7 +848,7 @@ namespace sol {
}
static error_result find_comparative(std::true_type, lua_State* L, T& self) {
decltype(auto) value = stack::get<V>(L, 2);
decltype(auto) value = stack::unqualified_get<V>(L, 2);
auto it = deferred_traits::begin(L, self);
auto e = deferred_traits::end(L, self);
std::size_t index = 1;
@ -927,7 +927,7 @@ namespace sol {
}
static error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key, iterator& pos) {
self.insert(pos, value_type(key.as<K>(), stack::get<V>(L, 3)));
self.insert(pos, value_type(key.as<K>(), stack::unqualified_get<V>(L, 3)));
return {};
}
@ -1119,7 +1119,7 @@ namespace sol {
template <bool ip>
static int next_associative(std::true_type, lua_State* L) {
iter& i = stack::get<user<iter>>(L, 1);
iter& i = stack::unqualified_get<user<iter>>(L, 1);
auto& source = i.source;
auto& it = i.it;
if (it == deferred_traits::end(L, source)) {
@ -1140,10 +1140,10 @@ namespace sol {
template <bool>
static int next_associative(std::false_type, lua_State* L) {
iter& i = stack::get<user<iter>>(L, 1);
iter& i = stack::unqualified_get<user<iter>>(L, 1);
auto& source = i.source;
auto& it = i.it;
next_K k = stack::get<next_K>(L, 2);
next_K k = stack::unqualified_get<next_K>(L, 2);
if (it == deferred_traits::end(L, source)) {
return 0;
}
@ -1183,7 +1183,7 @@ namespace sol {
auto& self = get_src(L);
error_result er;
{
std::ptrdiff_t pos = stack::get<std::ptrdiff_t>(L);
std::ptrdiff_t pos = stack::unqualified_get<std::ptrdiff_t>(L);
er = at_start(L, self, pos);
}
return handle_errors(L, er);
@ -1193,7 +1193,7 @@ namespace sol {
auto& self = get_src(L);
error_result er;
{
decltype(auto) key = stack::get<K>(L);
decltype(auto) key = stack::unqualified_get<K>(L);
er = get_start(L, self, key);
}
return handle_errors(L, er);
@ -1261,7 +1261,7 @@ namespace sol {
auto& self = get_src(L);
error_result er;
{
decltype(auto) key = stack::get<K>(L, 2);
decltype(auto) key = stack::unqualified_get<K>(L, 2);
er = erase_start(L, self, key);
}
return handle_errors(L, er);
@ -1316,7 +1316,7 @@ namespace sol {
};
static auto& get_src(lua_State* L) {
auto p = stack::check_get<T*>(L, 1);
auto p = stack::unqualified_check_get<T*>(L, 1);
#if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE
if (!p) {
luaL_error(L, "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle<T>().c_str());
@ -1330,7 +1330,7 @@ namespace sol {
static int find(std::true_type, lua_State* L) {
T& self = get_src(L);
decltype(auto) value = stack::get<value_type>(L, 2);
decltype(auto) value = stack::unqualified_get<value_type>(L, 2);
std::size_t N = std::extent<T>::value;
for (std::size_t idx = 0; idx < N; ++idx) {
const auto& v = self[idx];
@ -1346,10 +1346,10 @@ namespace sol {
}
static int next_iter(lua_State* L) {
iter& i = stack::get<user<iter>>(L, 1);
iter& i = stack::unqualified_get<user<iter>>(L, 1);
auto& source = i.source;
auto& it = i.it;
std::size_t k = stack::get<std::size_t>(L, 2);
std::size_t k = stack::unqualified_get<std::size_t>(L, 2);
if (it == deferred_traits::end(L, source)) {
return 0;
}
@ -1383,7 +1383,7 @@ namespace sol {
static int get(lua_State* L) {
T& self = get_src(L);
std::ptrdiff_t idx = stack::get<std::ptrdiff_t>(L, 2);
std::ptrdiff_t idx = stack::unqualified_get<std::ptrdiff_t>(L, 2);
idx += deferred_traits::index_adjustment(L, self);
if (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value) || idx < 0) {
return stack::push(L, lua_nil);
@ -1397,7 +1397,7 @@ namespace sol {
static int set(lua_State* L) {
T& self = get_src(L);
std::ptrdiff_t idx = stack::get<std::ptrdiff_t>(L, 2);
std::ptrdiff_t idx = stack::unqualified_get<std::ptrdiff_t>(L, 2);
idx += deferred_traits::index_adjustment(L, self);
if (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value)) {
return luaL_error(L, "sol: index out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
@ -1405,7 +1405,7 @@ namespace sol {
if (idx < 0) {
return luaL_error(L, "sol: index out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str());
}
self[idx] = stack::get<value_type>(L, 3);
self[idx] = stack::unqualified_get<value_type>(L, 3);
return 0;
}

View File

@ -60,7 +60,7 @@ namespace sol {
{ "pairs", &pairs_call },
{ "next", &next_call },
};
auto maybenameview = stack::check_get<string_view>(L, 2);
auto maybenameview = stack::unqualified_check_get<string_view>(L, 2);
if (maybenameview) {
const string_view& nameview = *maybenameview;
#if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH
@ -429,14 +429,14 @@ namespace sol {
template <typename T>
struct getter<as_container_t<T>> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack::get<T>(L, index, tracking);
return stack::unqualified_get<T>(L, index, tracking);
}
};
template <typename T>
struct getter<as_container_t<T>*> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack::get<T*>(L, index, tracking);
return stack::unqualified_get<T*>(L, index, tracking);
}
};
} // namespace stack

View File

@ -1,4 +1,4 @@
// sol2
// sol2
// The MIT License (MIT)
@ -52,5 +52,6 @@
#endif // C++17 only
#include <sol/config.hpp>
#include "config_setup.hpp"
#endif // SOL_FEATURE_TEST_HPP

View File

@ -94,11 +94,43 @@ namespace sol {
T* data = static_cast<T*>(voiddata);
return static_cast<void*>(ti != usertype_traits<T>::qualified_name() ? type_cast_bases(types<Bases...>(), data, ti) : data);
}
template <typename U>
static bool type_unique_cast_bases(void*, const string_view&) {
return false;
}
template <typename U, typename Base, typename... Args>
static bool type_unique_cast_bases(void* source_data, void* target_data, const string_view& ti) {
typedef unique_usertype_traits<U>::typename rebind_base<Base> base_ptr;
string_view base_ti = usertype_traits<Base>::qualified_name();
if (base_ti == ti) {
if (target_data != nullptr) {
U* source = static_cast<U*>(source_data);
base_ptr* target = static_cast<base_ptr*>(target_data);
// perform proper derived -> base conversion
*target = *source;
}
return true;
}
return type_unique_cast_bases<Args...>(source_data, target_data, ti);
}
template <typename U>
static bool type_unique_cast(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) {
typedef unique_usertype_traits<U>::typename rebind_base<void> rebind_t;
string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name();
if (rebind_ti != this_rebind_ti) {
// this is not even of the same container type
return false;
}
return type_unique_cast_bases<Bases...>(source_data, target_data, ti);
}
};
using inheritance_check_function = decltype(&inheritance<void>::type_check);
using inheritance_cast_function = decltype(&inheritance<void>::type_cast);
using inheritance_unique_cast_function = decltype(&inheritance<void>::type_unique_cast<void>);
} // namespace detail
} // namespace sol

View File

@ -122,7 +122,7 @@ namespace sol {
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 191426428 && _MSC_FULL_VER >= 191200000
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000
// MSVC is ass sometimes
return get<protected_function>().call<Ret...>(std::forward<Args>(args)...);
#else

View File

@ -30,6 +30,8 @@
#include "proxy_base.hpp"
#include "stack_iterator.hpp"
#include "stack_proxy.hpp"
#include "error.hpp"
#include "stack.hpp"
#include <cstdint>
namespace sol {

View File

@ -126,7 +126,7 @@ namespace sol {
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 191426428 && _MSC_FULL_VER >= 191200000
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000
// MSVC is ass sometimes
return get<function>().call<Ret...>(std::forward<Args>(args)...);
#else

View File

@ -24,615 +24,7 @@
#ifndef SOL_STACK_CHECK_HPP
#define SOL_STACK_CHECK_HPP
#include "stack_core.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include <memory>
#include <functional>
#include <utility>
#include <cmath>
#ifdef SOL_CXX17_FEATURES
#ifdef SOL_STD_VARIANT
#include <variant>
#endif // SOL_STD_VARIANT
#endif // SOL_CXX17_FEATURES
namespace sol {
namespace stack {
namespace stack_detail {
template <typename T, bool poptable = true>
inline bool check_metatable(lua_State* L, int index = -2) {
const auto& metakey = usertype_traits<T>::metatable();
luaL_getmetatable(L, &metakey[0]);
const type expectedmetatabletype = static_cast<type>(lua_type(L, -1));
if (expectedmetatabletype != type::lua_nil) {
if (lua_rawequal(L, -1, index) == 1) {
lua_pop(L, 1 + static_cast<int>(poptable));
return true;
}
}
lua_pop(L, 1);
return false;
}
template <type expected, int (*check_func)(lua_State*, int)>
struct basic_check {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
bool success = check_func(L, index) == 1;
if (!success) {
// expected type, actual type
handler(L, index, expected, type_of(L, index), "");
}
return success;
}
};
} // namespace stack_detail
template <typename T, typename>
struct userdata_checker {
template <typename Handler>
static bool check(lua_State*, int, type, Handler&&, record&) {
return false;
}
};
template <typename T, type expected, typename>
struct checker {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
const type indextype = type_of(L, index);
bool success = expected == indextype;
if (!success) {
// expected type, actual type, message
handler(L, index, expected, indextype, "");
}
return success;
}
};
template <typename T>
struct checker<T, type::number, std::enable_if_t<std::is_integral<T>::value>> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
#if SOL_LUA_VERSION >= 503
#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
int isnum = 0;
lua_tointegerx(L, index, &isnum);
const bool success = isnum != 0;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
}
#elif (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
// this check is precise, does not convert
if (lua_isinteger(L, index) == 1) {
return true;
}
const bool success = false;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric (integral) type");
}
#else
type t = type_of(L, index);
const bool success = t == type::number;
#endif // If numbers are enabled, use the imprecise check
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type");
}
return success;
#else
#if !defined(SOL_STRINGS_ARE_NUMBERS) || !SOL_STRINGS_ARE_NUMBERS
// must pre-check, because it will convert
type t = type_of(L, index);
if (t != type::number) {
// expected type, actual type
handler(L, index, type::number, t, "not a numeric type");
return false;
}
#endif // Do not allow strings to be numbers
int isnum = 0;
const lua_Number v = lua_tonumberx(L, index, &isnum);
const bool success = isnum != 0
#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
&& static_cast<lua_Number>(llround(v)) == v
#endif // Safe numerics and number precision checking
;
if (!success) {
// expected type, actual type
#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
handler(L, index, type::number, t, "not a numeric type");
#else
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
#endif
}
return success;
#endif // Lua Version 5.3 versus others
}
};
template <typename T>
struct checker<T, type::number, std::enable_if_t<std::is_floating_point<T>::value>> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
bool success = lua_isnumber(L, index) == 1;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
}
return success;
#else
type t = type_of(L, index);
bool success = t == type::number;
if (!success) {
// expected type, actual type
handler(L, index, type::number, t, "not a numeric type");
}
return success;
#endif // Strings are Numbers
}
};
template <type expected, typename C>
struct checker<lua_nil_t, expected, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
bool success = lua_isnil(L, index);
if (success) {
tracking.use(1);
return success;
}
tracking.use(0);
success = lua_isnone(L, index);
if (!success) {
// expected type, actual type
handler(L, index, expected, type_of(L, index), "");
}
return success;
}
};
template <typename C>
struct checker<detail::non_lua_nil_t, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
checker<lua_nil_t, type::lua_nil, C> c{};
(void)c;
return !c.check(L, index, std::forward<Handler>(handler), tracking);
}
};
template <type expected, typename C>
struct checker<nullopt_t, expected, C> : checker<lua_nil_t> {};
template <typename C>
struct checker<this_state, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct checker<this_main_state, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct checker<this_environment, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct checker<variadic_args, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct checker<type, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename T, typename C>
struct checker<T, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
bool success = is_lua_reference<T>::value || !lua_isnone(L, index);
if (!success) {
// expected type, actual type
handler(L, index, type::poly, type_of(L, index), "");
}
return success;
}
};
template <typename T, typename C>
struct checker<T, type::lightuserdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
bool success = t == type::userdata || t == type::lightuserdata;
if (!success) {
// expected type, actual type
handler(L, index, type::lightuserdata, t, "");
}
return success;
}
};
template <typename C>
struct checker<userdata_value, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
bool success = t == type::userdata;
if (!success) {
// expected type, actual type
handler(L, index, type::userdata, t, "");
}
return success;
}
};
template <typename B, typename C>
struct checker<basic_userdata<B>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::check<userdata_value>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T, typename C>
struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {};
template <typename T, typename C>
struct checker<non_null<T>, type::userdata, C> : checker<T, lua_type_of<T>::value, C> {};
template <typename C>
struct checker<lua_CFunction, type::function, C> : stack_detail::basic_check<type::function, lua_iscfunction> {};
template <typename C>
struct checker<std::remove_pointer_t<lua_CFunction>, type::function, C> : checker<lua_CFunction, type::function, C> {};
template <typename C>
struct checker<c_closure, type::function, C> : checker<lua_CFunction, type::function, C> {};
template <typename T, typename C>
struct checker<T, type::function, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::lua_nil || t == type::none || t == type::function) {
// allow for lua_nil to be returned
return true;
}
if (t != type::userdata && t != type::table) {
handler(L, index, type::function, t, "must be a function or table or a userdata");
return false;
}
// Do advanced check for call-style userdata?
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, "value is not a function and does not have overriden metatable");
return false;
}
if (lua_isnoneornil(L, -1)) {
lua_pop(L, 1);
handler(L, index, type::function, t, "value is not a function and does not have valid metatable");
return false;
}
lua_getfield(L, -1, &callkey[0]);
if (lua_isnoneornil(L, -1)) {
lua_pop(L, 2);
handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type");
return false;
}
// has call, is definitely a function
lua_pop(L, 2);
return true;
}
};
template <typename T, typename C>
struct checker<T, type::table, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::table) {
return true;
}
if (t != type::userdata) {
handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one");
return false;
}
return true;
}
};
template <type expected, typename C>
struct checker<metatable_t, expected, C> {
template <typename Handler>
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::lua_nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, expected, t, "value does not have a valid metatable");
return false;
}
return true;
}
};
template <typename C>
struct checker<env_t, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) {
return true;
}
handler(L, index, type::table, t, "value cannot not have a valid environment");
return true;
}
};
template <typename E, typename C>
struct checker<basic_environment<E>, type::poly, C> {
template <typename Handler>
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::lua_nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, type::table, t, "value does not have a valid metatable");
return false;
}
return true;
}
};
template <typename T, typename C>
struct checker<detail::as_value_tag<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
return check(types<T>(), L, index, indextype, handler, tracking);
}
template <typename U, typename Handler>
static bool check(types<U>, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
#if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP
userdata_checker<extensible<T>> uc;
(void)uc;
if (uc.check(L, index, indextype, handler, tracking)) {
return true;
}
#endif // interop extensibility
tracking.use(1);
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype, "value is not a valid userdata");
return false;
}
if (meta::any<std::is_same<T, lightuserdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value)
return true;
if (lua_getmetatable(L, index) == 0) {
return true;
}
int metatableindex = lua_gettop(L);
if (stack_detail::check_metatable<U>(L, metatableindex))
return true;
if (stack_detail::check_metatable<U*>(L, metatableindex))
return true;
if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex))
return true;
if (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex))
return true;
bool success = false;
if (detail::has_derived<T>::value) {
auto pn = stack::pop_n(L, 1);
lua_pushstring(L, &detail::base_class_check_key()[0]);
lua_rawget(L, metatableindex);
if (type_of(L, -1) != type::lua_nil) {
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_check_function ic = reinterpret_cast<detail::inheritance_check_function>(basecastdata);
success = ic(usertype_traits<T>::qualified_name());
}
}
if (!success) {
lua_pop(L, 1);
handler(L, index, type::userdata, indextype, "value at this index does not properly reflect the desired type");
return false;
}
lua_pop(L, 1);
return true;
}
};
template <typename T, typename C>
struct checker<detail::as_pointer_tag<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
if (indextype == type::lua_nil) {
tracking.use(1);
return true;
}
return stack_detail::check_usertype<T>(std::false_type(), L, index, indextype, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
return check(L, index, handler, indextype, tracking);
}
};
template <typename T, typename C>
struct checker<T, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T, typename C>
struct checker<T*, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return check_usertype<T*>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename X>
struct checker<X, type::userdata, std::enable_if_t<is_unique_usertype<X>::value>> {
typedef typename unique_usertype_traits<X>::type T;
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
tracking.use(1);
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype, "value is not a userdata");
return false;
}
if (lua_getmetatable(L, index) == 0) {
return true;
}
int metatableindex = lua_gettop(L);
if (stack_detail::check_metatable<detail::unique_usertype<T>>(L, metatableindex)) {
void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique_destructor(memory);
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
bool success = &detail::usertype_unique_alloc_destroy<T, X> == pdx;
if (!success) {
handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
}
return success;
}
lua_pop(L, 1);
handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)");
return false;
}
};
template <typename T, typename C>
struct checker<std::reference_wrapper<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return checker<T, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename... Args, typename C>
struct checker<std::tuple<Args...>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename A, typename B, typename C>
struct checker<std::pair<A, B>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T, typename C>
struct checker<optional<T>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&&, record& tracking) {
type t = type_of(L, index);
if (t == type::none) {
tracking.use(0);
return true;
}
if (t == type::lua_nil) {
tracking.use(1);
return true;
}
return stack::check<T>(L, index, no_panic, tracking);
}
};
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn, typename C>
struct checker<std::variant<Tn...>, type::poly, C> {
typedef std::variant<Tn...> V;
typedef std::variant_size<V> V_size;
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
template <typename Handler>
static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) {
if (V_is_empty::value && lua_isnone(L, index)) {
return true;
}
tracking.use(1);
handler(L, index, type::poly, type_of(L, index), "value does not fit any type present in the variant");
return false;
}
template <std::size_t I, typename Handler>
static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) {
typedef std::variant_alternative_t<I - 1, V> T;
if (stack::check<T>(L, index, no_panic, tracking)) {
return true;
}
return is_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return is_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking);
}
};
#endif // SOL_STD_VARIANT
#endif // SOL_CXX17_FEATURES
}
} // namespace sol::stack
#include "stack_check_unqualified.hpp"
#include "stack_check_qualified.hpp"
#endif // SOL_STACK_CHECK_HPP

View File

@ -24,170 +24,7 @@
#ifndef SOL_STACK_CHECK_GET_HPP
#define SOL_STACK_CHECK_GET_HPP
#include "stack_core.hpp"
#include "stack_get.hpp"
#include "stack_check.hpp"
#include "optional.hpp"
#include <cstdlib>
#include <cmath>
namespace sol {
namespace stack {
template <typename T, typename>
struct check_getter {
typedef decltype(stack_detail::unchecked_get<T>(nullptr, 0, std::declval<record&>())) R;
template <typename Handler>
static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {
if (!check<T>(L, index, std::forward<Handler>(handler))) {
tracking.use(static_cast<int>(!lua_isnone(L, index)));
return nullopt;
}
return stack_detail::unchecked_get<T>(L, index, tracking);
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<is_lua_reference<T>::value>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
// actually check if it's none here, otherwise
// we'll have a none object inside an optional!
bool success = stack::check<T>(L, index, no_panic);
if (!success) {
// expected type, actual type
tracking.use(static_cast<int>(success));
handler(L, index, type::poly, type_of(L, index), "");
return nullopt;
}
return stack_detail::unchecked_get<T>(L, index, tracking);
}
};
template <typename T>
struct check_getter<optional<T>> {
template <typename Handler>
static decltype(auto) get(lua_State* L, int index, Handler&&, record& tracking) {
return check_get<T>(L, index, no_panic, tracking);
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && lua_type_of<T>::value == type::number>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
#if SOL_LUA_VERSION >= 503
if (lua_isinteger(L, index) != 0) {
tracking.use(1);
return static_cast<T>(lua_tointeger(L, index));
}
#endif
int isnum = 0;
const lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum != 0) {
#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
const auto integer_value = llround(value);
if (static_cast<lua_Number>(integer_value) == value) {
tracking.use(1);
return static_cast<T>(integer_value);
}
#else
tracking.use(1);
return static_cast<T>(value);
#endif
}
const type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t, "not an integer");
return nullopt;
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_enum<T>::value && !meta::any_same<T, meta_function, type>::value>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
int isnum = 0;
lua_Integer value = lua_tointegerx(L, index, &isnum);
if (isnum == 0) {
type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t, "not a valid enumeration value");
return nullopt;
}
tracking.use(1);
return static_cast<T>(value);
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
int isnum = 0;
lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum == 0) {
type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t, "not a valid floating point number");
return nullopt;
}
tracking.use(1);
return static_cast<T>(value);
}
};
template <typename T>
struct getter<optional<T>> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return check_get<T>(L, index, no_panic, tracking);
}
};
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn>
struct check_getter<std::variant<Tn...>> {
typedef std::variant<Tn...> V;
typedef std::variant_size<V> V_size;
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
template <typename Handler>
static optional<V> get_empty(std::true_type, lua_State*, int, Handler&&, record&) {
return nullopt;
}
template <typename Handler>
static optional<V> get_empty(std::false_type, lua_State* L, int index, Handler&& handler, record&) {
// This should never be reached...
// please check your code and understand what you did to bring yourself here
// maybe file a bug report, or 5
handler(L, index, type::poly, type_of(L, index), "this variant code should never be reached: if it has, you have done something so terribly wrong");
return nullopt;
}
template <typename Handler>
static optional<V> get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) {
return get_empty(V_is_empty(), L, index, std::forward<Handler>(handler), tracking);
}
template <std::size_t I, typename Handler>
static optional<V> get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) {
typedef std::variant_alternative_t<I - 1, V> T;
if (stack::check<T>(L, index, no_panic, tracking)) {
return V(std::in_place_index<I - 1>, stack::get<T>(L, index));
}
return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
static optional<V> get(lua_State* L, int index, Handler&& handler, record& tracking) {
return get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking);
}
};
#endif // SOL_STD_VARIANT
#endif // SOL_CXX17_FEATURES
}
} // namespace sol::stack
#include "stack_check_get_unqualified.hpp"
#include "stack_check_get_qualified.hpp"
#endif // SOL_STACK_CHECK_GET_HPP

View File

@ -0,0 +1,52 @@
// sol2
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_CHECK_QUALIFIED_GET_HPP
#define SOL_STACK_CHECK_QUALIFIED_GET_HPP
#include "stack_core.hpp"
#include "stack_get.hpp"
#include "stack_check.hpp"
#include "optional.hpp"
#include <cstdlib>
#include <cmath>
namespace sol {
namespace stack {
template <typename T, typename C>
struct qualified_check_getter {
typedef decltype(stack_detail::unchecked_get<T>(nullptr, 0, std::declval<record&>())) R;
template <typename Handler>
static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {
if (!check<T>(L, index, std::forward<Handler>(handler))) {
tracking.use(static_cast<int>(!lua_isnone(L, index)));
return nullopt;
}
return stack_detail::unchecked_get<T>(L, index, tracking);
}
};
}
} // namespace sol::stack
#endif // SOL_STACK_CHECK_QUALIFIED_GET_HPP

View File

@ -0,0 +1,193 @@
// sol2
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_CHECK_UNQUALIFIED_GET_HPP
#define SOL_STACK_CHECK_UNQUALIFIED_GET_HPP
#include "stack_core.hpp"
#include "stack_get.hpp"
#include "stack_check.hpp"
#include "optional.hpp"
#include <cstdlib>
#include <cmath>
namespace sol {
namespace stack {
template <typename T, typename>
struct check_getter {
typedef decltype(stack_detail::unchecked_unqualified_get<T>(nullptr, 0, std::declval<record&>())) R;
template <typename Handler>
static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {
if (!unqualified_check<T>(L, index, std::forward<Handler>(handler))) {
tracking.use(static_cast<int>(!lua_isnone(L, index)));
return nullopt;
}
return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<is_lua_reference<T>::value>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
// actually check if it's none here, otherwise
// we'll have a none object inside an optional!
bool success = stack::check<T>(L, index, no_panic);
if (!success) {
// expected type, actual type
tracking.use(static_cast<int>(success));
handler(L, index, type::poly, type_of(L, index), "");
return nullopt;
}
return stack_detail::unchecked_get<T>(L, index, tracking);
}
};
template <typename T>
struct check_getter<optional<T>> {
template <typename Handler>
static decltype(auto) get(lua_State* L, int index, Handler&&, record& tracking) {
return check_get<T>(L, index, no_panic, tracking);
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && lua_type_of<T>::value == type::number>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
#if SOL_LUA_VERSION >= 503
if (lua_isinteger(L, index) != 0) {
tracking.use(1);
return static_cast<T>(lua_tointeger(L, index));
}
#endif
int isnum = 0;
const lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum != 0) {
#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
const auto integer_value = llround(value);
if (static_cast<lua_Number>(integer_value) == value) {
tracking.use(1);
return static_cast<T>(integer_value);
}
#else
tracking.use(1);
return static_cast<T>(value);
#endif
}
const type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t, "not an integer");
return nullopt;
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_enum<T>::value && !meta::any_same<T, meta_function, type>::value>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
int isnum = 0;
lua_Integer value = lua_tointegerx(L, index, &isnum);
if (isnum == 0) {
type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t, "not a valid enumeration value");
return nullopt;
}
tracking.use(1);
return static_cast<T>(value);
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
int isnum = 0;
lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum == 0) {
type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t, "not a valid floating point number");
return nullopt;
}
tracking.use(1);
return static_cast<T>(value);
}
};
template <typename T>
struct getter<optional<T>> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return check_get<T>(L, index, no_panic, tracking);
}
};
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn>
struct check_getter<std::variant<Tn...>> {
typedef std::variant<Tn...> V;
typedef std::variant_size<V> V_size;
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
template <typename Handler>
static optional<V> get_empty(std::true_type, lua_State*, int, Handler&&, record&) {
return nullopt;
}
template <typename Handler>
static optional<V> get_empty(std::false_type, lua_State* L, int index, Handler&& handler, record&) {
// This should never be reached...
// please check your code and understand what you did to bring yourself here
// maybe file a bug report, or 5
handler(L, index, type::poly, type_of(L, index), "this variant code should never be reached: if it has, you have done something so terribly wrong");
return nullopt;
}
template <typename Handler>
static optional<V> get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) {
return get_empty(V_is_empty(), L, index, std::forward<Handler>(handler), tracking);
}
template <std::size_t I, typename Handler>
static optional<V> get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) {
typedef std::variant_alternative_t<I - 1, V> T;
if (stack::check<T>(L, index, no_panic, tracking)) {
return V(std::in_place_index<I - 1>, stack::get<T>(L, index));
}
return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
static optional<V> get(lua_State* L, int index, Handler&& handler, record& tracking) {
return get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking);
}
};
#endif // SOL_STD_VARIANT
#endif // SOL_CXX17_FEATURES
}
} // namespace sol::stack
#endif // SOL_STACK_CHECK_UNQUALIFIED_GET_HPP

View File

@ -0,0 +1,100 @@
// sol2
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_CHECK_QUALIFIED_HPP
#define SOL_STACK_CHECK_QUALIFIED_HPP
#include "stack_check_unqualified.hpp"
namespace sol {
namespace stack {
#if 0
template <typename X>
struct qualified_checker<X, type::userdata, std::enable_if_t<is_unique_usertype<X>::value && !std::is_reference<X>::value>> {
typedef unique_usertype_traits<meta::unqualified_t<X>> u_traits;
typedef typename u_traits::type T;
typedef typename u_traits::base_id base_id;
template <typename Handler>
static bool check(std::false_type, lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
static bool check(std::true_type, lua_State* L, int index, Handler&& handler, record& tracking) {
// we have a unique pointer type that can be
// rebound to a base/derived type
const type indextype = type_of(L, index);
tracking.use(1);
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype, "value is not a userdata");
return false;
}
if (lua_getmetatable(L, index) == 0) {
return true;
}
int metatableindex = lua_gettop(L);
void* basecastdata = lua_touserdata(L, index);
void* memory = detail::align_usertype_unique_destructor(basecastdata);
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
if (&detail::usertype_unique_alloc_destroy<T, X> == pdx) {
return true;
}
if (detail::has_derived<T>::value) {
memory = detail::align_usertype_unique_cast<true>(memory);
detail::inheritance_unique_cast_function ic = reinterpret_cast<detail::inheritance_unique_cast_function>(memory);
string_view ti = usertype_traits<T>::qualified_name();
string_view rebind_ti = usertype_traits<base_id>::qualified_name();
if (ic(nullptr, basecastdata, ti, rebind_ti)) {
lua_pop(L, 1);
}
}
handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
return false;
}
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return check(meta::neg<std::is_void<typename u_traits::base_id>>(), L, index, std::forward<Handler>(handler), tracking);
}
};
#endif // Not implemented right now...
template <typename X>
struct qualified_checker<X, type::userdata, std::enable_if_t<is_container<meta::unqualified_t<X>>::value && !std::is_reference<X>::value>> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
if (type_of(L, index) == type::userdata) {
return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking);
}
else {
return stack::unqualified_check<nested<X>>(L, index, std::forward<Handler>(handler), tracking);
}
}
};
}
} // namespace sol::stack
#endif // SOL_STACK_CHECK_HPP

View File

@ -0,0 +1,648 @@
// sol2
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_CHECK_UNQUALIFIED_HPP
#define SOL_STACK_CHECK_UNQUALIFIED_HPP
#include "stack_core.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include <memory>
#include <functional>
#include <utility>
#include <cmath>
#ifdef SOL_CXX17_FEATURES
#ifdef SOL_STD_VARIANT
#include <variant>
#endif // SOL_STD_VARIANT
#endif // SOL_CXX17_FEATURES
namespace sol {
namespace stack {
namespace stack_detail {
template <typename T, bool poptable = true>
inline bool check_metatable(lua_State* L, int index = -2) {
const auto& metakey = usertype_traits<T>::metatable();
luaL_getmetatable(L, &metakey[0]);
const type expectedmetatabletype = static_cast<type>(lua_type(L, -1));
if (expectedmetatabletype != type::lua_nil) {
if (lua_rawequal(L, -1, index) == 1) {
lua_pop(L, 1 + static_cast<int>(poptable));
return true;
}
}
lua_pop(L, 1);
return false;
}
template <type expected, int (*check_func)(lua_State*, int)>
struct basic_check {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
bool success = check_func(L, index) == 1;
if (!success) {
// expected type, actual type
handler(L, index, expected, type_of(L, index), "");
}
return success;
}
};
} // namespace stack_detail
template <typename T, typename>
struct userdata_checker {
template <typename Handler>
static bool check(lua_State*, int, type, Handler&&, record&) {
return false;
}
};
template <typename T, type expected, typename>
struct checker {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
const type indextype = type_of(L, index);
bool success = expected == indextype;
if (!success) {
// expected type, actual type, message
handler(L, index, expected, indextype, "");
}
return success;
}
};
template <typename T, type expected, typename C>
struct qualified_checker : checker<meta::unqualified_t<T>, lua_type_of<meta::unqualified_t<T>>::value, C> {};
template <typename T>
struct checker<T, type::number, std::enable_if_t<std::is_integral<T>::value>> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
#if SOL_LUA_VERSION >= 503
#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
int isnum = 0;
lua_tointegerx(L, index, &isnum);
const bool success = isnum != 0;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
}
#elif (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
// this check is precise, does not convert
if (lua_isinteger(L, index) == 1) {
return true;
}
const bool success = false;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric (integral) type");
}
#else
type t = type_of(L, index);
const bool success = t == type::number;
#endif // If numbers are enabled, use the imprecise check
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type");
}
return success;
#else
#if !defined(SOL_STRINGS_ARE_NUMBERS) || !SOL_STRINGS_ARE_NUMBERS
// must pre-check, because it will convert
type t = type_of(L, index);
if (t != type::number) {
// expected type, actual type
handler(L, index, type::number, t, "not a numeric type");
return false;
}
#endif // Do not allow strings to be numbers
int isnum = 0;
const lua_Number v = lua_tonumberx(L, index, &isnum);
const bool success = isnum != 0
#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
&& static_cast<lua_Number>(llround(v)) == v
#endif // Safe numerics and number precision checking
;
if (!success) {
// expected type, actual type
#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
handler(L, index, type::number, t, "not a numeric type");
#else
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
#endif
}
return success;
#endif // Lua Version 5.3 versus others
}
};
template <typename T>
struct checker<T, type::number, std::enable_if_t<std::is_floating_point<T>::value>> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS
bool success = lua_isnumber(L, index) == 1;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
}
return success;
#else
type t = type_of(L, index);
bool success = t == type::number;
if (!success) {
// expected type, actual type
handler(L, index, type::number, t, "not a numeric type");
}
return success;
#endif // Strings are Numbers
}
};
template <type expected, typename C>
struct checker<lua_nil_t, expected, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
bool success = lua_isnil(L, index);
if (success) {
tracking.use(1);
return success;
}
tracking.use(0);
success = lua_isnone(L, index);
if (!success) {
// expected type, actual type
handler(L, index, expected, type_of(L, index), "");
}
return success;
}
};
template <typename C>
struct checker<detail::non_lua_nil_t, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return !stack::unqualified_check<lua_nil_t>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <type expected, typename C>
struct checker<nullopt_t, expected, C> : checker<lua_nil_t> {};
template <typename C>
struct checker<this_state, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct checker<this_main_state, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct checker<this_environment, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct checker<variadic_args, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C>
struct checker<type, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename T, typename C>
struct checker<T, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
bool success = is_lua_reference<T>::value || !lua_isnone(L, index);
if (!success) {
// expected type, actual type
handler(L, index, type::poly, type_of(L, index), "");
}
return success;
}
};
template <typename T, typename C>
struct checker<T, type::lightuserdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
bool success = t == type::userdata || t == type::lightuserdata;
if (!success) {
// expected type, actual type
handler(L, index, type::lightuserdata, t, "");
}
return success;
}
};
template <typename C>
struct checker<userdata_value, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
bool success = t == type::userdata;
if (!success) {
// expected type, actual type
handler(L, index, type::userdata, t, "");
}
return success;
}
};
template <typename B, typename C>
struct checker<basic_userdata<B>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::check<userdata_value>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T, typename C>
struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {};
template <typename T, typename C>
struct checker<non_null<T>, type::userdata, C> : checker<T, lua_type_of<T>::value, C> {};
template <typename C>
struct checker<lua_CFunction, type::function, C> : stack_detail::basic_check<type::function, lua_iscfunction> {};
template <typename C>
struct checker<std::remove_pointer_t<lua_CFunction>, type::function, C> : checker<lua_CFunction, type::function, C> {};
template <typename C>
struct checker<c_closure, type::function, C> : checker<lua_CFunction, type::function, C> {};
template <typename T, typename C>
struct checker<T, type::function, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::lua_nil || t == type::none || t == type::function) {
// allow for lua_nil to be returned
return true;
}
if (t != type::userdata && t != type::table) {
handler(L, index, type::function, t, "must be a function or table or a userdata");
return false;
}
// Do advanced check for call-style userdata?
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, "value is not a function and does not have overriden metatable");
return false;
}
if (lua_isnoneornil(L, -1)) {
lua_pop(L, 1);
handler(L, index, type::function, t, "value is not a function and does not have valid metatable");
return false;
}
lua_getfield(L, -1, &callkey[0]);
if (lua_isnoneornil(L, -1)) {
lua_pop(L, 2);
handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type");
return false;
}
// has call, is definitely a function
lua_pop(L, 2);
return true;
}
};
template <typename T, typename C>
struct checker<T, type::table, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::table) {
return true;
}
if (t != type::userdata) {
handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one");
return false;
}
return true;
}
};
template <type expected, typename C>
struct checker<metatable_t, expected, C> {
template <typename Handler>
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::lua_nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, expected, t, "value does not have a valid metatable");
return false;
}
return true;
}
};
template <typename C>
struct checker<env_t, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
type t = type_of(L, index);
if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) {
return true;
}
handler(L, index, type::table, t, "value cannot not have a valid environment");
return true;
}
};
template <typename E, typename C>
struct checker<basic_environment<E>, type::poly, C> {
template <typename Handler>
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::lua_nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, type::table, t, "value does not have a valid metatable");
return false;
}
return true;
}
};
template <typename T, typename C>
struct checker<detail::as_value_tag<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
return check(types<T>(), L, index, indextype, handler, tracking);
}
template <typename U, typename Handler>
static bool check(types<U>, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
#if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP
userdata_checker<extensible<T>> uc;
(void)uc;
if (uc.check(L, index, indextype, handler, tracking)) {
return true;
}
#endif // interop extensibility
tracking.use(1);
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype, "value is not a valid userdata");
return false;
}
if (meta::any<std::is_same<T, lightuserdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value)
return true;
if (lua_getmetatable(L, index) == 0) {
return true;
}
int metatableindex = lua_gettop(L);
if (stack_detail::check_metatable<U>(L, metatableindex))
return true;
if (stack_detail::check_metatable<U*>(L, metatableindex))
return true;
if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex))
return true;
if (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex))
return true;
bool success = false;
if (detail::has_derived<T>::value) {
auto pn = stack::pop_n(L, 1);
lua_pushstring(L, &detail::base_class_check_key()[0]);
lua_rawget(L, metatableindex);
if (type_of(L, -1) != type::lua_nil) {
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_check_function ic = reinterpret_cast<detail::inheritance_check_function>(basecastdata);
success = ic(usertype_traits<T>::qualified_name());
}
}
if (!success) {
lua_pop(L, 1);
handler(L, index, type::userdata, indextype, "value at this index does not properly reflect the desired type");
return false;
}
lua_pop(L, 1);
return true;
}
};
template <typename T, typename C>
struct checker<detail::as_pointer_tag<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
if (indextype == type::lua_nil) {
tracking.use(1);
return true;
}
return stack_detail::check_usertype<T>(std::false_type(), L, index, indextype, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
return check(L, index, handler, indextype, tracking);
}
};
template <typename T, typename C>
struct checker<T, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T, typename C>
struct checker<T*, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return check_usertype<T*>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename X>
struct checker<X, type::userdata, std::enable_if_t<is_unique_usertype<X>::value>> {
typedef typename unique_usertype_traits<X>::type T;
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
tracking.use(1);
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype, "value is not a userdata");
return false;
}
if (lua_getmetatable(L, index) == 0) {
return true;
}
int metatableindex = lua_gettop(L);
if (stack_detail::check_metatable<detail::unique_usertype<T>>(L, metatableindex)) {
void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique_destructor(memory);
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
bool success = &detail::usertype_unique_alloc_destroy<T, X> == pdx;
if (!success) {
memory = detail::align_usertype_unique_tag<true>(memory);
#if 0
// New version
#else
const char*& name_tag = *static_cast<const char**>(memory);
success = usertype_traits<X>::qualified_name() == name_tag;
#endif
if (!success) {
handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
}
}
return success;
}
lua_pop(L, 1);
handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)");
return false;
}
};
template <typename T, typename C>
struct checker<std::reference_wrapper<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::check<T>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename... Args, typename C>
struct checker<std::tuple<Args...>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename A, typename B, typename C>
struct checker<std::pair<A, B>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T, typename C>
struct checker<optional<T>, type::poly, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&&, record& tracking) {
type t = type_of(L, index);
if (t == type::none) {
tracking.use(0);
return true;
}
if (t == type::lua_nil) {
tracking.use(1);
return true;
}
return stack::check<T>(L, index, no_panic, tracking);
}
};
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn, typename C>
struct checker<std::variant<Tn...>, type::poly, C> {
typedef std::variant<Tn...> V;
typedef std::variant_size<V> V_size;
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
template <typename Handler>
static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) {
if (V_is_empty::value && lua_isnone(L, index)) {
return true;
}
tracking.use(1);
handler(L, index, type::poly, type_of(L, index), "value does not fit any type present in the variant");
return false;
}
template <std::size_t I, typename Handler>
static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) {
typedef std::variant_alternative_t<I - 1, V> T;
if (stack::check<T>(L, index, no_panic, tracking)) {
return true;
}
return is_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return is_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking);
}
};
#endif // SOL_STD_VARIANT
#endif // SOL_CXX17_FEATURES
}
} // namespace sol::stack
#endif // SOL_STACK_CHECK_UNQUALIFIED_HPP

View File

@ -25,6 +25,7 @@
#define SOL_STACK_CORE_HPP
#include "types.hpp"
#include "inheritance.hpp"
#include "error_handler.hpp"
#include "reference.hpp"
#include "stack_reference.hpp"
@ -51,6 +52,11 @@ namespace sol {
struct as_table_tag {};
using unique_destructor = void (*)(void*);
#if 0
using unique_tag = detail::inheritance_unique_cast_function;
#else
using unique_tag = const char*;
#endif
inline void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space, std::size_t& required_space) {
// this handels arbitrary alignments...
@ -102,6 +108,7 @@ namespace sol {
return align(std::alignment_of<void*>::value, sizeof(void*), ptr, space);
}
template <bool pre_aligned = false>
inline void* align_usertype_unique_destructor(void* ptr) {
typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
@ -111,15 +118,37 @@ namespace sol {
#endif
>
use_align;
if (!pre_aligned) {
ptr = align_usertype_pointer(ptr);
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(void*));
}
if (!use_align::value) {
return static_cast<void*>(static_cast<void**>(ptr) + 1);
}
ptr = align_usertype_pointer(ptr);
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(void*));
std::size_t space = (std::numeric_limits<std::size_t>::max)();
return align(std::alignment_of<unique_destructor>::value, sizeof(unique_destructor), ptr, space);
}
template <bool pre_aligned = false>
inline void* align_usertype_unique_tag(void* ptr) {
typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
false
#else
(std::alignment_of<unique_tag>::value > 1)
#endif
>
use_align;
if (!pre_aligned) {
ptr = align_usertype_unique_destructor(ptr);
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_destructor));
}
if (!use_align::value) {
return ptr;
}
std::size_t space = (std::numeric_limits<std::size_t>::max)();
return align(std::alignment_of<unique_tag>::value, sizeof(unique_tag), ptr, space);
}
template <typename T, bool pre_aligned = false>
inline void* align_usertype_unique(void* ptr) {
typedef std::integral_constant<bool,
@ -131,8 +160,8 @@ namespace sol {
>
use_align;
if (!pre_aligned) {
ptr = align_usertype_unique_destructor(ptr);
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_destructor));
ptr = align_usertype_unique_tag(ptr);
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_tag));
}
if (!use_align::value) {
return ptr;
@ -276,29 +305,31 @@ namespace sol {
}
template <typename T, typename Real>
inline Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx) {
inline Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx, unique_tag*& id) {
typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
false
#else
(std::alignment_of<T*>::value > 1 || std::alignment_of<unique_destructor>::value > 1 || std::alignment_of<Real>::value > 1)
(std::alignment_of<T*>::value > 1 || std::alignment_of<unique_tag>::value > 1 || std::alignment_of<unique_destructor>::value > 1 || std::alignment_of<Real>::value > 1)
#endif
>
use_align;
if (!use_align::value) {
pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(detail::unique_destructor) + sizeof(Real)));
pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(detail::unique_destructor) + sizeof(unique_tag) + sizeof(Real)));
dx = static_cast<detail::unique_destructor*>(static_cast<void*>(pref + 1));
Real* mem = static_cast<Real*>(static_cast<void*>(dx + 1));
id = static_cast<unique_tag*>(static_cast<void*>(dx + 1));
Real* mem = static_cast<Real*>(static_cast<void*>(id + 1));
return mem;
}
static const std::size_t initial_size = aligned_space_for<T*, unique_destructor, Real>(nullptr);
static const std::size_t misaligned_size = aligned_space_for<T*, unique_destructor, Real>(reinterpret_cast<void*>(0x1));
static const std::size_t initial_size = aligned_space_for<T*, unique_destructor, unique_tag, Real>(nullptr);
static const std::size_t misaligned_size = aligned_space_for<T*, unique_destructor, unique_tag, Real>(reinterpret_cast<void*>(0x1));
void* pointer_adjusted;
void* dx_adjusted;
void* id_adjusted;
void* data_adjusted;
auto attempt_alloc = [](lua_State* L, std::size_t allocated_size, void*& pointer_adjusted, void*& dx_adjusted, void*& data_adjusted) -> bool {
auto attempt_alloc = [](lua_State* L, std::size_t allocated_size, void*& pointer_adjusted, void*& dx_adjusted, void*& id_adjusted, void*& data_adjusted) -> bool {
void* adjusted = lua_newuserdata(L, allocated_size);
pointer_adjusted = align(std::alignment_of<T*>::value, sizeof(T*), adjusted, allocated_size);
if (pointer_adjusted == nullptr) {
@ -306,6 +337,7 @@ namespace sol {
return false;
}
allocated_size -= sizeof(T*);
adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + sizeof(T*));
dx_adjusted = align(std::alignment_of<unique_destructor>::value, sizeof(unique_destructor), adjusted, allocated_size);
if (dx_adjusted == nullptr) {
@ -313,7 +345,17 @@ namespace sol {
return false;
}
allocated_size -= sizeof(unique_destructor);
adjusted = static_cast<void*>(static_cast<char*>(dx_adjusted) + sizeof(unique_destructor));
id_adjusted = align(std::alignment_of<unique_tag>::value, sizeof(unique_tag), adjusted, allocated_size);
if (id_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
allocated_size -= sizeof(unique_tag);
adjusted = static_cast<void*>(static_cast<char*>(id_adjusted) + sizeof(unique_tag));
data_adjusted = align(std::alignment_of<Real>::value, sizeof(Real), adjusted, allocated_size);
if (data_adjusted == nullptr) {
lua_pop(L, 1);
@ -321,23 +363,24 @@ namespace sol {
}
return true;
};
bool result = attempt_alloc(L, initial_size, pointer_adjusted, dx_adjusted, data_adjusted);
bool result = attempt_alloc(L, initial_size, pointer_adjusted, dx_adjusted, id_adjusted, data_adjusted);
if (!result) {
// we're likely to get something that fails to perform the proper allocation a second time,
// so we use the suggested_new_size bump to help us out here
pointer_adjusted = nullptr;
dx_adjusted = nullptr;
id_adjusted = nullptr;
data_adjusted = nullptr;
result = attempt_alloc(L, misaligned_size, pointer_adjusted, dx_adjusted, data_adjusted);
result = attempt_alloc(L, misaligned_size, pointer_adjusted, dx_adjusted, id_adjusted, data_adjusted);
if (!result) {
if (pointer_adjusted == nullptr) {
luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str());
}
else if (dx_adjusted == nullptr) {
luaL_error(L, "aligned allocation of userdata block (deleter section) for '%s' failed", detail::demangle<Real>().c_str());
luaL_error(L, "aligned allocation of userdata block (deleter section) for '%s' failed", detail::demangle<T>().c_str());
}
else {
luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<Real>().c_str());
luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<T>().c_str());
}
return nullptr;
}
@ -345,6 +388,7 @@ namespace sol {
pref = static_cast<T**>(pointer_adjusted);
dx = static_cast<detail::unique_destructor*>(dx_adjusted);
id = static_cast<unique_tag*>(id_adjusted);
Real* mem = static_cast<Real*>(data_adjusted);
return mem;
}
@ -401,6 +445,8 @@ namespace sol {
memory = align_usertype_unique_destructor(memory);
unique_destructor& dx = *static_cast<unique_destructor*>(memory);
memory = static_cast<void*>(static_cast<char*>(memory) + sizeof(unique_destructor));
memory = align_usertype_unique_tag<true>(memory);
memory = static_cast<void*>(static_cast<char*>(memory) + sizeof(unique_tag));
(dx)(memory);
return 0;
}
@ -457,6 +503,8 @@ namespace sol {
template <typename T, typename = void>
struct getter;
template <typename T, typename = void>
struct qualified_getter;
template <typename T, typename = void>
struct userdata_getter;
template <typename T, typename = void>
struct popper;
@ -464,10 +512,14 @@ namespace sol {
struct pusher;
template <typename T, type = lua_type_of<T>::value, typename = void>
struct checker;
template <typename T, type = lua_type_of<T>::value, typename = void>
struct qualified_checker;
template <typename T, typename = void>
struct userdata_checker;
template <typename T, typename = void>
struct check_getter;
template <typename T, typename = void>
struct qualified_check_getter;
struct probe {
bool success;
@ -535,9 +587,17 @@ namespace sol {
return static_cast<int>(32);
}
template <typename T>
inline decltype(auto) unchecked_unqualified_get(lua_State* L, int index, record& tracking) {
typedef meta::unqualified_t<T> Tu;
getter<Tu> g{};
(void)g;
return g.get(L, index, tracking);
}
template <typename T>
inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) {
getter<meta::unqualified_t<T>> g{};
qualified_getter<T> g{};
(void)g;
return g.get(L, index, tracking);
}
@ -550,7 +610,9 @@ namespace sol {
meta::neg<is_lua_primitive<meta::unqualified_t<T>>>,
meta::neg<is_unique_usertype<meta::unqualified_t<T>>>>
use_reference_tag;
return pusher<std::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
pusher<std::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>> p{};
(void)p;
return p.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
template <typename T, typename Handler>
@ -646,8 +708,7 @@ namespace sol {
template <typename T, typename Handler>
bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
typedef meta::unqualified_t<T> Tu;
checker<Tu> c;
qualified_checker<T> c;
// VC++ has a bad warning here: shut it up
(void)c;
return c.check(L, index, std::forward<Handler>(handler), tracking);
@ -665,6 +726,27 @@ namespace sol {
return check<T>(L, index, handler);
}
template <typename T, typename Handler>
bool unqualified_check(lua_State* L, int index, Handler&& handler, record& tracking) {
typedef meta::unqualified_t<T> Tu;
checker<Tu> c;
// VC++ has a bad warning here: shut it up
(void)c;
return c.check(L, index, std::forward<Handler>(handler), tracking);
}
template <typename T, typename Handler>
bool unqualified_check(lua_State* L, int index, Handler&& handler) {
record tracking{};
return unqualified_check<T>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename T>
bool unqualified_check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = no_panic;
return unqualified_check<T>(L, index, handler);
}
template <typename T, typename Handler>
bool check_usertype(lua_State* L, int index, Handler&& handler, record& tracking) {
type indextype = type_of(L, index);
@ -683,10 +765,28 @@ namespace sol {
return check_usertype<T>(L, index, handler);
}
template <typename T, typename Handler>
inline decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
check_getter<T> cg{};
(void)cg;
return cg.get(L, index, std::forward<Handler>(handler), tracking);
}
template <typename T, typename Handler>
inline decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler) {
record tracking{};
return unqualified_check_get<T>(L, index, handler, tracking);
}
template <typename T>
inline decltype(auto) unqualified_check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = no_panic;
return unqualified_check_get<T>(L, index, handler);
}
template <typename T, typename Handler>
inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
typedef meta::unqualified_t<T> Tu;
check_getter<Tu> cg{};
qualified_check_getter<T> cg{};
(void)cg;
return cg.get(L, index, std::forward<Handler>(handler), tracking);
}
@ -706,6 +806,17 @@ namespace sol {
namespace stack_detail {
#if defined(SOL_SAFE_GETTER) && SOL_SAFE_GETTER
template <typename T>
inline auto tagged_unqualified_get(types<T>, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {
auto op = unqualified_check_get<T>(L, index, type_panic_c_str, tracking);
return *std::move(op);
}
template <typename T>
inline decltype(auto) tagged_unqualified_get(types<optional<T>>, lua_State* L, int index, record& tracking) {
return stack_detail::unchecked_unqualified_get<optional<T>>(L, index, tracking);
}
template <typename T>
inline auto tagged_get(types<T>, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {
auto op = check_get<T>(L, index, type_panic_c_str, tracking);
@ -717,6 +828,11 @@ namespace sol {
return stack_detail::unchecked_get<optional<T>>(L, index, tracking);
}
#else
template <typename T>
inline decltype(auto) tagged_unqualified_get(types<T>, lua_State* L, int index, record& tracking) {
return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
}
template <typename T>
inline decltype(auto) tagged_get(types<T>, lua_State* L, int index, record& tracking) {
return stack_detail::unchecked_get<T>(L, index, tracking);
@ -795,6 +911,17 @@ namespace sol {
return get_usertype<T>(L, index, tracking);
}
template <typename T>
inline decltype(auto) unqualified_get(lua_State* L, int index, record& tracking) {
return stack_detail::tagged_unqualified_get(types<T>(), L, index, tracking);
}
template <typename T>
inline decltype(auto) unqualified_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
record tracking{};
return unqualified_get<T>(L, index, tracking);
}
template <typename T>
inline decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack_detail::tagged_get(types<T>(), L, index, tracking);

View File

@ -24,864 +24,7 @@
#ifndef SOL_STACK_GET_HPP
#define SOL_STACK_GET_HPP
#include "stack_core.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include "overload.hpp"
#include "error.hpp"
#include "unicode.hpp"
#include <memory>
#include <functional>
#include <utility>
#include <cstdlib>
#include <cmath>
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#include <string_view>
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
#include <variant>
#endif // Apple clang screwed up
#endif // C++17
namespace sol {
namespace stack {
template <typename U>
struct userdata_getter<U> {
typedef stack_detail::strip_extensible_t<U> T;
static std::pair<bool, T*> get(lua_State*, int, void*, record&) {
return { false, nullptr };
}
};
template <typename T, typename>
struct getter {
static T& get(lua_State* L, int index, record& tracking) {
return getter<detail::as_value_tag<T>>{}.get(L, index, tracking);
}
};
template <typename T>
struct getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return static_cast<T>(lua_tonumber(L, index));
}
};
template <typename T>
struct getter<T, std::enable_if_t<std::is_integral<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
tracking.use(1);
#if SOL_LUA_VERSION >= 503
if (lua_isinteger(L, index) != 0) {
return static_cast<T>(lua_tointeger(L, index));
}
#endif
return static_cast<T>(llround(lua_tonumber(L, index)));
}
};
template <typename T>
struct getter<T, std::enable_if_t<std::is_enum<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return static_cast<T>(lua_tointegerx(L, index, nullptr));
}
};
template <typename T>
struct getter<as_table_t<T>> {
typedef meta::unqualified_t<T> Tu;
template <typename V>
static void push_back_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) {
arr.push_back(stack::get<V>(L, -lua_size<V>::value));
}
template <typename V>
static void push_back_at_end(std::false_type, types<V> t, lua_State* L, T& arr, std::size_t idx) {
insert_at_end(meta::has_insert<Tu>(), t, L, arr, idx);
}
template <typename V>
static void insert_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) {
using std::end;
arr.insert(end(arr), stack::get<V>(L, -lua_size<V>::value));
}
template <typename V>
static void insert_at_end(std::false_type, types<V>, lua_State* L, T& arr, std::size_t idx) {
arr[idx] = stack::get<V>(L, -lua_size<V>::value);
}
static T get(lua_State* L, int relindex, record& tracking) {
return get(meta::has_key_value_pair<meta::unqualified_t<T>>(), L, relindex, tracking);
}
static T get(std::false_type, lua_State* L, int relindex, record& tracking) {
typedef typename T::value_type V;
return get(types<V>(), L, relindex, tracking);
}
template <typename V>
static T get(types<V> t, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
int index = lua_absindex(L, relindex);
T arr;
std::size_t idx = 0;
#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<V>::value, lua_pop(L, lua_size<V>::value)) {
if (idx >= arr.max_size()) {
return arr;
}
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
type vt = static_cast<type>(lua_geti(L, index, i + vi));
isnil = vt == type::lua_nil;
if (isnil) {
if (i == 0) {
break;
}
lua_pop(L, (vi + 1));
return arr;
}
}
if (isnil)
continue;
push_back_at_end(meta::has_push_back<Tu>(), t, L, arr, idx);
++idx;
}
#else
// Zzzz slower but necessary thanks to the lower version API and missing functions qq
for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {
if (idx >= arr.max_size()) {
return arr;
}
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
lua_pushinteger(L, i);
lua_gettable(L, index);
type vt = type_of(L, -1);
isnil = vt == type::lua_nil;
if (isnil) {
if (i == 0) {
break;
}
lua_pop(L, (vi + 1));
return arr;
}
}
if (isnil)
continue;
push_back_at_end(meta::has_push_back<Tu>(), t, L, arr, idx);
++idx;
}
#endif
return arr;
}
static T get(std::true_type, 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;
return get(types<K, V>(), L, index, tracking);
}
template <typename K, typename V>
static T get(types<K, V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
T associative;
int index = lua_absindex(L, relindex);
lua_pushnil(L);
while (lua_next(L, index) != 0) {
decltype(auto) key = stack::check_get<K>(L, -2);
if (!key) {
lua_pop(L, 1);
continue;
}
associative.emplace(std::forward<decltype(*key)>(*key), stack::get<V>(L, -1));
lua_pop(L, 1);
}
return associative;
}
};
template <typename T, typename Al>
struct getter<as_table_t<std::forward_list<T, Al>>> {
typedef std::forward_list<T, Al> C;
static C get(lua_State* L, int relindex, record& tracking) {
return get(meta::has_key_value_pair<C>(), L, relindex, tracking);
}
static C get(std::true_type, 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;
return get(types<K, V>(), L, index, tracking);
}
static C get(std::false_type, lua_State* L, int relindex, record& tracking) {
typedef typename C::value_type V;
return get(types<V>(), L, relindex, tracking);
}
template <typename V>
static C get(types<V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
int index = lua_absindex(L, relindex);
C arr;
auto at = arr.cbefore_begin();
std::size_t idx = 0;
#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<V>::value, lua_pop(L, lua_size<V>::value)) {
if (idx >= arr.max_size()) {
return arr;
}
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
type t = static_cast<type>(lua_geti(L, index, i + vi));
isnil = t == type::lua_nil;
if (isnil) {
if (i == 0) {
break;
}
lua_pop(L, (vi + 1));
return arr;
}
}
if (isnil)
continue;
at = arr.insert_after(at, stack::get<V>(L, -lua_size<V>::value));
++idx;
}
#else
// Zzzz slower but necessary thanks to the lower version API and missing functions qq
for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {
if (idx >= arr.max_size()) {
return arr;
}
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
lua_pushinteger(L, i);
lua_gettable(L, index);
type t = type_of(L, -1);
isnil = t == type::lua_nil;
if (isnil) {
if (i == 0) {
break;
}
lua_pop(L, (vi + 1));
return arr;
}
}
if (isnil)
continue;
at = arr.insert_after(at, stack::get<V>(L, -lua_size<V>::value));
++idx;
}
#endif
return arr;
}
template <typename K, typename V>
static C get(types<K, V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
C associative;
auto at = associative.cbefore_begin();
int index = lua_absindex(L, relindex);
lua_pushnil(L);
while (lua_next(L, index) != 0) {
decltype(auto) key = stack::check_get<K>(L, -2);
if (!key) {
lua_pop(L, 1);
continue;
}
at = associative.emplace_after(at, std::forward<decltype(*key)>(*key), stack::get<V>(L, -1));
lua_pop(L, 1);
}
return associative;
}
};
template <typename T>
struct getter<nested<T>, std::enable_if_t<!is_container<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
getter<T> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(L, index, tracking);
}
};
template <typename T>
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::neg<meta::has_key_value_pair<meta::unqualified_t<T>>>>::value>> {
static T get(lua_State* L, int index, record& tracking) {
typedef typename T::value_type V;
getter<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(types<nested<V>>(), L, index, tracking);
}
};
template <typename T>
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::has_key_value_pair<meta::unqualified_t<T>>>::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<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(types<K, nested<V>>(), L, index, tracking);
}
};
template <typename T>
struct getter<T, std::enable_if_t<is_lua_reference<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return T(L, index);
}
};
template <>
struct getter<userdata_value> {
static userdata_value get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return userdata_value(lua_touserdata(L, index));
}
};
template <>
struct getter<lightuserdata_value> {
static lightuserdata_value get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return lightuserdata_value(lua_touserdata(L, index));
}
};
template <typename T>
struct getter<light<T>> {
static light<T> get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
return light<T>(static_cast<T*>(memory));
}
};
template <typename T>
struct getter<user<T>> {
static std::add_lvalue_reference_t<T> get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
memory = detail::align_user<T>(memory);
return *static_cast<std::remove_reference_t<T>*>(memory);
}
};
template <typename T>
struct getter<user<T*>> {
static T* get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
memory = detail::align_user<T*>(memory);
return static_cast<T*>(memory);
}
};
template <>
struct getter<type> {
static type get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return static_cast<type>(lua_type(L, index));
}
};
template <>
struct getter<bool> {
static bool get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return lua_toboolean(L, index) != 0;
}
};
template <>
struct getter<std::string> {
static std::string get(lua_State* L, int index, record& tracking) {
tracking.use(1);
std::size_t len;
auto str = lua_tolstring(L, index, &len);
return std::string(str, len);
}
};
template <>
struct getter<const char*> {
static const char* get(lua_State* L, int index, record& tracking) {
tracking.use(1);
size_t sz;
return lua_tolstring(L, index, &sz);
}
};
template <>
struct getter<char> {
static char get(lua_State* L, int index, record& tracking) {
tracking.use(1);
size_t len;
auto str = lua_tolstring(L, index, &len);
return len > 0 ? str[0] : '\0';
}
};
template <typename Traits>
struct getter<basic_string_view<char, Traits>> {
static string_view get(lua_State* L, int index, record& tracking) {
tracking.use(1);
size_t sz;
const char* str = lua_tolstring(L, index, &sz);
return basic_string_view<char, Traits>(str, sz);
}
};
template <typename Traits, typename Al>
struct getter<std::basic_string<wchar_t, Traits, Al>> {
typedef std::basic_string<wchar_t, Traits, Al> S;
static S get(lua_State* L, int index, record& tracking) {
typedef std::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t> Ch;
typedef typename std::allocator_traits<Al>::template rebind_alloc<Ch> ChAl;
typedef std::char_traits<Ch> ChTraits;
getter<std::basic_string<Ch, ChTraits, ChAl>> g;
(void)g;
return g.template get_into<S>(L, index, tracking);
}
};
template <typename Traits, typename Al>
struct getter<std::basic_string<char16_t, Traits, Al>> {
template <typename F>
static void convert(const char* strb, const char* stre, F&& f) {
char32_t cp = 0;
for (const char* strtarget = strb; strtarget < stre;) {
auto dr = unicode::utf8_to_code_point(strtarget, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
++strtarget;
}
else {
cp = dr.codepoint;
strtarget = dr.next;
}
auto er = unicode::code_point_to_utf16(cp);
f(er);
}
}
template <typename S>
static S get_into(lua_State* L, int index, record& tracking) {
typedef typename S::value_type Ch;
tracking.use(1);
size_t len;
auto utf8p = lua_tolstring(L, index, &len);
if (len < 1)
return S();
std::size_t needed_size = 0;
const char* strb = utf8p;
const char* stre = utf8p + len;
auto count_units = [&needed_size](const unicode::encoded_result<char16_t> er) {
needed_size += er.code_units_size;
};
convert(strb, stre, count_units);
S r(needed_size, static_cast<Ch>(0));
r.resize(needed_size);
Ch* target = &r[0];
auto copy_units = [&target](const unicode::encoded_result<char16_t> er) {
std::memcpy(target, er.code_units.data(), er.code_units_size * sizeof(Ch));
target += er.code_units_size;
};
convert(strb, stre, copy_units);
return r;
}
static std::basic_string<char16_t, Traits, Al> get(lua_State* L, int index, record& tracking) {
return get_into<std::basic_string<char16_t, Traits, Al>>(L, index, tracking);
}
};
template <typename Traits, typename Al>
struct getter<std::basic_string<char32_t, Traits, Al>> {
template <typename F>
static void convert(const char* strb, const char* stre, F&& f) {
char32_t cp = 0;
for (const char* strtarget = strb; strtarget < stre;) {
auto dr = unicode::utf8_to_code_point(strtarget, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
++strtarget;
}
else {
cp = dr.codepoint;
strtarget = dr.next;
}
auto er = unicode::code_point_to_utf32(cp);
f(er);
}
}
template <typename S>
static S get_into(lua_State* L, int index, record& tracking) {
typedef typename S::value_type Ch;
tracking.use(1);
size_t len;
auto utf8p = lua_tolstring(L, index, &len);
if (len < 1)
return S();
std::size_t needed_size = 0;
const char* strb = utf8p;
const char* stre = utf8p + len;
auto count_units = [&needed_size](const unicode::encoded_result<char32_t> er) {
needed_size += er.code_units_size;
};
convert(strb, stre, count_units);
S r(needed_size, static_cast<Ch>(0));
r.resize(needed_size);
Ch* target = &r[0];
auto copy_units = [&target](const unicode::encoded_result<char32_t> er) {
std::memcpy(target, er.code_units.data(), er.code_units_size * sizeof(Ch));
target += er.code_units_size;
};
convert(strb, stre, copy_units);
return r;
}
static std::basic_string<char32_t, Traits, Al> get(lua_State* L, int index, record& tracking) {
return get_into<std::basic_string<char32_t, Traits, Al>>(L, index, tracking);
}
};
template <>
struct getter<char16_t> {
static char16_t get(lua_State* L, int index, record& tracking) {
string_view utf8 = stack::get<string_view>(L, index, tracking);
const char* strb = utf8.data();
const char* stre = utf8.data() + utf8.size();
char32_t cp = 0;
auto dr = unicode::utf8_to_code_point(strb, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
}
else {
cp = dr.codepoint;
}
auto er = unicode::code_point_to_utf16(cp);
return er.code_units[0];
}
};
template <>
struct getter<char32_t> {
static char32_t get(lua_State* L, int index, record& tracking) {
string_view utf8 = stack::get<string_view>(L, index, tracking);
const char* strb = utf8.data();
const char* stre = utf8.data() + utf8.size();
char32_t cp = 0;
auto dr = unicode::utf8_to_code_point(strb, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
}
else {
cp = dr.codepoint;
}
auto er = unicode::code_point_to_utf32(cp);
return er.code_units[0];
}
};
template <>
struct getter<wchar_t> {
static wchar_t get(lua_State* L, int index, record& tracking) {
typedef std::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t> Ch;
getter<Ch> g;
(void)g;
auto c = g.get(L, index, tracking);
return static_cast<wchar_t>(c);
}
};
template <>
struct getter<meta_function> {
static meta_function get(lua_State* L, int index, record& tracking) {
tracking.use(1);
const char* name = getter<const char*>{}.get(L, index, tracking);
const auto& mfnames = meta_function_names();
for (std::size_t i = 0; i < mfnames.size(); ++i)
if (mfnames[i] == name)
return static_cast<meta_function>(i);
return meta_function::construct;
}
};
template <>
struct getter<lua_nil_t> {
static lua_nil_t get(lua_State*, int, record& tracking) {
tracking.use(1);
return lua_nil;
}
};
template <>
struct getter<std::nullptr_t> {
static std::nullptr_t get(lua_State*, int, record& tracking) {
tracking.use(1);
return nullptr;
}
};
template <>
struct getter<nullopt_t> {
static nullopt_t get(lua_State*, int, record& tracking) {
tracking.use(1);
return nullopt;
}
};
template <>
struct getter<this_state> {
static this_state get(lua_State* L, int, record& tracking) {
tracking.use(0);
return this_state(L);
}
};
template <>
struct getter<this_main_state> {
static this_main_state get(lua_State* L, int, record& tracking) {
tracking.use(0);
return this_main_state(main_thread(L, L));
}
};
template <>
struct getter<lua_CFunction> {
static lua_CFunction get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return lua_tocfunction(L, index);
}
};
template <>
struct getter<c_closure> {
static c_closure get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return c_closure(lua_tocfunction(L, index), -1);
}
};
template <>
struct getter<error> {
static error get(lua_State* L, int index, record& tracking) {
tracking.use(1);
size_t sz = 0;
const char* err = lua_tolstring(L, index, &sz);
if (err == nullptr) {
return error(detail::direct_error, "");
}
return error(detail::direct_error, std::string(err, sz));
}
};
template <>
struct getter<void*> {
static void* get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return lua_touserdata(L, index);
}
};
template <typename T>
struct getter<detail::as_value_tag<T>> {
static T* get_no_lua_nil(lua_State* L, int index, record& tracking) {
void* memory = lua_touserdata(L, index);
#if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP
userdata_getter<extensible<T>> ug;
(void)ug;
auto ugr = ug.get(L, index, memory, tracking);
if (ugr.first) {
return ugr.second;
}
#endif // interop extensibility
tracking.use(1);
void* rawdata = detail::align_usertype_pointer(memory);
void** pudata = static_cast<void**>(rawdata);
void* udata = *pudata;
return get_no_lua_nil_from(L, udata, index, tracking);
}
static T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) {
if (detail::has_derived<T>::value && luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_cast_function ic = reinterpret_cast<detail::inheritance_cast_function>(basecastdata);
// use the casting function to properly adjust the pointer for the desired T
udata = ic(udata, usertype_traits<T>::qualified_name());
lua_pop(L, 1);
}
T* obj = static_cast<T*>(udata);
return obj;
}
static T& get(lua_State* L, int index, record& tracking) {
return *get_no_lua_nil(L, index, tracking);
}
};
template <typename T>
struct getter<detail::as_pointer_tag<T>> {
static T* get(lua_State* L, int index, record& tracking) {
type t = type_of(L, index);
if (t == type::lua_nil) {
tracking.use(1);
return nullptr;
}
getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get_no_lua_nil(L, index, tracking);
}
};
template <typename T>
struct getter<non_null<T*>> {
static T* get(lua_State* L, int index, record& tracking) {
getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get_no_lua_nil(L, index, tracking);
}
};
template <typename T>
struct getter<T&> {
static T& get(lua_State* L, int index, record& tracking) {
getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
}
};
template <typename T>
struct getter<std::reference_wrapper<T>> {
static T& get(lua_State* L, int index, record& tracking) {
getter<T&> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
}
};
template <typename T>
struct getter<T*> {
static T* get(lua_State* L, int index, record& tracking) {
getter<detail::as_pointer_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
}
};
template <typename T>
struct getter<T, std::enable_if_t<is_unique_usertype<T>::value>> {
typedef typename unique_usertype_traits<T>::type P;
typedef typename unique_usertype_traits<T>::actual_type Real;
static Real& get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique<Real>(memory);
Real* mem = static_cast<Real*>(memory);
return *mem;
}
};
template <typename... Tn>
struct getter<std::tuple<Tn...>> {
typedef std::tuple<decltype(stack::get<Tn>(nullptr, 0))...> R;
template <typename... Args>
static R apply(std::index_sequence<>, lua_State*, int, record&, Args&&... args) {
// Fuck you too, VC++
return R{ std::forward<Args>(args)... };
}
template <std::size_t I, std::size_t... Ix, typename... Args>
static R apply(std::index_sequence<I, Ix...>, lua_State* L, int index, record& tracking, Args&&... args) {
// Fuck you too, VC++
typedef std::tuple_element_t<I, std::tuple<Tn...>> T;
return apply(std::index_sequence<Ix...>(), L, index, tracking, std::forward<Args>(args)..., stack::get<T>(L, index + tracking.used, tracking));
}
static R get(lua_State* L, int index, record& tracking) {
return apply(std::make_index_sequence<sizeof...(Tn)>(), L, index, tracking);
}
};
template <typename A, typename B>
struct getter<std::pair<A, B>> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))>{ stack::get<A>(L, index, tracking), stack::get<B>(L, index + tracking.used, tracking) };
}
};
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn>
struct getter<std::variant<Tn...>> {
typedef std::variant<Tn...> V;
typedef std::variant_size<V> V_size;
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
static V get_empty(std::true_type, lua_State*, int, record&) {
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<T>(L, index, tracking));
}
static V get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, record& tracking) {
return get_empty(V_is_empty(), L, index, tracking);
}
template <std::size_t I>
static V get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, record& tracking) {
typedef std::variant_alternative_t<I - 1, V> T;
if (stack::check<T>(L, index, no_panic, tracking)) {
return V(std::in_place_index<I - 1>, stack::get<T>(L, index));
}
return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, tracking);
}
static V get(lua_State* L, int index, record& tracking) {
return get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, tracking);
}
};
#endif // SOL_STD_VARIANT
#endif // SOL_CXX17_FEATURES
}
} // namespace sol::stack
#include "stack_get_unqualified.hpp"
#include "stack_get_qualified.hpp"
#endif // SOL_STACK_GET_HPP

View File

@ -0,0 +1,70 @@
// sol2
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_QUALIFIED_GET_HPP
#define SOL_STACK_QUALIFIED_GET_HPP
#include "stack_get_unqualified.hpp"
namespace sol {
namespace stack {
#if 0 // need static reflection / DERIVED_CLASS macros...
template <typename X>
struct qualified_getter<X, std::enable_if_t<
!std::is_reference<X>::value && is_unique_usertype<meta::unqualified_t<X>>::value
>> {
typedef typename unique_usertype_traits<meta::unqualified_t<X>>::type P;
typedef typename unique_usertype_traits<meta::unqualified_t<X>>::actual_type Real;
static Real& get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
void* del = detail::align_usertype_unique_destructor(memory);
memory = detail::align_usertype_unique<Real>(memory);
Real* mem = static_cast<Real*>(memory);
return *mem;
}
};
#endif // need static reflection
template <typename T>
struct qualified_getter<T, std::enable_if_t<
!std::is_reference<T>::value
&& is_container<meta::unqualified_t<T>>::value
&& !is_lua_primitive<T>::value
&& !is_transparent_argument<T>::value
>> {
static T get(lua_State* L, int index, record& tracking) {
if (type_of(L, index) == type::userdata) {
return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
}
else {
return stack_detail::unchecked_unqualified_get<sol::nested<T>>(L, index, tracking);
}
}
};
}
} // namespace sol::stack
#endif // SOL_STACK_QUALIFIED_GET_HPP

View File

@ -0,0 +1,918 @@
// sol2
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_UNQUALIFIED_GET_HPP
#define SOL_STACK_UNQUALIFIED_GET_HPP
#include "stack_core.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include "overload.hpp"
#include "error.hpp"
#include "unicode.hpp"
#include <memory>
#include <functional>
#include <utility>
#include <cstdlib>
#include <cmath>
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#include <string_view>
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
#include <variant>
#endif // Apple clang screwed up
#endif // C++17
namespace sol {
namespace stack {
template <typename U>
struct userdata_getter<U> {
typedef stack_detail::strip_extensible_t<U> T;
static std::pair<bool, T*> get(lua_State*, int, void*, record&) {
return { false, nullptr };
}
};
template <typename T, typename>
struct getter {
static T& get(lua_State* L, int index, record& tracking) {
return getter<detail::as_value_tag<T>>{}.get(L, index, tracking);
}
};
template <typename T, typename C>
struct qualified_getter : getter<meta::unqualified_t<T>, C> {};
template <typename T>
struct getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return static_cast<T>(lua_tonumber(L, index));
}
};
template <typename T>
struct getter<T, std::enable_if_t<std::is_integral<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
tracking.use(1);
#if SOL_LUA_VERSION >= 503
if (lua_isinteger(L, index) != 0) {
return static_cast<T>(lua_tointeger(L, index));
}
#endif
return static_cast<T>(llround(lua_tonumber(L, index)));
}
};
template <typename T>
struct getter<T, std::enable_if_t<std::is_enum<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return static_cast<T>(lua_tointegerx(L, index, nullptr));
}
};
template <typename T>
struct getter<as_table_t<T>> {
typedef meta::unqualified_t<T> Tu;
template <typename V>
static void push_back_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) {
arr.push_back(stack::get<V>(L, -lua_size<V>::value));
}
template <typename V>
static void push_back_at_end(std::false_type, types<V> t, lua_State* L, T& arr, std::size_t idx) {
insert_at_end(meta::has_insert<Tu>(), t, L, arr, idx);
}
template <typename V>
static void insert_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) {
using std::end;
arr.insert(end(arr), stack::get<V>(L, -lua_size<V>::value));
}
template <typename V>
static void insert_at_end(std::false_type, types<V>, lua_State* L, T& arr, std::size_t idx) {
arr[idx] = stack::get<V>(L, -lua_size<V>::value);
}
static bool max_size_check(std::false_type, T&, std::size_t) {
return false;
}
static bool max_size_check(std::true_type, T& arr, std::size_t idx) {
return idx >= arr.max_size();
}
static T get(lua_State* L, int relindex, record& tracking) {
return get(meta::has_key_value_pair<meta::unqualified_t<T>>(), L, relindex, tracking);
}
static T get(std::false_type, lua_State* L, int relindex, record& tracking) {
typedef typename T::value_type V;
return get(types<V>(), L, relindex, tracking);
}
template <typename V>
static T get(types<V> t, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
int index = lua_absindex(L, relindex);
T arr;
std::size_t idx = 0;
#if SOL_LUA_VERSION >= 503
// This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3
// Questionable in 5.4
for (lua_Integer i = 0;; i += lua_size<V>::value) {
if (max_size_check(meta::has_max_size<Tu>(), arr, idx)) {
return arr;
}
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
#if defined(LUA_NILINTABLE) && LUA_NILINTABLE
lua_pushinteger(L, static_cast<lua_Integer>(i + vi));
if (lua_keyin(L, index) == 0) {
// it's time to stop
isnil = true;
}
else {
// we have a key, have to get the value
lua_geti(L, index, i + vi);
}
#else
type vt = static_cast<type>(lua_geti(L, index, i + vi));
isnil = vt == type::none
|| vt == type::lua_nil;
#endif
if (isnil) {
if (i == 0) {
break;
}
lua_pop(L, (vi + 1));
return arr;
}
}
if (isnil) {
#if defined(LUA_NILINTABLE) && LUA_NILINTABLE
#else
lua_pop(L, lua_size<V>::value);
#endif
continue;
}
push_back_at_end(meta::has_push_back<Tu>(), t, L, arr, idx);
++idx;
lua_pop(L, lua_size<V>::value);
}
#else
// Zzzz slower but necessary thanks to the lower version API and missing functions qq
for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {
if (idx >= arr.max_size()) {
return arr;
}
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
lua_pushinteger(L, i);
lua_gettable(L, index);
type vt = type_of(L, -1);
isnil = vt == type::lua_nil;
if (isnil) {
if (i == 0) {
break;
}
lua_pop(L, (vi + 1));
return arr;
}
}
if (isnil)
continue;
push_back_at_end(meta::has_push_back<Tu>(), t, L, arr, idx);
++idx;
}
#endif
return arr;
}
static T get(std::true_type, 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;
return get(types<K, V>(), L, index, tracking);
}
template <typename K, typename V>
static T get(types<K, V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
T associative;
int index = lua_absindex(L, relindex);
lua_pushnil(L);
while (lua_next(L, index) != 0) {
decltype(auto) key = stack::check_get<K>(L, -2);
if (!key) {
lua_pop(L, 1);
continue;
}
associative.emplace(std::forward<decltype(*key)>(*key), stack::get<V>(L, -1));
lua_pop(L, 1);
}
return associative;
}
};
template <typename T, typename Al>
struct getter<as_table_t<std::forward_list<T, Al>>> {
typedef std::forward_list<T, Al> C;
static C get(lua_State* L, int relindex, record& tracking) {
return get(meta::has_key_value_pair<C>(), L, relindex, tracking);
}
static C get(std::true_type, 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;
return get(types<K, V>(), L, index, tracking);
}
static C get(std::false_type, lua_State* L, int relindex, record& tracking) {
typedef typename C::value_type V;
return get(types<V>(), L, relindex, tracking);
}
template <typename V>
static C get(types<V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
int index = lua_absindex(L, relindex);
C arr;
auto at = arr.cbefore_begin();
std::size_t idx = 0;
#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<V>::value, lua_pop(L, lua_size<V>::value)) {
if (idx >= arr.max_size()) {
return arr;
}
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
type t = static_cast<type>(lua_geti(L, index, i + vi));
isnil = t == type::lua_nil;
if (isnil) {
if (i == 0) {
break;
}
lua_pop(L, (vi + 1));
return arr;
}
}
if (isnil)
continue;
at = arr.insert_after(at, stack::get<V>(L, -lua_size<V>::value));
++idx;
}
#else
// Zzzz slower but necessary thanks to the lower version API and missing functions qq
for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {
if (idx >= arr.max_size()) {
return arr;
}
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
lua_pushinteger(L, i);
lua_gettable(L, index);
type t = type_of(L, -1);
isnil = t == type::lua_nil;
if (isnil) {
if (i == 0) {
break;
}
lua_pop(L, (vi + 1));
return arr;
}
}
if (isnil)
continue;
at = arr.insert_after(at, stack::get<V>(L, -lua_size<V>::value));
++idx;
}
#endif
return arr;
}
template <typename K, typename V>
static C get(types<K, V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
C associative;
auto at = associative.cbefore_begin();
int index = lua_absindex(L, relindex);
lua_pushnil(L);
while (lua_next(L, index) != 0) {
decltype(auto) key = stack::check_get<K>(L, -2);
if (!key) {
lua_pop(L, 1);
continue;
}
at = associative.emplace_after(at, std::forward<decltype(*key)>(*key), stack::get<V>(L, -1));
lua_pop(L, 1);
}
return associative;
}
};
template <typename T>
struct getter<nested<T>, std::enable_if_t<!is_container<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
getter<T> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(L, index, tracking);
}
};
template <typename T>
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::neg<meta::has_key_value_pair<meta::unqualified_t<T>>>>::value>> {
static T get(lua_State* L, int index, record& tracking) {
typedef typename T::value_type V;
getter<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(types<nested<V>>(), L, index, tracking);
}
};
template <typename T>
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::has_key_value_pair<meta::unqualified_t<T>>>::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<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(types<K, nested<V>>(), L, index, tracking);
}
};
template <typename T>
struct getter<T, std::enable_if_t<is_lua_reference<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return T(L, index);
}
};
template <>
struct getter<userdata_value> {
static userdata_value get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return userdata_value(lua_touserdata(L, index));
}
};
template <>
struct getter<lightuserdata_value> {
static lightuserdata_value get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return lightuserdata_value(lua_touserdata(L, index));
}
};
template <typename T>
struct getter<light<T>> {
static light<T> get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
return light<T>(static_cast<T*>(memory));
}
};
template <typename T>
struct getter<user<T>> {
static std::add_lvalue_reference_t<T> get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
memory = detail::align_user<T>(memory);
return *static_cast<std::remove_reference_t<T>*>(memory);
}
};
template <typename T>
struct getter<user<T*>> {
static T* get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
memory = detail::align_user<T*>(memory);
return static_cast<T*>(memory);
}
};
template <>
struct getter<type> {
static type get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return static_cast<type>(lua_type(L, index));
}
};
template <>
struct getter<bool> {
static bool get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return lua_toboolean(L, index) != 0;
}
};
template <>
struct getter<std::string> {
static std::string get(lua_State* L, int index, record& tracking) {
tracking.use(1);
std::size_t len;
auto str = lua_tolstring(L, index, &len);
return std::string(str, len);
}
};
template <>
struct getter<const char*> {
static const char* get(lua_State* L, int index, record& tracking) {
tracking.use(1);
size_t sz;
return lua_tolstring(L, index, &sz);
}
};
template <>
struct getter<char> {
static char get(lua_State* L, int index, record& tracking) {
tracking.use(1);
size_t len;
auto str = lua_tolstring(L, index, &len);
return len > 0 ? str[0] : '\0';
}
};
template <typename Traits>
struct getter<basic_string_view<char, Traits>> {
static string_view get(lua_State* L, int index, record& tracking) {
tracking.use(1);
size_t sz;
const char* str = lua_tolstring(L, index, &sz);
return basic_string_view<char, Traits>(str, sz);
}
};
template <typename Traits, typename Al>
struct getter<std::basic_string<wchar_t, Traits, Al>> {
typedef std::basic_string<wchar_t, Traits, Al> S;
static S get(lua_State* L, int index, record& tracking) {
typedef std::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t> Ch;
typedef typename std::allocator_traits<Al>::template rebind_alloc<Ch> ChAl;
typedef std::char_traits<Ch> ChTraits;
getter<std::basic_string<Ch, ChTraits, ChAl>> g;
(void)g;
return g.template get_into<S>(L, index, tracking);
}
};
template <typename Traits, typename Al>
struct getter<std::basic_string<char16_t, Traits, Al>> {
template <typename F>
static void convert(const char* strb, const char* stre, F&& f) {
char32_t cp = 0;
for (const char* strtarget = strb; strtarget < stre;) {
auto dr = unicode::utf8_to_code_point(strtarget, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
++strtarget;
}
else {
cp = dr.codepoint;
strtarget = dr.next;
}
auto er = unicode::code_point_to_utf16(cp);
f(er);
}
}
template <typename S>
static S get_into(lua_State* L, int index, record& tracking) {
typedef typename S::value_type Ch;
tracking.use(1);
size_t len;
auto utf8p = lua_tolstring(L, index, &len);
if (len < 1)
return S();
std::size_t needed_size = 0;
const char* strb = utf8p;
const char* stre = utf8p + len;
auto count_units = [&needed_size](const unicode::encoded_result<char16_t> er) {
needed_size += er.code_units_size;
};
convert(strb, stre, count_units);
S r(needed_size, static_cast<Ch>(0));
r.resize(needed_size);
Ch* target = &r[0];
auto copy_units = [&target](const unicode::encoded_result<char16_t> er) {
std::memcpy(target, er.code_units.data(), er.code_units_size * sizeof(Ch));
target += er.code_units_size;
};
convert(strb, stre, copy_units);
return r;
}
static std::basic_string<char16_t, Traits, Al> get(lua_State* L, int index, record& tracking) {
return get_into<std::basic_string<char16_t, Traits, Al>>(L, index, tracking);
}
};
template <typename Traits, typename Al>
struct getter<std::basic_string<char32_t, Traits, Al>> {
template <typename F>
static void convert(const char* strb, const char* stre, F&& f) {
char32_t cp = 0;
for (const char* strtarget = strb; strtarget < stre;) {
auto dr = unicode::utf8_to_code_point(strtarget, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
++strtarget;
}
else {
cp = dr.codepoint;
strtarget = dr.next;
}
auto er = unicode::code_point_to_utf32(cp);
f(er);
}
}
template <typename S>
static S get_into(lua_State* L, int index, record& tracking) {
typedef typename S::value_type Ch;
tracking.use(1);
size_t len;
auto utf8p = lua_tolstring(L, index, &len);
if (len < 1)
return S();
std::size_t needed_size = 0;
const char* strb = utf8p;
const char* stre = utf8p + len;
auto count_units = [&needed_size](const unicode::encoded_result<char32_t> er) {
needed_size += er.code_units_size;
};
convert(strb, stre, count_units);
S r(needed_size, static_cast<Ch>(0));
r.resize(needed_size);
Ch* target = &r[0];
auto copy_units = [&target](const unicode::encoded_result<char32_t> er) {
std::memcpy(target, er.code_units.data(), er.code_units_size * sizeof(Ch));
target += er.code_units_size;
};
convert(strb, stre, copy_units);
return r;
}
static std::basic_string<char32_t, Traits, Al> get(lua_State* L, int index, record& tracking) {
return get_into<std::basic_string<char32_t, Traits, Al>>(L, index, tracking);
}
};
template <>
struct getter<char16_t> {
static char16_t get(lua_State* L, int index, record& tracking) {
string_view utf8 = stack::get<string_view>(L, index, tracking);
const char* strb = utf8.data();
const char* stre = utf8.data() + utf8.size();
char32_t cp = 0;
auto dr = unicode::utf8_to_code_point(strb, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
}
else {
cp = dr.codepoint;
}
auto er = unicode::code_point_to_utf16(cp);
return er.code_units[0];
}
};
template <>
struct getter<char32_t> {
static char32_t get(lua_State* L, int index, record& tracking) {
string_view utf8 = stack::get<string_view>(L, index, tracking);
const char* strb = utf8.data();
const char* stre = utf8.data() + utf8.size();
char32_t cp = 0;
auto dr = unicode::utf8_to_code_point(strb, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
}
else {
cp = dr.codepoint;
}
auto er = unicode::code_point_to_utf32(cp);
return er.code_units[0];
}
};
template <>
struct getter<wchar_t> {
static wchar_t get(lua_State* L, int index, record& tracking) {
typedef std::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t> Ch;
getter<Ch> g;
(void)g;
auto c = g.get(L, index, tracking);
return static_cast<wchar_t>(c);
}
};
template <>
struct getter<meta_function> {
static meta_function get(lua_State* L, int index, record& tracking) {
tracking.use(1);
const char* name = getter<const char*>{}.get(L, index, tracking);
const auto& mfnames = meta_function_names();
for (std::size_t i = 0; i < mfnames.size(); ++i)
if (mfnames[i] == name)
return static_cast<meta_function>(i);
return meta_function::construct;
}
};
template <>
struct getter<lua_nil_t> {
static lua_nil_t get(lua_State*, int, record& tracking) {
tracking.use(1);
return lua_nil;
}
};
template <>
struct getter<std::nullptr_t> {
static std::nullptr_t get(lua_State*, int, record& tracking) {
tracking.use(1);
return nullptr;
}
};
template <>
struct getter<nullopt_t> {
static nullopt_t get(lua_State*, int, record& tracking) {
tracking.use(1);
return nullopt;
}
};
template <>
struct getter<this_state> {
static this_state get(lua_State* L, int, record& tracking) {
tracking.use(0);
return this_state(L);
}
};
template <>
struct getter<this_main_state> {
static this_main_state get(lua_State* L, int, record& tracking) {
tracking.use(0);
return this_main_state(main_thread(L, L));
}
};
template <>
struct getter<lua_CFunction> {
static lua_CFunction get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return lua_tocfunction(L, index);
}
};
template <>
struct getter<c_closure> {
static c_closure get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return c_closure(lua_tocfunction(L, index), -1);
}
};
template <>
struct getter<error> {
static error get(lua_State* L, int index, record& tracking) {
tracking.use(1);
size_t sz = 0;
const char* err = lua_tolstring(L, index, &sz);
if (err == nullptr) {
return error(detail::direct_error, "");
}
return error(detail::direct_error, std::string(err, sz));
}
};
template <>
struct getter<void*> {
static void* get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return lua_touserdata(L, index);
}
};
template <typename T>
struct getter<detail::as_value_tag<T>> {
static T* get_no_lua_nil(lua_State* L, int index, record& tracking) {
void* memory = lua_touserdata(L, index);
#if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP
userdata_getter<extensible<T>> ug;
(void)ug;
auto ugr = ug.get(L, index, memory, tracking);
if (ugr.first) {
return ugr.second;
}
#endif // interop extensibility
tracking.use(1);
void* rawdata = detail::align_usertype_pointer(memory);
void** pudata = static_cast<void**>(rawdata);
void* udata = *pudata;
return get_no_lua_nil_from(L, udata, index, tracking);
}
static T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) {
if (detail::has_derived<T>::value && luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_cast_function ic = reinterpret_cast<detail::inheritance_cast_function>(basecastdata);
// use the casting function to properly adjust the pointer for the desired T
udata = ic(udata, usertype_traits<T>::qualified_name());
lua_pop(L, 1);
}
T* obj = static_cast<T*>(udata);
return obj;
}
static T& get(lua_State* L, int index, record& tracking) {
return *get_no_lua_nil(L, index, tracking);
}
};
template <typename T>
struct getter<detail::as_pointer_tag<T>> {
static T* get(lua_State* L, int index, record& tracking) {
type t = type_of(L, index);
if (t == type::lua_nil) {
tracking.use(1);
return nullptr;
}
getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get_no_lua_nil(L, index, tracking);
}
};
template <typename T>
struct getter<non_null<T*>> {
static T* get(lua_State* L, int index, record& tracking) {
getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get_no_lua_nil(L, index, tracking);
}
};
template <typename T>
struct getter<T&> {
static T& get(lua_State* L, int index, record& tracking) {
getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
}
};
template <typename T>
struct getter<std::reference_wrapper<T>> {
static T& get(lua_State* L, int index, record& tracking) {
getter<T&> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
}
};
template <typename T>
struct getter<T*> {
static T* get(lua_State* L, int index, record& tracking) {
getter<detail::as_pointer_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
}
};
template <typename T>
struct getter<T, std::enable_if_t<is_unique_usertype<T>::value>> {
typedef typename unique_usertype_traits<T>::type P;
typedef typename unique_usertype_traits<T>::actual_type Real;
static Real& get(lua_State* L, int index, record& tracking) {
tracking.use(1);
void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique<Real>(memory);
Real* mem = static_cast<Real*>(memory);
return *mem;
}
};
template <typename... Tn>
struct getter<std::tuple<Tn...>> {
typedef std::tuple<decltype(stack::get<Tn>(nullptr, 0))...> R;
template <typename... Args>
static R apply(std::index_sequence<>, lua_State*, int, record&, Args&&... args) {
// Fuck you too, VC++
return R{ std::forward<Args>(args)... };
}
template <std::size_t I, std::size_t... Ix, typename... Args>
static R apply(std::index_sequence<I, Ix...>, lua_State* L, int index, record& tracking, Args&&... args) {
// Fuck you too, VC++
typedef std::tuple_element_t<I, std::tuple<Tn...>> T;
return apply(std::index_sequence<Ix...>(), L, index, tracking, std::forward<Args>(args)..., stack::get<T>(L, index + tracking.used, tracking));
}
static R get(lua_State* L, int index, record& tracking) {
return apply(std::make_index_sequence<sizeof...(Tn)>(), L, index, tracking);
}
};
template <typename A, typename B>
struct getter<std::pair<A, B>> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))>{ stack::get<A>(L, index, tracking), stack::get<B>(L, index + tracking.used, tracking) };
}
};
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn>
struct getter<std::variant<Tn...>> {
typedef std::variant<Tn...> V;
typedef std::variant_size<V> V_size;
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
static V get_empty(std::true_type, lua_State*, int, record&) {
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<T>(L, index, tracking));
}
static V get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, record& tracking) {
return get_empty(V_is_empty(), L, index, tracking);
}
template <std::size_t I>
static V get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, record& tracking) {
typedef std::variant_alternative_t<I - 1, V> T;
if (stack::check<T>(L, index, no_panic, tracking)) {
return V(std::in_place_index<I - 1>, stack::get<T>(L, index));
}
return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, tracking);
}
static V get(lua_State* L, int index, record& tracking) {
return get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, tracking);
}
};
#endif // SOL_STD_VARIANT
#endif // SOL_CXX17_FEATURES
}
} // namespace sol::stack
#endif // SOL_STACK_UNQUALIFIED_GET_HPP

View File

@ -164,8 +164,14 @@ namespace stack {
static int push_deep(lua_State* L, Args&&... args) {
P** pref = nullptr;
detail::unique_destructor* fx = nullptr;
Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx);
detail::unique_tag* id = nullptr;
Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id);
*fx = detail::usertype_unique_alloc_destroy<P, Real>;
#if 0
*id = &detail::inheritance<P>::type_unique_cast_bases<Real>;
#else
*id = &usertype_traits<Real>::qualified_name()[0];
#endif
detail::default_construct::construct(mem, std::forward<Args>(args)...);
*pref = unique_usertype_traits<T>::get(*mem);
if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) {

View File

@ -29,7 +29,7 @@
#include "function.hpp"
#include "object.hpp"
#ifdef SOL_PRINT_ERRORS
#if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS
#include <iostream>
#endif

View File

@ -41,6 +41,9 @@ namespace sol {
using index_value = std::integral_constant<std::size_t, I>;
namespace meta {
typedef std::array<char, 1> sfinae_yes_t;
typedef std::array<char, 2> sfinae_no_t;
template <typename T>
struct identity { typedef T type; };
@ -378,76 +381,82 @@ namespace sol {
template <typename T>
struct has_push_back_test {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C>
static one test(decltype(std::declval<C>().push_back(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
static sfinae_yes_t test(decltype(std::declval<C>().push_back(std::declval<std::add_rvalue_reference_t<typename C::value_type>>())) *);
template <typename C>
static two test(...);
static sfinae_no_t test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
static const bool value = sizeof(test<T>(0)) == sizeof(sfinae_yes_t);
};
template <typename T>
struct has_insert_test {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C>
static one test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
static sfinae_yes_t test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C>
static two test(...);
static sfinae_no_t test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
static const bool value = sizeof(test<T>(0)) == sizeof(sfinae_yes_t);
};
template <typename T>
struct has_insert_after_test {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C>
static one test(decltype(std::declval<C>().insert_after(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
static sfinae_yes_t test(decltype(std::declval<C>().insert_after(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C>
static two test(...);
static sfinae_no_t test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
static const bool value = sizeof(test<T>(0)) == sizeof(sfinae_yes_t);
};
template <typename T>
struct has_size_test {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
typedef std::array<char, 1> sfinae_yes_t;
typedef std::array<char, 2> sfinae_no_t;
template <typename C>
static one test(decltype(std::declval<C>().size())*);
static sfinae_yes_t test(decltype(std::declval<C>().size())*);
template <typename C>
static two test(...);
static sfinae_no_t test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
static const bool value = sizeof(test<T>(0)) == sizeof(sfinae_yes_t);
};
template <typename T>
struct has_max_size_test {
private:
typedef std::array<char, 1> sfinae_yes_t;
typedef std::array<char, 2> sfinae_no_t;
template <typename C>
static sfinae_yes_t test(decltype(std::declval<C>().max_size())*);
template <typename C>
static sfinae_no_t test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(sfinae_yes_t);
};
template <typename T>
struct has_to_string_test {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
typedef std::array<char, 1> sfinae_yes_t;
typedef std::array<char, 2> sfinae_no_t;
template <typename C>
static one test(decltype(std::declval<C>().to_string())*);
static sfinae_yes_t test(decltype(std::declval<C>().to_string())*);
template <typename C>
static two test(...);
static sfinae_no_t test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
static const bool value = sizeof(test<T>(0)) == sizeof(sfinae_yes_t);
};
#if defined(_MSC_VER) && _MSC_VER <= 1910
template <typename T, typename U, typename = decltype(std::declval<T&>() < std::declval<U&>())>
@ -539,6 +548,9 @@ namespace sol {
template <typename T>
using has_push_back = meta::boolean<meta_detail::has_push_back_test<T>::value>;
template <typename T>
using has_max_size = meta::boolean<meta_detail::has_max_size_test<T>::value>;
template <typename T>
using has_insert = meta::boolean<meta_detail::has_insert_test<T>::value>;

View File

@ -29,7 +29,7 @@
#include <exception>
#include <cstring>
#ifdef SOL_PRINT_ERRORS
#if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS
#include <iostream>
#endif
@ -47,7 +47,7 @@ namespace sol {
// must push at least 1 object on the stack
inline int default_exception_handler(lua_State* L, optional<const std::exception&>, string_view what) {
#ifdef SOL_PRINT_ERRORS
#if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS
std::cerr << "[sol2] An exception occurred: ";
std::cerr.write(what.data(), what.size());
std::cerr << std::endl;

View File

@ -155,6 +155,9 @@ namespace sol {
struct unique_usertype_traits {
typedef T type;
typedef T actual_type;
template <typename X>
using base_id = void;
static const bool value = false;
template <typename U>
@ -172,7 +175,12 @@ namespace sol {
struct unique_usertype_traits<std::shared_ptr<T>> {
typedef T type;
typedef std::shared_ptr<T> actual_type;
// rebind is non-void
// and tag is a unique integer
// if and only if unique usertype
// is cast-capable
using base_id = std::shared_ptr<void>;
static const bool value = true;
static bool is_null(const actual_type& p) {
@ -188,7 +196,9 @@ namespace sol {
struct unique_usertype_traits<std::unique_ptr<T, D>> {
typedef T type;
typedef std::unique_ptr<T, D> actual_type;
template <typename X>
using base_id = void;
static const bool value = true;
static bool is_null(const actual_type& p) {
@ -309,7 +319,7 @@ namespace sol {
struct user {
U value;
user(U x)
user(U&& x)
: value(std::forward<U>(x)) {
}
operator std::add_pointer_t<std::remove_reference_t<U>>() {
@ -778,6 +788,30 @@ namespace sol {
return lua_typename(L, static_cast<int>(t));
}
template <typename T>
struct is_lua_reference : std::integral_constant<bool,
std::is_base_of<reference, meta::unqualified_t<T>>::value
|| std::is_base_of<main_reference, meta::unqualified_t<T>>::value
|| std::is_base_of<stack_reference, meta::unqualified_t<T>>::value> {};
template <typename T>
struct is_lua_reference_or_proxy : std::integral_constant<bool,
is_lua_reference<meta::unqualified_t<T>>::value
|| meta::is_specialization_of<meta::unqualified_t<T>, proxy>::value> {};
template <typename T>
struct is_transparent_argument : std::false_type {};
template <>
struct is_transparent_argument<this_state> : std::true_type {};
template <>
struct is_transparent_argument<this_main_state> : std::true_type {};
template <>
struct is_transparent_argument<this_environment> : std::true_type {};
template <>
struct is_transparent_argument<variadic_args> : std::true_type {};
template <typename T>
struct is_variadic_arguments : std::is_same<meta::unqualified_t<T>, variadic_args> {};
namespace detail {
template <typename T>
struct is_initializer_list : std::false_type {};
@ -1048,23 +1082,10 @@ namespace sol {
|| ((type::userdata == lua_type_of<meta::unqualified_t<T>>::value)
&& detail::has_internal_marker<lua_type_of<meta::unqualified_t<T>>>::value
&& !detail::has_internal_marker<lua_size<meta::unqualified_t<T>>>::value)
|| std::is_base_of<reference, meta::unqualified_t<T>>::value
|| std::is_base_of<main_reference, meta::unqualified_t<T>>::value
|| std::is_base_of<stack_reference, meta::unqualified_t<T>>::value
|| is_lua_reference<meta::unqualified_t<T>>::value
|| meta::is_specialization_of<meta::unqualified_t<T>, std::tuple>::value
|| meta::is_specialization_of<meta::unqualified_t<T>, std::pair>::value> {};
template <typename T>
struct is_lua_reference : std::integral_constant<bool,
std::is_base_of<reference, meta::unqualified_t<T>>::value
|| std::is_base_of<main_reference, meta::unqualified_t<T>>::value
|| std::is_base_of<stack_reference, meta::unqualified_t<T>>::value> {};
template <typename T>
struct is_lua_reference_or_proxy : std::integral_constant<bool,
is_lua_reference<meta::unqualified_t<T>>::value
|| meta::is_specialization_of<meta::unqualified_t<T>, proxy>::value> {};
template <typename T>
struct is_main_threaded : std::is_base_of<main_reference, T> {};
@ -1109,19 +1130,6 @@ namespace sol {
template <typename T>
struct is_proxy_primitive : is_lua_primitive<T> {};
template <typename T>
struct is_transparent_argument : std::false_type {};
template <>
struct is_transparent_argument<this_state> : std::true_type {};
template <>
struct is_transparent_argument<this_main_state> : std::true_type {};
template <>
struct is_transparent_argument<this_environment> : std::true_type {};
template <>
struct is_transparent_argument<variadic_args> : std::true_type {};
template <typename T>
struct is_variadic_arguments : std::is_same<meta::unqualified_t<T>, variadic_args> {};
template <typename T>
struct is_lua_index : std::is_integral<T> {};
template <>

View File

@ -35,11 +35,11 @@ namespace sol {
template <typename T>
class usertype {
private:
std::unique_ptr<usertype_detail::registrar, detail::deleter> metatableregister;
std::unique_ptr<usertype_detail::registrar> metatableregister;
template <typename... Args>
usertype(detail::verified_tag, Args&&... args)
: metatableregister(detail::make_unique_deleter<usertype_metatable<T, std::make_index_sequence<sizeof...(Args) / 2>, Args...>, detail::deleter>(std::forward<Args>(args)...)) {
: metatableregister(std::make_unique<usertype_metatable<T, std::make_index_sequence<sizeof...(Args) / 2>, Args...>>(std::forward<Args>(args)...)) {
static_assert(detail::has_destructor<Args...>::value, "this type does not have an explicit destructor declared; please pass a custom destructor function wrapped in sol::destruct, especially if the type does not have an accessible (private) destructor");
}
@ -71,7 +71,7 @@ namespace sol {
template <typename... Args>
usertype(simple_tag, lua_State* L, Args&&... args)
: metatableregister(detail::make_unique_deleter<simple_usertype_metatable<T>, detail::deleter>(L, std::forward<Args>(args)...)) {
: metatableregister(std::make_unique<simple_usertype_metatable<T>>(L, std::forward<Args>(args)...)) {
}
usertype_detail::registrar* registrar_data() {

View File

@ -76,7 +76,7 @@ namespace sol {
template <typename T>
inline int oss_default_to_string(std::true_type, lua_State* L) {
std::ostringstream oss;
oss << stack::get<T>(L, 1);
oss << stack::unqualified_get<T>(L, 1);
return stack::push(L, oss.str());
}
@ -92,9 +92,9 @@ namespace sol {
template <typename T, typename Op>
int comparsion_operator_wrap(lua_State* L) {
auto maybel = stack::check_get<T>(L, 1);
auto maybel = stack::unqualified_check_get<T>(L, 1);
if (maybel) {
auto mayber = stack::check_get<T>(L, 2);
auto mayber = stack::unqualified_check_get<T&>(L, 2);
if (mayber) {
auto& l = *maybel;
auto& r = *mayber;

View File

@ -324,6 +324,28 @@ TEST_CASE("containers/table conversion", "test table conversions with as_table a
REQUIRE(nested_strings.source == expected_values);
}
TEST_CASE("containers/from table argument conversions", "test table conversions without as_table and nested for function args") {
const std::vector<std::string> expected_values{ "bark", "woof" };
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.set_function("f", [&](std::vector<std::string> t) {
return t == expected_values;
});
auto result0 = lua.safe_script("t = { \"bark\", \"woof\" }");
REQUIRE(result0.valid());
auto result1 = lua.safe_script("assert(f(t))", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::function f = lua["f"];
sol::table t = lua["t"];
bool passed = f(t);
REQUIRE(passed);
}
TEST_CASE("containers/vector roundtrip", "make sure vectors can be round-tripped") {
sol::state lua;
std::vector<int> v{ 1, 2, 3 };

View File

@ -335,7 +335,6 @@ TEST_CASE("functions/returning functions from C++", "check to see if returning a
}
}
#if !defined(SOL2_CI)
TEST_CASE("functions/function_result and protected_function_result", "Function result should be the beefy return type for sol::function that allows for error checking and error handlers") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::debug);
@ -345,42 +344,38 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r
// Some function; just using a lambda to be cheap
auto doomfx = []() {
INFO("doomfx called");
throw std::runtime_error(unhandlederrormessage);
};
auto luadoomfx = [&lua]() {
INFO("luadoomfx called");
// Does not bypass error function, will call it
luaL_error(lua.lua_state(), unhandlederrormessage);
};
lua.set_function("doom", doomfx);
lua.set_function("luadoom", luadoomfx);
auto cpphandlerfx = [](std::string x) {
INFO("c++ handler called with: " << x);
return handlederrormessage;
};
lua.set_function("cpphandler", cpphandlerfx);
auto result1 = lua.safe_script(
std::string("function luahandler ( message )")
+ " print('lua handler called with: ' .. message)"
+ " return '" + handlederrormessage + "'"
+ "end", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto nontrampolinefx = [](lua_State*) -> int { throw "x"; };
auto nontrampolinefx = [](lua_State* L) -> int {
return luaL_error(L, "x");
};
lua_CFunction c_nontrampolinefx = nontrampolinefx;
lua.set("nontrampoline", c_nontrampolinefx);
lua.set_function("bark", []() -> int { return 100; });
sol::function luahandler = lua["luahandler"];
sol::function cpphandler = lua["cpphandler"];
sol::protected_function doom(lua["doom"], luahandler);
sol::protected_function luadoom(lua["luadoom"]);
sol::protected_function nontrampoline = lua["nontrampoline"];
sol::protected_function nontrampoline(lua["nontrampoline"], cpphandler);
sol::protected_function justfine = lua["bark"];
sol::protected_function justfinewithhandler = lua["bark"];
luadoom.error_handler = cpphandler;
nontrampoline.error_handler = cpphandler;
justfinewithhandler.error_handler = luahandler;
bool present = true;
{
@ -395,18 +390,6 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r
sol::error err = result;
REQUIRE(err.what() == handlederrormessage_s);
}
{
sol::protected_function_result result = luadoom();
REQUIRE_FALSE(result.valid());
sol::optional<sol::error> operr = result;
sol::optional<int> opvalue = result;
present = (bool)operr;
REQUIRE(present);
present = (bool)opvalue;
REQUIRE_FALSE(present);
sol::error err = result;
REQUIRE(err.what() == handlederrormessage_s);
}
{
sol::protected_function_result result = nontrampoline();
REQUIRE_FALSE(result.valid());
@ -444,7 +427,72 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r
REQUIRE(value == 100);
}
}
#endif // x86 VC++ in release mode
#if !defined(SOL2_CI) && ((!defined(_M_IX86) || defined(_M_IA64)) || (defined(_WIN64)) || (defined(__LLP64__) || defined(__LP64__)) )
TEST_CASE("functions/unsafe protected_function_result handlers", "This test will thrash the stack and allocations on weaker compilers (e.g., non 64-bit ones). Run with caution.") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::debug);
static const char unhandlederrormessage[] = "true error message";
static const char handlederrormessage[] = "doodle";
static const std::string handlederrormessage_s = handlederrormessage;
auto luadoomfx = [&lua]() {
// Does not bypass error function, will call it
// however, this bypasses `catch` state
// in trampoline entirely...
luaL_error(lua.lua_state(), unhandlederrormessage);
};
lua.set_function("luadoom", luadoomfx);
auto cpphandlerfx = [](std::string x) {
INFO("c++ handler called with: " << x);
return handlederrormessage;
};
lua.set_function("cpphandler", cpphandlerfx);
auto nontrampolinefx = [](lua_State*) -> int {
// this code shoots an exception
// through the C API, without the trampoline
// present.
// it is probably guaranteed to kill our code.
throw "x";
};
lua_CFunction c_nontrampolinefx = nontrampolinefx;
lua.set("nontrampoline", c_nontrampolinefx);
lua.set_function("bark", []() -> int { return 100; });
sol::function cpphandler = lua["cpphandler"];
sol::protected_function luadoom(lua["luadoom"]);
sol::protected_function nontrampoline = lua["nontrampoline"];
luadoom.error_handler = cpphandler;
nontrampoline.error_handler = cpphandler;
bool present = true;
{
sol::protected_function_result result = luadoom();
REQUIRE_FALSE(result.valid());
sol::optional<sol::error> operr = result;
sol::optional<int> opvalue = result;
present = (bool)operr;
REQUIRE(present);
present = (bool)opvalue;
REQUIRE_FALSE(present);
sol::error err = result;
REQUIRE(err.what() == handlederrormessage_s);
}
{
sol::protected_function_result result = nontrampoline();
REQUIRE_FALSE(result.valid());
sol::optional<sol::error> operr = result;
sol::optional<int> opvalue = result;
present = (bool)operr;
REQUIRE(present);
present = (bool)opvalue;
REQUIRE_FALSE(present);
sol::error err = result;
REQUIRE(err.what() == handlederrormessage_s);
}
}
#endif // This test will thrash the stack and allocations on weaker compilers
TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure they all compile and work") {
sol::state lua;

View File

@ -36,14 +36,14 @@
#endif // SOL_DEFAULT_PASS_ON_ERROR
*/
#include <iostream>
#include <cstdlib>
#ifdef TEST_SINGLE
#include <sol_forward.hpp>
#endif // Single
#include <sol.hpp>
#include <iostream>
#include <cstdlib>
struct test_stack_guard {
lua_State* L;
int& begintop;

View File

@ -1,4 +1,4 @@
// sol2
// sol2
// The MIT License (MIT)
@ -304,8 +304,13 @@ struct matrix_xi {
};
template <typename SelfType>
struct alignas(16) weird_aligned_wrapper {
void operator()(SelfType& self, sol::object param) const {
template <typename F>
weird_aligned_wrapper(F&& f)
: lambda(std::forward<F>(f)) {
}
void operator()(SelfType& self, sol::object param) const {
lambda(self, param.as<float>());
}
std::function<void(SelfType&, float)> lambda;
};
@ -447,7 +452,8 @@ TEST_CASE("usertype/self-referential usertype", "usertype classes must play nice
auto result = lua.safe_script(
"local a = test.new()\n"
"a:g(\"woof\")\n"
"a:f(a)\n", sol::script_pass_on_error);
"a:f(a)\n",
sol::script_pass_on_error);
REQUIRE(result.valid());
}
@ -531,14 +537,14 @@ TEST_CASE("usertype/issue-number-thirty-five", "using value types created from l
{
auto result = lua.safe_script(
"v = Vec.new(1, 2, 3)\n"
"print(v:length())");
"v = Vec.new(1, 2, 3)\n"
"print(v:length())");
REQUIRE(result.valid());
}
{
auto result = lua.safe_script(
"v = Vec.new(1, 2, 3)\n"
"print(v:normalized():length())");
"v = Vec.new(1, 2, 3)\n"
"print(v:normalized():length())");
REQUIRE(result.valid());
}
}
@ -687,7 +693,8 @@ TEST_CASE("regressions/one", "issue number 48") {
sol::state lua;
lua.new_usertype<vars>("vars",
"boop", &vars::boop);
auto code = "beep = vars.new()\n"
auto code =
"beep = vars.new()\n"
"beep.boop = 1";
auto result1 = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(result1.valid());
@ -755,7 +762,8 @@ TEST_CASE("usertype/private-constructible", "Check to make sure special snowflak
REQUIRE(result.valid());
}
auto code1 = "local fresh_f = factory_test:new()\n"
auto code1 =
"local fresh_f = factory_test:new()\n"
"assert(fresh_f.a == true_a)\n";
auto result1 = lua.safe_script(code1, sol::script_pass_on_error);
REQUIRE(result1.valid());
@ -1798,9 +1806,11 @@ TEST_CASE("usertype/alignment", "ensure that alignment does not trigger weird al
struct aligned_derived : aligned_base {};
sol::state lua;
auto f = [](aligned_base& f, float d) {
REQUIRE(d == 5.0f);
};
lua.new_usertype<aligned_base>("Base",
"x", sol::writeonly_property(weird_aligned_wrapper<aligned_base>{}));
"x", sol::writeonly_property(weird_aligned_wrapper<aligned_base>(std::ref(f))));
lua.new_usertype<aligned_derived>("Derived",
sol::base_classes, sol::bases<aligned_base>());