overhaul examples and add 2 new ones in preparation for the coming hell

fix how `stack_aligned_protected_function` and its friends behave
add new internal handler details to allow for stack-based handlers with maximum performance
update `string_shim` typedef to simply be called `string_view` and use `string_view` in all public-facing APIs.
This commit is contained in:
ThePhD 2017-08-06 12:20:32 -04:00
parent 50040dec36
commit 03c229b25b
20 changed files with 390 additions and 152 deletions

View File

@ -1,4 +1,4 @@
## Sol 2.17 ## Sol 2.18
[![Join the chat at https://gitter.im/chat-sol2/Lobby](https://badges.gitter.im/chat-sol2/Lobby.svg)](https://gitter.im/chat-sol2/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/chat-sol2/Lobby](https://badges.gitter.im/chat-sol2/Lobby.svg)](https://gitter.im/chat-sol2/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

View File

@ -13,4 +13,48 @@ All of the base types have ``stack`` versions of themselves, and the APIs are id
stack_aligned_function stack_aligned_function
---------------------- ----------------------
This type is particular to working with the stack. It does not push the function object on the stack before pushing the arguments, assuming that the function present is already on the stack before going ahead and invoking the function it is targeted at. It is identical to :doc:`sol::function<function>` and has a protected counterpart as well. If you are working with the stack and know there is a callable object in the right place (i.e., at the top of the Lua stack), use this abstraction to work with the very top of the stack and have it call your function while still having the easy-to-use Lua abstractions on top. This type is particular to working with the stack. It does not push the function object on the stack before pushing the arguments, assuming that the function present is already on the stack before going ahead and invoking the function it is targeted at. It is identical to :doc:`sol::function<function>` and has a protected counterpart as well. If you are working with the stack and know there is a callable object in the right place (i.e., at the top of the Lua stack), use this abstraction to have it call your stack-based function while still having the easy-to-use Lua abstractions.
Furthermore, if you know you have a function in the right place alongside proper arguments on top of it, you can use the ``sol::stack_count`` structure and give its constructor the number of arguments off the top that you want to call your pre-prepared function with:
.. code-block:: cpp
:caption: stack_aligned_function.cpp
:linenos:
:name: stack-top-example
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
int main (int, char*[]) {
sol::state lua;
lua.set_function("func", [](int a, int b) { return (a + b) * 2;});
sol::reference func_ref = lua["func"];
lua_State* L = lua.lua_state();
// for some reason, you need to use the low-level API
func_ref.push(); // function on stack now
// maybe this is in a lua_CFunction you bind,
// or maybe you're trying to work with a pre-existing system
sol::stack_aligned_function func(L, -1);
lua_pushinteger(L, 5); // argument 1
lua_pushinteger(L, 6); // argument 2
// take 2 arguments from the top,
// and use "stack_aligned_function" to call
int result = func(sol::stack_count(2));
// make sure everything is clean
assert(result == 22);
assert(lua.stack_top() == 0); // stack is empty/balanced
return 0;
}
Finally, there is a special abstraction that provides further stack optimizations for ``sol::protected_function`` variants that are aligned, and it is called ``sol::stack_aligned_stack_handler_protected_function``. This typedef expects you to pass a ``stack_reference`` handler to its constructor, meaning that you have already placed an appropriate error-handling function somewhere on the stack before the aligned function. You can use ``sol::stack_count`` with this type as well,
.. warning::
Do not use ``sol::stack_top`` with a ``sol::stack_aligned_protected_function``. The default behavior checks if the ``error_handler`` member variable is valid, and attempts to push the handler onto the stack in preparation for calling the function. This inevitably changes the stack. Only use ``sol::stack_aligned_protected_function`` if you know that the handler is not valid (``nil``), or if you use ``sol::stack_aligned_stack_handler_protected_function``, which references an existing stack index that can be before the precise placement of the function and its arguments.

View File

@ -52,26 +52,28 @@ members
This function takes a number of :ref:`sol::lib<lib-enum>` as arguments and opens up the associated Lua core libraries. This function takes a number of :ref:`sol::lib<lib-enum>` as arguments and opens up the associated Lua core libraries.
.. code-block:: cpp .. code-block:: cpp
:caption: function: script / script_file :caption: function: script / safe_script / script_file / safe_script_file / unsafe_script / unsafe_script_file
:name: state-script-function :name: state-script-function
sol::function_result script(const std::string& code); function_result script(const string_view& code, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::protected_function_result script(const std::string& code, const environment& env); protected_function_result script(const string_view& code, const environment& env, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
template <typename ErrorFunc> template <typename ErrorFunc>
sol::protected_function_result script(const std::string& code, ErrorFunc&& on_error); protected_function_result script(const string_view& code, ErrorFunc&& on_error, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
template <typename ErrorFunc> template <typename ErrorFunc>
sol::protected_function_result script(const std::string& code, const environment& env, ErrorFunc&& on_error); protected_function_result script(const string_view& code, const environment& env, ErrorFunc&& on_error, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::function_result script_file(const std::string& filename); function_result script_file(const std::string& filename, load_mode mode = load_mode::any);
sol::protected_function_result script_file(const std::string& filename, const environment& env); protected_function_result script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any);
template <typename ErrorFunc> template <typename ErrorFunc>
sol::protected_function_result script_file(const std::string& filename, ErrorFunc&& on_error); protected_function_result script_file(const std::string& filename, ErrorFunc&& on_error, load_mode mode = load_mode::any);
template <typename ErrorFunc> template <typename ErrorFunc>
sol::protected_function_result script_file(const std::string& filename, const environment& env, ErrorFunc&& on_error); protected_function_result script_file(const std::string& filename, const environment& env, ErrorFunc&& on_error, load_mode mode = load_mode::any);
If you need safety, please use the version of these functions with ``safe_script(_file)`` appended in front of them. They will always check for errors and always return a ``sol::protected_function_result``. If you explicitly do not want to check for errors and want to simply invoke ``lua_error`` in the case of errors, use ``unsafe_script(_file)`` versions.
These functions run the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. It will not run isolated: any scripts or code run will affect code in the ``lua_State*`` the object uses as well (unless ``local`` is applied to a variable declaration, as specified by the Lua language). Code ran in this fashion is not isolated. If you need isolation, consider creating a new state or traditional Lua sandboxing techniques. These functions run the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. It will not run isolated: any scripts or code run will affect code in the ``lua_State*`` the object uses as well (unless ``local`` is applied to a variable declaration, as specified by the Lua language). Code ran in this fashion is not isolated. If you need isolation, consider creating a new state or traditional Lua sandboxing techniques.
If your script returns a value, you can capture it from the returned :ref:`sol::function_result<function-result>`/:ref:`sol::protected_function_result<protected-function-result>`. Note that the plain versions that do not take an environment or a callback function assume that the contents internally not only loaded properly but ran to completion without errors, for the sake of simplicity. If your script returns a value, you can capture it from the returned :ref:`sol::function_result<function-result>`/:ref:`sol::protected_function_result<protected-function-result>`. Note that the plain versions that do not take an environment or a callback function assume that the contents internally not only loaded properly but ran to completion without errors, for the sake of simplicity and performance.
To handle errors when using the second overload, provide a callable function/object that takes a ``lua_State*`` as its first argument and a ``sol::protected_function_result`` as its second argument. Then, handle the errors any way you like: To handle errors when using the second overload, provide a callable function/object that takes a ``lua_State*`` as its first argument and a ``sol::protected_function_result`` as its second argument. Then, handle the errors any way you like:
@ -82,8 +84,8 @@ To handle errors when using the second overload, provide a callable function/obj
int main () { int main () {
sol::state lua; sol::state lua;
// the default handler panics or throws, depending on your settings // the default handler panics or throws, depending on your settings
auto result1 = lua.script("bad.code", &sol::default_on_error); auto result1 = lua.safe_script("bad.code");
auto result2 = lua.script("123 bad.code", [](lua_State* L, sol::protected_function_result pfr) { auto result2 = lua.safe_script("123 bad.code", [](lua_State* L, sol::protected_function_result pfr) {
// pfr will contain things that went wrong, for either loading or executing the script // pfr will contain things that went wrong, for either loading or executing the script
// the user can do whatever they like here, including throw. Otherwise, // the user can do whatever they like here, including throw. Otherwise,
// they need to return the protected_function_result // they need to return the protected_function_result
@ -117,15 +119,17 @@ Thanks to `Eric (EToreo) for the suggestion on this one`_!
These functions *load* the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. That blob will be turned into a Lua Function. It will not be run: it returns a ``load_result`` proxy that can be called to actually run the code, when you are ready. It can also be turned into a ``sol::function``, a ``sol::protected_function``, or some other abstraction that can serve to call the function. If it is called, it will run on the object's current ``lua_State*``: it is not isolated. If you need isolation, consider using :doc:`sol::environment<environment>`, creating a new state, or other Lua sandboxing techniques. These functions *load* the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. That blob will be turned into a Lua Function. It will not be run: it returns a ``load_result`` proxy that can be called to actually run the code, when you are ready. It can also be turned into a ``sol::function``, a ``sol::protected_function``, or some other abstraction that can serve to call the function. If it is called, it will run on the object's current ``lua_State*``: it is not isolated. If you need isolation, consider using :doc:`sol::environment<environment>`, creating a new state, or other Lua sandboxing techniques.
Finally, if you have a custom source of data, you can use the ``lua_Reader`` overloaded function alongside passing in a ``void*`` pointing to a single type that has everything you need to run it. Use that callback to provide data to the underlying Lua implementation to read data, as explained `in the Lua manual`_.
This is a low-level function and if you do not understand the difference between loading a piece of code versus running that code, you should be using :ref:`state_view::script<state-script-function>`. This is a low-level function and if you do not understand the difference between loading a piece of code versus running that code, you should be using :ref:`state_view::script<state-script-function>`.
.. code-block:: cpp .. code-block:: cpp
:caption: function: do_string / do_file :caption: function: do_string / do_file
:name: state-do-code :name: state-do-code
sol::protected_function_result do_string(const std::string& code); sol::protected_function_result do_string(const string_view& code);
sol::protected_function_result do_file(const std::string& filename); sol::protected_function_result do_file(const std::string& filename);
sol::protected_function_result do_string(const std::string& code, sol::environment env); sol::protected_function_result do_string(const string_view& code, sol::environment env);
sol::protected_function_result do_file(const std::string& filename, sol::environment env); sol::protected_function_result do_file(const std::string& filename, sol::environment env);
These functions *loads and performs* the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. It *will* run, and then return a ``protected_function_result`` proxy that can be examined for either an error or the return value. This function does not provide a callback like :ref:`state_view::script<state-script-function>` does. It is a lower-level function that performs less checking and directly calls ``load(_file)`` before running the result, with the optional environment. These functions *loads and performs* the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. It *will* run, and then return a ``protected_function_result`` proxy that can be examined for either an error or the return value. This function does not provide a callback like :ref:`state_view::script<state-script-function>` does. It is a lower-level function that performs less checking and directly calls ``load(_file)`` before running the result, with the optional environment.
@ -187,4 +191,5 @@ Creates a table. Forwards its arguments to :ref:`table::create<table-create>`. A
.. _standard lua libraries: http://www.lua.org/manual/5.3/manual.html#6 .. _standard lua libraries: http://www.lua.org/manual/5.3/manual.html#6
.. _luaL_requiref: https://www.lua.org/manual/5.3/manual.html#luaL_requiref .. _luaL_requiref: https://www.lua.org/manual/5.3/manual.html#luaL_requiref
.. _Eric (EToreo) for the suggestion on this one: https://github.com/ThePhD/sol2/issues/90 .. _Eric (EToreo) for the suggestion on this one: https://github.com/ThePhD/sol2/issues/90
.. _in the Lua manual: https://www.lua.org/manual/5.3/manual.html#lua_Reader

View File

@ -51,7 +51,7 @@ master_doc = 'index'
# General information about the project. # General information about the project.
project = 'Sol' project = 'Sol'
copyright = '2016, ThePhD' copyright = '2017, ThePhD'
author = 'ThePhD' author = 'ThePhD'
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
@ -59,9 +59,9 @@ author = 'ThePhD'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '2.17' version = '2.18'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '2.17.5' release = '2.18.0'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -1,8 +1,18 @@
containers containers
========== ==========
*working with containers in sol2*
Containers are objects that are meant to be inspected and iterated and whose job is to typically provide storage to a collection of items. The ``std::`` library has several containers of varying types, and all of them have ``begin()`` and ``end()`` function which return iterators. C-style arrays are also containers, and sol2 will detect all of them for use and bestow them with special properties and functions. Containers are objects that are meant to be inspected and iterated and whose job is to typically provide storage to a collection of items. The ``std::`` library has several containers of varying types, and all of them have ``begin()`` and ``end()`` function which return iterators. C-style arrays are also containers, and sol2 will detect all of them for use and bestow them with special properties and functions.
* Containers from C++ are stored as ``userdata`` with special ``usertype`` metatables with :ref:`special operations<container-operations>`
* Containers can be manipulated from C++ and Lua and, like userdata, will `reflect changes if you use a reference`_ to the data.
* This means containers **do not automatically serialize as Lua tables**
- If you need tables, consider using ``sol::as_table`` and ``sol::nested``
- See `this table serialization example`_ for more details
* Lua 5.1 has different semantics for ``pairs`` and ``ipairs``: see the example for plain containers in the :doc:`api documentation page for containers<api/containers>`
* You can override container behavior by overriding :ref:`the detection trait<container-detection>` and :ref:`specializing the container_traits template<container-traits>`
* You can bind typical C-style arrays, but must follow :ref:`the rules<container-c-array>`
.. _container-c-array: .. _container-c-array:
.. note:: .. note::
@ -40,6 +50,8 @@ You can also specialize ``sol::is_container<T>`` to turn off container detection
This will let the type be pushed as a regular userdata. This will let the type be pushed as a regular userdata.
.. _container-traits:
container overriding container overriding
-------------------- --------------------
@ -71,6 +83,7 @@ The various operations provided by ``container_traits<T>`` are expected to be li
Exception handling **WILL** be provided around these particular raw C functions, so you do not need to worry about exceptions or errors bubbling through and handling that part. It is specifically handled for you in this specific instance, and **ONLY** in this specific instance. The raw note still applies to every other raw C function you make manually. Exception handling **WILL** be provided around these particular raw C functions, so you do not need to worry about exceptions or errors bubbling through and handling that part. It is specifically handled for you in this specific instance, and **ONLY** in this specific instance. The raw note still applies to every other raw C function you make manually.
.. _container-operations::
container operations container operations
------------------------- -------------------------
@ -167,3 +180,5 @@ When you serialize a container into sol2, the default container handler deals wi
.. _online version's information: https://www.lua.org/pil/26.html .. _online version's information: https://www.lua.org/pil/26.html
.. _reflect changes if you use a reference: https://github.com/ThePhD/sol2/blob/develop/examples/containers.cpp
.. _this table serialization example: https://github.com/ThePhD/sol2/blob/develop/examples/containers_as_table.cpp

View File

@ -0,0 +1,41 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
#include <iostream>
struct cpp_class {
int value = 0;
};
int main(int, char*[]) {
std::cout << "=== runtime_additions example ===" << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<cpp_class>("object");
// runtime additions: through the sol API
lua["object"]["func"] = [](cpp_class& o) {
++o.value;
return o.value;
};
// runtime additions: through a lua script
lua.script(R"(
function object:print ()
print(self:func())
end
)");
// see it work
lua.script(R"(
obj = object.new()
obj:print()
)");
object& obj = lua["obj"];
assert(obj.value == 1);
return 0;
}

View File

@ -16,7 +16,7 @@ namespace my_object {
return module; return module;
} }
} } // namespace my_object
extern "C" int luaopen_my_object(lua_State* L) { extern "C" int luaopen_my_object(lua_State* L) {
// pass the lua_State, // pass the lua_State,

View File

@ -2,6 +2,14 @@
#include "my_object_api.hpp" #include "my_object_api.hpp"
// forward declare as a C struct
// so a pointer to lua_State can be part of a signature
extern "C" {
struct lua_State;
}
// you can replace the above if you're fine with including
// <sol.hpp> earlier than absolutely necessary
namespace my_object { namespace my_object {
struct test { struct test {
@ -11,7 +19,7 @@ namespace my_object {
test(int val) : value(val) {} test(int val) : value(val) {}
}; };
} // my_object } // namespace my_object
// this function needs to be exported from your // this function needs to be exported from your
// dll. "extern 'C'" should do the trick, but // dll. "extern 'C'" should do the trick, but

View File

@ -3,30 +3,25 @@
namespace my_object { namespace my_object {
#if defined _MSC_VER #if defined _MSC_VER
#define MY_OBJECT_VC #define MY_OBJECT_VC
#elif defined __GNUC__ #elif defined __GNUC__
#define MY_OBJECT_GCC #define MY_OBJECT_GCC
#elif defined __clang__ #elif defined __clang__
#define MY_OBJECT_CLANG #define MY_OBJECT_CLANG
#endif #endif
#if !defined(_NDEBUG)
#define MY_OBJECT_DEBUG
#else
#endif // Debug || Not-Debug
#if defined MY_OBJECT_VC #if defined MY_OBJECT_VC
#if defined MY_OBJECT_DLL #if defined MY_OBJECT_DLL
#if defined MY_OBJECT_BUILD #if defined MY_OBJECT_BUILD
#define MY_OBJECT_API __declspec(dllexport) #define MY_OBJECT_API __declspec(dllexport)
#else #else
#define MY_OBJECT_API __declspec(dllexport) #define MY_OBJECT_API __declspec(dllexport)
#endif // MY_OBJECT_BUILD - Building the Library vs. Using the Library #endif // MY_OBJECT_BUILD - Building the Library vs. Using the Library
#else #else
#define MY_OBJECT_API #define MY_OBJECT_API
#endif // Building a DLL vs. Static Library #endif // Building a DLL vs. Static Library
#else #else // g++ / clang++
#define MY_OBJECT_API #define MY_OBJECT_API __attribute__ ((visibility ("default")))
#endif #endif // MY_OBJECT_BUILD
} // my_object } // namespace my_object

View File

@ -0,0 +1,34 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
int main(int, char*[]) {
sol::state lua;
lua.script("function func (a, b) return (a + b) * 2 end");
sol::reference func_ref = lua["func"];
// for some reason, you need to use the low-level API
func_ref.push(); // function on stack now
// maybe this is in a lua_CFunction you bind,
// or maybe you're trying to work with a pre-existing system
// maybe you've used a custom lua_load call, or you're working
// with state_view's load(lua_Reader, ...) call...
// here's a little bit of how you can work with the stack
lua_State* L = lua.lua_state();
sol::stack_aligned_function func(L, -1);
lua_pushinteger(L, 5); // argument 1, using plain API
lua_pushinteger(L, 6); // argument 2
// take 2 arguments from the top,
// and use "stack_aligned_function" to call
int result = func(sol::stack_count(2));
// make sure everything is clean
assert(result == 22);
assert(lua.stack_top() == 0); // stack is empty/balanced
return 0;
}

View File

@ -53,14 +53,14 @@ namespace sol {
using stack_environment = basic_environment<stack_reference>; using stack_environment = basic_environment<stack_reference>;
template <typename T, bool> template <typename T, bool>
class basic_function; class basic_function;
template <typename T, bool> template <typename T, bool, typename H>
class basic_protected_function; class basic_protected_function;
using unsafe_function = basic_function<reference, false>; using unsafe_function = basic_function<reference, false>;
using safe_function = basic_protected_function<reference, false>; using safe_function = basic_protected_function<reference, false, reference>;
using stack_unsafe_function = basic_function<stack_reference, false>; using stack_unsafe_function = basic_function<stack_reference, false>;
using stack_safe_function = basic_protected_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_unsafe_function = basic_function<stack_reference, true>;
using stack_aligned_safe_function = basic_protected_function<stack_reference, true>; using stack_aligned_safe_function = basic_protected_function<stack_reference, true, reference>;
using protected_function = safe_function; using protected_function = safe_function;
using stack_protected_function = stack_safe_function; using stack_protected_function = stack_safe_function;
using stack_aligned_protected_function = stack_aligned_safe_function; using stack_aligned_protected_function = stack_aligned_safe_function;
@ -73,6 +73,8 @@ namespace sol {
using stack_function = stack_unsafe_function; using stack_function = stack_unsafe_function;
using stack_aligned_function = stack_aligned_unsafe_function; using stack_aligned_function = stack_aligned_unsafe_function;
#endif #endif
using stack_aligned_stack_handler_function = basic_protected_function<stack_reference, true, stack_reference>;
struct function_result; struct function_result;
struct protected_function_result; struct protected_function_result;
using safe_function_result = protected_function_result; using safe_function_result = protected_function_result;

View File

@ -46,9 +46,7 @@ namespace sol {
// Must be manual, otherwise destructor will screw us // Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean // return count being 0 is enough to keep things clean
// but will be thorough // but will be thorough
o.L = nullptr; o.abandon();
o.index = 0;
o.returncount = 0;
} }
function_result& operator=(function_result&& o) { function_result& operator=(function_result&& o) {
L = o.L; L = o.L;
@ -57,9 +55,7 @@ namespace sol {
// Must be manual, otherwise destructor will screw us // Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean // return count being 0 is enough to keep things clean
// but will be thorough // but will be thorough
o.L = nullptr; o.abandon();
o.index = 0;
o.returncount = 0;
return *this; return *this;
} }
@ -79,7 +75,11 @@ namespace sol {
lua_State* lua_state() const { return L; }; lua_State* lua_state() const { return L; };
int stack_index() const { return index; }; int stack_index() const { return index; };
int return_count() const { return returncount; }; int return_count() const { return returncount; };
void abandon() noexcept {
L = nullptr;
index = 0;
returncount = 0;
}
~function_result() { ~function_result() {
lua_pop(L, returncount); lua_pop(L, returncount);
} }

View File

@ -36,63 +36,90 @@ namespace sol {
return name; return name;
} }
template <bool b, typename target_t = reference>
struct handler { struct handler {
const reference& target; typedef std::is_base_of<stack_reference, target_t> is_stack;
const target_t& target;
int stackindex; int stackindex;
handler(const reference& target) : target(target), stackindex(0) {
if (target.valid()) { handler(std::false_type, const target_t& target) : target(target), stackindex(0) {
if (b) {
stackindex = lua_gettop(target.lua_state()) + 1; stackindex = lua_gettop(target.lua_state()) + 1;
target.push(); target.push();
} }
} }
bool valid() const { return stackindex != 0; }
handler(std::true_type, const target_t& target) : target(target), stackindex(0) {
if (b) {
stackindex = target.stack_index();
}
}
handler(const target_t& target) : handler(is_stack(), target) {}
bool valid() const noexcept { return b; }
~handler() { ~handler() {
if (valid()) { if (b && !is_stack::value) {
lua_remove(target.lua_state(), stackindex); lua_remove(target.lua_state(), stackindex);
} }
} }
}; };
} } // detail
template <typename base_t, bool aligned = false> template <typename base_t, bool aligned = false, typename handler_t = reference>
class basic_protected_function : public base_t { class basic_protected_function : public base_t {
public: public:
static reference get_default_handler(lua_State* L) { typedef std::is_base_of<stack_reference, handler_t> is_stack_handler;
if (L == nullptr)
return reference(lua_nil); static handler_t get_default_handler(lua_State* L) {
if (is_stack_handler::value || L == nullptr)
return handler_t(L, lua_nil);
lua_getglobal(L, detail::default_handler_name()); lua_getglobal(L, detail::default_handler_name());
auto pp = stack::pop_n(L, 1); auto pp = stack::pop_n(L, 1);
return reference(L, -1); return handler_t(L, -1);
} }
static void set_default_handler(const reference& ref) { template <typename T>
ref.push(); static void set_default_handler(const T& ref) {
lua_setglobal(ref.lua_state(), detail::default_handler_name()); if (ref.lua_state() == nullptr) {
return;
}
if (!ref.valid()) {
lua_pushnil(ref.lua_state());
lua_setglobal(ref.lua_state(), detail::default_handler_name());
}
else {
ref.push();
lua_setglobal(ref.lua_state(), detail::default_handler_name());
}
} }
private: private:
call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::handler& h) const { template <bool b>
call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::handler<b, handler_t>& h) const {
return static_cast<call_status>(lua_pcallk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr)); return static_cast<call_status>(lua_pcallk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr));
} }
template<std::size_t... I, typename... Ret> template<std::size_t... I, bool b, typename... Ret>
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::handler& h) const { auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const {
luacall(n, sizeof...(Ret), h); luacall(n, sizeof...(Ret), h);
return stack::pop<std::tuple<Ret...>>(lua_state()); return stack::pop<std::tuple<Ret...>>(lua_state());
} }
template<std::size_t I, typename Ret> template<std::size_t I, bool b, typename Ret>
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler& h) const { Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const {
luacall(n, 1, h); luacall(n, 1, h);
return stack::pop<Ret>(lua_state()); return stack::pop<Ret>(lua_state());
} }
template <std::size_t I> template <std::size_t I, bool b>
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler& h) const { void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const {
luacall(n, 0, h); luacall(n, 0, h);
} }
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::handler& h) const { template <bool b>
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const {
int stacksize = lua_gettop(lua_state()); int stacksize = lua_gettop(lua_state());
int poststacksize = stacksize; int poststacksize = stacksize;
int firstreturn = 1; int firstreturn = 1;
@ -141,7 +168,7 @@ namespace sol {
public: public:
using base_t::lua_state; using base_t::lua_state;
reference error_handler; handler_t error_handler;
basic_protected_function() = default; basic_protected_function() = default;
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler>
@ -159,12 +186,12 @@ namespace sol {
basic_protected_function& operator=(basic_protected_function&&) = default; basic_protected_function& operator=(basic_protected_function&&) = default;
basic_protected_function(const basic_function<base_t>& b) : basic_protected_function(b, get_default_handler(b.lua_state())) {} basic_protected_function(const basic_function<base_t>& b) : basic_protected_function(b, get_default_handler(b.lua_state())) {}
basic_protected_function(basic_function<base_t>&& b) : basic_protected_function(std::move(b), get_default_handler(b.lua_state())) {} basic_protected_function(basic_function<base_t>&& b) : basic_protected_function(std::move(b), get_default_handler(b.lua_state())) {}
basic_protected_function(const basic_function<base_t>& b, reference eh) : base_t(b), error_handler(std::move(eh)) {} basic_protected_function(const basic_function<base_t>& b, handler_t eh) : base_t(b), error_handler(std::move(eh)) {}
basic_protected_function(basic_function<base_t>&& b, reference eh) : base_t(std::move(b)), error_handler(std::move(eh)) {} basic_protected_function(basic_function<base_t>&& b, handler_t eh) : base_t(std::move(b)), error_handler(std::move(eh)) {}
basic_protected_function(const stack_reference& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {} basic_protected_function(const stack_reference& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {}
basic_protected_function(stack_reference&& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {} basic_protected_function(stack_reference&& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {}
basic_protected_function(const stack_reference& r, reference eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {} basic_protected_function(const stack_reference& r, handler_t eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {}
basic_protected_function(stack_reference&& r, reference eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {} basic_protected_function(stack_reference&& r, handler_t eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {}
template <typename Super> template <typename Super>
basic_protected_function(const proxy_base<Super>& p) : basic_protected_function(p.operator basic_function<base_t>(), get_default_handler(p.lua_state())) {} basic_protected_function(const proxy_base<Super>& p) : basic_protected_function(p.operator basic_function<base_t>(), get_default_handler(p.lua_state())) {}
template <typename Super> template <typename Super>
@ -172,27 +199,27 @@ namespace sol {
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler> template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_protected_function(lua_State* L, T&& r) : basic_protected_function(L, std::forward<T>(r), get_default_handler(L)) {} basic_protected_function(lua_State* L, T&& r) : basic_protected_function(L, std::forward<T>(r), get_default_handler(L)) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler> template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_protected_function(lua_State* L, T&& r, reference eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {} basic_protected_function(lua_State* L, T&& r, handler_t eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {}
basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, int index, reference eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic); stack::check<basic_protected_function>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_State* L, absolute_index index) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, absolute_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, absolute_index index, reference eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic); stack::check<basic_protected_function>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_State* L, raw_index index) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, raw_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, raw_index index, reference eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic); stack::check<basic_protected_function>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_State* L, ref_index index) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, ref_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, ref_index index, reference eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_protected_function>(L, -1, type_panic); stack::check<basic_protected_function>(L, -1, type_panic);
@ -211,12 +238,45 @@ namespace sol {
template<typename... Ret, typename... Args> template<typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) const { decltype(auto) call(Args&&... args) const {
detail::handler h(error_handler);
if (!aligned) { if (!aligned) {
base_t::push(); // we do not expect the function to already be on the stack: push it
if (error_handler.valid()) {
detail::handler<true, handler_t> h(error_handler);
base_t::push();
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
}
else {
detail::handler<false, handler_t> h(error_handler);
base_t::push();
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
}
}
else {
// the function is already on the stack at the right location
if (error_handler.valid()) {
// the handler will be pushed onto the stack manually,
// since it's not already on the stack this means we need to push our own
// function on the stack too and swap things to be in-place
if (!is_stack_handler::value) {
// so, we need to remove the function at the top and then dump the handler out ourselves
base_t::push();
}
detail::handler<true, handler_t> h(error_handler);
if (!is_stack_handler::value) {
lua_replace(lua_state(), -3);
h.stackindex = lua_absindex(lua_state(), -2);
}
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
}
else {
detail::handler<false, handler_t> h(error_handler);
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
}
} }
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
} }
}; };
} // sol } // sol

View File

@ -82,11 +82,7 @@ namespace sol {
// Must be manual, otherwise destructor will screw us // Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean // return count being 0 is enough to keep things clean
// but we will be thorough // but we will be thorough
o.L = nullptr; o.abandon();
o.index = 0;
o.returncount = 0;
o.popcount = 0;
o.err = call_status::runtime;
} }
protected_function_result& operator=(protected_function_result&& o) noexcept { protected_function_result& operator=(protected_function_result&& o) noexcept {
L = o.L; L = o.L;
@ -97,11 +93,7 @@ namespace sol {
// Must be manual, otherwise destructor will screw us // Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean // return count being 0 is enough to keep things clean
// but we will be thorough // but we will be thorough
o.L = nullptr; o.abandon();
o.index = 0;
o.returncount = 0;
o.popcount = 0;
o.err = call_status::runtime;
return *this; return *this;
} }
@ -122,7 +114,13 @@ namespace sol {
int stack_index() const noexcept { return index; }; int stack_index() const noexcept { return index; };
int return_count() const noexcept { return returncount; }; int return_count() const noexcept { return returncount; };
int pop_count() const noexcept { return popcount; }; int pop_count() const noexcept { return popcount; };
void abandon() noexcept {
L = nullptr;
index = 0;
returncount = 0;
popcount = 0;
err = call_status::runtime;
}
~protected_function_result() { ~protected_function_result() {
stack::remove(L, index, popcount); stack::remove(L, index, popcount);
} }

View File

@ -140,6 +140,7 @@ namespace sol {
lua_rawgeti(L, LUA_REGISTRYINDEX, index.index); lua_rawgeti(L, LUA_REGISTRYINDEX, index.index);
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
} }
reference(lua_State* L, lua_nil_t) noexcept : luastate(L) {}
~reference() noexcept { ~reference() noexcept {
deref(); deref();

View File

@ -38,6 +38,7 @@ namespace sol {
public: public:
stack_reference() noexcept = default; stack_reference() noexcept = default;
stack_reference(lua_nil_t) noexcept : stack_reference() {}; stack_reference(lua_nil_t) noexcept : stack_reference() {};
stack_reference(lua_State* L, lua_nil_t) noexcept : L(L), index(0) {}
stack_reference(lua_State* L, int i) noexcept : L(L), index(lua_absindex(L, i)) {} stack_reference(lua_State* L, int i) noexcept : L(L), index(lua_absindex(L, i)) {}
stack_reference(lua_State* L, absolute_index i) noexcept : L(L), index(i) {} stack_reference(lua_State* L, absolute_index i) noexcept : L(L), index(i) {}
stack_reference(lua_State* L, raw_index i) noexcept : L(L), index(i) {} stack_reference(lua_State* L, raw_index i) noexcept : L(L), index(i) {}

View File

@ -64,7 +64,7 @@ namespace sol {
err += " error:"; err += " error:";
if (t == type::string) { if (t == type::string) {
err += " "; err += " ";
string_detail::string_shim serr = stack::get<string_detail::string_shim>(L, pfr.stack_index()); string_view serr = stack::get<string_view>(L, pfr.stack_index());
err.append(serr.data(), serr.size()); err.append(serr.data(), serr.size());
} }
#ifdef SOL_NO_EXCEPTIONS #ifdef SOL_NO_EXCEPTIONS
@ -253,7 +253,7 @@ namespace sol {
return stack::pop<object>(L); return stack::pop<object>(L);
} }
object require_script(const std::string& key, const string_detail::string_shim& code, bool create_global = true, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { object require_script(const std::string& key, const string_view& code, bool create_global = true, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return require_core(key, [this, &code, &chunkname, &mode]() {stack::script(L, code, chunkname, mode); }, create_global); return require_core(key, [this, &code, &chunkname, &mode]() {stack::script(L, code, chunkname, mode); }, create_global);
} }
@ -262,13 +262,12 @@ namespace sol {
} }
template <typename E> template <typename E>
protected_function_result do_string(const string_detail::string_shim& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result do_string(const string_view& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunkname.c_str(), to_string(mode).c_str())); load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunkname.c_str(), to_string(mode).c_str()));
if (x != load_status::ok) { if (x != load_status::ok) {
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x)); return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));
} }
protected_function pf(L, -1); stack_aligned_protected_function pf(L, -1);
pf.pop();
set_environment(env, pf); set_environment(env, pf);
return pf(); return pf();
} }
@ -277,36 +276,33 @@ namespace sol {
protected_function_result do_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) { protected_function_result do_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));
if (x != load_status::ok) { if (x != load_status::ok) {
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x)); return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));
} }
protected_function pf(L, -1); stack_aligned_protected_function pf(L, -1);
pf.pop();
set_environment(env, pf); set_environment(env, pf);
return pf(); return pf();
} }
protected_function_result do_string(const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result do_string(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunkname.c_str(), to_string(mode).c_str())); load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunkname.c_str(), to_string(mode).c_str()));
if (x != load_status::ok) { if (x != load_status::ok) {
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x)); return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));
} }
protected_function pf(L, -1); stack_aligned_protected_function pf(L, -1);
pf.pop();
return pf(); return pf();
} }
protected_function_result do_file(const std::string& filename, load_mode mode = load_mode::any) { protected_function_result do_file(const std::string& filename, load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));
if (x != load_status::ok) { if (x != load_status::ok) {
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x)); return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));
} }
protected_function pf(L, -1); stack_aligned_protected_function pf(L, -1);
pf.pop();
return pf(); return pf();
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result safe_script(const string_detail::string_shim& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result safe_script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
protected_function_result pfr = do_string(code, chunkname, mode); protected_function_result pfr = do_string(code, chunkname, mode);
if (!pfr.valid()) { if (!pfr.valid()) {
return on_error(L, std::move(pfr)); return on_error(L, std::move(pfr));
@ -314,18 +310,27 @@ namespace sol {
return pfr; return pfr;
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, typename E>
protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { protected_function_result safe_script(const string_view& code, const basic_environment<E>& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
protected_function_result pfr = do_file(filename, mode); protected_function_result pfr = do_string(code, env, chunkname, mode);
if (!pfr.valid()) { if (!pfr.valid()) {
return on_error(L, std::move(pfr)); return on_error(L, std::move(pfr));
} }
return pfr; return pfr;
} }
template <typename Fx, typename E> template <typename E>
protected_function_result safe_script(const string_detail::string_shim& code, const basic_environment<E>& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result safe_script(const string_view& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
protected_function_result pfr = do_string(code, env, chunkname, mode); return safe_script(code, env, script_default_on_error, chunkname, mode);
}
protected_function_result safe_script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, script_default_on_error, chunkname, mode);
}
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) {
protected_function_result pfr = do_file(filename, mode);
if (!pfr.valid()) { if (!pfr.valid()) {
return on_error(L, std::move(pfr)); return on_error(L, std::move(pfr));
} }
@ -341,23 +346,31 @@ namespace sol {
return pfr; return pfr;
} }
protected_function_result safe_script(const string_detail::string_shim& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { template <typename E>
return safe_script(code, env, sol::script_default_on_error, chunkname, mode); protected_function_result safe_script_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) {
} return safe_script_file(filename, env, script_default_on_error, mode);
protected_function_result safe_script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any) {
return safe_script_file(filename, env, sol::script_default_on_error, mode);
}
protected_function_result safe_script(const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, sol::script_default_on_error, chunkname, mode);
} }
protected_function_result safe_script_file(const std::string& filename, load_mode mode = load_mode::any) { protected_function_result safe_script_file(const std::string& filename, load_mode mode = load_mode::any) {
return safe_script_file(filename, sol::script_default_on_error, mode); return safe_script_file(filename, script_default_on_error, mode);
} }
function_result unsafe_script(const string_detail::string_shim& code, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) { template <typename E>
function_result unsafe_script(const string_view& code, const sol::basic_environment<E>& env, load_mode mode = load_mode::any) {
int index = lua_gettop(L);
if (luaL_loadbufferx(L, code.data(), code.size(), name.data(), to_string(mode).c_str())) {
lua_error(L);
}
set_environment(env, stack_reference(L, raw_index(index + 1)));
if (lua_call(L, 0, LUA_MULTRET)) {
lua_error(L);
}
int postindex = lua_gettop(L);
int returns = postindex - index;
return function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
}
function_result unsafe_script(const string_view& code, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) {
int index = lua_gettop(L); int index = lua_gettop(L);
stack::script(L, code, name, mode); stack::script(L, code, name, mode);
int postindex = lua_gettop(L); int postindex = lua_gettop(L);
@ -365,6 +378,21 @@ namespace sol {
return function_result(L, (std::max)(postindex - (returns - 1), 1), returns); return function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
} }
template <typename E>
function_result unsafe_script_file(const std::string& filename, const sol::basic_environment<E>& env, load_mode mode = load_mode::any) {
int index = lua_gettop(L);
if (luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())) {
lua_error(L);
}
set_environment(env, stack_reference(L, raw_index(index + 1)));
if (lua_call(L, 0, LUA_MULTRET)) {
lua_error(L);
}
int postindex = lua_gettop(L);
int returns = postindex - index;
return function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
}
function_result unsafe_script_file(const std::string& filename, load_mode mode = load_mode::any) { function_result unsafe_script_file(const std::string& filename, load_mode mode = load_mode::any) {
int index = lua_gettop(L); int index = lua_gettop(L);
stack::script_file(L, filename, mode); stack::script_file(L, filename, mode);
@ -374,7 +402,7 @@ namespace sol {
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result script(const string_detail::string_shim& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, std::forward<Fx>(on_error), chunkname, mode); return safe_script(code, std::forward<Fx>(on_error), chunkname, mode);
} }
@ -384,7 +412,7 @@ namespace sol {
} }
template <typename Fx, typename E> template <typename Fx, typename E>
protected_function_result script(const string_detail::string_shim& code, const basic_environment<E>& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result script(const string_view& code, const basic_environment<E>& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, env, std::forward<Fx>(on_error), chunkname, mode); return safe_script(code, env, std::forward<Fx>(on_error), chunkname, mode);
} }
@ -393,15 +421,15 @@ namespace sol {
return safe_script_file(filename, env, std::forward<Fx>(on_error), mode); return safe_script_file(filename, env, std::forward<Fx>(on_error), mode);
} }
protected_function_result script(const string_detail::string_shim& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result script(const string_view& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, env, sol::script_default_on_error, chunkname, mode); return safe_script(code, env, script_default_on_error, chunkname, mode);
} }
protected_function_result script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any) { protected_function_result script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any) {
return safe_script_file(filename, env, sol::script_default_on_error, mode); return safe_script_file(filename, env, script_default_on_error, mode);
} }
function_result script(const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return unsafe_script(code, chunkname, mode); return unsafe_script(code, chunkname, mode);
} }
@ -409,7 +437,7 @@ namespace sol {
return unsafe_script_file(filename, mode); return unsafe_script_file(filename, mode);
} }
load_result load(const string_detail::string_shim& code, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) { load_result load(const string_view& code, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), name.c_str(), to_string(mode).c_str())); load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), name.c_str(), to_string(mode).c_str()));
return load_result(L, lua_absindex(L, -1), 1, 1, x); return load_result(L, lua_absindex(L, -1), 1, 1, x);
} }
@ -452,6 +480,10 @@ namespace sol {
return total_memory_used(lua_state()); return total_memory_used(lua_state());
} }
int stack_top() const {
return stack::top(L);
}
void collect_garbage() { void collect_garbage() {
lua_gc(lua_state(), LUA_GCCOLLECT, 0); lua_gc(lua_state(), LUA_GCCOLLECT, 0);
} }

