From 1f90b049f201c9278981704362d1c8caf95cb5b6 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Fri, 9 Nov 2018 09:41:44 -0800 Subject: [PATCH 1/4] cut off containers if they are not specialization --- single/sol/sol.hpp | 5 +++-- single/sol/sol_forward.hpp | 4 ++-- sol/stack_get_qualified.hpp | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index 42cecba1..d66c2b53 100644 --- a/single/sol/sol.hpp +++ b/single/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 2018-10-28 14:26:05.925454 UTC -// This header was generated with sol v2.20.4 (revision a19a5a3) +// Generated 2018-11-09 17:41:04.453384 UTC +// This header was generated with sol v2.20.4 (revision 47bbe98) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -10077,6 +10077,7 @@ namespace stack { struct qualified_getter::value && is_container>::value + && std::is_default_constructible>::value && !is_lua_primitive::value && !is_transparent_argument::value >> { diff --git a/single/sol/sol_forward.hpp b/single/sol/sol_forward.hpp index 11984fa8..f4f3d79d 100644 --- a/single/sol/sol_forward.hpp +++ b/single/sol/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 2018-10-28 14:26:06.124383 UTC -// This header was generated with sol v2.20.4 (revision a19a5a3) +// Generated 2018-11-09 17:41:04.668612 UTC +// This header was generated with sol v2.20.4 (revision 47bbe98) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP diff --git a/sol/stack_get_qualified.hpp b/sol/stack_get_qualified.hpp index bcdd8110..447e5e75 100644 --- a/sol/stack_get_qualified.hpp +++ b/sol/stack_get_qualified.hpp @@ -52,6 +52,7 @@ namespace stack { struct qualified_getter::value && is_container>::value + && std::is_default_constructible>::value && !is_lua_primitive::value && !is_transparent_argument::value >> { From 091ca39438743914eeae82efc9a0d9302e66fff2 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Fri, 9 Nov 2018 10:53:46 -0800 Subject: [PATCH 2/4] update call --- single/sol/sol.hpp | 13 +++++++++---- single/sol/sol_forward.hpp | 4 ++-- sol/call.hpp | 9 +++++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index d66c2b53..1aa57816 100644 --- a/single/sol/sol.hpp +++ b/single/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 2018-11-09 17:41:04.453384 UTC -// This header was generated with sol v2.20.4 (revision 47bbe98) +// Generated 2018-11-09 18:52:51.075276 UTC +// This header was generated with sol v2.20.4 (revision 1f90b04) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -13141,7 +13141,7 @@ namespace sol { } template - inline int construct(lua_State* L) { + inline int construct_trampolined(lua_State* L) { static const auto& meta = usertype_traits::metatable(); int argcount = lua_gettop(L); call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits::user_metatable(), 1) : call_syntax::dot; @@ -13157,7 +13157,12 @@ namespace sol { stack::stack_detail::undefined_metatable umf(L, &meta[0]); umf(); - return 1; + return 1; + } + + template + inline int construct(lua_State* L) { + return detail::static_trampoline<&construct_trampolined>(L); } template diff --git a/single/sol/sol_forward.hpp b/single/sol/sol_forward.hpp index f4f3d79d..371c3873 100644 --- a/single/sol/sol_forward.hpp +++ b/single/sol/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 2018-11-09 17:41:04.668612 UTC -// This header was generated with sol v2.20.4 (revision 47bbe98) +// Generated 2018-11-09 18:52:51.285820 UTC +// This header was generated with sol v2.20.4 (revision 1f90b04) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP diff --git a/sol/call.hpp b/sol/call.hpp index 70757819..f8d90ea5 100644 --- a/sol/call.hpp +++ b/sol/call.hpp @@ -208,7 +208,7 @@ namespace sol { } template - inline int construct(lua_State* L) { + inline int construct_trampolined(lua_State* L) { static const auto& meta = usertype_traits::metatable(); int argcount = lua_gettop(L); call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits::user_metatable(), 1) : call_syntax::dot; @@ -224,7 +224,12 @@ namespace sol { stack::stack_detail::undefined_metatable umf(L, &meta[0]); umf(); - return 1; + return 1; + } + + template + inline int construct(lua_State* L) { + return detail::static_trampoline<&construct_trampolined>(L); } template From a7048aea45178594eef69bff8689034895093791 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Fri, 9 Nov 2018 14:36:27 -0800 Subject: [PATCH 3/4] fix up variables tutorial --- docs/source/build.rst | 8 + docs/source/cmake.rst | 61 ------ docs/source/conf.py | 2 +- docs/source/index.rst | 2 +- docs/source/tutorial/functions.rst | 2 +- docs/source/tutorial/variables.rst | 195 +++----------------- examples/tutorials/erase_demo.cpp | 16 ++ examples/tutorials/lazy_demo.cpp | 23 +++ examples/tutorials/variables_demo.cpp | 71 +++++++ examples/tutorials/write_variables_demo.cpp | 39 ++++ 10 files changed, 187 insertions(+), 232 deletions(-) create mode 100644 docs/source/build.rst delete mode 100644 docs/source/cmake.rst create mode 100644 examples/tutorials/erase_demo.cpp create mode 100644 examples/tutorials/lazy_demo.cpp create mode 100644 examples/tutorials/variables_demo.cpp create mode 100644 examples/tutorials/write_variables_demo.cpp diff --git a/docs/source/build.rst b/docs/source/build.rst new file mode 100644 index 00000000..97c52287 --- /dev/null +++ b/docs/source/build.rst @@ -0,0 +1,8 @@ +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. + +sol2 also comes with a Meson Script. If things stop working, file a bug report. + + diff --git a/docs/source/cmake.rst b/docs/source/cmake.rst deleted file mode 100644 index b62d1326..00000000 --- a/docs/source/cmake.rst +++ /dev/null @@ -1,61 +0,0 @@ -CMake Script -============ - -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. If you have any problems with it or its targets, please do file a report, or a pull request because CMake is not my forte. - - -.. warning:: - - The below is slightly outdated, but will probably still work for you! - -Thanks to `Kevin Brightwell`_, you can drop this CMake Script into your CMake Projects to have Sol part of one of its builds: - -.. code-block:: cmake - :caption: CMake Build Script - :name: cmake-build-script - - # Needed for ExternalProject_Add() - include(ExternalProject) - - # Needed for building single header for sol2 - find_package(PythonInterp 3 REQUIRED) - - # Configuration data for What sol2 version to use and where to put it - set(SOL2_TAG v2.5.6) - set(SOL2_HPP "${CMAKE_BINARY_DIR}/include/sol.hpp") - - # Download and "install" sol2 - ExternalProject_add( - sol2 - PREFIX ${VENDOR_PATH} # Set this value yourself - - GIT_REPOSITORY "https://github.com/ThePhD/sol2.git" - GIT_TAG ${SOL2_TAG} - - # No CMake commands to run, so tell CMake not to configure - CONFIGURE_COMMAND "" - - # Generate the single header and put it in ${SOL2_HPP} - BINARY_DIR ${VENDOR_PREFIX}/src/sol2 - BUILD_COMMAND - ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include - COMMAND - ${PYTHON_EXECUTABLE} ./single.py -o "${SOL2_HPP}" - - # No install or test command for the library - INSTALL_COMMAND "" - TEST_COMMAND "") - - # Conditionally turn on SOL_CHECK_ARGUMENTS if using Debug mode - if (CMAKE_BUILD_TYPE MATCHES "[Dd]ebug") - if (VERBOSE) - message(STATUS "Turning on SOL_CHECK_ARGUMENTS in Debug mode.") - endif() - add_definitions(-DSOL_CHECK_ARGUMENTS) - endif() - - # Make sure sol2 is found as a system directory - include_directories(SYSTEM ${CMAKE_BINARY_DIR}/include) - - -.. _Kevin Brightwell: https://github.com/ThePhD/sol2/issues/89 diff --git a/docs/source/conf.py b/docs/source/conf.py index 18b27b68..795d96a4 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -57,7 +57,7 @@ author = 'ThePhD' # The short X.Y version. version = '2.20' # The full version, including alpha/beta/rc tags. -release = '2.20.2' +release = '2.20.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/index.rst b/docs/source/index.rst index e751847c..2dd6f1ec 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -40,7 +40,7 @@ get going: exceptions rtti codecvt - cmake + build licenses origin diff --git a/docs/source/tutorial/functions.rst b/docs/source/tutorial/functions.rst index ee3aea10..75afac7b 100644 --- a/docs/source/tutorial/functions.rst +++ b/docs/source/tutorial/functions.rst @@ -6,7 +6,7 @@ Sol can register all kinds of functions. Many are shown in the :doc:`quick 'n' d Setting a new function ---------------------- -Given a C++ function, you can drop it into Sol in several equivalent ways, working similar to how :ref:`setting variables` works: +Given a C++ function, you can drop it into Sol in several equivalent ways, working similar to how :ref:`setting variables` works: .. code-block:: cpp :linenos: diff --git a/docs/source/tutorial/variables.rst b/docs/source/tutorial/variables.rst index bd82253b..1222643b 100644 --- a/docs/source/tutorial/variables.rst +++ b/docs/source/tutorial/variables.rst @@ -1,112 +1,47 @@ variables ========= -Working with variables is easy with Sol, and behaves pretty much like any associative array / map structure you've dealt with previously. Given this lua file that gets loaded into Sol: +Working with variables is easy with sol, and behaves pretty much like any associative array / map structure you might have dealt with previously. reading ------- -.. code-block:: lua - :caption: variables.lua +Given this lua file that gets loaded into sol: - config = { - fullscreen = false, - resolution = { x = 1024, y = 768 } - } +.. literalinclude:: ../../../examples/tutorials/variables_demo.cpp + :linenos: + :lines: 15-18 -.. code-block:: cpp - :caption: main.cpp - :name: variables-main-cpp - - #define SOL_CHECK_ARGUMENTS 1 - #include - - - int main () { - - sol::state lua; - lua.script_file( variables.lua ); - - return 0; - } - -You can interact with the variables like this: - -.. code-block:: cpp - :caption: main.cpp extended - :name: extended-variables-main-cpp - - #define SOL_CHECK_ARGUMENTS 1 - #include - - #include - #include // for std::pair - - int main () { - - sol::state lua; - lua.script_file( variables.lua ); - - // the type "state" behaves exactly like a table! - bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables - sol::table config = lua["config"]; - - // can also get it using the "get" member function - // auto replaces the unqualified type name - auto resolution = config.get( "resolution" ); - - // table and state can have multiple things pulled out of it too - std::pair xyresolution = resolution.get( "x", "y" ); - // As an example, you can also pull out a tuple as well - std::tuple xyresolutiontuple = resolution.get( "x", "y" ); +You can interact with the Lua Virtual Machine like so: - return 0; - } +.. literalinclude:: ../../../examples/tutorials/variables_demo.cpp + :linenos: + :lines: 1-10, 12-12, 20-24, 70- From this example, you can see that there's many ways to pull out the varaibles you want. For example, to determine if a nested variable exists or not, you can use ``auto`` to capture the value of a ``table[key]`` lookup, and then use the ``.valid()`` method: -.. code-block:: cpp - :caption: safe lookup - auto bark = lua["config"]["bark"]; - if (bark.valid()) { - // branch not taken: config / bark is not a variable - } - else { - // Branch taken: config is a not a variable - } +.. literalinclude:: ../../../examples/tutorials/variables_demo.cpp + :linenos: + :lines: 1-10, 12-12, 34-43, 70- + This comes in handy when you want to check if a nested variable exists. You can also check if a toplevel variable is present or not by using ``sol::optional``, which also checks if A) the keys you're going into exist and B) the type you're trying to get is of a specific type: -.. code-block:: cpp +.. literalinclude:: ../../../examples/tutorials/variables_demo.cpp + :linenos: :caption: optional lookup + :lines: 1-10, 12-12, 43-58, 70- - sol::optional not_an_integer = lua["config"]["fullscreen"]; - if (not_an_integer) { - // Branch not taken: value is not an integer - } - - sol::optional is_a_boolean = lua["config"]["fullscreen"]; - if (is_a_boolean) { - // Branch taken: the value is a boolean - } - - sol::optional does_not_exist = lua["not_a_variable"]; - if (does_not_exist) { - // Branch not taken: that variable is not present - } This can come in handy when, even in optimized or release modes, you still want the safety of checking. You can also use the `get_or` methods to, if a certain value may be present but you just want to default the value to something else: -.. code-block:: cpp - :caption: get_or lookup +.. literalinclude:: ../../../examples/tutorials/variables_demo.cpp + :linenos: + :caption: optional lookup + :lines: 1-10, 12-12, 60- - // this will result in a value of '24' - int is_defaulted = lua["config"]["fullscreen"].get_or( 24 ); - - // This will result in the value of the config, which is 'false' - bool is_not_defaulted = lua["config"]["fullscreen"]; That's all it takes to read variables! @@ -116,96 +51,20 @@ writing Writing gets a lot simpler. Even without scripting a file or a string, you can read and write variables into lua as you please: -.. code-block:: cpp - :caption: main.cpp - :name: writing-main-cpp - - #define SOL_CHECK_ARGUMENTS 1 - #include - - #include - - int main () { - - sol::state lua; - - // open those basic lua libraries again, like print() etc. - lua.open_libraries( sol::lib::base ); - - // value in the global table - lua["bark"] = 50; - - // a table being created in the global table - lua["some_table"] = lua.create_table_with( - "key0", 24, - "key1", 25, - lua["bark"], "the key is 50 and this string is its value!" - ); - - // Run a plain ol' string of lua code - // Note you can interact with things set through Sol in C++ with lua! - // Using a "Raw String Literal" to have multi-line goodness: http://en.cppreference.com/w/cpp/language/string_literal - lua.script(R"( - - print(some_table[50]) - print(some_table["key0"]) - print(some_table["key1"]) - - -- a lua comment: access a global in a lua script with the _G table - print(_G["bark"]) - - )"); - - return 0; - } +.. literalinclude:: ../../../examples/tutorials/write_variables_demo.cpp + :linenos: + :name: writing-variables-demo This example pretty much sums up what can be done. Note that the syntax ``lua["non_existing_key_1"] = 1`` will make that variable, but if you tunnel too deep without first creating a table, the Lua API will panic (e.g., ``lua["does_not_exist"]["b"] = 20`` will trigger a panic). You can also be lazy with reading / writing values: -.. code-block:: cpp - :caption: main.cpp - :name: lazy-main-cpp +.. literalinclude:: ../../../examples/tutorials/lazy_demo.cpp + :linenos: - #define SOL_CHECK_ARGUMENTS 1 - #include - - #include - - int main () { - - sol::state lua; - - auto barkkey = lua["bark"]; - if (barkkey.valid()) { - // Branch not taken: doesn't exist yet - std::cout << "How did you get in here, arf?!" << std::endl; - } - - barkkey = 50; - if (barkkey.valid()) { - // Branch taken: value exists! - std::cout << "Bark Bjork Wan Wan Wan" << std::endl; - } - } Finally, it's possible to erase a reference/variable by setting it to ``nil``, using the constant ``sol::nil`` in C++: -.. code-block:: cpp - :caption: main.cpp - :name: erase-main-cpp +.. literalinclude:: ../../../examples/tutorials/erase_demo.cpp + :linenos: - #define SOL_CHECK_ARGUMENTS 1 - #include - - int main () { - - sol::state lua; - lua["bark"] = 50; - sol::optional x = lua["bark"]; - // x will have a value - - lua["bark"] = sol::nil; - sol::optional y = lua["bark"]; - // y will not have a value - } It's easy to see that there's a lot of options to do what you want here. But, these are just traditional numbers and strings. What if we want more power, more capabilities than what these limited types can offer us? Let's throw some :doc:`functions in there` :doc:`C++ classes into the mix`! diff --git a/examples/tutorials/erase_demo.cpp b/examples/tutorials/erase_demo.cpp new file mode 100644 index 00000000..c303ee7b --- /dev/null +++ b/examples/tutorials/erase_demo.cpp @@ -0,0 +1,16 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +int main() { + + sol::state lua; + lua["bark"] = 50; + sol::optional x = lua["bark"]; + // x will have a value + + lua["bark"] = sol::nil; + sol::optional y = lua["bark"]; + // y will not have a value + + return 0; +} diff --git a/examples/tutorials/lazy_demo.cpp b/examples/tutorials/lazy_demo.cpp new file mode 100644 index 00000000..3645046b --- /dev/null +++ b/examples/tutorials/lazy_demo.cpp @@ -0,0 +1,23 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include + +int main() { + + sol::state lua; + + auto barkkey = lua["bark"]; + if (barkkey.valid()) { + // Branch not taken: doesn't exist yet + std::cout << "How did you get in here, arf?!" << std::endl; + } + + barkkey = 50; + if (barkkey.valid()) { + // Branch taken: value exists! + std::cout << "Bark Bjork Wan Wan Wan" << std::endl; + } + + return 0; +} diff --git a/examples/tutorials/variables_demo.cpp b/examples/tutorials/variables_demo.cpp new file mode 100644 index 00000000..3327ab7c --- /dev/null +++ b/examples/tutorials/variables_demo.cpp @@ -0,0 +1,71 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include +#include "../assert.hpp" +#include // for std::pair + +int main() { + + sol::state lua; + /* + lua.script_file("variables.lua"); + */ + lua.script(R"( +config = { + fullscreen = false, + resolution = { x = 1024, y = 768 } +} + )"); + // the type "sol::state" behaves + // exactly like a table! + bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables + sol::table config = lua["config"]; + c_assert(isfullscreen); + + // can also get it using the "get" member function + // auto replaces the unqualified type name + auto resolution = config.get("resolution"); + + // table and state can have multiple things pulled out of it too + std::tuple xyresolutiontuple = resolution.get("x", "y"); + c_assert(std::get<0>(xyresolutiontuple) == 1024); + c_assert(std::get<1>(xyresolutiontuple) == 768); + + // test variable + auto bark = lua["config"]["bark"]; + if (bark.valid()) { + // branch not taken: config and/or bark are not variables + } + else { + // Branch taken: config and bark are existing variables + } + + // can also use optional + sol::optional not_an_integer = lua["config"]["fullscreen"]; + if (not_an_integer) { + // Branch not taken: value is not an integer + } + + sol::optional is_a_boolean = lua["config"]["fullscreen"]; + if (is_a_boolean) { + // Branch taken: the value is a boolean + } + + sol::optional does_not_exist = lua["not_a_variable"]; + if (does_not_exist) { + // Branch not taken: that variable is not present + } + + // this will result in a value of '24' + // (it tries to get a number, and fullscreen is + // not a number + int is_defaulted = lua["config"]["fullscreen"].get_or(24); + c_assert(is_defaulted == 24); + + // This will result in the value of the config, which is 'false' + bool is_not_defaulted = lua["config"]["fullscreen"]; + c_assert(!is_not_defaulted); + + return 0; +} diff --git a/examples/tutorials/write_variables_demo.cpp b/examples/tutorials/write_variables_demo.cpp new file mode 100644 index 00000000..307f9fc1 --- /dev/null +++ b/examples/tutorials/write_variables_demo.cpp @@ -0,0 +1,39 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include + +int main() { + + sol::state lua; + + // open those basic lua libraries + // again, for print() and other basic utilities + lua.open_libraries(sol::lib::base); + + // value in the global table + lua["bark"] = 50; + + // a table being created in the global table + lua["some_table"] = lua.create_table_with( + "key0", 24, + "key1", 25, + lua["bark"], "the key is 50 and this string is its value!"); + + // Run a plain ol' string of lua code + // Note you can interact with things set through Sol in C++ with lua! + // Using a "Raw String Literal" to have multi-line goodness: + // http://en.cppreference.com/w/cpp/language/string_literal + lua.script(R"( + + print(some_table[50]) + print(some_table["key0"]) + print(some_table["key1"]) + + -- a lua comment: access a global in a lua script with the _G table + print(_G["bark"]) + + )"); + + return 0; +} From 2cfbc8c0ea3fc839dd3cc7dddcb242d7bf8e2ae2 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Sat, 10 Nov 2018 06:41:06 -0800 Subject: [PATCH 4/4] Fix up the remaining sol2 issues, prepare for more sol3 stuff --- docs/source/api/proxy.rst | 11 ++++ .../tutorials/quick_n_dirty/namespacing.cpp | 9 +++- single/sol/sol.hpp | 51 +++++++++++++------ single/sol/sol_forward.hpp | 4 +- sol/function_types.hpp | 2 +- sol/proxy.hpp | 23 ++++++++- sol/stack_check_unqualified.hpp | 8 +-- sol/usertype_metatable.hpp | 17 ++++--- tests/test_usertypes.cpp | 30 ++++++++++- 9 files changed, 122 insertions(+), 33 deletions(-) diff --git a/docs/source/api/proxy.rst b/docs/source/api/proxy.rst index c31edcb6..03f01369 100644 --- a/docs/source/api/proxy.rst +++ b/docs/source/api/proxy.rst @@ -78,6 +78,17 @@ Gets the value associated with the keys and converts it to the type ``T``. Gets the value associated with the keys and converts it to the type ``T``. If it is not of the proper type, it will return a ``sol::nullopt`` instead. +.. code-block:: c++ + :caption: function: [overloaded] optionally get or create a value + :name: regular-get-or-create + + template + decltype(auto) get_or_create(); + template + decltype(auto) get_or_create( Otherwise&& other ); + +Gets the value associated with the keys if it exists. If it does not, it will set it with the value and return the result. + ``operator[]`` proxy-only members --------------------------------- diff --git a/examples/tutorials/quick_n_dirty/namespacing.cpp b/examples/tutorials/quick_n_dirty/namespacing.cpp index e00cee8c..e556e867 100644 --- a/examples/tutorials/quick_n_dirty/namespacing.cpp +++ b/examples/tutorials/quick_n_dirty/namespacing.cpp @@ -24,7 +24,14 @@ int main() { // "bark" namespacing in Lua // namespacing is just putting things in a table - sol::table bark = lua.create_named_table("bark"); + // forces creation if it does not exist + auto bark = lua["bark"].get_or_create(); + // equivalent-ish: + //sol::table bark = lua["bark"].force(); // forces table creation + // equivalent, and more flexible: + //sol::table bark = lua["bark"].get_or_create(sol::new_table()); + // equivalent, but less efficient/ugly: + //sol::table bark = lua["bark"] = lua.get_or("bark", lua.create_table()); bark.new_usertype("my_class", "f", &my_class::f, "g", &my_class::g); // the usual diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index 1aa57816..cb4f8a22 100644 --- a/single/sol/sol.hpp +++ b/single/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 2018-11-09 18:52:51.075276 UTC -// This header was generated with sol v2.20.4 (revision 1f90b04) +// Generated 2018-11-10 14:40:45.361811 UTC +// This header was generated with sol v2.20.5 (revision a7048ae) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -8247,12 +8247,12 @@ namespace stack { } #endif // Do not allow strings to be numbers int isnum = 0; - const lua_Number v = lua_tonumberx(L, index, &isnum); - const bool success = isnum != 0 #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) - && static_cast(llround(v)) == v + const lua_Number v = lua_tonumberx(L, index, &isnum); + const bool success = isnum != 0 && static_cast(llround(v)) == v; +#else + const bool success = isnum != 0; #endif // Safe numerics and number precision checking - ; if (!success) { // expected type, actual type #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS @@ -14542,7 +14542,7 @@ namespace sol { template static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = function_detail::call, 2, is_yielding>; + lua_CFunction freefunc = detail::static_trampoline, 2, is_yielding>>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -15512,6 +15512,19 @@ namespace sol { return static_cast(std::forward(otherwise)); } + template + decltype(auto) get_or_create() { + return get_or_create(new_table()); + } + + template + decltype(auto) get_or_create(Otherwise&& other) { + if (!this->valid()) { + this->set(std::forward(other)); + } + return get(); + } + template decltype(auto) operator[](K&& k) const { auto keys = meta::tuplefy(key, std::forward(k)); @@ -15562,6 +15575,13 @@ namespace sol { lua_State* lua_state() const { return tbl.lua_state(); } + + proxy& force() { + if (this->valid()) { + this->set(new_table()); + } + return *this; + } }; template @@ -18280,6 +18300,9 @@ namespace sol { #include namespace sol { + + struct usertype_metatable_core; + namespace usertype_detail { const int metatable_index = 2; const int metatable_core_index = 3; @@ -18291,7 +18314,7 @@ namespace sol { const int newindex_function_index = 4; typedef void (*base_walk)(lua_State*, bool&, int&, string_view&); - typedef int (*member_search)(lua_State*, void*, int); + typedef int (*member_search)(lua_State*, void*, usertype_metatable_core&, int); struct call_information { member_search index; @@ -18443,8 +18466,7 @@ namespace sol { return isnum != 0 && magic == toplevel_magic; } - inline int runtime_object_call(lua_State* L, void*, int runtimetarget) { - usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + inline int runtime_object_call(lua_State* L, void*, usertype_metatable_core& umc, int runtimetarget) { std::vector& runtime = umc.runtime; object& runtimeobj = runtime[runtimetarget]; return stack::push(L, runtimeobj); @@ -18476,7 +18498,7 @@ namespace sol { } } - int runtime_new_index(lua_State* L, void*, int runtimetarget); + int runtime_new_index(lua_State* L, void*, usertype_metatable_core&, int runtimetarget); template inline int metatable_new_index(lua_State* L) { @@ -18575,8 +18597,7 @@ namespace sol { return indexing_fail(L); } - inline int runtime_new_index(lua_State* L, void*, int runtimetarget) { - usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + inline int runtime_new_index(lua_State* L, void*, usertype_metatable_core& umc, int runtimetarget) { std::vector& runtime = umc.runtime; object& runtimeobj = runtime[runtimetarget]; runtimeobj = object(L, 3); @@ -18781,7 +18802,7 @@ namespace sol { usertype_metatable& operator=(usertype_metatable&&) = default; template - static int real_find_call(lua_State* L, void* um, int) { + static int real_find_call(lua_State* L, void* um, usertype_metatable_core&, int) { auto& f = *static_cast(um); if (is_variable_binding(f.functions))>::value) { return real_call_with(L, f); @@ -18827,7 +18848,7 @@ namespace sol { } } if (member != nullptr) { - return (member)(L, static_cast(&f), runtime_target); + return (member)(L, static_cast(&f), static_cast(f), runtime_target); } string_view accessor = stack::get(L, keyidx); int ret = 0; diff --git a/single/sol/sol_forward.hpp b/single/sol/sol_forward.hpp index 371c3873..6b6080bb 100644 --- a/single/sol/sol_forward.hpp +++ b/single/sol/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 2018-11-09 18:52:51.285820 UTC -// This header was generated with sol v2.20.4 (revision 1f90b04) +// Generated 2018-11-10 14:40:45.917037 UTC +// This header was generated with sol v2.20.5 (revision a7048ae) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP diff --git a/sol/function_types.hpp b/sol/function_types.hpp index d0c49e16..ad2b4bda 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -220,7 +220,7 @@ namespace sol { template static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = function_detail::call, 2, is_yielding>; + lua_CFunction freefunc = detail::static_trampoline, 2, is_yielding>>; int upvalues = 0; upvalues += stack::push(L, nullptr); diff --git a/sol/proxy.hpp b/sol/proxy.hpp index 6b68cd81..99f0f0c6 100644 --- a/sol/proxy.hpp +++ b/sol/proxy.hpp @@ -1,4 +1,4 @@ -// sol2 +// sol2 // The MIT License (MIT) @@ -118,6 +118,20 @@ namespace sol { return static_cast(std::forward(otherwise)); } + + template + decltype(auto) get_or_create() { + return get_or_create(new_table()); + } + + template + decltype(auto) get_or_create(Otherwise&& other) { + if (!this->valid()) { + this->set(std::forward(other)); + } + return get(); + } + template decltype(auto) operator[](K&& k) const { auto keys = meta::tuplefy(key, std::forward(k)); @@ -168,6 +182,13 @@ namespace sol { lua_State* lua_state() const { return tbl.lua_state(); } + + proxy& force() { + if (this->valid()) { + this->set(new_table()); + } + return *this; + } }; template diff --git a/sol/stack_check_unqualified.hpp b/sol/stack_check_unqualified.hpp index b05f73ce..e63a70e2 100644 --- a/sol/stack_check_unqualified.hpp +++ b/sol/stack_check_unqualified.hpp @@ -140,12 +140,12 @@ namespace stack { } #endif // Do not allow strings to be numbers int isnum = 0; - const lua_Number v = lua_tonumberx(L, index, &isnum); - const bool success = isnum != 0 #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) - && static_cast(llround(v)) == v + const lua_Number v = lua_tonumberx(L, index, &isnum); + const bool success = isnum != 0 && static_cast(llround(v)) == v; +#else + const bool success = isnum != 0; #endif // Safe numerics and number precision checking - ; if (!success) { // expected type, actual type #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index a091f4f3..cc511cee 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -43,6 +43,9 @@ #include namespace sol { + + struct usertype_metatable_core; + namespace usertype_detail { const int metatable_index = 2; const int metatable_core_index = 3; @@ -54,7 +57,7 @@ namespace sol { const int newindex_function_index = 4; typedef void (*base_walk)(lua_State*, bool&, int&, string_view&); - typedef int (*member_search)(lua_State*, void*, int); + typedef int (*member_search)(lua_State*, void*, usertype_metatable_core&, int); struct call_information { member_search index; @@ -206,8 +209,7 @@ namespace sol { return isnum != 0 && magic == toplevel_magic; } - inline int runtime_object_call(lua_State* L, void*, int runtimetarget) { - usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + inline int runtime_object_call(lua_State* L, void*, usertype_metatable_core& umc, int runtimetarget) { std::vector& runtime = umc.runtime; object& runtimeobj = runtime[runtimetarget]; return stack::push(L, runtimeobj); @@ -239,7 +241,7 @@ namespace sol { } } - int runtime_new_index(lua_State* L, void*, int runtimetarget); + int runtime_new_index(lua_State* L, void*, usertype_metatable_core&, int runtimetarget); template inline int metatable_new_index(lua_State* L) { @@ -338,8 +340,7 @@ namespace sol { return indexing_fail(L); } - inline int runtime_new_index(lua_State* L, void*, int runtimetarget) { - usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + inline int runtime_new_index(lua_State* L, void*, usertype_metatable_core& umc, int runtimetarget) { std::vector& runtime = umc.runtime; object& runtimeobj = runtime[runtimetarget]; runtimeobj = object(L, 3); @@ -544,7 +545,7 @@ namespace sol { usertype_metatable& operator=(usertype_metatable&&) = default; template - static int real_find_call(lua_State* L, void* um, int) { + static int real_find_call(lua_State* L, void* um, usertype_metatable_core&, int) { auto& f = *static_cast(um); if (is_variable_binding(f.functions))>::value) { return real_call_with(L, f); @@ -590,7 +591,7 @@ namespace sol { } } if (member != nullptr) { - return (member)(L, static_cast(&f), runtime_target); + return (member)(L, static_cast(&f), static_cast(f), runtime_target); } string_view accessor = stack::get(L, keyidx); int ret = 0; diff --git a/tests/test_usertypes.cpp b/tests/test_usertypes.cpp index a39387e9..d647d6b6 100644 --- a/tests/test_usertypes.cpp +++ b/tests/test_usertypes.cpp @@ -310,7 +310,7 @@ struct alignas(16) weird_aligned_wrapper { } void operator()(SelfType& self, sol::object param) const { lambda(self, param.as()); - } + } std::function lambda; }; @@ -1627,6 +1627,16 @@ TEST_CASE("usertype/runtime-extensibility", "Check if usertypes are runtime exte }; int val = 0; + class base_a { + public: + int x; + }; + + class derived_b : public base_a { + }; + + + SECTION("just functions") { sol::state lua; lua.open_libraries(sol::lib::base); @@ -1722,6 +1732,24 @@ end val = lua["val"]; REQUIRE(val == 3); } + SECTION("with bases") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("A", + "x", &base_a::x //no crash without this + ); + + lua.new_usertype("B", + sol::base_classes, sol::bases()); + + auto pfr0 = lua.safe_script("function A:c() print('A') return 1 end", sol::script_pass_on_error); + REQUIRE(pfr0.valid()); + auto pfr1 = lua.safe_script("function B:c() print('B') return 2 end", sol::script_pass_on_error); + REQUIRE(pfr1.valid()); + auto pfr2 = lua.safe_script("local obja = A.new() local objb = B.new() assert(obja:c() == 1) assert(objb:c() == 2)", sol::script_pass_on_error); + REQUIRE(pfr2.valid()); + } } TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly replaced at runtime for non-indexed things") {