Update version numbers, fix tests, and change bond -> tie, since nobody understands what bond means

This commit is contained in:
ThePhD 2016-04-24 10:09:05 -04:00
parent 38d21827b1
commit b19d1a0854
9 changed files with 274 additions and 180 deletions

View File

@ -27,6 +27,7 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo
table table
this_state this_state
thread thread
tie
types types
usertype usertype
userdata userdata

26
docs/source/api/tie.rst Normal file
View File

@ -0,0 +1,26 @@
tie
===
An improved version of ``std::tie``
-----------------------------------
`std::tie()`_ does not work well with :doc:`sol::function<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

View File

@ -59,9 +59,9 @@ author = 'ThePhD'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '2.0' version = '2.5'
# The full version, including alpha/beta/rc tags. # 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 # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -3,7 +3,7 @@
You can adapt this file completely to your liking, but it should at least You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive. contain the root `toctree` directive.
Sol 2.3 Sol 2.5
======= =======
a fast, simple C++ and Lua Binding a fast, simple C++ and Lua Binding
---------------------------------- ----------------------------------

View File

@ -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 ) { int pre_existing_system( lua_State* L ) {
sol::state_view lua(L); sol::state_view lua(L);
lua.script( "print('bark bark bark!')" ); lua.script( "print('bark bark bark!')" );
return 0;
} }
@ -57,10 +58,6 @@ You can set/get everything.
.. code-block:: cpp .. code-block:: cpp
struct some_class {
bool some_variable = false;
};
sol::lua_state lua; sol::lua_state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
@ -84,12 +81,6 @@ You can set/get everything.
// strings too // strings too
std::string important_string = lua["important_string"]; 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 // get a function
sol::function a_function = lua["a_function"]; sol::function a_function = lua["a_function"];
int value_is_100 = a_function(); int value_is_100 = a_function();
@ -98,7 +89,6 @@ You can set/get everything.
std::function<int()> a_std_function = lua["a_function"]; std::function<int()> a_std_function = lua["a_function"];
int value_is_still_100 = a_std_function(); int value_is_still_100 = a_std_function();
Retrieve Lua types using ``object`` and other ``sol::`` types. Retrieve Lua types using ``object`` and other ``sol::`` types.
.. code-block:: cpp .. code-block:: cpp
@ -120,6 +110,158 @@ Retrieve Lua types using ``object`` and other ``sol::`` types.
sol::optional<int> check_for_me = lua["a_function"]; sol::optional<int> 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<int>( 322 );
// first_try == 250
lua.set("exists", sol::nil);
int second_try = lua.get_or<int>( 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<int, int, int> 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<int, int, int> 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<int> will_not_error = lua["abc"]["DOESNOTEXIST"]["ghi"];
// will_not_error == sol::nullopt
int will_not_error2 = lua["abc"]["def"]["ghi"]["jklm"].get_or<int>(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 functions
--------- ---------
@ -143,8 +285,8 @@ They're great. Use them:
// call through operator[] // call through operator[]
int is_three = lua["g"](1, 2); int is_three = lua["g"](1, 2);
// is_three == 3 // is_three == 3
double is_2_8 = lua["g"](2.4, 2.4); double is_4_8 = lua["g"](2.4, 2.4);
// is_2_8 == 2.8 // is_4_8 == 4.8
You can bind member variables as functions too: 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. 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 C++ classes in Lua
------------------------- ------------------
.. code-block:: cpp
sol::state lua;
lua.script("function f (a, b, c) return a, b, c end");
std::tuple<int, int, int> 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<int, int, int> 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<int> will_not_error = lua["abc"]["DOESNOTEXIST"]["ghi"];
// will_not_error == sol::nullopt
int will_not_error2 = lua["abc"]["def"]["ghi"]["jklm"].get_or<int>(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)
---------------------------------
Everything that is not a: Everything that is not a:
* primitive type: ``bool``, ``char/short/int/long/long long``, ``float/double`` * primitive type: ``bool``, ``char/short/int/long/long long``, ``float/double``
* string type: ``std::string``, ``const char*`` * 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>` * 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>` * transparent argument type: :doc:`sol::variadic_arg<../api/variadic_args>`, :doc:`sol::this_state<../api/this_state>`
* usertype<T> class: :doc:`sol::usertype<../api/usertype>` * usertype<T> class: :doc:`sol::usertype<../api/usertype>`
Is set as a userdata. Is set as a :doc:`userdata + usertype<../api/usertype>`.
.. code-block:: cpp .. code-block:: cpp
struct Doge { int tailwag = 50; } struct Doge {
int tailwag = 50;
}
Doge dog{}; Doge dog{};
// Copy into lua: destroyed when lua VM garbage collects // Copy into lua: destroyed by Lua VM during garbage collection
lua["dog"] = dog; lua["dog"] = dog;
// OR: move semantics - will call move constructor if present instead // OR: move semantics - will call move constructor if present instead
// Again, owned by Lua
lua["dog"] = std::move( dog ); lua["dog"] = std::move( dog );
lua["dog"] = Doge{}; lua["dog"] = Doge{};
lua["dog"] = std::make_unique<Doge>(); lua["dog"] = std::make_unique<Doge>();
@ -375,10 +390,17 @@ Is set as a userdata.
lua.set("dog", std::unique_ptr<Doge>(new Doge())); lua.set("dog", std::unique_ptr<Doge>(new Doge()));
lua.set("dog", std::shared_ptr<Doge>(new Doge())); lua.set("dog", std::shared_ptr<Doge>(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 .. code-block:: cpp
struct Doge {
int tailwag = 50;
}
sol::state lua;
lua.open_libraries(sol::lib::base);
Doge dog{}; // Kept alive somehow Doge dog{}; // Kept alive somehow
// Later... // Later...
@ -396,6 +418,28 @@ Get userdata in the same way as everything else:
.. code-block:: cpp .. 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 = lua["dog"]; // References Lua memory
Doge* dog_pointer = lua["dog"]; // References Lua memory Doge* dog_pointer = lua["dog"]; // References Lua memory
Doge dog_copy = lua["dog"]; // Copies, will not affect lua 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)"); lua.script("assert(dog.tailwag == 100)");
more userdata + usertypes C++ classes in Lua
------------------------- ------------------
Because there's a LOT you can do with Sol: 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, // 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 // 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 // make usertype metatable
lua.new_usertype<player>( "player", lua.new_usertype<player>( "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. 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. Sol will not take ownership of raw pointers: raw pointers do not own anything.
.. code-block:: cpp .. code-block:: cpp
struct my_type {
void stuff () {}
};
sol::state lua;
// AAAHHH BAD // AAAHHH BAD
// dangling pointer! // dangling pointer!
lua["my_func"] = []() -> my_type* { lua["my_func"] = []() -> my_type* {
return new 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 .. code-block:: cpp
@ -564,6 +617,16 @@ Return a ``unique_ptr`` or ``shared_ptr`` instead or just return a value:
return my_type(); return my_type();
}; };
// :ok:
lua.set("something", std::unique_ptr<my_type>(new my_type()));
std::shared_ptr<my_type> my_shared = std::make_shared<my_type>();
// :ok:
lua.set("something_else", my_shared);
auto my_unique = std::make_unique<my_type>();
lua["other_thing"] = std::move(my_unique);
advanced advanced
-------- --------

View File

@ -28,7 +28,7 @@
#include "userdata.hpp" #include "userdata.hpp"
#include "tuple.hpp" #include "tuple.hpp"
#include "traits.hpp" #include "traits.hpp"
#include "bond.hpp" #include "tie.hpp"
namespace sol { namespace sol {
namespace detail { namespace detail {

View File

@ -78,7 +78,7 @@ struct pusher<stack_proxy> {
} // stack } // stack
template <> template <>
struct bond_size<function_result> : std::integral_constant<std::size_t, SIZE_MAX> {}; struct tie_size<function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
template <std::size_t I> template <std::size_t I>
stack_proxy get(const function_result& fr) { stack_proxy get(const function_result& fr) {
@ -86,7 +86,7 @@ stack_proxy get(const function_result& fr) {
} }
template <> template <>
struct bond_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {}; struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
template <std::size_t I> template <std::size_t I>
stack_proxy get(const protected_function_result& fr) { stack_proxy get(const protected_function_result& fr) {

View File

@ -19,21 +19,21 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_BOND_HPP #ifndef SOL_TIE_HPP
#define SOL_BOND_HPP #define SOL_TIE_HPP
#include "traits.hpp" #include "traits.hpp"
namespace sol { namespace sol {
template <typename T> template <typename T>
struct bond_size : std::tuple_size<T> {}; struct tie_size : std::tuple_size<T> {};
template <typename T> template <typename T>
struct is_bondable : std::integral_constant<bool, (::sol::bond_size<T>::value > 0)> {}; struct is_tieable : std::integral_constant<bool, (::sol::tie_size<T>::value > 0)> {};
template <typename... Tn> template <typename... Tn>
struct bond_t : public std::tuple<std::add_lvalue_reference_t<Tn>...> { struct tie_t : public std::tuple<std::add_lvalue_reference_t<Tn>...> {
private: private:
typedef std::tuple<std::add_lvalue_reference_t<Tn>...> base_t; typedef std::tuple<std::add_lvalue_reference_t<Tn>...> base_t;
@ -44,8 +44,8 @@ private:
template <typename T> template <typename T>
void set( std::true_type, T&& target ) { void set( std::true_type, T&& target ) {
typedef bond_size<meta::Unqualified<T>> value_size; typedef tie_size<meta::Unqualified<T>> value_size;
typedef bond_size<std::tuple<Tn...>> tie_size; typedef tie_size<std::tuple<Tn...>> tie_size;
typedef std::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size; typedef std::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size;
typedef std::make_index_sequence<indices_size::value> indices; typedef std::make_index_sequence<indices_size::value> indices;
set( indices(), std::forward<T>( target ) ); set( indices(), std::forward<T>( target ) );
@ -63,8 +63,8 @@ public:
using base_t::base_t; using base_t::base_t;
template <typename T> template <typename T>
bond_t& operator= ( T&& value ) { tie_t& operator= ( T&& value ) {
typedef is_bondable<meta::Unqualified<T>> bondable; typedef is_tieable<meta::Unqualified<T>> bondable;
set( bondable(), std::forward<T>( value ) ); set( bondable(), std::forward<T>( value ) );
return *this; return *this;
} }
@ -72,13 +72,17 @@ public:
}; };
template <typename... Tn> template <typename... Tn>
struct bond_size<::sol::bond_t<Tn...>> : ::std::tuple_size<::std::tuple<Tn...>> { }; struct tie_size<::sol::tie_t<Tn...>> : ::std::tuple_size<::std::tuple<Tn...>> { };
namespace adl_barrier_detail {
template <typename... Tn> template <typename... Tn>
inline bond_t<std::remove_reference_t<Tn>...> bond( Tn&&... argn ) { inline tie_t<std::remove_reference_t<Tn>...> tie(Tn&&... argn) {
return bond_t<std::remove_reference_t<Tn>...>( std::forward<Tn>( argn )... ); return tie_t<std::remove_reference_t<Tn>...>(std::forward<Tn>(argn)...);
} }
}
using namespace adl_barrier_detail;
} // sol } // sol
#endif // SOL_BOND_HPP #endif // SOL_TIE_HPP

View File

@ -545,7 +545,7 @@ N = n(1, 2, 3)
REQUIRE( N == 13 ); 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<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>( = lua.get<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>(
"ob", "A", "B", "C", "D", "F", "G0", "G1", "H", "I", "J0", "J1", "K0", "K1", "L0", "L1", "M0", "M1", "N" "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); 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; sol::state lua;
lua.script(R"(function f () lua.script(R"(function f ()
@ -744,7 +744,7 @@ end)");
sol::function f = lua["f"]; sol::function f = lua["f"];
int a, b, c; int a, b, c;
sol::bond(a, b, c) = f(); sol::tie(a, b, c) = f();
REQUIRE(a == 1); REQUIRE(a == 1);
REQUIRE(b == 2); REQUIRE(b == 2);
REQUIRE(c == 3); REQUIRE(c == 3);