View File

@ -91,6 +91,8 @@ namespace sol {
}; };
#endif // C++17 #endif // C++17
} }
typedef string_detail::string_shim string_view;
} }
#endif // SOL_STRING_SHIM_HPP #endif // SOL_STRING_SHIM_HPP

View File

@ -868,8 +868,8 @@ namespace sol {
template <typename Base, bool aligned> template <typename Base, bool aligned>
struct lua_type_of<basic_function<Base, aligned>> : std::integral_constant<type, type::function> {}; struct lua_type_of<basic_function<Base, aligned>> : std::integral_constant<type, type::function> {};
template <typename Base, bool aligned> template <typename Base, bool aligned, typename Handler>
struct lua_type_of<basic_protected_function<Base, aligned>> : std::integral_constant<type, type::function> {}; struct lua_type_of<basic_protected_function<Base, aligned, Handler>> : std::integral_constant<type, type::function> {};
template <> template <>
struct lua_type_of<coroutine> : std::integral_constant<type, type::function> {}; struct lua_type_of<coroutine> : std::integral_constant<type, type::function> {};
@ -1063,8 +1063,8 @@ namespace sol {
struct is_function : std::false_type {}; struct is_function : std::false_type {};
template <typename T, bool aligned> template <typename T, bool aligned>
struct is_function<basic_function<T, aligned>> : std::true_type {}; struct is_function<basic_function<T, aligned>> : std::true_type {};
template <typename T, bool aligned> template <typename T, bool aligned, typename Handler>
struct is_function<basic_protected_function<T, aligned>> : std::true_type{}; struct is_function<basic_protected_function<T, aligned, Handler>> : std::true_type{};
template <typename T> template <typename T>
struct is_lightuserdata : std::false_type {}; struct is_lightuserdata : std::false_type {};

View File

@ -199,13 +199,13 @@ TEST_CASE("state/script returns", "make sure script returns are done properly")
R"( R"(
local example = local example =
{ {
str = "this is a string", str = "this is a string",
num = 1234, num = 1234,
func = function(self) func = function(self)
print(self.str) print(self.str)
return "fstr" return "fstr"
end end
} }
return example; return example;