Documents nullptr (Closes #159)

Documents callable structures and the function to use with `table.set` if needed (Closes #162)
This commit is contained in:
ThePhD 2016-08-06 00:30:35 -04:00
parent 89e0b62f2d
commit 89250697aa
14 changed files with 67 additions and 21 deletions

View File

@ -23,9 +23,10 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo
overload overload
protect protect
readonly readonly
resolve
as_function
property property
proxy proxy
resolve
stack stack
optional optional
state state

View File

@ -0,0 +1,29 @@
as_function
===========
make sure a parameter is pushed as a function
---------------------------------------------
.. code-block:: cpp
template <typename Sig = sol::function_sig<>, typename... Args>
function_argumants<Sig, Args...> as_function ( Args&& ... );
This function serves the purpose of ensuring that a callable struct (like a lambda) can be passed to the ``set( key, value )`` calls on :ref:`sol::table<set-value>` and be treated like a function binding instead of a userdata. It is recommended that one uses the :ref:`sol::table::set_function<set-function>` call instead, but if for some reason one must use `set`, then `as_function` can help ensure a callable struct is handled like a lambda / callable, and not as just a userdata structure.
.. code-block:: cpp
struct callable {
int operator()( int a, bool b ) {
return a + b ? 10 : 20;
}
};
sol::state lua;
// Binds struct as userdata
lua.set( "not_func", callable() );
// Binds struct as function
lua.set( "func", sol::as_function( callable() ) );
// equivalent: lua.set_function( "func", sol::as_function( callable() ) );
Note that if you actually want a userdata, but you want it to be callable, you simply need to create a :ref:`sol::table::new_usertype<new-usertype>` and then bind the ``"__call"`` metamethod (or just use ``sol::meta_function::call`` :ref:`enumeration<meta_function_enum>`).

View File

@ -62,6 +62,7 @@ If your script returns a value, you can capture it from the returned :ref:`funct
.. code-block:: cpp .. code-block:: cpp
:caption: function: require / require_file :caption: function: require / require_file
:name: state-require-function
sol::object require(const std::string& key, lua_CFunction open_function, bool create_global = true); sol::object require(const std::string& key, lua_CFunction open_function, bool create_global = true);
sol::object require_script(const std::string& key, const std::string& code, bool create_global = true); sol::object require_script(const std::string& key, const std::string& code, bool create_global = true);

View File

@ -50,6 +50,7 @@ If the keys within nested queries try to traverse into a table that doesn't exis
.. code-block:: cpp .. code-block:: cpp
:caption: function: set / traversing set :caption: function: set / traversing set
:name: set-value
template<typename... Args> template<typename... Args>
table& set(Args&&... args); table& set(Args&&... args);
@ -63,6 +64,15 @@ These functions set items into the table. The first one (``set``) can set *mult
Value semantics are applied to all set operations. If you do not ``std::ref( obj )`` or specifically make a pointer with ``std::addressof( obj )`` or ``&obj``, it will copy / move. This is different from how :doc:`sol::function<function>` behaves with its call operator. Value semantics are applied to all set operations. If you do not ``std::ref( obj )`` or specifically make a pointer with ``std::addressof( obj )`` or ``&obj``, it will copy / move. This is different from how :doc:`sol::function<function>` behaves with its call operator.
.. code-block:: cpp
:caption: function: set a function with the specified key into lua
:name: set-function
template<typename Key, typename Fx>
state_view& set_function(Key&& key, Fx&& fx, [...]);
Sets the desired function to the specified key value. Note that it also allows for passing a member function plus a member object or just a single member function: however, using a lambda is almost always better when you want to bind a member function + class instance to a single function call in Lua.
.. code-block:: cpp .. code-block:: cpp
:caption: function: add :caption: function: add
@ -159,14 +169,6 @@ A functional ``for_each`` loop that calls the desired function. The passed in fu
Generates a :doc:`proxy<proxy>` that is templated on the table type and the key type. Enables lookup of items and their implicit conversion to a desired type. Generates a :doc:`proxy<proxy>` that is templated on the table type and the key type. Enables lookup of items and their implicit conversion to a desired type.
.. code-block:: cpp
:caption: function: set a function with the specified key into lua
template<typename Key, typename Fx>
state_view& set_function(Key&& key, Fx&& fx, [...]);
Sets the desired function to the specified key value. Note that it also allows for passing a member function plus a member object or just a single member function: however, using a lambda is almost always better when you want to bind a member function + class instance to a single function call in Lua.
.. code-block:: cpp .. code-block:: cpp
:caption: function: create a table with defaults :caption: function: create a table with defaults
:name: table-create :name: table-create

View File

@ -40,3 +40,5 @@ A traits type for alerting the library that a certain type is to be pushed as a
} }
This will allow the framework to properly handle ``boost::shared_ptr<T>``, with ref-counting and all. The `type` is the type that lua and sol will interact with, and will allow you to pull out a non-owning reference / pointer to the data when you just ask for a plain `T*` or `T&` or `T` using the getter functions and properties of Sol. This will allow the framework to properly handle ``boost::shared_ptr<T>``, with ref-counting and all. The `type` is the type that lua and sol will interact with, and will allow you to pull out a non-owning reference / pointer to the data when you just ask for a plain `T*` or `T&` or `T` using the getter functions and properties of Sol.
Note that if ``is_null`` triggers, a ``nil`` value will be pushed into Sol.

View File

@ -11,7 +11,7 @@ These are some informal and formal benchmarks done by both the developers of sol
As of the writing of this documentation (July 29th, 2016), :doc:`Sol<index>` (Sol2) seems to take the cake in most categories for speed! Below are some graphs from `lua-bench`_. 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<features>`. As of the writing of this documentation (July 29th, 2016), :doc:`Sol<index>` (Sol2) seems to take the cake in most categories for speed! Below are some graphs from `lua-bench`_. 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<features>`.
Note that Sol here makes use of its more performant variants (see :doc:`c_call<api/c-call>`), and ThePhD also does his best to make use of the most performant variants for other frameworks by disabling type checks where possible as well (Thanks to Liam Devine of OOLua for explaining how to turn off type checks in OOLua). Note that Sol here makes use of its more performant variants (see :doc:`c_call<api/c_call>`), and ThePhD also does his best to make use of the most performant variants for other frameworks by disabling type checks where possible as well (Thanks to Liam Devine of OOLua for explaining how to turn off type checks in OOLua).
Bars go up to the average execution time. Lower is better. Reported times are for the desired operation run through `nonius`_ Results are sorted from top to bottom by best to worst. Note that there are error bars to show potential variance in performance: generally, same-sized errors bars plus very close average execution time implies no significant difference in speed, despite the vastly different abstraction techniques used. Bars go up to the average execution time. Lower is better. Reported times are for the desired operation run through `nonius`_ Results are sorted from top to bottom by best to worst. Note that there are error bars to show potential variance in performance: generally, same-sized errors bars plus very close average execution time implies no significant difference in speed, despite the vastly different abstraction techniques used.

View File

@ -20,6 +20,8 @@ If you're already using lua and you just want to use ``sol`` in some places, you
:doc:`sol::state_view<../api/state>` is exactly like ``sol::state``, but it doesn't manage the lifetime of a ``lua_State*``. Therefore, you get all the goodies that come with a ``sol::state`` without any of the ownership implications. Sol has no initialization components that need to deliberately remain alive for the duration of the program. It's entirely self-containing and uses lua's garbage collectors and various implementation techniques to require no state C++-side. After you do that, all of the power of `Sol` is available to you, and then some! :doc:`sol::state_view<../api/state>` is exactly like ``sol::state``, but it doesn't manage the lifetime of a ``lua_State*``. Therefore, you get all the goodies that come with a ``sol::state`` without any of the ownership implications. Sol has no initialization components that need to deliberately remain alive for the duration of the program. It's entirely self-containing and uses lua's garbage collectors and various implementation techniques to require no state C++-side. After you do that, all of the power of `Sol` is available to you, and then some!
You may also want to call ``require`` and supply a string of a script file or something that returns an object that you set equal to something in C++. For that, you can use the :ref:`require functionality<state-require-function>`.
Remember that Sol can be as lightweight as you want it: almost all of Sol's types take the ``lua_State*`` argument and then a second ``int index`` stack index argument, meaning you can use :doc:`tables<../api/table>`, :doc:`lua functions<../api/function>`, :doc:`coroutines<../api/coroutine>`, and other reference-derived objects that expose the proper constructor for your use. You can also set :doc:`usertypes<../api/usertype>` and other things you need without changing your entire architecture. Remember that Sol can be as lightweight as you want it: almost all of Sol's types take the ``lua_State*`` argument and then a second ``int index`` stack index argument, meaning you can use :doc:`tables<../api/table>`, :doc:`lua functions<../api/function>`, :doc:`coroutines<../api/coroutine>`, and other reference-derived objects that expose the proper constructor for your use. You can also set :doc:`usertypes<../api/usertype>` and other things you need without changing your entire architecture.
Note that you can also make non-standard pointer and reference types with custom reference counting and such also play nice with the system. See :doc:`unique_usertype_traits\<T><../api/unique_usertype_traits>` to see how! Note that you can also make non-standard pointer and reference types with custom reference counting and such also play nice with the system. See :doc:`unique_usertype_traits\<T><../api/unique_usertype_traits>` to see how! Custom types is also mentioned in the :doc:`customization tutorial<customization>`.

View File

@ -293,5 +293,7 @@ You can also return mutiple items yourself from a C++-bound function. Here, we'r
Note here that we use :doc:`sol::object<../api/object>` to transport through "any value" that can come from Lua. You can also use ``sol::make_object`` to create an object from some value, so that it can be returned into Lua as well. Note here that we use :doc:`sol::object<../api/object>` to transport through "any value" that can come from Lua. You can also use ``sol::make_object`` to create an object from some value, so that it can be returned into Lua as well.
Finally, note that there's a caveat if you use the regular :ref:`sol::table::set<set-value>` function to set a lambda / callable C++ struct (see :doc:`here for more details<../api/as_function>`).
This covers almost everything you need to know about Functions and how they interact with Sol. For some advanced tricks and neat things, check out :doc:`sol::this_state<../api/this_state>` and :doc:`sol::variadic_args<../api/variadic_args>`. The last stop in this tutorial is about :doc:`C++ types (usertypes) in Lua<cxx-in-lua>`! This covers almost everything you need to know about Functions and how they interact with Sol. For some advanced tricks and neat things, check out :doc:`sol::this_state<../api/this_state>` and :doc:`sol::variadic_args<../api/variadic_args>`. The last stop in this tutorial is about :doc:`C++ types (usertypes) in Lua<cxx-in-lua>`!

View File

@ -35,7 +35,7 @@ Using this simple command line:
>>> g++ -std=c++14 test.cpp -llua -I"path/to/lua/include" -L"path/to/lua/lib" >>> g++ -std=c++14 test.cpp -llua -I"path/to/lua/include" -L"path/to/lua/lib"
Or using your favorite IDE / tool after setting up your include paths and library paths to lua according to the documentation of the Lua distribution you got. Remember your linked lua library (``-llua``) and include / library paths will depend on your OS, file system, Lua distribution and your installation / compilation method of your Lua distribution. Or using your favorite IDE / tool after setting up your include paths and library paths to Lua according to the documentation of the Lua distribution you got. Remember your linked lua library (``-llua``) and include / library paths will depend on your OS, file system, Lua distribution and your installation / compilation method of your Lua distribution.
.. note:: .. note::
@ -60,7 +60,7 @@ If this works, you're ready to start! The first line creates the ``lua_State`` a
return 0; return 0;
} }
If you're interested in integrating Sol with a project that already uses some other library or Lua in the codebase, check out the :doc:`existing example<existing>` to see how to work with Sol when you add it to a project! If you're interested in integrating Sol with a project that already uses some other library or Lua in the codebase, check out the :doc:`existing example<existing>` to see how to work with Sol when you add it to a project (the existing example covers ``require`` as well)!
Next, let's start :doc:`reading/writing some variables<variables>` from Lua into C++, and vice-versa! Next, let's start :doc:`reading/writing some variables<variables>` from Lua into C++, and vice-versa!

View File

@ -79,6 +79,13 @@ Sol can detect ``nullptr``, so if you happen to return it there won't be any dan
return nullptr; return nullptr;
}; };
lua["my_func_2"] = [] () -> std::unique_ptr<my_type> {
// default-constructs as a nullptr,
// gets pushed as nil to Lua
return std::unique_ptr<my_type>();
// same happens for std::shared_ptr
}
// Acceptable, it will set 'something' to nil // Acceptable, it will set 'something' to nil
// (and delete it on next GC if there's no more references) // (and delete it on next GC if there's no more references)
lua.set("something", nullptr); lua.set("something", nullptr);

View File

@ -39,7 +39,7 @@ namespace sol {
}; };
template <typename Sig = function_sig<>, typename... Args> template <typename Sig = function_sig<>, typename... Args>
function_arguments<Sig, Args...> function_args(Args&&... args) { function_arguments<Sig, Args...> as_function(Args&&... args) {
return function_arguments<Sig, Args...>(std::forward<Args>(args)...); return function_arguments<Sig, Args...>(std::forward<Args>(args)...);
} }

View File

@ -38,7 +38,7 @@ namespace sol {
template <typename N, typename F, meta::enable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler> template <typename N, typename F, meta::enable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler>
void add(lua_State* L, N&& n, F&& f) { void add(lua_State* L, N&& n, F&& f) {
registrations.emplace_back(make_object(L, std::forward<N>(n)), make_object(L, function_args(std::forward<F>(f)))); registrations.emplace_back(make_object(L, std::forward<N>(n)), make_object(L, as_function(std::forward<F>(f))));
} }
template <typename N, typename F, meta::disable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler> template <typename N, typename F, meta::disable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler>

View File

@ -373,12 +373,12 @@ namespace sol {
template<typename Fx, typename Key, typename... Args, meta::disable<meta::is_specialization_of<overload_set, meta::unqualified_t<Fx>>> = meta::enabler> template<typename Fx, typename Key, typename... Args, meta::disable<meta::is_specialization_of<overload_set, meta::unqualified_t<Fx>>> = meta::enabler>
void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) { void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) {
set(std::forward<Key>(key), function_args(std::forward<Fx>(fx), std::forward<Args>(args)...)); set(std::forward<Key>(key), as_function(std::forward<Fx>(fx), std::forward<Args>(args)...));
} }
template<typename... Sig, typename... Args, typename Key> template<typename... Sig, typename... Args, typename Key>
void set_resolved_function(Key&& key, Args&&... args) { void set_resolved_function(Key&& key, Args&&... args) {
set(std::forward<Key>(key), function_args<function_sig<Sig...>>(std::forward<Args>(args)...)); set(std::forward<Key>(key), as_function<function_sig<Sig...>>(std::forward<Args>(args)...));
} }
public: public:

View File

@ -335,7 +335,7 @@ TEST_CASE("state/require", "opening using a file") {
struct open { struct open {
static int open_func(lua_State* L) { static int open_func(lua_State* L) {
sol::state_view lua = L; sol::state_view lua = L;
return sol::stack::push(L, lua.create_table_with("modfunc", sol::function_args([]() { return 221; }))); return sol::stack::push(L, lua.create_table_with("modfunc", sol::as_function([]() { return 221; })));
} }
}; };
@ -356,7 +356,7 @@ TEST_CASE("state/multi-require", "make sure that requires transfers across hand-
struct open { struct open {
static int open_func(lua_State* L) { static int open_func(lua_State* L) {
sol::state_view lua = L; sol::state_view lua = L;
return sol::stack::push(L, lua.create_table_with("modfunc", sol::function_args([]() { return 221; }))); return sol::stack::push(L, lua.create_table_with("modfunc", sol::as_function([]() { return 221; })));
} }
}; };