From 4808e7cad8fdd539c3e13ca37b73565aeb44b44b Mon Sep 17 00:00:00 2001 From: ThePhD Date: Tue, 21 May 2019 03:57:10 -0400 Subject: [PATCH] filters -> policies shill out on the docs prepare to update all docs fix #809 --- README.md | 12 +-- docs/source/api/api-top.rst | 2 +- docs/source/api/c_call.rst | 2 +- docs/source/api/{filters.rst => policies.rst} | 20 ++-- docs/source/api/proxy.rst | 2 +- docs/source/api/stack.rst | 16 +-- docs/source/api/this_environment.rst | 2 +- docs/source/api/usertype.rst | 2 +- docs/source/api/usertype_memory.rst | 4 +- docs/source/benchmarks.rst | 2 +- docs/source/build.rst | 8 +- docs/source/codecvt.rst | 2 +- docs/source/compilation.rst | 8 +- docs/source/conf.py | 4 +- docs/source/containers.rst | 8 +- docs/source/errors.rst | 8 +- docs/source/exceptions.rst | 2 +- docs/source/features.rst | 2 +- docs/source/functions.rst | 14 +-- docs/source/index.rst | 80 ++++++++++---- docs/source/media/Ko-fi_Blue.png | Bin 0 -> 8129 bytes docs/source/media/become_a_patron_button.png | Bin 0 -> 6579 bytes docs/source/media/discord_logo_wordmark.png | Bin 0 -> 4131 bytes docs/source/media/github_logo.png | Bin 0 -> 4268 bytes docs/source/media/liberapay_logo.png | Bin 0 -> 12732 bytes docs/source/media/pp_cc_mark_111x69.jpg | Bin 0 -> 11005 bytes docs/source/mentions.rst | 28 ++--- docs/source/origin.rst | 2 +- docs/source/safety.rst | 6 +- docs/source/traits.rst | 2 +- docs/source/tutorial/all-the-things.rst | 12 +-- docs/source/usertypes.rst | 12 +-- include/sol/call.hpp | 30 +++--- include/sol/forward.hpp | 4 +- include/sol/function_types.hpp | 12 +-- include/sol/{filters.hpp => policies.hpp} | 38 +++---- include/sol/stack_push.hpp | 2 +- include/sol/table_core.hpp | 2 +- include/sol/types.hpp | 6 +- include/sol/usertype.hpp | 2 +- single/include/sol/forward.hpp | 8 +- single/include/sol/sol.hpp | 98 +++++++++--------- .../source/{filters.cpp => policies.cpp} | 2 +- .../source/{filters.cpp => policies.cpp} | 16 +-- 44 files changed, 264 insertions(+), 218 deletions(-) rename docs/source/api/{filters.rst => policies.rst} (85%) create mode 100644 docs/source/media/Ko-fi_Blue.png create mode 100644 docs/source/media/become_a_patron_button.png create mode 100644 docs/source/media/discord_logo_wordmark.png create mode 100644 docs/source/media/github_logo.png create mode 100644 docs/source/media/liberapay_logo.png create mode 100644 docs/source/media/pp_cc_mark_111x69.jpg rename include/sol/{filters.hpp => policies.hpp} (70%) rename tests/compile_tests/source/{filters.cpp => policies.cpp} (97%) rename tests/runtime_tests/source/{filters.cpp => policies.cpp} (88%) diff --git a/README.md b/README.md index 7072a901..8bda4b9e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## sol2 (Sol v3.0.0-beta2) +## sol3 (sol2 v3.0.2) [![Join the chat in Discord: https://discord.gg/buxkYNT](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/buxkYNT) @@ -6,6 +6,8 @@ [![Windows Build status](https://ci.appveyor.com/api/projects/status/n38suofr21e9uk7h?svg=true)](https://ci.appveyor.com/project/ThePhD/sol2) [![Documentation Status](https://readthedocs.org/projects/sol2/badge/?version=latest)](http://sol2.readthedocs.io/en/latest/?badge=latest) +![Liberapay patrons](https://img.shields.io/liberapay/patrons/ThePhD.svg) ![Patrons](https://shieldsio-patreon.herokuapp.com/ThePhD/pledges) [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/W7W8Q619) [![Support via PayPal](https://cdn.rawgit.com/twolfson/paypal-github-button/1.0.0/dist/button.svg)](https://www.paypal.me/thephd) + Sol is a C++ library binding to Lua. It currently supports all Lua versions 5.1+ (LuaJIT 2.x included). Sol aims to be easy to use and easy to add to a project. The library is header-only for easy integration with projects. @@ -49,9 +51,7 @@ More examples are given in the examples directory [here](https://github.com/TheP ## Supporting -Help the project grow on [Patreon](https://www.patreon.com/thephd)! - -You can also [donate to support Sol](https://www.paypal.me/LMeneide), which is always appreciated! There are reward tiers for patrons on Patreon, too! +Please use the buttons above and help this project grow. 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. @@ -86,7 +86,7 @@ CppCon 2018 - 404 Keystone, Meydenbauer Center, Aspen, Colorado You can grab a single header (and the single forward header) out of the library [here](https://github.com/ThePhD/sol2/tree/develop/single). For stable version, check the releases tab on GitHub for a provided single header file for maximum ease of use. A script called [`single.py`](https://github.com/ThePhD/sol2/blob/develop/single/single.py) is provided in the repository if there's some bleeding edge change that hasn't been published on the releases page. You can run this script to create a single file version of the library so you can only include that part of it. Check `single.py --help` for more info. -If you use CMake, you can also configure and generate a project that will generate the sol2_single_header for you. You can also include the project using CMake. Run CMake for more details. Thanks @Nava2, @alkino, @mrgreywater and others for help with making the CMake build a reality. +If you use CMake, you can also configure and generate a project that will generate the `sol2_single_header` for you. You can also include the project using CMake. Run CMake for more details. Thanks @Nava2, @alkino, @mrgreywater and others for help with making the CMake build a reality. ## Features @@ -122,7 +122,7 @@ Please make sure you use the `-std=c++2a`, `-std=c++1z`, `-std=c++17` or better If you would like support for an older compiler (at the cost of some features), use the latest tagged sol2 branch. If you would like support for an even older compiler, feel free to contact me for a Custom Solution. -sol2 is checked by-hand for other platforms as well, including Android-based builds with GCC and iOS-based builds out of XCode with Apple-clang. It should work on both of these platforms, so long as you have the proper standards flags. +sol3 is checked by-hand for other platforms as well, including Android-based builds with GCC and iOS-based builds out of XCode with Apple-clang. It should work on both of these platforms, so long as you have the proper standards flags. ## Running the Tests diff --git a/docs/source/api/api-top.rst b/docs/source/api/api-top.rst index cc8f1545..62cde27a 100644 --- a/docs/source/api/api-top.rst +++ b/docs/source/api/api-top.rst @@ -42,7 +42,7 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo property var protect - filters + policies readonly as_function c_call diff --git a/docs/source/api/c_call.rst b/docs/source/api/c_call.rst index 44356cfe..b23c7837 100644 --- a/docs/source/api/c_call.rst +++ b/docs/source/api/c_call.rst @@ -17,7 +17,7 @@ The goal of ``sol::c_call<...>`` is to provide a way to wrap a function and tran This can also be placed into the argument list for a :doc:`usertype` as well. -This pushes a raw ``lua_CFunction`` into whatever you pass the resulting ``c_call`` function pointer into, whether it be a table or a userdata or whatever else using sol2's API. The resulting ``lua_CFunction`` can also be used directly with the lua API, just like many of sol2's types can be intermingled with Lua's API if you know what you're doing. +This pushes a raw ``lua_CFunction`` into whatever you pass the resulting ``c_call`` function pointer into, whether it be a table or a userdata or whatever else using sol3's API. The resulting ``lua_CFunction`` can also be used directly with the lua API, just like many of sol3's types can be intermingled with Lua's API if you know what you're doing. It is advisable for the user to consider making a macro to do the necessary ``decltype( &function_name, ), function_name``. Sol does not provide one because many codebases already have `one similar to this`_. diff --git a/docs/source/api/filters.rst b/docs/source/api/policies.rst similarity index 85% rename from docs/source/api/filters.rst rename to docs/source/api/policies.rst index ebe263ec..c6d127d4 100644 --- a/docs/source/api/filters.rst +++ b/docs/source/api/policies.rst @@ -1,26 +1,26 @@ -filters -======= +policies +======== *stack modification right before lua call returns* -``sol::filters`` is an advanced, low-level modification feature allowing you to take advantage of sol2's abstractions before applying your own stack-based modifications at the last moment. They cover the same functionality as `luabind's "return reference to" and "dependency"`_ types. A few pre-rolled filters are defined for your use: +``sol::policies`` is an advanced, low-level modification feature allowing you to take advantage of sol3's abstractions before applying your own stack-based modifications at the last moment. They cover the same functionality as `luabind's "return reference to" and "dependency"`_ types. A few pre-rolled policies are defined for your use: +------------------------------------+----------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| filter | usage | modification | +| policy | usage | modification | +------------------------------------+----------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``sol::returns_self`` | ``sol::filters( some_function, sol::returns_self() )`` | - takes the argument at stack index 1 (``self`` in member function calls and lambdas that take a specific userdata first) and makes that to be the return value | +| ``sol::returns_self`` | ``sol::policies( some_function, sol::returns_self() )`` | - takes the argument at stack index 1 (``self`` in member function calls and lambdas that take a specific userdata first) and makes that to be the return value | | | | - rather than creating a new userdata that references the same C++ memory, it copies the userdata, similar to writing ``obj2 = obj1`` just increases the reference count | | | | - saves memory space on top of keeping original memory alive | +------------------------------------+----------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``sol::returns_self_with`` | ``sol::filters( some_function, sol::returns_self_with<2, 3>() )`` | - same as above, with the caveat that the ``self`` is returned while also putting dependencies into the ``self`` | +| ``sol::returns_self_with`` | ``sol::policies( some_function, sol::returns_self_with<2, 3>() )`` | - same as above, with the caveat that the ``self`` is returned while also putting dependencies into the ``self`` | | | | - can keep external dependencies alive | +------------------------------------+----------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``sol::self_dependency`` | ``sol::filters( some_function, sol::self_dependency() );`` | - this makes the value returned by the bindable take a dependency on the ``self`` argument | +| ``sol::self_dependency`` | ``sol::policies( some_function, sol::self_dependency() );`` | - this makes the value returned by the bindable take a dependency on the ``self`` argument | | | | - useful for returning a reference to a member variable and keeping the parent class of that member variable alive | +------------------------------------+----------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``sol::stack_dependencies`` | ``sol::filters( some_function, sol::stack_dependencies( target_index, 2, 1, ... ) );`` | - whatever is at ``target_index`` on the stack is given a special "keep alive" table with the elements on the stack specified by the integer indices after ``target_index`` | +| ``sol::stack_dependencies`` | ``sol::policies( some_function, sol::stack_dependencies( target_index, 2, 1, ... ) );`` | - whatever is at ``target_index`` on the stack is given a special "keep alive" table with the elements on the stack specified by the integer indices after ``target_index`` | | | | - allows you to keep arguments and other things alive for the duration of the existence of the class | +------------------------------------+----------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| custom | ``sol::filters( some_function, [](lua_State* L, int current_stack_return_count) -> int { ... } )`` | - whatever you want, so long as it has the form ``int (lua_State*, int )`` | +| custom | ``sol::policies( some_function, [](lua_State* L, int current_stack_return_count) -> int { ... } )``| - whatever you want, so long as it has the form ``int (lua_State*, int )`` | | | | - works with callables (such as lambdas), so long as it has the correct form | | | | - expected to return the number of things on the stack to return to Lua | +------------------------------------+----------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -30,6 +30,6 @@ filters | - works with ``table::set( ... )``, ``table::set_function( ... );``, and on all usertype bindings | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -You can specify multiple filters on the same ``sol::filters`` call, and can also specify custom filters as long as the signature is correct. +You can specify multiple policies on the same ``sol::policies`` call, and can also specify custom policies as long as the signature is correct. .. _luabind's "return reference to" and "dependency": http://www.rasterbar.com/products/luabind/docs.html#dependency diff --git a/docs/source/api/proxy.rst b/docs/source/api/proxy.rst index 14e1fef1..6f385625 100644 --- a/docs/source/api/proxy.rst +++ b/docs/source/api/proxy.rst @@ -171,5 +171,5 @@ on function objects and proxies .. note:: - As of recent versions of sol2 (2.18.2 and above), this is no longer an issue, as even bound classes will have any detectable function call operator automatically bound to the object, to allow this to work without having to use ``.set`` or ``.set_function``. The note here is kept for posterity and information for older versions. There are only some small caveats, see: :ref:`this note here`. + As of recent versions of sol3 (2.18.2 and above), this is no longer an issue, as even bound classes will have any detectable function call operator automatically bound to the object, to allow this to work without having to use ``.set`` or ``.set_function``. The note here is kept for posterity and information for older versions. There are only some small caveats, see: :ref:`this note here`. diff --git a/docs/source/api/stack.rst b/docs/source/api/stack.rst index d9695d82..fb9ab55b 100644 --- a/docs/source/api/stack.rst +++ b/docs/source/api/stack.rst @@ -58,7 +58,7 @@ members template inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs); -This function is helpful for when you bind to a raw C function but need sol's abstractions to save you the agony of setting up arguments and know how `calling C functions works`_. The ``start`` parameter tells the function where to start pulling arguments from. The parameter ``fx`` is what's supposed to be called. Extra arguments are passed to the function directly. There are intermediate versions of this (``sol::stack::call_into_lua`` and similar) for more advanced users, but they are not documented as they are subject to change to improve performance or adjust the API accordingly in later iterations of sol2. Use the more advanced versions at your own peril. +This function is helpful for when you bind to a raw C function but need sol's abstractions to save you the agony of setting up arguments and know how `calling C functions works`_. The ``start`` parameter tells the function where to start pulling arguments from. The parameter ``fx`` is what's supposed to be called. Extra arguments are passed to the function directly. There are intermediate versions of this (``sol::stack::call_into_lua`` and similar) for more advanced users, but they are not documented as they are subject to change to improve performance or adjust the API accordingly in later iterations of sol3. Use the more advanced versions at your own peril. .. code-block:: cpp :caption: function: get @@ -97,7 +97,7 @@ Checks if the object at ``index`` is of type ``T``. If it is not, it will call t template auto get_usertype( lua_State* L, int index, record& tracking ) -Directly attempts to rertieve the type ``T`` using sol2's usertype mechanisms. Similar to a regular ``get`` for a user-defined type. Useful when you need to access sol2's usertype getter mechanism while at the same time `providing your own customization`_. +Directly attempts to rertieve the type ``T`` using sol3's usertype mechanisms. Similar to a regular ``get`` for a user-defined type. Useful when you need to access sol3's usertype getter mechanism while at the same time `providing your own customization`_. .. code-block:: cpp :caption: function: check_usertype @@ -112,7 +112,7 @@ Directly attempts to rertieve the type ``T`` using sol2's usertype mechanisms. S template bool check_usertype( lua_State* L, int index, Handler&& handler, record& tracking ) -Checks if the object at ``index`` is of type ``T`` and stored as a sol2 usertype. Useful when you need to access sol2's usertype checker mechanism while at the same time `providing your own customization`_. +Checks if the object at ``index`` is of type ``T`` and stored as a sol3 usertype. Useful when you need to access sol3's usertype checker mechanism while at the same time `providing your own customization`_. .. code-block:: cpp :caption: function: check_get @@ -160,7 +160,7 @@ Based on how it is called, pushes a variable amount of objects onto the stack. i int multi_push_reference( lua_State* L, Args&&... args ) -These functinos behave similarly to the ones above, but they check for specific criteria and instead attempt to push a reference rather than forcing a copy if appropriate. Use cautiously as sol2 uses this mainly as a return from usertype functions and variables to preserve chaining/variable semantics from that a class object. Its internals are updated to fit the needs of sol2 and while it generally does the "right thing" and has not needed to be changed for a while, sol2 reserves the right to change its internal detection mechanisms to suit its users needs at any time, generally without breaking backwards compatibility and expectations but not exactly guaranteed. +These functinos behave similarly to the ones above, but they check for specific criteria and instead attempt to push a reference rather than forcing a copy if appropriate. Use cautiously as sol3 uses this mainly as a return from usertype functions and variables to preserve chaining/variable semantics from that a class object. Its internals are updated to fit the needs of sol3 and while it generally does the "right thing" and has not needed to be changed for a while, sol3 reserves the right to change its internal detection mechanisms to suit its users needs at any time, generally without breaking backwards compatibility and expectations but not exactly guaranteed. .. code-block:: cpp :caption: function: pop @@ -294,7 +294,7 @@ This is an SFINAE-friendly struct that is meant to expose static function ``chec } }; -This is an SFINAE-friendly struct that is meant to expose a function ``check=`` that returns ``true`` if a type meets some custom userdata specifiction, and ``false`` if it does not. The default implementation just returns ``false`` to let the original sol2 handlers take care of everything. If you want to implement your own usertype checking; e.g., for messing with ``toLua`` or ``OOLua`` or ``kaguya`` or some other libraries. Note that the library must have a with a :doc:`memory compatible layout` if you **want to specialize this checker method but not the subsequent getter method**. You can specialize it as shown in the `interop examples`_. +This is an SFINAE-friendly struct that is meant to expose a function ``check=`` that returns ``true`` if a type meets some custom userdata specifiction, and ``false`` if it does not. The default implementation just returns ``false`` to let the original sol3 handlers take care of everything. If you want to implement your own usertype checking; e.g., for messing with ``toLua`` or ``OOLua`` or ``kaguya`` or some other libraries. Note that the library must have a with a :doc:`memory compatible layout` if you **want to specialize this checker method but not the subsequent getter method**. You can specialize it as shown in the `interop examples`_. .. note:: @@ -308,18 +308,18 @@ This is an SFINAE-friendly struct that is meant to expose a function ``check=`` template struct userdata_getter { static std::pair get ( lua_State* L, int index, void* unadjusted_pointer, record& tracking ) { - // implement custom getting here for non-sol2 userdatas: + // implement custom getting here for non-sol3 userdatas: // if it doesn't match, return "false" and regular // sol userdata checks will kick in return { false, nullptr }; } }; -This is an SFINAE-friendly struct that is meant to expose a function ``get`` that returns ``true`` and an adjusted pointer if a type meets some custom userdata specifiction (from, say, another library or an internal framework). The default implementation just returns ``{ false, nullptr }`` to let the original sol2 getter take care of everything. If you want to implement your own usertype getter; e.g., for messing with ``kaguya`` or some other libraries. You can specialize it as shown in the `interop examples`_. +This is an SFINAE-friendly struct that is meant to expose a function ``get`` that returns ``true`` and an adjusted pointer if a type meets some custom userdata specifiction (from, say, another library or an internal framework). The default implementation just returns ``{ false, nullptr }`` to let the original sol3 getter take care of everything. If you want to implement your own usertype getter; e.g., for messing with ``kaguya`` or some other libraries. You can specialize it as shown in the `interop examples`_. .. note:: - You do NOT need to use this method in particular if the :doc:`memory layout` is compatible. (For example, ``toLua`` stores userdata in a sol2-compatible way.) + You do NOT need to use this method in particular if the :doc:`memory layout` is compatible. (For example, ``toLua`` stores userdata in a sol3-compatible way.) .. note:: diff --git a/docs/source/api/this_environment.rst b/docs/source/api/this_environment.rst index f08f4a81..9973ab36 100644 --- a/docs/source/api/this_environment.rst +++ b/docs/source/api/this_environment.rst @@ -3,7 +3,7 @@ this_environment *retrieving the environment of the calling function* -Sometimes in C++ it's useful to know where a Lua call is coming from and what :doc:`environment` it is from. The former is covered by Lua's Debug API, which is extensive and is not fully wrapped up by sol2. But, sol2 covers the latter in letting you get the environment of the calling script / function, if it has one. ``sol::this_environment`` is a *transparent argument* and does not need to be passed in Lua scripts or provided when using :doc:`sol::function`, similar to :doc:`sol::this_state`: +Sometimes in C++ it's useful to know where a Lua call is coming from and what :doc:`environment` it is from. The former is covered by Lua's Debug API, which is extensive and is not fully wrapped up by sol3. But, sol3 covers the latter in letting you get the environment of the calling script / function, if it has one. ``sol::this_environment`` is a *transparent argument* and does not need to be passed in Lua scripts or provided when using :doc:`sol::function`, similar to :doc:`sol::this_state`: .. code-block:: cpp :linenos: diff --git a/docs/source/api/usertype.rst b/docs/source/api/usertype.rst index 01608886..64bfe7c3 100644 --- a/docs/source/api/usertype.rst +++ b/docs/source/api/usertype.rst @@ -132,7 +132,7 @@ If you don't specify anything at all and the type is `destructible`_, then a des usertype automatic meta functions +++++++++++++++++++++++++++++++++ -If you don't specify a ``sol::meta_function`` name (or equivalent string metamethod name) and the type ``T`` supports certain operations, sol2 will generate the following operations provided it can find a good default implementation: +If you don't specify a ``sol::meta_function`` name (or equivalent string metamethod name) and the type ``T`` supports certain operations, sol3 will generate the following operations provided it can find a good default implementation: * for ``to_string`` operations where ``std::ostream& operator<<( std::ostream&, const T& )``, ``obj.to_string()``, or ``to_string( const T& )`` (in the namespace) exists on the C++ type - a ``sol::meta_function::to_string`` operator will be generated diff --git a/docs/source/api/usertype_memory.rst b/docs/source/api/usertype_memory.rst index f675cba0..bcfe119f 100644 --- a/docs/source/api/usertype_memory.rst +++ b/docs/source/api/usertype_memory.rst @@ -12,7 +12,7 @@ In general, we always insert a ``T*`` in the first ``sizeof(T*)`` bytes, so the .. warning:: - The layout of memory described below does **not** take into account alignment. sol2 now takes alignment into account and aligns memory, which is important for misbehaving allocators and types that do not align well to the size of a pointer on their system. If you need to obtain proper alignments for usertypes stored in userdata pointers, **please** use the detail functions named ``sol::detail::align_usertype_pointer``, ``sol::detail::align_usertype``, and ``sol::detail::align_usertype_unique``. This will shift a ``void*`` pointer by the appropriate amount to reach a certain section in memory. For almost all other use cases, please use ``void* memory = lua_touserdata(L, index);``, followed by ``memory = sol::detail::align_usertype_pointer( memory );`` to adjust the pointer to be at the right place. + The layout of memory described below does **not** take into account alignment. sol3 now takes alignment into account and aligns memory, which is important for misbehaving allocators and types that do not align well to the size of a pointer on their system. If you need to obtain proper alignments for usertypes stored in userdata pointers, **please** use the detail functions named ``sol::detail::align_usertype_pointer``, ``sol::detail::align_usertype``, and ``sol::detail::align_usertype_unique``. This will shift a ``void*`` pointer by the appropriate amount to reach a certain section in memory. For almost all other use cases, please use ``void* memory = lua_touserdata(L, index);``, followed by ``memory = sol::detail::align_usertype_pointer( memory );`` to adjust the pointer to be at the right place. .. warning:: @@ -23,7 +23,7 @@ In general, we always insert a ``T*`` in the first ``sizeof(T*)`` bytes, so the To retrieve a ``T`` ------------------- -If you want to retrieve a ``T*`` pointer to the data managed by a sol2 userdata and are not using sol2's abstractions to do it (e.g., messing with the plain Lua C API), simply use ``lua_touserdata`` to get the ``void*`` pointer. Then, execute a ``T* object_pointer = *static_cast(the_void_pointer);``. Every type pushed into C++ that is classified as a userdata (e.g., all user-defined objects that are not covered by the stack abstraction's basic types) can be retrieved in this format, whether they are values or pointers or ``unique_ptr``. The reasons for why this works is below. +If you want to retrieve a ``T*`` pointer to the data managed by a sol3 userdata and are not using sol3's abstractions to do it (e.g., messing with the plain Lua C API), simply use ``lua_touserdata`` to get the ``void*`` pointer. Then, execute a ``T* object_pointer = *static_cast(the_void_pointer);``. Every type pushed into C++ that is classified as a userdata (e.g., all user-defined objects that are not covered by the stack abstraction's basic types) can be retrieved in this format, whether they are values or pointers or ``unique_ptr``. The reasons for why this works is below. For ``T`` --------- diff --git a/docs/source/benchmarks.rst b/docs/source/benchmarks.rst index c4d24e85..7de43438 100644 --- a/docs/source/benchmarks.rst +++ b/docs/source/benchmarks.rst @@ -8,7 +8,7 @@ Here are measurements of the *overhead that libraries impose around the Lua C AP These are some informal and formal benchmarks done by both the developers of sol and other library developers / users. We leave you to interpret the data as you see fit. -* `lua_binding_benchmarks`_ by satoren (developer of `kaguya`_) (`sol`_ is the "sol2" entry) +* `lua_binding_benchmarks`_ by satoren (developer of `kaguya`_) (`sol`_ is the "sol3" entry) * `lua-bindings-shootout`_ by ThePhD (developer of `sol`_) As of the writing of this documentation (May 17th, 2018), :doc:`sol` seems to take the cake in most categories for speed! Below are some graphs from `lua-bindings-shootout`_. You can read the benchmarking code there if you think something was done wrong, and submit a pull requests or comment on something to make sure that ThePhD is being honest about his work. All categories are the performance of things described at the top of the :doc:`feature table`. diff --git a/docs/source/build.rst b/docs/source/build.rst index 97c52287..b5be6077 100644 --- a/docs/source/build.rst +++ b/docs/source/build.rst @@ -1,8 +1,10 @@ -Build +build ===== -sol2 comes with a CMake script in the top level. It is primarily made for building and running the examples and tests, but it includes exported and configured targets (``sol2``, ``sol2_single``) for your use. +sol3 is a header-only library. -sol2 also comes with a Meson Script. If things stop working, file a bug report. +sol3 comes with a CMake script in the top level. It is primarily made for building and running the examples and tests, but it includes exported and configured targets (``sol2``, ``sol2_single``) for your use. + +sol3 also comes with a Meson Script. If things stop working, file a bug report. diff --git a/docs/source/codecvt.rst b/docs/source/codecvt.rst index edd3d115..66f1966e 100644 --- a/docs/source/codecvt.rst +++ b/docs/source/codecvt.rst @@ -5,7 +5,7 @@ because this is surprisingly hard using standard C++ .. note:: - The ```` header is no longer used and sol2 now converts utf8, utf16, and utf32 with internal routines. If you have a problem with the transcoding, please `file an issue report`_. + The ```` header is no longer used and sol3 now converts utf8, utf16, and utf32 with internal routines. If you have a problem with the transcoding, please `file an issue report`_. ``std::(w)string(u16/u32)`` are assumed to be in the platform's native wide (for ``wstring``) or unicode format. Lua canonically stores its string literals as utf8 and embraces utf8, albeit its storage is simply a sequence of bytes that are also null-terminated (it is also counted and the size is kept around, so embedded nulls can be used in the string). Therefore, if you need to interact with the unicode or wide alternatives of strings, runtime conversions are performed from the (assumed) utf8 string data into other forms. These conversions check for well-formed UTF, and will replace ill-formed characters with the unicode replacement codepoint, 0xFFFD. diff --git a/docs/source/compilation.rst b/docs/source/compilation.rst index 1c24993a..d68b3eef 100644 --- a/docs/source/compilation.rst +++ b/docs/source/compilation.rst @@ -26,7 +26,7 @@ GCC 7.x is now out alongside Visual Studio 2018. This means that `sol release v2 - v3.6.x - Note: this applies to XCode's Apple Clang as well, but that compiler packs its own deficiencies and problems as well -**This does not mean we are immediately abandoning older compilers.** We will update this page as relevant bugfixes are backported to the v2.x.x releases. Remember that sol2 is feature-complete: there is nothing more we can add to the library at this time with C++11/C++14 compiler support, so your code will be covered for a long time to come. +**This does not mean we are immediately abandoning older compilers.** We will update this page as relevant bugfixes are backported to the v2.x.x releases. Remember that sol3 is feature-complete: there is nothing more we can add to the library at this time with C++11/C++14 compiler support, so your code will be covered for a long time to come. Newer features will be targeted at the following compilers: @@ -47,9 +47,9 @@ Note that Visual Studio's 2018 Community Edition is absolutely free now, and ins MinGW's GCC version 7.x of the compiler fixes a long-standing derp in the header that swapped the endianness of utf16 and utf32 strings. -Clang 3.4, 3.5 and 3.6 have many bugs we have run into when developing sol2 and that have negatively impacted users for a long time now. +Clang 3.4, 3.5 and 3.6 have many bugs we have run into when developing sol3 and that have negatively impacted users for a long time now. -We encourage all users to upgrade immediately. If you need old code for some reason, use `sol release v2.20.1`_: otherwise, always grab sol2's latest. +We encourage all users to upgrade immediately. If you need old code for some reason, use `sol release v2.20.1`_: otherwise, always grab sol3's latest. feature support @@ -84,7 +84,7 @@ Here are some notes on achieving better compile times without sacrificing too mu * Consider placing groups of bindings in multiple different translation units (multiple C++ source files) so that only part of the bindings are recompiled when you have to change the bindings. - Avoid putting your bindings into headers: it *will* slow down your compilation * If you are developing a shared library, restrict your overall surface area by specifically and explicitly marking functions as visible and exported and leaving everything else as hidden or invisible by default -* For people who already have a tool that retrieves function signatures and arguments, it might be in your best interest to hook into that tool or generator and dump out the information once using sol2's lower-level abstractions. An `issue describing preliminary steps can be found here`_. +* For people who already have a tool that retrieves function signatures and arguments, it might be in your best interest to hook into that tool or generator and dump out the information once using sol3's lower-level abstractions. An `issue describing preliminary steps can be found here`_. next steps diff --git a/docs/source/conf.py b/docs/source/conf.py index 852bb4bd..3c0d20f4 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -47,7 +47,7 @@ master_doc = 'index' # General information about the project. project = 'Sol' -copyright = '2018, ThePhD' +copyright = '2019, ThePhD' author = 'ThePhD' # The version info for the project you're documenting, acts as replacement for @@ -57,7 +57,7 @@ author = 'ThePhD' # The short X.Y version. version = '3.0' # The full version, including alpha/beta/rc tags. -release = '3.0.0' +release = '3.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/containers.rst b/docs/source/containers.rst index cea8d73d..7267d768 100644 --- a/docs/source/containers.rst +++ b/docs/source/containers.rst @@ -1,8 +1,8 @@ containers ========== -*working with containers in sol2* +*working with containers in sol3* -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 standard library has several containers of varying types, and all of them have ``begin()`` and ``end()`` methods which return iterators. C-style arrays are also containers, and sol2 will detect all of them for use and bestow upon them 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 standard library has several containers of varying types, and all of them have ``begin()`` and ``end()`` methods which return iterators. C-style arrays are also containers, and sol3 will detect all of them for use and bestow upon them special properties and functions. * Containers from C++ are stored as ``userdata`` with special ``usertype`` metatables with :ref:`special operations` - In Lua 5.1, this means containers pushed without wrappers like :doc:`as_table` and :doc:`nested` will not work with ``pairs`` or other built-in iteration functions from Lua @@ -27,7 +27,7 @@ Containers are objects that are meant to be inspected and iterated and whose job container detection ------------------- -containers are detected by the type trait ``sol::is_container``. If that turns out to be true, sol2 will attempt to push a userdata into Lua for the specified type ``T``, and bestow it with some of the functions and properties listed below. These functions and properties are provided by a template struct ``sol::container_traits``, which has a number of static Lua C functions bound to a safety metatable. If you want to override the behavior for a specific container, you must first specialize ``sol::is_container`` to drive from ``std::true_type``, then override the functions you want to change. Any function you do not override will call the default implementation or equivalent. The default implementation for unrecognized containers is simply errors. +containers are detected by the type trait ``sol::is_container``. If that turns out to be true, sol3 will attempt to push a userdata into Lua for the specified type ``T``, and bestow it with some of the functions and properties listed below. These functions and properties are provided by a template struct ``sol::container_traits``, which has a number of static Lua C functions bound to a safety metatable. If you want to override the behavior for a specific container, you must first specialize ``sol::is_container`` to drive from ``std::true_type``, then override the functions you want to change. Any function you do not override will call the default implementation or equivalent. The default implementation for unrecognized containers is simply errors. You can also specialize ``sol::is_container`` to turn off container detection, if you find it too eager for a type that just happens to have ``begin`` and ``end`` functions, like so: @@ -178,7 +178,7 @@ Below are the many container operations and their override points for ``containe container classifications ------------------------- -When you serialize a container into sol2, the default container handler deals with the containers by inspecting various properties, functions, and typedefs on them. Here are the broad implications of containers sol2's defaults will recognize, and which already-known containers fall into their categories: +When you serialize a container into sol3, the default container handler deals with the containers by inspecting various properties, functions, and typedefs on them. Here are the broad implications of containers sol3's defaults will recognize, and which already-known containers fall into their categories: +------------------------+----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------+ | container type | requirements | known containers | notes/caveats | diff --git a/docs/source/errors.rst b/docs/source/errors.rst index 9aaf93cc..07b4c0c7 100644 --- a/docs/source/errors.rst +++ b/docs/source/errors.rst @@ -55,7 +55,7 @@ Linker Errors There are lots of reasons for compiler linker errors. A common one is not knowing that you've compiled the Lua library as C++: when building with C++, it is important to note that every typical (static or dynamic) library expects the C calling convention to be used and that Sol includes the code using ``extern 'C'`` where applicable. -However, when the target Lua library is compiled with C++, one must change the calling convention and name mangling scheme by getting rid of the ``extern 'C'`` block. This can be achieved by adding ``#define SOL_USING_CXX_LUA`` before including sol2, or by adding it to your compilation's command line. If you build LuaJIT in C++ mode (how you would even, is beyond me), then you need to ``#define SOL_USING_CXX_LUAJIT`` as well. Typically, there is never a need to use this last one. +However, when the target Lua library is compiled with C++, one must change the calling convention and name mangling scheme by getting rid of the ``extern 'C'`` block. This can be achieved by adding ``#define SOL_USING_CXX_LUA`` before including sol3, or by adding it to your compilation's command line. If you build LuaJIT in C++ mode (how you would even, is beyond me), then you need to ``#define SOL_USING_CXX_LUAJIT`` as well. Typically, there is never a need to use this last one. Note that you should not be defining these with standard builds of either Lua or LuaJIT. See the :ref:`config page` for more details. @@ -64,7 +64,7 @@ Note that you should not be defining these with standard builds of either Lua or Sometimes, you expect properly written errors and instead receive an error about catching a ``...`` exception instead. This might mean that you either built Lua as C++ or are using a framework like LuaJIT that has full interopability support for exceptions on certain system types (x64 for LuaJIT 2.0.5, x86 and x64 on LuaJIT 2.1.x-beta and later). -Please make sure to use the ``SOL_EXCEPTIONS_SAFE_PROPAGATION`` define before including sol2 to make this work out. You can read more :ref:`at the exception page here`. +Please make sure to use the ``SOL_EXCEPTIONS_SAFE_PROPAGATION`` define before including sol3 to make this work out. You can read more :ref:`at the exception page here`. Catch and CRASH! ---------------- @@ -73,7 +73,7 @@ By default, Sol will add a ``default_at_panic`` handler to states opened by Sol It is preferred if you catch an error that you log what happened, terminate the Lua VM as soon as possible, and then crash if your application cannot handle spinning up a new Lua state. Catching can be done, but you should understand the risks of what you're doing when you do it. For more information about catching exceptions, the potentials, not turning off exceptions and other tricks and caveats, read about :doc:`exceptions in Sol here`. -Lua is a C API first and foremost: exceptions bubbling out of it is essentially last-ditch, terminal behavior that the VM does not expect. You can see an example of handling a panic on the exceptions page :ref:`here`. This means that setting up a ``try { ... } catch (...) {}`` around an unprotected sol2 function or script call is **NOT** enough to keep the VM in a clean state. Lua does not understand exceptions and throwing them results in undefined behavior if they bubble through the C API once and then the state is used again. Please catch, and crash. +Lua is a C API first and foremost: exceptions bubbling out of it is essentially last-ditch, terminal behavior that the VM does not expect. You can see an example of handling a panic on the exceptions page :ref:`here`. This means that setting up a ``try { ... } catch (...) {}`` around an unprotected sol3 function or script call is **NOT** enough to keep the VM in a clean state. Lua does not understand exceptions and throwing them results in undefined behavior if they bubble through the C API once and then the state is used again. Please catch, and crash. Furthermore, it would be a great idea for you to use the safety features talked about :doc:`safety section`, especially for those related to functions. @@ -94,7 +94,7 @@ By default, :doc:`sol::function` assumes the code ran just fine an Protected Functions Are Not Catch All ------------------------------------- -Sometimes, some scripts load poorly. Even if you protect the function call, the actual file loading or file execution will be bad, in which case :doc:`sol::protected_function` will not save you. Make sure you register your own panic handler so you can catch errors, or follow the advice of the catch + crash behavior above. Remember that you can also bind your own functions and forego sol2's built-in protections for you own by binding a :ref:`raw lua_CFunction function` +Sometimes, some scripts load poorly. Even if you protect the function call, the actual file loading or file execution will be bad, in which case :doc:`sol::protected_function` will not save you. Make sure you register your own panic handler so you can catch errors, or follow the advice of the catch + crash behavior above. Remember that you can also bind your own functions and forego sol3's built-in protections for you own by binding a :ref:`raw lua_CFunction function` Iteration --------- diff --git a/docs/source/exceptions.rst b/docs/source/exceptions.rst index 870dc0f3..3fb300d5 100644 --- a/docs/source/exceptions.rst +++ b/docs/source/exceptions.rst @@ -32,7 +32,7 @@ Lua comes with two kind of built-in handlers that sol provides easy opt-ins for. :linenos: -The other handler is specific to sol2. If you open a ``sol::state``, or open the default state handlers for your ``lua_State*`` (see :ref:`sol::state's automatic handlers` for more details), there is a ``sol::exception_handler_function`` type. It allows you to register a function in the event that an exception happens that bubbles out of your functions. The function requires that you push 1 item onto the stack that will be used with a call to `lua_error`_ +The other handler is specific to sol3. If you open a ``sol::state``, or open the default state handlers for your ``lua_State*`` (see :ref:`sol::state's automatic handlers` for more details), there is a ``sol::exception_handler_function`` type. It allows you to register a function in the event that an exception happens that bubbles out of your functions. The function requires that you push 1 item onto the stack that will be used with a call to `lua_error`_ .. literalinclude:: ../../examples/source/exception_handler.cpp :caption: exception handling diff --git a/docs/source/features.rst b/docs/source/features.rst index 40cdb956..c74517db 100644 --- a/docs/source/features.rst +++ b/docs/source/features.rst @@ -92,7 +92,7 @@ Explanations for a few categories are below (rest are self-explanatory). * environments: an abstraction for getting, setting and manipulating an environment, using table techniques, functions or otherwise. Typically for the purposes of sandboxing +---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+ -| | plain C | luawrapper | lua-intf | luabind | Selene | Sol2 | oolua | lua-api-pp | kaguya | SLB3 | SWIG | luacppinterface | luwra | +| | plain C | luawrapper | lua-intf | luabind | Selene | Sol3 | oolua | lua-api-pp | kaguya | SLB3 | SWIG | luacppinterface | luwra | | | | | | | | | | | | | | | | +===========================+=============+============+==========+=========+==========+===========+===========+================+==========+==========+===========+=================+========+ | optional | ~ | ✗ | ✔ | ✗ | ✗ | ✔ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ | ✗ | diff --git a/docs/source/functions.rst b/docs/source/functions.rst index 892986f3..55c111d7 100644 --- a/docs/source/functions.rst +++ b/docs/source/functions.rst @@ -1,13 +1,13 @@ functions ========= -*working with functions in sol2* +*working with functions in sol3* -There are a number of examples dealing with functions and how they can be bound to sol2: +There are a number of examples dealing with functions and how they can be bound to sol3: * For a quicker walkthrough that demonstrates almost everything, see `the examples`_ and the :doc:`the quick and dirty tutorial` * For a full explanation, :doc:`read the tutorial` and consult the subjects below -* If you have bindings and set-ups that want to leverage the C API without sol2's interference, you can push a raw function, which has certain implications (noted :ref:`below`) +* If you have bindings and set-ups that want to leverage the C API without sol3's interference, you can push a raw function, which has certain implications (noted :ref:`below`) * Return multiple values into Lua by: - returning a ``std::tuple`` - using :doc:`sol::variadic_results` @@ -21,7 +21,7 @@ There are a number of examples dealing with functions and how they can be bound - :doc:`sol::this_environment`, for potentially retrieving the current Lua environment * Control serialization of arguments and return types with :doc:`sol::nested`, :doc:`sol::as_table`, :doc:`sol::as_args` and :doc:`sol::as_function` * Set environments for Lua functions and scripts with :doc:`sol::environment` -* You can use :doc:`filters` to control dependencies and streamline return values, as well as apply custom behavior to a functions return +* You can use :doc:`policies` to control dependencies and streamline return values, as well as apply custom behavior to a functions return @@ -51,7 +51,7 @@ Furthermore, it is important to know that lambdas without a specified return typ exception safety/handling ------------------------- -All functions bound to sol2 set up an exception trampoline around the function (unless you are working with a :ref:`raw lua_CFunction you pushed yourself`). :doc:`protected_function` also has an error handler member and an exception trampoline around its internals, but it is not guaranteed safe if an exception bubbles outside of it. Catching that exception is not safe either: if an exception has exploded out from the sol2 API somehow, you must assume the VM is in some indeterminate and/or busted state. +All functions bound to sol3 set up an exception trampoline around the function (unless you are working with a :ref:`raw lua_CFunction you pushed yourself`). :doc:`protected_function` also has an error handler member and an exception trampoline around its internals, but it is not guaranteed safe if an exception bubbles outside of it. Catching that exception is not safe either: if an exception has exploded out from the sol3 API somehow, you must assume the VM is in some indeterminate and/or busted state. Please read the :doc:`error page` and :doc:`exception page` for more details about what to do with exceptions that explode out from the API. @@ -68,11 +68,11 @@ All arguments are forwarded. Unlike :doc:`get/set/operator[] on sol::state`` when the function is passed a ``std::shared_ptr``. Sometimes it may work because the compiler might be able to line up your classes in such a way that raw casts work, but this is undefined behavior through and through and sol2 has no mechanisms by which it can make this safe and not blow up in the user's face. +When you bind a function to Lua, please take any pointer arguments as ``T*``, unless you specifically know you are going to match the exact type of the unique/shared pointer and the class it wraps. sol3 cannot support "implicit wrapped pointer casting", such as taking a ``std::shared_ptr`` when the function is passed a ``std::shared_ptr``. Sometimes it may work because the compiler might be able to line up your classes in such a way that raw casts work, but this is undefined behavior through and through and sol3 has no mechanisms by which it can make this safe and not blow up in the user's face. .. note:: - Please avoid taking special unique_usertype arguments, by either reference or value. In many cases, by-value does not work (e.g., with ``std::unique_ptr``) because many types are move-only and Lua has no concept of "move" semantics. By-reference is dangerous because sol2 will hand you a reference to the original data: but, any pointers stored in Lua can be invalidated if you call ``.reset()`` or similar on the core pointer. Please take a pointer (``T*``) if you anticipate ``nil``/``nullptr`` being passed to your function, or a reference (``const T&`` or ``T&``) if you do not. As a side note, if you write a small wrapping class that holds a base pointer type, and interact using the wrapper, then when you get the wrapper as an argument in a C++-function bound to Lua you can cast the internal object freely. It is simply a direct cast as an argument to a function that is the problem. + Please avoid taking special unique_usertype arguments, by either reference or value. In many cases, by-value does not work (e.g., with ``std::unique_ptr``) because many types are move-only and Lua has no concept of "move" semantics. By-reference is dangerous because sol3 will hand you a reference to the original data: but, any pointers stored in Lua can be invalidated if you call ``.reset()`` or similar on the core pointer. Please take a pointer (``T*``) if you anticipate ``nil``/``nullptr`` being passed to your function, or a reference (``const T&`` or ``T&``) if you do not. As a side note, if you write a small wrapping class that holds a base pointer type, and interact using the wrapper, then when you get the wrapper as an argument in a C++-function bound to Lua you can cast the internal object freely. It is simply a direct cast as an argument to a function that is the problem. .. note:: diff --git a/docs/source/index.rst b/docs/source/index.rst index eab9d860..f624aec3 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -45,6 +45,32 @@ get going: origin +connect +-------- + +Come to the Github Issues or the Discord! We've got a friendly community, and they can help you out or you can come just to talk about the things you are working on! + +|ds| |gh| + + +support +------- + +You can support the project and other related endeavors in various ways. + +|pa| |kf| |lp| |pp| + + +You can support sol3 development by using any of the above. 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 sol3'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. + + "I need feature X, maybe you have it?" -------------------------------------- Take a look at the :doc:`Features` page: it links to much of the API. You can also just straight up browse the :doc:`api` or ease in with the :doc:`tutorials`. To know more about the implementation for usertypes, see :doc:`here` To know how function arguments are handled, see :ref:`this note`. Don't see a feature you want? Send inquiries for support for a particular abstraction to the `issues`_ tracker. @@ -54,7 +80,7 @@ the basics: ----------- .. note:: - The code below *and* more examples can be found in the `examples directory`_ + The code below *and* more examples can be found in the `examples directory`_. .. literalinclude:: ../../examples/source/docs/simple_functions.cpp @@ -63,23 +89,9 @@ the basics: .. literalinclude:: ../../examples/source/docs/simple_structs.cpp :name: simple-structs-example - :linenos: + :linenos: -helping out ------------ - -You can support sol2 development by `donating here`_. 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. - -Finally, `come join in Discord`_! - Indices and tables ================== @@ -89,5 +101,37 @@ 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 here: https://www.paypal.me/LMeneide -.. _come join in Discord: https://discord.gg/buxkYNT + +.. |pa| image:: media/become_a_patron_button.png + :height: 50 + :target: https://www.patreon.com/thephd + :alt: sol3 Patreon + :align: middle + +.. |kf| image:: media/Ko-fi_Blue.png + :height: 50 + :target: https://ko-fi.com/thephd + :alt: sol3 ko-fi + :align: middle + +.. |lp| image:: media/liberapay_logo.png + :height: 50 + :target: https://ko-fi.com/thephd + :alt: sol3 ko-fi + :align: middle + +.. |pp| image:: media/pp_cc_mark_111x69.jpg + :height: 50 + :target: https://www.paypal.me/thephd + :alt: sol3 PayPal + :align: middle + +.. |ds| image:: media/discord_logo_wordmark.png + :height: 75 + :target: https://discord.gg/buxkYNT + :alt: sol3 Discord + +.. |gh| image:: media/github_logo.png + :height: 75 + :target: https://github.com/ThePhD/sol2/issues + :alt: sol3 Github Issues Page diff --git a/docs/source/media/Ko-fi_Blue.png b/docs/source/media/Ko-fi_Blue.png new file mode 100644 index 0000000000000000000000000000000000000000..3b93ed47e6f951782e2dca3761712878900c8443 GIT binary patch literal 8129 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 literal 0 HcmV?d00001 diff --git a/docs/source/media/become_a_patron_button.png b/docs/source/media/become_a_patron_button.png new file mode 100644 index 0000000000000000000000000000000000000000..5443ec96319d128bc1f2c8cf348f97c4565c5cc1 GIT binary patch literal 6579 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 XLyRvu{aX3a{{tgEGu={c*U0|?Dtn-9 literal 0 HcmV?d00001 diff --git a/docs/source/media/liberapay_logo.png b/docs/source/media/liberapay_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..385a9a655a49a852d50207c4e54fbc5670c7b388 GIT binary patch literal 12732 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 WWwTFOBWZuNpffSDG;Bh-C;bmGY0yIe literal 0 HcmV?d00001 diff --git a/docs/source/media/pp_cc_mark_111x69.jpg b/docs/source/media/pp_cc_mark_111x69.jpg new file mode 100644 index 0000000000000000000000000000000000000000..956bb454d6ed2b70a3cb9ca03e3b83c7cbce3c4a GIT binary patch literal 11005 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 WWBsd%t&23ZQ|TW$ literal 0 HcmV?d00001 diff --git a/docs/source/mentions.rst b/docs/source/mentions.rst index 2d1a163a..5588b155 100644 --- a/docs/source/mentions.rst +++ b/docs/source/mentions.rst @@ -4,9 +4,9 @@ mentions First off, feel free to `tell me about your uses!`_ -Okay, so the features don't convince you, the documentation doesn't convince you, you want to see what *other* people think about Sol? Well, aside from the well-wishes that come through in the issue tracker, here's a few things floating around about sol2 that I occasionally get pinged about: +Okay, so the features don't convince you, the documentation doesn't convince you, you want to see what *other* people think about Sol? Well, aside from the well-wishes that come through in the issue tracker, here's a few things floating around about sol3 that I occasionally get pinged about: -`eevee`_ demonstrating the sheer code reduction by using sol2: +`eevee`_ demonstrating the sheer code reduction by using sol3: .. |before| image:: media/eevee_code_before.jpg @@ -16,7 +16,7 @@ Okay, so the features don't convince you, the documentation doesn't convince you .. |after| image:: media/eevee_code_after.jpg :target: https://twitter.com/eevee/status/762039984085798913 - :alt: Now with sol2! + :alt: Now with sol3! :align: middle +----------+---------+ @@ -24,10 +24,10 @@ Okay, so the features don't convince you, the documentation doesn't convince you +----------+---------+ * In `High Performance Computing research`_ -* The `Multiple Arcade Machine Emulator (MAME)`_ project switched from using LuaBridge to sol2! +* The `Multiple Arcade Machine Emulator (MAME)`_ project switched from using LuaBridge to sol3! - `The pull request`_ in which it was introduced to the master branch. * For scripting, in `OpenMPT`_ -* (CppNow) sol2 was mentioned in a comparison to other scripting languages by ChaiScript developer, Jason Turner (@lefticus), at a conference! +* (CppNow) sol3 was mentioned in a comparison to other scripting languages by ChaiScript developer, Jason Turner (@lefticus), at a conference! - `Jason Turner's presentation`_ * (CppCast) Showed up in CppCast with Elias Daler! - `Elias Daler's blog`_ @@ -36,16 +36,16 @@ Okay, so the features don't convince you, the documentation doesn't convince you - `eevee's blog`_ * (Twitter) Twitter has some people that link it: - The image above, `tweeted out by eevee`_ - - Eevee: `"I heartily recommend sol2"`_ - - Elias Daler: `"sol2 saved my life."`_ - - Racod's Lair: `"from outdated LuaBridge to superior #sol2"`_ + - Eevee: `"I heartily recommend sol3"`_ + - Elias Daler: `"sol3 saved my life."`_ + - Racod's Lair: `"from outdated LuaBridge to superior #sol3"`_ * (Reddit) Posts on reddit about it! - - `sol2's initial reddit release`_ + - `sol3's initial reddit release`_ - `Benchmarking Discussing`_ * Somehow landed on a Torque3D thread... - http://forums.torque3d.org/viewtopic.php?f=32&t=629&p=5246&sid=8e759990ab1ce38a48e896fc9fd62653#p5241 -Are you using sol2 for something neat? Want it to be featured here or think it's unfair that ThePhD hasn't found it yet? Well, drop an issue in the repo or send an e-mail! +Are you using sol3 for something neat? Want it to be featured here or think it's unfair that ThePhD hasn't found it yet? Well, drop an issue in the repo or send an e-mail! .. _tell me about your uses!: https://github.com/ThePhD/sol2/issues/189 .. _eevee: https://twitter.com/eevee @@ -54,11 +54,11 @@ Are you using sol2 for something neat? Want it to be featured here or think it's .. _Elias Daler's blog: https://eliasdaler.github.io/cppcast#read-more .. _CppCast: http://cppcast.com/2016/07/elias-daler/ .. _tweeted out by eevee: https://twitter.com/eevee/status/762039984085798913 -.. _"I heartily recommend sol2": https://twitter.com/eevee/status/762040086540144644 -.. _"from outdated LuaBridge to superior #sol2": https://twitter.com/racodslair/status/754031870640267264 -.. _sol2's initial reddit release: https://www.reddit.com/r/cpp/comments/4a8gy7/sol2_lua_c_binding_framework/ +.. _"I heartily recommend sol3": https://twitter.com/eevee/status/762040086540144644 +.. _"from outdated LuaBridge to superior #sol3": https://twitter.com/racodslair/status/754031870640267264 +.. _sol3's initial reddit release: https://www.reddit.com/r/cpp/comments/4a8gy7/sol2_lua_c_binding_framework/ .. _Benchmarking Discussing: https://www.reddit.com/r/cpp/comments/4x82hd/plain_c_versus_lua_libraries_benchmarking_speed/ -.. _"sol2 saved my life.": https://twitter.com/EliasDaler/status/739215685264494593 +.. _"sol3 saved my life.": https://twitter.com/EliasDaler/status/739215685264494593 .. _Multiple Arcade Machine Emulator (MAME): http://www.mamedev.org/index.php .. _The pull request: https://github.com/mamedev/mame/pull/1626 .. _OpenMPT: https://openmpt.org/ diff --git a/docs/source/origin.rst b/docs/source/origin.rst index fa90844a..19105acc 100644 --- a/docs/source/origin.rst +++ b/docs/source/origin.rst @@ -13,7 +13,7 @@ And lo, `Danny Y., Rapptz`_ did stand firm in the sea and cast his hands to the seriously --------- -Sol was originally started by many moon cycles ago to interop with Lua and C++, by `Rapptz`_. It was very successful and many rejoiced at having an easy to use abstraction on top of the Lua API. Rapptz continued to make a number of great projects and has been busy with other things, so upon seeing the repository grow stagnant and tired in the last very long while (over a year), `ThePhD`_ forked it into Sol2 and rebooted the code with the hopes of reaching the Milestone and the documentation you have today. +Sol was originally started by many moon cycles ago to interop with Lua and C++, by `Rapptz`_. It was very successful and many rejoiced at having an easy to use abstraction on top of the Lua API. Rapptz continued to make a number of great projects and has been busy with other things, so upon seeing the repository grow stagnant and tired in the last very long while (over a year), `ThePhD`_ forked it into Sol3 and rebooted the code with the hopes of reaching the Milestone and the documentation you have today. To get to the old repo, head over `here`_. diff --git a/docs/source/safety.rst b/docs/source/safety.rst index ff6b2396..6c793875 100644 --- a/docs/source/safety.rst +++ b/docs/source/safety.rst @@ -10,7 +10,7 @@ config Note that you can obtain safety with regards to functions you bind by using the :doc:`protect` wrapper around function/variable bindings you set into Lua. Additionally, you can have basic boolean checks when using the API by just converting to a :doc:`sol::optional\` when necessary for getting things out of Lua and for function arguments. -Also note that you can have your own states use sol2's safety panics and similar to protect your code from crashes. See :ref:`sol::state automatic handlers` for more details. +Also note that you can have your own states use sol3's safety panics and similar to protect your code from crashes. See :ref:`sol::state automatic handlers` for more details. .. _config-safety: @@ -64,7 +64,7 @@ Safety Config ``SOL_STRINGS_ARE_NUMBERS`` triggers the following changes: * Allows automatic to-string conversions for numbers - - ``lua_tolstring`` conversions are not permitted on numbers through sol2 by default: only actual strings are allowed + - ``lua_tolstring`` conversions are not permitted on numbers through sol3 by default: only actual strings are allowed - This is necessary to allow :doc:`sol::overload` to work properly * ``sol::stack::get`` and ``sol::stack::check_get`` will allow anything that Lua thinks is number-worthy to be number-worthy * This includes: integers, floating-point numbers, and strings @@ -142,7 +142,7 @@ Memory safety can be tricky. Lua is handled by a garbage-collected runtime, mean The usertype memory layout for all Lua-instantiated userdata and for all objects pushed/set into the Lua Runtime is also described :doc:`here`. Things before or after that specified memory slot is implementation-defined and no assumptions are to be made about it. -Please be wary of alignment issues. sol2 **aligns memory** by default. If you need to access underlying userdata memory from sol, please see the :doc:`usertype memory documentation` +Please be wary of alignment issues. sol3 **aligns memory** by default. If you need to access underlying userdata memory from sol, please see the :doc:`usertype memory documentation` functions --------- diff --git a/docs/source/traits.rst b/docs/source/traits.rst index 908df124..ca1b5664 100644 --- a/docs/source/traits.rst +++ b/docs/source/traits.rst @@ -1,7 +1,7 @@ customization traits ==================== -These are customization points within the library to help you make sol2 work for the types in your framework and types. +These are customization points within the library to help you make sol3 work for the types in your framework and types. To learn more about various customizable traits, visit: diff --git a/docs/source/tutorial/all-the-things.rst b/docs/source/tutorial/all-the-things.rst index 3656546d..4633096d 100644 --- a/docs/source/tutorial/all-the-things.rst +++ b/docs/source/tutorial/all-the-things.rst @@ -9,16 +9,16 @@ These are all the things. Use your browser's search to find things you want. .. note:: - All of the code below is available at the `sol2 tutorial examples`_. + All of the code below is available at the `sol3 tutorial examples`_. asserts / prerequisites ----------------------- -You'll need to ``#include ``/``#include "sol.hpp"`` somewhere in your code. Sol is header-only, so you don't need to compile anything. However, **Lua must be compiled and available**. See the :doc:`getting started tutorial` for more details. +You'll need to ``#include `` somewhere in your code. Sol is header-only, so you don't need to compile anything. However, **Lua must be compiled and available**. See the :doc:`getting started tutorial` for more details. The implementation for ``assert.hpp`` with ``c_assert`` looks like so: -.. literalinclude:: ../../../examples/source/assert.hpp +.. literalinclude:: ../../../examples/include/assert.hpp :linenos: :lines: 1-3, 19- @@ -33,10 +33,10 @@ opening a state .. _sol-state-on-lua-state: -using sol2 on a lua_State\* +using sol3 on a lua_State\* --------------------------- -For your system/game that already has Lua or uses an in-house or pre-rolled Lua system (LuaBridge, kaguya, Luwra, etc.), but you'd still like sol2 and nice things: +For your system/game that already has Lua or uses an in-house or pre-rolled Lua system (LuaBridge, kaguya, Luwra, etc.), but you'd still like sol3 and nice things: .. literalinclude:: ../../../examples/source/tutorials/quick_n_dirty/opening_state_on_raw_lua.cpp @@ -278,4 +278,4 @@ Some more things you can do/read about: .. _basic example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype.cpp .. _special functions example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_special_functions.cpp .. _initializers example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_initializers.cpp -.. _sol2 tutorial examples: https://github.com/ThePhD/sol2/tree/develop/examples/tutorials/quick_n_dirty +.. _sol3 tutorial examples: https://github.com/ThePhD/sol2/tree/develop/examples/tutorials/quick_n_dirty diff --git a/docs/source/usertypes.rst b/docs/source/usertypes.rst index c7169576..ef84e46c 100644 --- a/docs/source/usertypes.rst +++ b/docs/source/usertypes.rst @@ -1,7 +1,7 @@ usertypes ========= -Perhaps the most powerful feature of sol2, ``usertypes`` are the way sol2 and C++ communicate your classes to the Lua runtime and bind things between both tables and to specific blocks of C++ memory, allowing you to treat Lua userdata and other things like classes. +Perhaps the most powerful feature of sol3, ``usertypes`` are the way sol3 and C++ communicate your classes to the Lua runtime and bind things between both tables and to specific blocks of C++ memory, allowing you to treat Lua userdata and other things like classes. To learn more about usertypes, visit: @@ -19,7 +19,7 @@ The examples folder also has a number of really great examples for you to see. T - If you need dynamic callbacks or runtime overridable functions, have a ``std::function`` member variable and get/set it on the usertype object - ``std::function`` works as a member variable or in passing as an argument / returning as a value (you can even use it with ``sol::property``) - You can also create an entirely dynamic object: see the `dynamic_object example`_ for more details -* You can use :doc:`filters` to control dependencies and streamline return values, as well as apply custom behavior to a functions return +* You can use :doc:`policies` to control dependencies and streamline return values, as well as apply custom behavior to a functions return * You can work with special wrapper types such as ``std::unique_ptr``, ``std::shared_ptr``, and others by default - Extend them using the :doc:`sol::unique_usertype\ traits` - This allows for custom smart pointers, special pointers, custom handles and others to be given certain handling semantics to ensure proper RAII with Lua's garbage collection @@ -30,7 +30,7 @@ The examples folder also has a number of really great examples for you to see. T .. _usertype-special-features: .. note:: - Note that to use many of sol2's features, such as automatic constructor creation, ``sol::property``, and similar, one must pass these things to the usertype as part of its initial creation and grouping of arguments. Attempting to do so afterwards will result in unexpected and wrong behavior, as the system will be missing information it needs. This is because many of these features rely on ``__index`` and ``__newindex`` Lua metamethods being overridden and handled in a special way! + Note that to use many of sol3's features, such as automatic constructor creation, ``sol::property``, and similar, one must pass these things to the usertype as part of its initial creation and grouping of arguments. Attempting to do so afterwards will result in unexpected and wrong behavior, as the system will be missing information it needs. This is because many of these features rely on ``__index`` and ``__newindex`` Lua metamethods being overridden and handled in a special way! Here are some other general advice and tips for understanding and dealing with usertypes: @@ -50,14 +50,14 @@ Here are some other general advice and tips for understanding and dealing with u - Retrieve a plain ``T`` to get a copy - Return types and passing arguments to ``sol::function``-types use perfect forwarding and reference semantics, which means no copies happen unless you specify a value explicitly. See :ref:`this note for details` * You can set ``index`` and ``new_index`` freely on any usertype you like to override the default "if a key is missing, find it / set it here" functionality of a specific object of a usertype - - ``new_index`` and ``index`` will not be called if you try to manipulate the named usertype table directly. sol2's will be called to add that function to the usertype's function/variable lookup table + - ``new_index`` and ``index`` will not be called if you try to manipulate the named usertype table directly. sol3's will be called to add that function to the usertype's function/variable lookup table - ``new_index`` and ``index`` will be called if you attempt to call a key that does not exist on an actual userdata object (the C++ object) itself - If you made a usertype named ``test``, this means ``t = test()``, with ``t.hi = 54`` will call your function, but ``test.hi = function () print ("hi"); end`` will instead set the key ``hi`` to to lookup that function for all ``test`` types -* The first ``sizeof( void* )`` bytes is always a pointer to the typed C++ memory. What comes after is based on what you've pushed into the system according to :doc:`the memory specification for usertypes`. This is compatible with a number of systems other than just sol2, making it easy to interop with select other Lua systems. +* The first ``sizeof( void* )`` bytes is always a pointer to the typed C++ memory. What comes after is based on what you've pushed into the system according to :doc:`the memory specification for usertypes`. This is compatible with a number of systems other than just sol3, making it easy to interop with select other Lua systems. * Member methods, properties, variables and functions taking ``self&`` arguments modify data directly - Work on a copy by taking arguments or returning by value. - Do not use r-value references: they do not mean anything in Lua code. - - Move-only types can only be taken by reference: sol2 cannot know if/when to move a value (except when serializing with perfect forwarding *into* Lua, but not calling a C++ function from Lua) + - Move-only types can only be taken by reference: sol3 cannot know if/when to move a value (except when serializing with perfect forwarding *into* Lua, but not calling a C++ function from Lua) * The actual metatable associated with the usertype has a long name and is defined to be opaque by the Sol implementation. * The actual metatable inner workings is opaque and defined by the Sol implementation, and there are no internal docs because optimizations on the operations are applied based on heuristics we discover from performance testing the system. diff --git a/include/sol/call.hpp b/include/sol/call.hpp index 3322cfc6..811ce57d 100644 --- a/include/sol/call.hpp +++ b/include/sol/call.hpp @@ -28,7 +28,7 @@ #include "protect.hpp" #include "wrapper.hpp" #include "trampoline.hpp" -#include "filters.hpp" +#include "policies.hpp" #include "stack.hpp" #include "unique_usertype_traits.hpp" @@ -37,9 +37,9 @@ namespace sol { } // namespace u_detail - namespace filter_detail { + namespace policy_detail { template - inline void handle_filter(static_stack_dependencies, lua_State* L, int&) { + inline void handle_policy(static_stack_dependencies, lua_State* L, int&) { if constexpr (sizeof...(In) == 0) { (void)L; return; @@ -65,12 +65,12 @@ namespace sol { } template - inline void handle_filter(returns_self_with, lua_State* L, int& pushed) { + inline void handle_policy(returns_self_with, lua_State* L, int& pushed) { pushed = stack::push(L, raw_index(1)); - handle_filter(static_stack_dependencies<-1, In...>(), L, pushed); + handle_policy(static_stack_dependencies<-1, In...>(), L, pushed); } - inline void handle_filter(const stack_dependencies& sdeps, lua_State* L, int&) { + inline void handle_policy(const stack_dependencies& sdeps, lua_State* L, int&) { absolute_index ai(L, sdeps.target); if (type_of(L, ai) != type::userdata) { return; @@ -87,11 +87,11 @@ namespace sol { lua_setuservalue(L, ai); } - template >> = meta::enabler> - inline void handle_filter(P&& p, lua_State* L, int& pushed) { + template >> = meta::enabler> + inline void handle_policy(P&& p, lua_State* L, int& pushed) { pushed = std::forward

