mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Some minor fixes and DOCS AND EXAMPLES WOOoOooOOooOoo
This commit is contained in:
parent
77a1ce76b5
commit
3a00ce0adf
|
@ -4,10 +4,13 @@ structures and classes from C++ made available to Lua code (simpler)
|
|||
--------------------------------------------------------------------
|
||||
|
||||
|
||||
This type is no different from :doc:`regular usertype<usertype>`, but allows much of its work to be done at runtime instead of compile-time. The goal here was to avoid compiler complaints about too-large usertypes (some individuals needed to register 190+ functions, and the compiler choked from the templated implementation of ``usertype``). As of Sol 2.14, this implementation has been heavily refactored to allow for all the same syntax and uses of usertype to apply here, with no caveats.
|
||||
This type is no different from :doc:`regular usertype<usertype>`, but allows much of its work to be done at runtime instead of compile-time. You can reduce compilation times from a plain `usertype` when you have an exceedingly bulky registration listing.
|
||||
|
||||
You can set functions incrementally to reduce compile-time burden with ``simple_usertype`` as well, as shown in `this example`_.
|
||||
|
||||
Some developers used ``simple_usertype`` to have variables automatically be functions. To achieve this behavior, wrap the desired variable into :doc:`sol::as_function<as_function>`.
|
||||
|
||||
The performance `seems to be good enough`_ to not warn about any implications of having to serialize things at runtime. You do run the risk of using (slightly?) more memory, however, since variables and functions need to be stored differently and separately from the metatable data itself like with a regular ``usertype``.
|
||||
The performance `seems to be good enough`_ to not warn about any implications of having to serialize things at runtime. You do run the risk of using (slightly?) more memory, however, since variables and functions need to be stored differently and separately from the metatable data itself like with a regular ``usertype``. The goal here was to avoid compiler complaints about too-large usertypes (some individuals needed to register 190+ functions, and the compiler choked from the templated implementation of ``usertype``). As of Sol 2.14, this implementation has been heavily refactored to allow for all the same syntax and uses of usertype to apply here, with no caveats/exceptions.
|
||||
|
||||
.. _seems to be good enough: https://github.com/ThePhD/sol2/issues/202#issuecomment-246767629
|
||||
.. _seems to be good enough: https://github.com/ThePhD/sol2/issues/202#issuecomment-246767629
|
||||
.. _this example: .. _ usertype examples: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_simple.cpp
|
|
@ -542,8 +542,7 @@ Note that you can change the data of usertype variables and it will affect thing
|
|||
C++ classes put into Lua
|
||||
------------------------
|
||||
|
||||
See this :doc:`section here<cxx-in-lua>`.
|
||||
|
||||
See this :doc:`section here<cxx-in-lua>` and after perhaps see if :doc:`simple usertypes suit your needs<../api/simple_usertype>`. Also check out some `a basic example`_, `special functions`_ and `initializers`_,
|
||||
|
||||
namespacing
|
||||
-----------
|
||||
|
@ -597,3 +596,8 @@ Some more advanced things you can do/read about:
|
|||
* :doc:`variadic arguments<../api/variadic_args>` in functions with ``sol::variadic_args``.
|
||||
* :doc:`this_state<../api/this_state>` to get the current ``lua_State*``.
|
||||
* :doc:`resolve<../api/resolve>` overloads in case you have overloaded functions; a cleaner casting utility.
|
||||
|
||||
.. _a basic example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype.cpp
|
||||
.. _special functions: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_special_functions.cpp
|
||||
.. _initializers: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_initializers.cpp
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ It's a fairly minimal class, but we don't want to have to rewrite this with meta
|
|||
p1 = player.new(2)
|
||||
|
||||
-- p2 is still here from being
|
||||
-- set with lua["p2"] = player(0); below
|
||||
-- set with lua["p2"] = player(0);
|
||||
-- in cpp file
|
||||
local p2shoots = p2:shoot()
|
||||
assert(not p2shoots)
|
||||
-- had 0 ammo
|
||||
|
@ -130,4 +131,8 @@ To do this, you bind things using the ``new_usertype`` and ``set_usertype`` meth
|
|||
|
||||
That script should run fine now, and you can observe and play around with the values. Even more stuff :doc:`you can do<../api/usertype>` is described elsewhere, like initializer functions (private constructors / destructors support), "static" functions callable with ``name.my_function( ... )``, and overloaded member functions. You can even bind global variables (even by reference with ``std::ref``) with ``sol::var``. There's a lot to try out!
|
||||
|
||||
This is a powerful way to allow reuse of C++ code from Lua beyond just registering functions, and should get you on your way to having more complex classes and data structures! In the case that you need more customization than just usertypes, however, you can customize Sol to behave more fit to your desires by using the desired :doc:`customization and extension structures<customization>`.
|
||||
This is a powerful way to allow reuse of C++ code from Lua beyond just registering functions, and should get you on your way to having more complex classes and data structures! In the case that you need more customization than just usertypes, however, you can customize Sol to behave more fit to your desires by using the desired :doc:`customization and extension structures<customization>`.
|
||||
|
||||
You can check out this code and more complicated code at the `examples directory`_ by looking at the ``usertype_``-prefixed examples.
|
||||
|
||||
.. _examples directory: https://github.com/ThePhD/sol2/tree/develop/examples
|
67
examples/usertype_initializers.cpp
Normal file
67
examples/usertype_initializers.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#define SOL_CHECK_ARGUMENTS
|
||||
#include <sol.hpp>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
struct holy {
|
||||
private:
|
||||
holy() : data() {}
|
||||
holy(int value) : data(value) {}
|
||||
~holy() {}
|
||||
|
||||
public:
|
||||
struct deleter {
|
||||
void operator()(holy* p) const {
|
||||
destroy(*p);
|
||||
}
|
||||
};
|
||||
|
||||
const int data;
|
||||
|
||||
static std::unique_ptr<holy, deleter> create() {
|
||||
std::cout << "creating 'holy' unique_ptr directly and letting sol/Lua handle it" << std::endl;
|
||||
return std::unique_ptr<holy, deleter>(new holy(50));
|
||||
}
|
||||
|
||||
static void initialize(holy& uninitialized_memory) {
|
||||
std::cout << "initializing 'holy' userdata at " << static_cast<void*>(&uninitialized_memory) << std::endl;
|
||||
// receive uninitialized memory from Lua:
|
||||
// properly set it by calling a constructor
|
||||
// on it
|
||||
// "placement new"
|
||||
new (&uninitialized_memory) holy();
|
||||
}
|
||||
|
||||
static void destroy(holy& memory_from_lua) {
|
||||
std::cout << "destroying 'holy' userdata at " << static_cast<void*>(&memory_from_lua) << std::endl;
|
||||
memory_from_lua.~holy();
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype_initializers example ===" << std::endl;
|
||||
{ // additional scope to make usertype destroy earlier
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua.new_usertype<holy>("holy",
|
||||
"new", sol::initializers(&holy::initialize),
|
||||
"create", sol::factories(&holy::create),
|
||||
sol::meta_function::garbage_collect, sol::destructor(&holy::destroy),
|
||||
"data", &holy::data
|
||||
);
|
||||
|
||||
lua.script(R"(
|
||||
h1 = holy.create()
|
||||
h2 = holy.new()
|
||||
print('h1.data is ' .. h1.data)
|
||||
print('h2.data is ' .. h2.data)
|
||||
)");
|
||||
holy& h1 = lua["h1"];
|
||||
holy& h2 = lua["h2"];
|
||||
assert(h1.data == 50);
|
||||
assert(h2.data == 0);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
95
examples/usertype_simple.cpp
Normal file
95
examples/usertype_simple.cpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
#define SOL_CHECK_ARGUMENTS
|
||||
#include <sol.hpp>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
class generator {
|
||||
private:
|
||||
int data = 2;
|
||||
|
||||
public:
|
||||
int get_data() const { return data; }
|
||||
void set_data(int value) { data = value % 10; }
|
||||
|
||||
std::vector<int> generate_list() {
|
||||
return { data, data * 2, data * 3, data * 4, data * 5 };
|
||||
}
|
||||
};
|
||||
|
||||
struct my_data {
|
||||
int first = 4;
|
||||
int second = 8;
|
||||
int third = 12;
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype_simple example ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
// simple_usertype acts and behaves like
|
||||
// a regular usertype
|
||||
lua.new_simple_usertype<my_data>("my_data",
|
||||
"first", &my_data::first,
|
||||
"second", &my_data::second,
|
||||
"third", &my_data::third
|
||||
);
|
||||
|
||||
{
|
||||
// But, simple_usertype also has a `set` function
|
||||
// where you can append things to the
|
||||
// method listing after doing `create_simple_usertype`.
|
||||
auto generator_registration = lua.create_simple_usertype<generator>();
|
||||
generator_registration.set("data", sol::property(&generator::get_data, &generator::set_data));
|
||||
// you MUST set the usertype after
|
||||
// creating it
|
||||
lua.set_usertype("generator", generator_registration);
|
||||
}
|
||||
|
||||
// Can update a simple_usertype at runtime, after registration
|
||||
lua["generator"]["generate_list"] = [](generator& self) { return self.generate_list(); };
|
||||
// can set 'static methods' (no self) as well
|
||||
lua["generator"]["get_num"] = []() { return 100; };
|
||||
|
||||
// Mix it all together!
|
||||
lua.script(R"(
|
||||
mdata = my_data.new()
|
||||
|
||||
local g = generator.new()
|
||||
g.data = mdata.first
|
||||
list1 = g:generate_list()
|
||||
g.data = mdata.second
|
||||
list2 = g:generate_list()
|
||||
g.data = mdata.third
|
||||
list3 = g:generate_list()
|
||||
|
||||
print("From lua: ")
|
||||
for i, v in pairs(list1) do
|
||||
print("\tlist1[" .. i .. "] = " .. v)
|
||||
end
|
||||
for i, v in pairs(list2) do
|
||||
print("\tlist2[" .. i .. "] = " .. v)
|
||||
end
|
||||
for i, v in pairs(list3) do
|
||||
print("\tlist3[" .. i .. "] = " .. v)
|
||||
end
|
||||
|
||||
)");
|
||||
my_data& mdata = lua["mdata"];
|
||||
std::vector<int>& list1 = lua["list1"];
|
||||
std::vector<int>& list2 = lua["list2"];
|
||||
std::vector<int>& list3 = lua["list3"];
|
||||
assert(list1.size() == 5);
|
||||
assert(list2.size() == 5);
|
||||
assert(list3.size() == 5);
|
||||
for (int i = 1; i <= 5; ++i) {
|
||||
assert(list1[i - 1] == (mdata.first % 10) * i);
|
||||
assert(list2[i - 1] == (mdata.second % 10) * i);
|
||||
assert(list3[i - 1] == (mdata.third % 10) * i);
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
74
examples/usertype_special_functions.cpp
Normal file
74
examples/usertype_special_functions.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
#define SOL_CHECK_ARGUMENTS
|
||||
#include <sol.hpp>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
struct vec {
|
||||
double x;
|
||||
double y;
|
||||
|
||||
vec() : x(0), y(0) {}
|
||||
vec(double x, double y) : x(x), y(y) {}
|
||||
|
||||
vec operator-(const vec& right) const {
|
||||
return vec(x - right.x, y - right.y);
|
||||
}
|
||||
};
|
||||
|
||||
double dot(const vec& left, const vec& right) {
|
||||
return left.x * right.x + left.x * right.x;
|
||||
}
|
||||
|
||||
vec operator+(const vec& left, const vec& right) {
|
||||
return vec(left.x + right.x, left.y + right.y);
|
||||
}
|
||||
|
||||
int main() {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua.new_usertype<vec>("vec",
|
||||
sol::constructors<sol::types<>, sol::types<double, double>>(),
|
||||
"dot", &dot,
|
||||
"norm", [](const vec& self) { double len = std::sqrt(dot(self, self)); return vec(self.x / len, self.y / len); },
|
||||
// we use `sol::resolve` because other operator+ can exist
|
||||
// in the (global) namespace
|
||||
sol::meta_function::addition, sol::resolve<const vec&, const vec&>(::operator+),
|
||||
sol::meta_function::subtraction, &vec::operator-
|
||||
);
|
||||
|
||||
lua.script(R"(
|
||||
v1 = vec.new(1, 0)
|
||||
v2 = vec.new(0, 1)
|
||||
-- as "member function"
|
||||
d1 = v1:dot(v2)
|
||||
-- as "static" / "free function"
|
||||
d2 = vec.dot(v1, v2)
|
||||
assert(d1 == d2)
|
||||
|
||||
-- doesn't matter if
|
||||
-- bound as free function
|
||||
-- or member function:
|
||||
a1 = v1 + v2
|
||||
s1 = v1 - v2
|
||||
)");
|
||||
|
||||
vec& a1 = lua["a1"];
|
||||
vec& s1 = lua["s1"];
|
||||
|
||||
assert(a1.x == 1 && a1.y == 1);
|
||||
assert(s1.x == 1 && s1.y == -1);
|
||||
|
||||
lua["a2"] = lua["a1"];
|
||||
lua["a3"] = &a1;
|
||||
|
||||
lua.script(R"(
|
||||
-- automatic comparison generated for Lua:
|
||||
-- pointers are equal
|
||||
assert(a1 == a2)
|
||||
assert(a1 == a3)
|
||||
assert(a2 == a3)
|
||||
)");
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
|
@ -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 2016-09-20 03:39:12.452520 UTC
|
||||
// This header was generated with sol v2.14.2 (revision 9d52ed4)
|
||||
// Generated 2016-09-22 11:12:24.469225 UTC
|
||||
// This header was generated with sol v2.14.2 (revision 77a1ce7)
|
||||
// https://github.com/ThePhD/sol2
|
||||
|
||||
#ifndef SOL_SINGLE_INCLUDE_HPP
|
||||
|
@ -10019,6 +10019,14 @@ namespace sol {
|
|||
simple_map(const char* mkey, base_walk index, base_walk newindex, variable_map&& vars, function_map&& funcs) : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {}
|
||||
};
|
||||
|
||||
inline int simple_metatable_newindex(lua_State* L) {
|
||||
simple_map& sm = stack::get<user<simple_map>>(L, upvalue_index(1));
|
||||
luaL_getmetatable(L, sm.metakey);
|
||||
stack::set_field<false, true>(L, stack_reference(L, 2), stack_reference(L, 3), lua_gettop(L));
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <bool is_index, bool toplevel = false>
|
||||
inline int simple_core_indexing_call(lua_State* L) {
|
||||
simple_map& sm = toplevel ? stack::get<user<simple_map>>(L, upvalue_index(1)) : stack::pop<user<simple_map>>(L);
|
||||
|
@ -10220,7 +10228,7 @@ namespace sol {
|
|||
template<std::size_t... I, typename Tuple>
|
||||
simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
|
||||
: callconstructfunc(nil),
|
||||
indexfunc(&usertype_detail::indexing_fail<true>), newindexfunc(&usertype_detail::indexing_fail<false>),
|
||||
indexfunc(&usertype_detail::indexing_fail<true>), newindexfunc(&usertype_detail::simple_metatable_newindex),
|
||||
indexbase(&usertype_detail::simple_core_indexing_call<true>), newindexbase(&usertype_detail::simple_core_indexing_call<false>),
|
||||
indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>),
|
||||
baseclasscheck(nullptr), baseclasscast(nullptr),
|
||||
|
|
|
@ -66,6 +66,14 @@ namespace sol {
|
|||
simple_map(const char* mkey, base_walk index, base_walk newindex, variable_map&& vars, function_map&& funcs) : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {}
|
||||
};
|
||||
|
||||
inline int simple_metatable_newindex(lua_State* L) {
|
||||
simple_map& sm = stack::get<user<simple_map>>(L, upvalue_index(1));
|
||||
luaL_getmetatable(L, sm.metakey);
|
||||
stack::set_field<false, true>(L, stack_reference(L, 2), stack_reference(L, 3), lua_gettop(L));
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <bool is_index, bool toplevel = false>
|
||||
inline int simple_core_indexing_call(lua_State* L) {
|
||||
simple_map& sm = toplevel ? stack::get<user<simple_map>>(L, upvalue_index(1)) : stack::pop<user<simple_map>>(L);
|
||||
|
@ -267,7 +275,7 @@ namespace sol {
|
|||
template<std::size_t... I, typename Tuple>
|
||||
simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
|
||||
: callconstructfunc(nil),
|
||||
indexfunc(&usertype_detail::indexing_fail<true>), newindexfunc(&usertype_detail::indexing_fail<false>),
|
||||
indexfunc(&usertype_detail::indexing_fail<true>), newindexfunc(&usertype_detail::simple_metatable_newindex),
|
||||
indexbase(&usertype_detail::simple_core_indexing_call<true>), newindexbase(&usertype_detail::simple_core_indexing_call<false>),
|
||||
indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>),
|
||||
baseclasscheck(nullptr), baseclasscast(nullptr),
|
||||
|
|
Loading…
Reference in New Issue
Block a user