From b19d1a085428078651a748ced9ecf4bca51ca7d4 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Sun, 24 Apr 2016 10:09:05 -0400 Subject: [PATCH] Update version numbers, fix tests, and change bond -> tie, since nobody understands what bond means --- docs/source/api/api-top.rst | 1 + docs/source/api/tie.rst | 26 ++ docs/source/conf.py | 4 +- docs/source/index.rst | 2 +- docs/source/tutorial/all-the-things.rst | 379 ++++++++++++++---------- sol/stack_core.hpp | 2 +- sol/stack_proxy.hpp | 4 +- sol/{bond.hpp => tie.hpp} | 30 +- test_functions.cpp | 6 +- 9 files changed, 274 insertions(+), 180 deletions(-) create mode 100644 docs/source/api/tie.rst rename sol/{bond.hpp => tie.hpp} (74%) diff --git a/docs/source/api/api-top.rst b/docs/source/api/api-top.rst index e1595406..516a4050 100644 --- a/docs/source/api/api-top.rst +++ b/docs/source/api/api-top.rst @@ -27,6 +27,7 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo table this_state thread + tie types usertype userdata diff --git a/docs/source/api/tie.rst b/docs/source/api/tie.rst new file mode 100644 index 00000000..080c8a1c --- /dev/null +++ b/docs/source/api/tie.rst @@ -0,0 +1,26 @@ +tie +=== +An improved version of ``std::tie`` +----------------------------------- + +`std::tie()`_ does not work well with :doc:`sol::function`'s ``sol::function_result`` returns. Use ``sol::tie`` instead. Because they're both named `tie`, you'll need to be explicit when you use Sol's by naming it with the namespace (``sol::tie``), even with a ``using namespace sol;``. Here's an example: + +.. code-block:: cpp + + sol::state lua; + lua.open_libraries(sol::lib::base); + + const auto& code = R"( + function test() + return 1, 2, 3 + end + )"; + lua.script(code); + + int a, b, c; + //std::tie(a, b, c) = lua["test"](); + // will error: use the line below + sol::tie(a, b, c) = lua["test"](); + + +.. _std::tie(): http://en.cppreference.com/w/cpp/utility/tuple/tie diff --git a/docs/source/conf.py b/docs/source/conf.py index 2fa0c6df..cf95d45b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -59,9 +59,9 @@ author = 'ThePhD' # built documents. # # The short X.Y version. -version = '2.0' +version = '2.5' # The full version, including alpha/beta/rc tags. -release = '2.0.0' +release = '2.5.0' # 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 be410bda..5327fe7c 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,7 +3,7 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Sol 2.3 +Sol 2.5 ======= a fast, simple C++ and Lua Binding ---------------------------------- diff --git a/docs/source/tutorial/all-the-things.rst b/docs/source/tutorial/all-the-things.rst index 8953f9cd..2ba53dc3 100644 --- a/docs/source/tutorial/all-the-things.rst +++ b/docs/source/tutorial/all-the-things.rst @@ -28,6 +28,7 @@ For your system/game that already has lua, but you'd like something nice: int pre_existing_system( lua_State* L ) { sol::state_view lua(L); lua.script( "print('bark bark bark!')" ); + return 0; } @@ -57,10 +58,6 @@ You can set/get everything. .. code-block:: cpp - struct some_class { - bool some_variable = false; - }; - sol::lua_state lua; lua.open_libraries(sol::lib::base); @@ -84,12 +81,6 @@ You can set/get everything. // strings too std::string important_string = lua["important_string"]; - // returns a plain reference - some_class& myuserdata = lua["myuserdata"]; - // Modifies this in LUA VM AS WELL - // its a reference, not a copy! - myuserdata.some_variable = true; - // get a function sol::function a_function = lua["a_function"]; int value_is_100 = a_function(); @@ -98,7 +89,6 @@ You can set/get everything. std::function a_std_function = lua["a_function"]; int value_is_still_100 = a_std_function(); - Retrieve Lua types using ``object`` and other ``sol::`` types. .. code-block:: cpp @@ -120,6 +110,158 @@ Retrieve Lua types using ``object`` and other ``sol::`` types. sol::optional check_for_me = lua["a_function"]; +You can erase things by setting it to ``nullptr`` or ``sol::nil``. + +.. code-block:: cpp + + sol::state lua; + + lua.script("exists = 250"); + + int first_try = lua.get_or( 322 ); + // first_try == 250 + + lua.set("exists", sol::nil); + + int second_try = lua.get_or( 322 ); + // second_try == 322 + + +multiple returns from lua +------------------------- + +.. code-block:: cpp + + sol::state lua; + + lua.script("function f (a, b, c) return a, b, c end"); + + std::tuple result = lua["f"](100, 200, 300); + // result == { 100, 200, 300 } + int a, int b; + std::string c; + sol::tie( a, b, c ) = lua["f"](100, 200, "bark"); + // a == 100 + // b == 200 + // c == "bark" + + +multiple returns to lua +----------------------- + +.. code-block:: cpp + + sol::state lua; + + lua["f"] = [](int a, int b, sol::object c) { + // sol::object can be anything here: just pass it through + return std::make_tuple( 100, 200, c ); + }; + + std::tuple result = lua["f"](100, 200, 300); + // result == { 100, 200, 300 } + + lua[] + // result == { 100, 200, 300 } + int a, int b; + std::string c; + sol::tie( a, b, c ) = lua["f"](100, 200, "bark"); + // a == 100 + // b == 200 + // c == "bark" + + +tables +------ + +:doc:`sol::state<../api/state>` is a table too. + +.. code-block:: cpp + + sol::state lua; + + // Raw string literal for easy multiline + lua.script( R"( + abc = { [0] = 24 } + def = { + ghi = { + bark = 50, + woof = abc + } + } + )" + ); + + sol::table abc = lua["abc"]; + sol::state def = lua["def"]; + sol::table ghi = lua["def"]["ghi"]; + + int bark1 = def["ghi"]["bark"]; + // bark1 == 50 + int bark2 = lua["def"]["ghi"]["bark"]; + // bark2 == 50 + + bool bark_equal = bark1 == bark2; + // true + + int abcval1 = abc[0]; + // abcval2 == 24 + int abcval2 = ghi["woof"][0]; + // abcval2 == 24 + + bool abcval_equal = abcval1 == abcval2; + // true + +If you're going deep, be safe: + +.. code-block:: cpp + + sol::state lua; + + sol::optional will_not_error = lua["abc"]["DOESNOTEXIST"]["ghi"]; + // will_not_error == sol::nullopt + int will_not_error2 = lua["abc"]["def"]["ghi"]["jklm"].get_or(25); + // is 25 + + // if you don't go safe, + // will throw (or do at_panic if no exceptions) + int aaaahhh = lua["abc"]["hope_u_liek_crash"]; + + +make tables +----------- + +Make some: + +.. code-block:: cpp + + lua["abc"] = lua.create_table_with( + 0, 24 + ); + + lua.create_named_table("def", + "ghi", lua.create_table_with( + "bark", 50, + "woof", lua["abc"] // can reference other existing stuff too + ) + ); + +Equivalent Lua code: + +.. code-block:: lua + + abc = { [0] = 24 } + def = { + ghi = { + bark = 50, + woof = abc + } + } + + +You can put anything you want in tables as values or keys, including strings, numbers, functions, other tables. + + functions --------- @@ -143,8 +285,8 @@ They're great. Use them: // call through operator[] int is_three = lua["g"](1, 2); // is_three == 3 - double is_2_8 = lua["g"](2.4, 2.4); - // is_2_8 == 2.8 + double is_4_8 = lua["g"](2.4, 2.4); + // is_4_8 == 4.8 You can bind member variables as functions too: @@ -211,159 +353,32 @@ You can bind member variables as functions too: Can use ``sol::readonly( &some_class::variable )`` to make a variable readonly and error if someone tries to write to it. -multiple returns from lua -------------------------- - -.. code-block:: cpp - - sol::state lua; - - lua.script("function f (a, b, c) return a, b, c end"); - - std::tuple result = lua["f"](100, 200, 300); - // result == { 100, 200, 300 } - int a, int b; - std::string c; - sol::bond( a, b, c ) = lua["f"](100, 200, "bark"); - // a == 100 - // b == 200 - // c == "bark" - - -multiple returns to lua ------------------------ - -.. code-block:: cpp - - sol::state lua; - - lua["f"] = [](int a, int b, sol::object c) { - // sol::object can be anything here: just pass it through - return std::make_tuple( 100, 200, c ); - }; - - std::tuple result = lua["f"](100, 200, 300); - // result == { 100, 200, 300 } - - lua[] - // result == { 100, 200, 300 } - int a, int b; - std::string c; - sol::bond( a, b, c ) = lua["f"](100, 200, "bark"); - // a == 100 - // b == 200 - // c == "bark" - - -tables ------- - -:doc:`state<../api/state>` is a table too. - -.. code-block:: cpp - - sol::state lua; - - // Raw string literal for easy multiline - lua.script( R"( - abc = { [0] = 24 } - def = { - ghi = { - bark = 50, - woof = abc - } - } - )" - ); - - sol::table abc = lua["abc"]; - sol::state def = lua["def"]; - sol::table ghi = lua["def"]["ghi"]; - - int bark1 = def["ghi"]["bark"]; - // bark1 == 50 - int bark2 = lua["def"]["ghi"]["bark"]; - // bark2 == 50 - - bool bark_equal = bark1 == bark2; - // true - - int abcval1 = abc[0]; - // abcval2 == 24 - int abcval2 = ghi["woof"][0]; - // abcval2 == 24 - - bool abcval_equal = abcval1 == abcval2; - // true - -If you're going deep, be safe: - -.. code-block:: cpp - - sol::optional will_not_error = lua["abc"]["DOESNOTEXIST"]["ghi"]; - // will_not_error == sol::nullopt - int will_not_error2 = lua["abc"]["def"]["ghi"]["jklm"].get_or(25); - // is 25 - - // if you don't go safe, - // will throw (or do at_panic if no exceptions) - int aaaahhh = lua["abc"]["hope_u_liek_crash"]; - - -make tables ------------ - -Make some: - -.. code-block:: cpp - - lua["abc"] = lua.create_table_with( - 0, 24 - ); - - lua.create_named_table("def", - "ghi", lua.create_table_with( - "bark", 50, - "woof", lua["abc"] // can reference other existing stuff too - ) - ); - -Equivalent Lua code: - -.. code-block:: lua - - abc = { [0] = 24 } - def = { - ghi = { - bark = 50, - woof = abc - } - } - - -userdata + usertypes (metatables) ---------------------------------- +C++ classes in Lua +------------------ Everything that is not a: * primitive type: ``bool``, ``char/short/int/long/long long``, ``float/double`` * string type: ``std::string``, ``const char*`` - * function type: function pointers, ``lua_CFunction``, ``std::function``, :doc:`sol::function/sol::protected_function<../api/function>`, :doc:`sol::coroutine<../api/coroutine>` + * function type: function pointers, ``lua_CFunction``, ``std::function``, :doc:`sol::function/sol::protected_function<../api/function>`, :doc:`sol::coroutine<../api/coroutine>`, member variable, member function * designated sol type: :doc:`sol::table<../api/table>`, :doc:`sol::thread<../api/thread>`, :doc:`sol::error<../api/error>`, :doc:`sol::object<../api/object>` * transparent argument type: :doc:`sol::variadic_arg<../api/variadic_args>`, :doc:`sol::this_state<../api/this_state>` * usertype class: :doc:`sol::usertype<../api/usertype>` -Is set as a userdata. +Is set as a :doc:`userdata + usertype<../api/usertype>`. .. code-block:: cpp - struct Doge { int tailwag = 50; } + struct Doge { + int tailwag = 50; + } Doge dog{}; - // Copy into lua: destroyed when lua VM garbage collects + // Copy into lua: destroyed by Lua VM during garbage collection lua["dog"] = dog; // OR: move semantics - will call move constructor if present instead + // Again, owned by Lua lua["dog"] = std::move( dog ); lua["dog"] = Doge{}; lua["dog"] = std::make_unique(); @@ -375,10 +390,17 @@ Is set as a userdata. lua.set("dog", std::unique_ptr(new Doge())); lua.set("dog", std::shared_ptr(new Doge())); -``std::unique_ptr``/``std::shared_ptr``'s reference counts / deleters will be respected. If you want it to refer to something, whose memory you know won't die in C++, do the following: +``std::unique_ptr``/``std::shared_ptr``'s reference counts / deleters will :doc:`be respected<../api/unique_usertype_traits>`. If you want it to refer to something, whose memory you know won't die in C++, do the following: .. code-block:: cpp + struct Doge { + int tailwag = 50; + } + + sol::state lua; + lua.open_libraries(sol::lib::base); + Doge dog{}; // Kept alive somehow // Later... @@ -396,6 +418,28 @@ Get userdata in the same way as everything else: .. code-block:: cpp + struct Doge { + int tailwag = 50; + } + + sol::state lua; + lua.open_libraries(sol::lib::base); + + Doge& dog = lua["dog"]; // References Lua memory + Doge* dog_pointer = lua["dog"]; // References Lua memory + Doge dog_copy = lua["dog"]; // Copies, will not affect lua + +Note that you can change the data of usertype variables and it will affect things in lua if you get a pointer or a reference from Sol: + +.. code-block:: cpp + + struct Doge { + int tailwag = 50; + } + + sol::state lua; + lua.open_libraries(sol::lib::base); + Doge& dog = lua["dog"]; // References Lua memory Doge* dog_pointer = lua["dog"]; // References Lua memory Doge dog_copy = lua["dog"]; // Copies, will not affect lua @@ -409,8 +453,8 @@ Get userdata in the same way as everything else: lua.script("assert(dog.tailwag == 100)"); -more userdata + usertypes -------------------------- +C++ classes in Lua +------------------ Because there's a LOT you can do with Sol: @@ -470,9 +514,6 @@ Bind all the things: // note that you can set a userdata before you register a usertype, // and it will still carry the right metatable if you register it later - lua.set("p2", player(0)); - // p2 has no ammo - // make usertype metatable lua.new_usertype( "player", @@ -532,20 +573,32 @@ And the script: Even more stuff :doc:`you can do<../api/usertype>` described elsewhere, like initializer functions (private constructors / destructors support), "static" functions callable with ``name.my_function( ... )``, and overloaded member functions. -pointers --------- +ownership +--------- Sol will not take ownership of raw pointers: raw pointers do not own anything. .. code-block:: cpp + struct my_type { + void stuff () {} + }; + + sol::state lua; + // AAAHHH BAD // dangling pointer! lua["my_func"] = []() -> my_type* { return new my_type(); }; -Return a ``unique_ptr`` or ``shared_ptr`` instead or just return a value: + // AAAHHH! + lua.set("something", new my_type()); + + // AAAAAAHHH!!! + lua["something_else"] = new my_type(); + +Use/return a ``unique_ptr`` or ``shared_ptr`` instead or just return a value: .. code-block:: cpp @@ -564,6 +617,16 @@ Return a ``unique_ptr`` or ``shared_ptr`` instead or just return a value: return my_type(); }; + // :ok: + lua.set("something", std::unique_ptr(new my_type())); + + std::shared_ptr my_shared = std::make_shared(); + // :ok: + lua.set("something_else", my_shared); + + auto my_unique = std::make_unique(); + lua["other_thing"] = std::move(my_unique); + advanced -------- diff --git a/sol/stack_core.hpp b/sol/stack_core.hpp index f4e0c180..3c1af25a 100644 --- a/sol/stack_core.hpp +++ b/sol/stack_core.hpp @@ -28,7 +28,7 @@ #include "userdata.hpp" #include "tuple.hpp" #include "traits.hpp" -#include "bond.hpp" +#include "tie.hpp" namespace sol { namespace detail { diff --git a/sol/stack_proxy.hpp b/sol/stack_proxy.hpp index 005acb97..2577ba6e 100644 --- a/sol/stack_proxy.hpp +++ b/sol/stack_proxy.hpp @@ -78,7 +78,7 @@ struct pusher { } // stack template <> -struct bond_size : std::integral_constant {}; +struct tie_size : std::integral_constant {}; template stack_proxy get(const function_result& fr) { @@ -86,7 +86,7 @@ stack_proxy get(const function_result& fr) { } template <> -struct bond_size : std::integral_constant {}; +struct tie_size : std::integral_constant {}; template stack_proxy get(const protected_function_result& fr) { diff --git a/sol/bond.hpp b/sol/tie.hpp similarity index 74% rename from sol/bond.hpp rename to sol/tie.hpp index d6ea6e01..3d5d0ce3 100644 --- a/sol/bond.hpp +++ b/sol/tie.hpp @@ -19,21 +19,21 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#ifndef SOL_BOND_HPP -#define SOL_BOND_HPP +#ifndef SOL_TIE_HPP +#define SOL_TIE_HPP #include "traits.hpp" namespace sol { template -struct bond_size : std::tuple_size {}; +struct tie_size : std::tuple_size {}; template -struct is_bondable : std::integral_constant::value > 0)> {}; +struct is_tieable : std::integral_constant::value > 0)> {}; template -struct bond_t : public std::tuple...> { +struct tie_t : public std::tuple...> { private: typedef std::tuple...> base_t; @@ -44,8 +44,8 @@ private: template void set( std::true_type, T&& target ) { - typedef bond_size> value_size; - typedef bond_size> tie_size; + typedef tie_size> value_size; + typedef tie_size> tie_size; typedef std::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size; typedef std::make_index_sequence indices; set( indices(), std::forward( target ) ); @@ -63,8 +63,8 @@ public: using base_t::base_t; template - bond_t& operator= ( T&& value ) { - typedef is_bondable> bondable; + tie_t& operator= ( T&& value ) { + typedef is_tieable> bondable; set( bondable(), std::forward( value ) ); return *this; } @@ -72,13 +72,17 @@ public: }; template -struct bond_size<::sol::bond_t> : ::std::tuple_size<::std::tuple> { }; +struct tie_size<::sol::tie_t> : ::std::tuple_size<::std::tuple> { }; +namespace adl_barrier_detail { template -inline bond_t...> bond( Tn&&... argn ) { - return bond_t...>( std::forward( argn )... ); +inline tie_t...> tie(Tn&&... argn) { + return tie_t...>(std::forward(argn)...); } +} + +using namespace adl_barrier_detail; } // sol -#endif // SOL_BOND_HPP +#endif // SOL_TIE_HPP diff --git a/test_functions.cpp b/test_functions.cpp index 65fb36f9..e87e4392 100644 --- a/test_functions.cpp +++ b/test_functions.cpp @@ -545,7 +545,7 @@ N = n(1, 2, 3) REQUIRE( N == 13 ); - sol::bond( ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N ) + sol::tie( ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N ) = lua.get( "ob", "A", "B", "C", "D", "F", "G0", "G1", "H", "I", "J0", "J1", "K0", "K1", "L0", "L1", "M0", "M1", "N" ); @@ -735,7 +735,7 @@ TEST_CASE("advanced/call-referenced_obj", "A C++ object is passed by pointer/ref REQUIRE(y == 9); } -TEST_CASE("functions/bond", "make sure advanced syntax with 'bond' works") { +TEST_CASE("functions/tie", "make sure advanced syntax with 'tie' works") { sol::state lua; lua.script(R"(function f () @@ -744,7 +744,7 @@ end)"); sol::function f = lua["f"]; int a, b, c; - sol::bond(a, b, c) = f(); + sol::tie(a, b, c) = f(); REQUIRE(a == 1); REQUIRE(b == 2); REQUIRE(c == 3);