(p)(L, pushed); } - } // namespace filter_detail + } // namespace policy_detail namespace function_detail { inline int no_construction_error(lua_State* L) { @@ -807,14 +807,14 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { - typedef filter_wrapper P; + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { + typedef policy_wrapper P; template static int call(std::index_sequence, lua_State* L, P& fx) { int pushed = lua_call_wrapper{}.call(L, fx.value); - (void)detail::swallow{ int(), (filter_detail::handle_filter(std::get(fx.filters), L, pushed), int())... }; + (void)detail::swallow{ int(), (policy_detail::handle_policy(std::get(fx.policies), L, pushed), int())... }; return pushed; } @@ -888,8 +888,8 @@ namespace sol { template struct is_var_bind> : is_var_bind> {}; - template - struct is_var_bind> : is_var_bind> {}; + template + struct is_var_bind> : is_var_bind> {}; } // namespace call_detail template diff --git a/include/sol/forward.hpp b/include/sol/forward.hpp index be1de3bd..b555504c 100644 --- a/include/sol/forward.hpp +++ b/include/sol/forward.hpp @@ -187,8 +187,8 @@ namespace sol { struct as_args_t; template struct protect_t; - template - struct filter_wrapper; + template + struct policy_wrapper; template struct usertype_traits; diff --git a/include/sol/function_types.hpp b/include/sol/function_types.hpp index 333dc0af..cad99097 100644 --- a/include/sol/function_types.hpp +++ b/include/sol/function_types.hpp @@ -564,9 +564,9 @@ namespace sol { } }; - template - struct unqualified_pusher> { - using P = filter_wrapper; + template + struct unqualified_pusher> { + using P = policy_wrapper; static int push(lua_State* L, const P& p) { lua_CFunction cf = call_detail::call_user; @@ -585,9 +585,9 @@ namespace sol { } }; - template - struct unqualified_pusher>> { - using P = filter_wrapper; + template + struct unqualified_pusher>> { + using P = policy_wrapper; using Tagged = detail::tagged; static int push(lua_State* L, const Tagged& p) { diff --git a/include/sol/filters.hpp b/include/sol/policies.hpp similarity index 70% rename from include/sol/filters.hpp rename to include/sol/policies.hpp index 1cead6df..7b8d738e 100644 --- a/include/sol/filters.hpp +++ b/include/sol/policies.hpp @@ -30,17 +30,17 @@ namespace sol { namespace detail { - struct filter_base_tag {}; + struct policy_base_tag {}; } // namespace detail template - struct static_stack_dependencies : detail::filter_base_tag {}; + struct static_stack_dependencies : detail::policy_base_tag {}; typedef static_stack_dependencies<-1, 1> self_dependency; template - struct returns_self_with : detail::filter_base_tag {}; + struct returns_self_with : detail::policy_base_tag {}; typedef returns_self_with<> returns_self; - struct stack_dependencies : detail::filter_base_tag { + struct stack_dependencies : detail::policy_base_tag { int target; std::array stack_indices; std::size_t len; @@ -65,35 +65,35 @@ namespace sol { } }; - template - struct filter_wrapper { - typedef std::index_sequence_for indices; + template + struct policy_wrapper { + typedef std::index_sequence_for indices; F value; - std::tuple filters; + std::tuple policies; - template , filter_wrapper>>> = meta::enabler> - filter_wrapper(Fx&& fx, Args&&... args) - : value(std::forward(fx)), filters(std::forward(args)...) { + template , policy_wrapper>>> = meta::enabler> + policy_wrapper(Fx&& fx, Args&&... args) + : value(std::forward(fx)), policies(std::forward(args)...) { } - filter_wrapper(const filter_wrapper&) = default; - filter_wrapper& operator=(const filter_wrapper&) = default; - filter_wrapper(filter_wrapper&&) = default; - filter_wrapper& operator=(filter_wrapper&&) = default; + policy_wrapper(const policy_wrapper&) = default; + policy_wrapper& operator=(const policy_wrapper&) = default; + policy_wrapper(policy_wrapper&&) = default; + policy_wrapper& operator=(policy_wrapper&&) = default; }; template - auto filters(F&& f, Args&&... args) { - return filter_wrapper, std::decay_t...>(std::forward(f), std::forward(args)...); + auto policies(F&& f, Args&&... args) { + return policy_wrapper, std::decay_t...>(std::forward(f), std::forward(args)...); } namespace detail { template - using is_filter = meta::is_specialization_of; + using is_policy = meta::is_specialization_of; template - inline constexpr bool is_filter_v = is_filter::value; + inline constexpr bool is_policy_v = is_policy::value; } } // namespace sol diff --git a/include/sol/stack_push.hpp b/include/sol/stack_push.hpp index f9dd93a1..2564324c 100644 --- a/include/sol/stack_push.hpp +++ b/include/sol/stack_push.hpp @@ -28,7 +28,7 @@ #include "raii.hpp" #include "optional.hpp" #include "usertype_traits.hpp" -#include "filters.hpp" +#include "policies.hpp" #include "unicode.hpp" #include diff --git a/include/sol/table_core.hpp b/include/sol/table_core.hpp index eef76de8..294c25a8 100644 --- a/include/sol/table_core.hpp +++ b/include/sol/table_core.hpp @@ -478,7 +478,7 @@ namespace sol { constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t...> > 0); auto pp = stack::push_pop(*this); lua_State* L = base_t::lua_state(); - auto pn = stack::pop_n(L, static_cast(sizeof...(Keys) - 2 - meta::count_for_pack...>)); + auto pn = stack::pop_n(L, static_cast(sizeof...(Keys) - 2 - meta::count_for_pack_v...>)); traverse_set_deep(std::forward(keys)...); return *this; } diff --git a/include/sol/types.hpp b/include/sol/types.hpp index 115669c2..c32f9ad6 100644 --- a/include/sol/types.hpp +++ b/include/sol/types.hpp @@ -32,7 +32,7 @@ #include "traits.hpp" #include "string_view.hpp" #include "raii.hpp" -#include "filters.hpp" +#include "policies.hpp" #include "ebco.hpp" #include @@ -1332,8 +1332,8 @@ namespace sol { template struct is_constructor> : is_constructor> {}; - template - struct is_constructor> : is_constructor> {}; + template + struct is_constructor> : is_constructor> {}; template inline constexpr bool is_constructor_v = is_constructor::value; diff --git a/include/sol/usertype.hpp b/include/sol/usertype.hpp index d340e10c..fc485a6e 100644 --- a/include/sol/usertype.hpp +++ b/include/sol/usertype.hpp @@ -73,7 +73,7 @@ namespace sol { else { using ValueU = meta::unqualified_t; // cannot get metatable: try regular table set? - if constexpr (detail::is_non_factory_constructor_v || detail::is_filter_v) { + if constexpr (detail::is_non_factory_constructor_v || detail::is_policy_v) { // tag constructors so we don't get destroyed by lack of info table_base_t::set(std::forward(key), detail::tagged(std::forward(value))); } diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index f4c7285d..d6d7e591 100644 --- a/single/include/sol/forward.hpp +++ b/single/include/sol/forward.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-05-21 06:26:29.108703 UTC -// This header was generated with sol v3.0.1-beta2 (revision 5dee45c) +// Generated 2019-05-21 07:55:59.916335 UTC +// This header was generated with sol v3.0.1-beta2 (revision ad1b966) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP @@ -403,8 +403,8 @@ namespace sol { struct as_args_t; template struct protect_t; - template - struct filter_wrapper; + template + struct policy_wrapper; template struct usertype_traits; diff --git a/single/include/sol/sol.hpp b/single/include/sol/sol.hpp index 910ff89c..bb71e83b 100644 --- a/single/include/sol/sol.hpp +++ b/single/include/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-05-21 06:26:28.717749 UTC -// This header was generated with sol v3.0.1-beta2 (revision 5dee45c) +// Generated 2019-05-21 07:55:59.198915 UTC +// This header was generated with sol v3.0.1-beta2 (revision ad1b966) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -429,8 +429,8 @@ namespace sol { struct as_args_t; template struct protect_t; - template - struct filter_wrapper; + template + struct policy_wrapper; template struct usertype_traits; @@ -6019,21 +6019,21 @@ namespace sol { // end of sol/raii.hpp -// beginning of sol/filters.hpp +// beginning of sol/policies.hpp namespace sol { namespace detail { - struct filter_base_tag {}; + struct policy_base_tag {}; } // namespace detail template - struct static_stack_dependencies : detail::filter_base_tag {}; + struct static_stack_dependencies : detail::policy_base_tag {}; typedef static_stack_dependencies<-1, 1> self_dependency; template - struct returns_self_with : detail::filter_base_tag {}; + struct returns_self_with : detail::policy_base_tag {}; typedef returns_self_with<> returns_self; - struct stack_dependencies : detail::filter_base_tag { + struct stack_dependencies : detail::policy_base_tag { int target; std::array stack_indices; std::size_t len; @@ -6058,39 +6058,39 @@ namespace sol { } }; - template - struct filter_wrapper { - typedef std::index_sequence_for indices; + template + struct policy_wrapper { + typedef std::index_sequence_for indices; F value; - std::tuple filters; + std::tuple policies; - template , filter_wrapper>>> = meta::enabler> - filter_wrapper(Fx&& fx, Args&&... args) - : value(std::forward(fx)), filters(std::forward(args)...) { + template , policy_wrapper>>> = meta::enabler> + policy_wrapper(Fx&& fx, Args&&... args) + : value(std::forward(fx)), policies(std::forward(args)...) { } - filter_wrapper(const filter_wrapper&) = default; - filter_wrapper& operator=(const filter_wrapper&) = default; - filter_wrapper(filter_wrapper&&) = default; - filter_wrapper& operator=(filter_wrapper&&) = default; + policy_wrapper(const policy_wrapper&) = default; + policy_wrapper& operator=(const policy_wrapper&) = default; + policy_wrapper(policy_wrapper&&) = default; + policy_wrapper& operator=(policy_wrapper&&) = default; }; template - auto filters(F&& f, Args&&... args) { - return filter_wrapper, std::decay_t...>(std::forward(f), std::forward(args)...); + auto policies(F&& f, Args&&... args) { + return policy_wrapper, std::decay_t...>(std::forward(f), std::forward(args)...); } namespace detail { template - using is_filter = meta::is_specialization_of; + using is_policy = meta::is_specialization_of; template - inline constexpr bool is_filter_v = is_filter::value; + inline constexpr bool is_policy_v = is_policy::value; } } // namespace sol -// end of sol/filters.hpp +// end of sol/policies.hpp // beginning of sol/ebco.hpp @@ -7516,8 +7516,8 @@ namespace sol { template struct is_constructor> : is_constructor> {}; - template - struct is_constructor> : is_constructor> {}; + template + struct is_constructor> : is_constructor> {}; template inline constexpr bool is_constructor_v = is_constructor::value; @@ -15856,9 +15856,9 @@ namespace sol { } // namespace u_detail - namespace filter_detail { + namespace policy_detail { template - inline void handle_filter(static_stack_dependencies, lua_State* L, int&) { + inline void handle_policy(static_stack_dependencies, lua_State* L, int&) { if constexpr (sizeof...(In) == 0) { (void)L; return; @@ -15884,12 +15884,12 @@ namespace sol { } template - inline void handle_filter(returns_self_with, lua_State* L, int& pushed) { + inline void handle_policy(returns_self_with, lua_State* L, int& pushed) { pushed = stack::push(L, raw_index(1)); - handle_filter(static_stack_dependencies<-1, In...>(), L, pushed); + handle_policy(static_stack_dependencies<-1, In...>(), L, pushed); } - inline void handle_filter(const stack_dependencies& sdeps, lua_State* L, int&) { + inline void handle_policy(const stack_dependencies& sdeps, lua_State* L, int&) { absolute_index ai(L, sdeps.target); if (type_of(L, ai) != type::userdata) { return; @@ -15906,11 +15906,11 @@ namespace sol { lua_setuservalue(L, ai); } - template >> = meta::enabler> - inline void handle_filter(P&& p, lua_State* L, int& pushed) { + template >> = meta::enabler> + inline void handle_policy(P&& p, lua_State* L, int& pushed) { pushed = std::forward

(p)(L, pushed); } - } // namespace filter_detail + } // namespace policy_detail namespace function_detail { inline int no_construction_error(lua_State* L) { @@ -16626,14 +16626,14 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { - typedef filter_wrapper P; + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { + typedef policy_wrapper P; template static int call(std::index_sequence, lua_State* L, P& fx) { int pushed = lua_call_wrapper{}.call(L, fx.value); - (void)detail::swallow{ int(), (filter_detail::handle_filter(std::get(fx.filters), L, pushed), int())... }; + (void)detail::swallow{ int(), (policy_detail::handle_policy(std::get(fx.policies), L, pushed), int())... }; return pushed; } @@ -16707,8 +16707,8 @@ namespace sol { template struct is_var_bind> : is_var_bind> {}; - template - struct is_var_bind> : is_var_bind> {}; + template + struct is_var_bind> : is_var_bind> {}; } // namespace call_detail template @@ -17916,9 +17916,9 @@ namespace sol { } }; - template - struct unqualified_pusher> { - using P = filter_wrapper; + template + struct unqualified_pusher> { + using P = policy_wrapper; static int push(lua_State* L, const P& p) { lua_CFunction cf = call_detail::call_user; @@ -17937,9 +17937,9 @@ namespace sol { } }; - template - struct unqualified_pusher>> { - using P = filter_wrapper; + template + struct unqualified_pusher>> { + using P = policy_wrapper; using Tagged = detail::tagged; static int push(lua_State* L, const Tagged& p) { @@ -22806,7 +22806,7 @@ namespace sol { constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t...> > 0); auto pp = stack::push_pop(*this); lua_State* L = base_t::lua_state(); - auto pn = stack::pop_n(L, static_cast(sizeof...(Keys) - 2 - meta::count_for_pack...>)); + auto pn = stack::pop_n(L, static_cast(sizeof...(Keys) - 2 - meta::count_for_pack_v...>)); traverse_set_deep(std::forward(keys)...); return *this; } @@ -23198,7 +23198,7 @@ namespace sol { else { using ValueU = meta::unqualified_t; // cannot get metatable: try regular table set? - if constexpr (detail::is_non_factory_constructor_v || detail::is_filter_v) { + if constexpr (detail::is_non_factory_constructor_v || detail::is_policy_v) { // tag constructors so we don't get destroyed by lack of info table_base_t::set(std::forward(key), detail::tagged(std::forward(value))); } diff --git a/tests/compile_tests/source/filters.cpp b/tests/compile_tests/source/policies.cpp similarity index 97% rename from tests/compile_tests/source/filters.cpp rename to tests/compile_tests/source/policies.cpp index fa9ec2b2..6d15e2f0 100644 --- a/tests/compile_tests/source/filters.cpp +++ b/tests/compile_tests/source/policies.cpp @@ -23,4 +23,4 @@ #include "sol_defines.hpp" -#include +#include diff --git a/tests/runtime_tests/source/filters.cpp b/tests/runtime_tests/source/policies.cpp similarity index 88% rename from tests/runtime_tests/source/filters.cpp rename to tests/runtime_tests/source/policies.cpp index e1882ee2..fec240fa 100644 --- a/tests/runtime_tests/source/filters.cpp +++ b/tests/runtime_tests/source/policies.cpp @@ -28,7 +28,7 @@ #include #include -TEST_CASE("filters/self", "ensure we return a direct reference to the lua userdata rather than creating a new one") { +TEST_CASE("policies/self", "ensure we return a direct reference to the lua userdata rather than creating a new one") { struct vec2 { float x = 20.f; float y = 20.f; @@ -55,7 +55,7 @@ TEST_CASE("filters/self", "ensure we return a direct reference to the lua userda lua.new_usertype("vec2", "x", &vec2::x, "y", &vec2::y, - "normalize", sol::filters(&vec2::normalize, sol::returns_self())); + "normalize", sol::policies(&vec2::normalize, sol::returns_self())); auto result1 = lua.safe_script(R"( v1 = vec2.new() @@ -72,7 +72,7 @@ print(v2) -- v2 points to same, is not destroyed REQUIRE(result1.valid()); } -TEST_CASE("filters/self_dependency", "ensure we can keep a userdata instance alive by attaching it to the lifetime of another userdata") { +TEST_CASE("policies/self_dependency", "ensure we can keep a userdata instance alive by attaching it to the lifetime of another userdata") { struct dep; struct gc_test; static std::vector deps_destroyed; @@ -108,7 +108,7 @@ TEST_CASE("filters/self_dependency", "ensure we can keep a userdata instance ali return "{ " + std::to_string(d.value) + " }"; }); lua.new_usertype("gc_test", - "d", sol::filters(&gc_test::d, sol::self_dependency()), + "d", sol::policies(&gc_test::d, sol::self_dependency()), sol::meta_function::to_string, [](gc_test& g) { return "{ d: { " + std::to_string(g.d.value) + " } }"; }); @@ -150,7 +150,7 @@ collectgarbage() REQUIRE(gc_tests_destroyed[0] == g); } -TEST_CASE("filters/stack_dependencies", "ensure we can take dependencies even to arguments pushed on the stack") { +TEST_CASE("policies/stack_dependencies", "ensure we can take dependencies even to arguments pushed on the stack") { struct holder; struct depends_on_reference; struct composition_related; @@ -198,7 +198,7 @@ TEST_CASE("filters/stack_dependencies", "ensure we can take dependencies even to lua.new_usertype("holder", "value", &holder::value); lua.new_usertype("depends_on_reference", - "new", sol::filters(sol::constructors(), sol::stack_dependencies(-1, 1)), + "new", sol::policies(sol::constructors(), sol::stack_dependencies(-1, 1)), "comp", &depends_on_reference::comp); auto result1 = lua.safe_script(R"( @@ -255,10 +255,10 @@ int always_return_24(lua_State* L, int) { return sol::stack::push(L, 24); } -TEST_CASE("filters/custom", "ensure we can return dependencies on multiple things in the stack") { +TEST_CASE("policies/custom", "ensure we can return dependencies on multiple things in the stack") { sol::state lua; - lua.set_function("f", sol::filters([]() { return std::string("hi there"); }, always_return_24)); + lua.set_function("f", sol::policies([]() { return std::string("hi there"); }, always_return_24)); int value = lua["f"](); REQUIRE(value == 24);