diff --git a/README.md b/README.md index d61231c9..c02f2770 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Sol 2.10 +## Sol 2.11 [![Build Status](https://travis-ci.org/ThePhD/sol2.svg?branch=develop)](https://travis-ci.org/ThePhD/sol2) [![Documentation Status](https://readthedocs.org/projects/sol2/badge/?version=latest)](http://sol2.readthedocs.io/en/latest/?badge=latest) diff --git a/bootstrap.py b/bootstrap.py index 4a472d0b..bf95a939 100755 --- a/bootstrap.py +++ b/bootstrap.py @@ -58,6 +58,8 @@ include = [ '.', './include' ] depends = [os.path.join('Catch', 'include')] cxxflags = [ '-Wall', '-Wextra', '-Wpedantic', '-pedantic', '-pedantic-errors', '-std=c++14', '-ftemplate-depth=1024' ] cxxflags.extend([p for p in re.split("( |\\\".*?\\\"|'.*?')", args.cxx_flags) if p.strip()]) +example_cxxflags = [ '-Wall', '-Wextra', '-Wpedantic', '-pedantic', '-pedantic-errors', '-std=c++14', '-ftemplate-depth=1024' ] +example_cxxflags.extend([p for p in re.split("( |\\\".*?\\\"|'.*?')", args.cxx_flags) if p.strip()]) ldflags = [] script_dir = os.path.dirname(os.path.realpath(sys.argv[0])) sol_dir = os.path.join(script_dir, 'sol') @@ -77,6 +79,7 @@ if args.debug: cxxflags.extend(['-g', '-O0']) else: cxxflags.extend(['-DNDEBUG', '-O3']) +example_cxxflags.extend(['-g', '-O0']) if args.lua_dir: include.extend([os.path.join(args.lua_dir, 'include')]) @@ -160,6 +163,7 @@ ninja.variable('ninja_required_version', '1.3') ninja.variable('builddir', 'bin') ninja.variable('cxx', args.cxx) ninja.variable('cxxflags', flags(cxxflags + includes(include) + dependencies(depends))) +ninja.variable('example_cxxflags', flags(example_cxxflags + includes(include) + dependencies(depends))) ninja.variable('ldflags', flags(ldflags)) ninja.newline() @@ -171,7 +175,7 @@ ninja.rule('compile', command = '$cxx -MMD -MF $out.d -c $cxxflags -Werror $in - ninja.rule('link', command = '$cxx $cxxflags $in -o $out $ldflags', description = 'creating $out') ninja.rule('tests_runner', command = tests) ninja.rule('examples_runner', command = 'cmd /c ' + (' && '.join(examples)) if 'win32' in sys.platform else ' && '.join(examples) ) -ninja.rule('example', command = '$cxx $cxxflags -MMD -MF $out.d $in -o $out $ldflags', +ninja.rule('example', command = '$cxx $example_cxxflags -MMD -MF $out.d $in -o $out $ldflags', deps = 'gcc', depfile = '$out.d', description = 'compiling example $in to $out') ninja.rule('installer', command = copy_command) diff --git a/docs/source/conf.py b/docs/source/conf.py index 8744c894..9e08bbc9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -61,7 +61,7 @@ author = 'ThePhD' # The short X.Y version. version = '2.11' # The full version, including alpha/beta/rc tags. -release = '2.11.3' +release = '2.11.7' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/mentions.rst b/docs/source/mentions.rst index fb7e1051..4b11d3b1 100644 --- a/docs/source/mentions.rst +++ b/docs/source/mentions.rst @@ -6,17 +6,23 @@ so does anyone cool use this thing...? Okay, so the features don't convince you, the documentation doesn't convince you, you want to see what *other* people think about Sol? Well, aside from the well-wishes that come through in the issue tracker, here's a few things floating around about sol2 that I occasionally get pinged about: -* (Reddit) Posts on reddit about it +* (Reddit) Posts on reddit about it! - https://www.reddit.com/r/cpp/comments/4a8gy7/sol2_lua_c_binding_framework/ - https://www.reddit.com/r/cpp/comments/4x82hd/plain_c_versus_lua_libraries_benchmarking_speed/ * (CppNow) sol2 was mentioned in a comparison to other scripting languages by ChaiScript developer, Jason Turner (@lefticus), at a conference! - https://github.com/lefticus/presentations/blob/master/HowAndWhyToAddScripting.md -* (CppCast) Showed up in CppCast with Elias Daler +* (CppCast) Showed up in CppCast with Elias Daler! - https://eliasdaler.github.io/cppcast#read-more - http://cppcast.com/2016/07/elias-daler/ -* (Twitter) Retweets by ThePhD from others!: +* (Eevee) A really nice and neat developer/artist/howaretheysotalented person is attempting to use it for zdoom! + - https://eev.ee/dev/2016/08/07/weekly-roundup-three-big-things/ +* (Twitter) Retweets by ThePhD from others! - https://twitter.com/thephantomderp/status/755214464950034432 - https://twitter.com/thephantomderp/status/762043162835709952 - https://twitter.com/thephantomderp/status/755214464950034432 +* Somehow landed on a Torque3D thread... that's nothing something ThePhD was planning for...! + - http://forums.torque3d.org/viewtopic.php?f=32&t=629&p=5246&sid=8e759990ab1ce38a48e896fc9fd62653#p5241 -And, of course, I use it. Isn't that enough? +And, of course, ThePhD uses it. Isn't that enough? + +Are you using sol2 for something neat? Want it to be featured here or think it's unfair that ThePhD hasn't found it yet? Well, drop an issue in the repo or send an e-mail! \ No newline at end of file diff --git a/docs/source/tutorial/customization.rst b/docs/source/tutorial/customization.rst index 032e4d60..31fcad46 100644 --- a/docs/source/tutorial/customization.rst +++ b/docs/source/tutorial/customization.rst @@ -1,11 +1,9 @@ adding your own types ===================== -Sometimes, overriding Sol to make it handle certain ``struct``s and ``class``es as something other than just userdata is desirable. The way to do this is to take advantage of the 4 customization points for Sol. These are ``sol::lua_size``, ``sol::stack::pusher``, ``sol::stack::getter``, ``sol::stack::checker``. +Sometimes, overriding Sol to make it handle certain ``struct``'s and ``class``'es as something other than just userdata is desirable. The way to do this is to take advantage of the 4 customization points for Sol. These are ``sol::lua_size``, ``sol::stack::pusher``, ``sol::stack::getter``, ``sol::stack::checker``. -The first thing to do is decide whether or not your type can be gotten from the stack, and whether or not it should also be pushed as arguments or such into Lua. If you need to retrieve it (as a return using one or multiple values from a Lua return), you should override but ``sol::stack::getter`` and ``sol::stack::checker``. If you need to push it into Lua at some point, then you'll want to override ``sol::stack::pusher``. For both cases, you need to override ``sol::lua_size``. - -These are structures, so you'll override them using a technique C++ calls *class/struct specialization*. Below is an example of a struct that gets broken apart into 2 pieces when being pushed into Lua, and then pulled back into a struct when retrieved from Lua: +These are template class/structs, so you'll override them using a technique C++ calls *class/struct specialization*. Below is an example of a struct that gets broken apart into 2 pieces when going in the C++ --> Lua direction, and then pulled back into a struct when going in the Lua --> C++: .. code-block:: cpp :caption: two_things.hpp @@ -22,6 +20,7 @@ These are structures, so you'll override them using a technique C++ calls *class // First, the expected size // Specialization of a struct + // We expect 2, so use 2 template <> struct lua_size : std::integral_constant {}; @@ -32,9 +31,14 @@ These are structures, so you'll override them using a technique C++ calls *class struct checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + // indices can be negative to count backwards from the top of the stack, + // rather than the bottom up + // to deal with this, we adjust the index to + // its absolute position using the lua_absindex function + int absolute_index = lua_absindex(L, index); // Check first and second second index for being the proper types - bool success = stack::check(L, index, handler) - && stack::check(L, index + 1, handler); + bool success = stack::check(L, absolute_index - 1, handler) + && stack::check(L, absolute_index, handler); tracking.use(2); return success; } @@ -43,11 +47,12 @@ These are structures, so you'll override them using a technique C++ calls *class template <> struct getter { static two_things get(lua_State* L, int index, record& tracking) { + int absolute_index = lua_absindex(L, index); // Get the first element - int a = stack::get(L, index); + int a = stack::get(L, absolute_index - 1); // Get the second element, // in the +1 position from the first - bool b = stack::get(L, index + 1); + bool b = stack::get(L, absolute_index); // we use 2 slots, each of the previous takes 1 tracking.use(2); return two_things{ a, b }; @@ -58,7 +63,9 @@ These are structures, so you'll override them using a technique C++ calls *class struct pusher { static int push(lua_State* L, const two_things& things) { int amount = stack::push(L, things.a); + // amount will be 1: int pushes 1 item amount += stack::push(L, things.b); + // amount 2 now, since bool pushes a single item // Return 2 things return amount; } @@ -68,7 +75,7 @@ These are structures, so you'll override them using a technique C++ calls *class } -This is the base formula that you can follow to extend to your own classes. Using it in the rest of the framework should then be seamless: +This is the base formula that you can follow to extend to your own classes. Using it in the rest of the library should then be seamless: .. code-block:: cpp :caption: customization: using it @@ -99,6 +106,9 @@ And that's it! A few things of note about the implementation: First, there's an auxiliary parameter of type :doc:`sol::stack::record<../api/stack>` for the getters and checkers. This keeps track of what the last complete operation performed. Since we retrieved 2 members, we use ``tracking.use(2);`` to indicate that we used 2 stack positions (one for ``bool``, one for ``int``). The second thing to note here is that we made sure to use the ``index`` parameter, and then proceeded to add 1 to it for the next one. +You can make something pushable into Lua, but not get-able in the same way if you only specialize one part of the system. If you need to retrieve it (as a return using one or multiple values from Lua), you should specialize the ``sol::stack::getter`` template class and the ``sol::stack::checker`` template class. If you need to push it into Lua at some point, then you'll want to specialize the ``sol::stack::pusher`` template class. The ``sol::lua_size`` template class trait needs to be specialized for both cases, unless it only pushes 1 item, in which case the default implementation will assume 1. + + In general, this is fine since most getters/checkers only use 1 stack point. But, if you're doing more complex nested classes, it would be useful to use ``tracking.last`` to understand how many stack indices the last getter/checker operation did and increment it by ``index + tracking.last`` after using a ``stack::check<..>( L, index, tracking)`` call. You can read more about the structs themselves :ref:`over on the API page for stack`, and if there's something that goes wrong or you have anymore questions, please feel free to drop a line on the Github Issues page or send an e-mail! \ No newline at end of file diff --git a/docs/source/tutorial/getting-started.rst b/docs/source/tutorial/getting-started.rst index e1e6ce75..fd83e4fc 100644 --- a/docs/source/tutorial/getting-started.rst +++ b/docs/source/tutorial/getting-started.rst @@ -3,6 +3,8 @@ getting started Let's get you going with Sol! To start, you'll need to use a lua distribution of some sort. Sol doesn't provide that: it only wraps the API that comes with it, so you can pick whatever distribution you like for your application. There are lots, but the two popular ones are `vanilla Lua`_ and speedy `LuaJIT`_ . We recommend vanilla Lua if you're getting started, LuaJIT if you need speed and can handle some caveats: the interface for Sol doesn't change no matter what Lua version you're using. +If you need help getting or building Lua, check out the `Lua page on getting started`_. Note that for Visual Studio, one can simply download the sources, include all the Lua library files in that project, and then build for debug/release, x86/x64/ARM rather easily and with minimal interference. Just make sure to adjust the Project Property page to build as a static library (or a DLL with the proper define set in the ``Preprocessor`` step). + After that, make sure you grab either the `single header file release`_, or just perform a clone of the `github repository here`_ and set your include paths up so that you can get at ``sol.hpp`` somehow. Note that we also have the latest version of the single header file with all dependencies included kept in the `repository as well`_. We recommend the single-header-file release, since it's easier to move around, manage and update if you commit it with some form of version control. If you use the github clone method and do not point to the `single/sol/sol.hpp`_ on your include files, you *must* update submodules in order to make sure Optional is present in the repository. Clone with: >>> git clone https://github.com/ThePhD/sol2.git @@ -33,7 +35,7 @@ When you're ready, try compiling this short snippet: 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 -I"path/to/lua/include" -L"path/to/lua/lib" -llua 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. @@ -77,4 +79,6 @@ Next, let's start :doc:`reading/writing some variables` from Lua into .. _single/sol/sol.hpp: https://github.com/ThePhD/sol2/blob/develop/single/sol/sol.hpp -.. _github repository here: https://github.com/ThePhD/sol2 \ No newline at end of file +.. _github repository here: https://github.com/ThePhD/sol2 + +.. _Lua page on getting started: https://www.lua.org/start.html \ No newline at end of file diff --git a/docs/source/tutorial/tutorial-top.rst b/docs/source/tutorial/tutorial-top.rst index 398aa5ae..0fa90819 100644 --- a/docs/source/tutorial/tutorial-top.rst +++ b/docs/source/tutorial/tutorial-top.rst @@ -1,7 +1,7 @@ tutorial ======== -Take some time to learn the framework with thse tutorials. But, if you need to get going FAST, try using the :doc:`quick 'n' dirty` approach and your browser's / editors search function. +Take some time to learn the framework with thse tutorials. But, if you need to get going FAST, try using the :doc:`quick 'n' dirty` approach and your browser's / editors search function. It will also serve you well to look at all the `examples`_, which have recently gotten a bit of an overhaul to contain more relevant work. .. toctree:: @@ -17,3 +17,5 @@ Take some time to learn the framework with thse tutorials. But, if you need to g cxx-in-lua ownership customization + +.. _examples: https://github.com/ThePhD/sol2/tree/develop/examples diff --git a/examples/any_return.cpp b/examples/any_return.cpp index 4f613036..f286071b 100644 --- a/examples/any_return.cpp +++ b/examples/any_return.cpp @@ -1,6 +1,7 @@ #include #include +#include // Uses some of the fancier bits of sol2, including the "transparent argument", // sol::this_state, which gets the current state and does not increment @@ -25,14 +26,17 @@ int main() { int result = lua["f"](1, 2); // result == 3 + assert(result == 3); double result2 = lua["f"](false, 2.5); // result2 == 2.5 + assert(result2 == 2.5); // call in Lua, get result // notice we only need 2 arguments here, not 3 (sol::this_state is transparent) lua.script("result3 = f(true, 5.5)"); double result3 = lua["result3"]; // result3 == 16.5 + assert(result3 == 16.5); std::cout << "=== any_return example ===" << std::endl; std::cout << "result : " << result << std::endl; diff --git a/examples/config.cpp b/examples/config.cpp index 70734332..be55bab3 100644 --- a/examples/config.cpp +++ b/examples/config.cpp @@ -29,6 +29,10 @@ height = 1080 screen.name = lua.get("name"); screen.width = lua.get("width"); screen.height = lua.get("height"); + assert(screen.name == "Asus"); + assert(screen.width == 1920); + assert(screen.height == 1080); + std::cout << "=== config example ===" << std::endl; screen.print(); std::cout << std::endl; diff --git a/examples/customization.cpp b/examples/customization.cpp index 19b143bd..45280e59 100644 --- a/examples/customization.cpp +++ b/examples/customization.cpp @@ -2,6 +2,7 @@ #include #include +#include struct two_things { int a; @@ -22,9 +23,14 @@ namespace sol { struct checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + // indices can be negative to count backwards from the top of the stack, + // rather than the bottom up + // to deal with this, we adjust the index to + // its absolute position using the lua_absindex function + int absolute_index = lua_absindex(L, index); // Check first and second second index for being the proper types - bool success = stack::check(L, index, handler) - && stack::check(L, index + 1, handler); + bool success = stack::check(L, absolute_index + 1, handler) + && stack::check(L, absolute_index, handler); tracking.use(2); return success; } @@ -33,11 +39,12 @@ namespace sol { template <> struct getter { static two_things get(lua_State* L, int index, record& tracking) { + int absolute_index = lua_absindex(L, index); // Get the first element - int a = stack::get(L, index); - // Get the second element, + int a = stack::get(L, absolute_index); + // Get the second element, // in the +1 position from the first - bool b = stack::get(L, index + 1); + bool b = stack::get(L, absolute_index + 1); // we use 2 slots, each of the previous takes 1 tracking.use(2); return two_things{ a, b }; @@ -48,7 +55,9 @@ namespace sol { struct pusher { static int push(lua_State* L, const two_things& things) { int amount = stack::push(L, things.a); + // amount will be 1: int pushes 1 item amount += stack::push(L, things.b); + // amount 2 now, since bool pushes a single item // Return 2 things return amount; } @@ -67,6 +76,8 @@ int main() { sol::function f = lua["f"]; two_things things = f(two_things{ 24, true }); + assert(things.a == 24); + assert(things.b == true); // things.a == 24 // things.b == true diff --git a/examples/functions.cpp b/examples/functions.cpp index 129671b2..f91ae5a5 100644 --- a/examples/functions.cpp +++ b/examples/functions.cpp @@ -51,7 +51,7 @@ int main() { assert(x == 10); if (x == 10) { // Do something based on this information - std::cout << "Yahoo!" << std::endl; + std::cout << "Yahoo! x is " << x << std::endl; } // this can be done as many times as you want @@ -63,7 +63,7 @@ inc() assert(x == 40); if (x == 40) { // Do something based on this information - std::cout << "Yahoo!" << std::endl; + std::cout << "Yahoo! x is " << x << std::endl; } // retrieval of a function is done similarly // to other variables, using sol::function @@ -74,7 +74,7 @@ inc() assert(value == 21); assert(value2 == 21); if (value == 21 && value2 == 21) { - std::cout << "Woo, it's 21!" << std::endl; + std::cout << "Woo, value is 21!" << std::endl; } // multi-return functions are supported using diff --git a/examples/protected_functions.cpp b/examples/protected_functions.cpp index a60e3826..340f0134 100644 --- a/examples/protected_functions.cpp +++ b/examples/protected_functions.cpp @@ -32,13 +32,13 @@ int main() { if (result.valid()) { // Call succeeded int x = result; - std::cout << x << std::endl; + std::cout << "call succeeded, result is " << x << std::endl; } else { // Call failed sol::error err = result; std::string what = err.what(); - std::cout << what << std::endl; + std::cout << "call failed, sol::error::what() is " << what << std::endl; // 'what' Should read // "Handled this message: negative number detected" } diff --git a/examples/static_variables.cpp b/examples/static_variables.cpp index 2b8d00d2..c101e824 100644 --- a/examples/static_variables.cpp +++ b/examples/static_variables.cpp @@ -1,6 +1,7 @@ #include #include +#include struct test { static int muh_variable; @@ -20,13 +21,16 @@ int main() { ); int direct_value = lua["test"]["direct"]; - std::cout << "direct_value: " << direct_value << std::endl; // direct_value == 2 + assert(direct_value == 2); + std::cout << "direct_value: " << direct_value << std::endl; int global = lua["test"]["global"]; - // global == 25 int global2 = lua["test"]["ref_global"]; + // global == 25 // global2 == 25 + assert(global == 25); + assert(global2 == 25); std::cout << "First round of values --" << std::endl; std::cout << global << std::endl; @@ -45,6 +49,9 @@ int main() { // if muh_variable goes out of scope or is deleted // problems could arise, so be careful! + assert(global == 25); + assert(global2 == 542); + std::cout << "Second round of values --" << std::endl; std::cout << "global : " << global << std::endl; std::cout << "global2: " << global2 << std::endl; diff --git a/examples/usertype_advanced.cpp b/examples/usertype_advanced.cpp index 0e358acb..752bef18 100644 --- a/examples/usertype_advanced.cpp +++ b/examples/usertype_advanced.cpp @@ -89,9 +89,10 @@ assert(not p2shoots) -- had 0 ammo -- set variable property setter -p1.hp = 545; +p1.hp = 545 -- get variable through property getter -print(p1.hp); +print(p1.hp) +assert(p1.hp == 545) local did_shoot_1 = p1:shoot() print(did_shoot_1) diff --git a/examples/variadic_args.cpp b/examples/variadic_args.cpp index 93a575f5..918e33ec 100644 --- a/examples/variadic_args.cpp +++ b/examples/variadic_args.cpp @@ -30,6 +30,9 @@ int main() { // will error: not enough arguments //lua.script("x4 = v(1)"); + lua.script("assert(x == 50)"); + lua.script("assert(x2 == 600)"); + lua.script("assert(x3 == 21)"); lua.script("print(x)"); // 50 lua.script("print(x2)"); // 600 lua.script("print(x3)"); // 21 diff --git a/sol/stack_core.hpp b/sol/stack_core.hpp index f73521b2..b5061803 100644 --- a/sol/stack_core.hpp +++ b/sol/stack_core.hpp @@ -206,7 +206,7 @@ namespace sol { } template - bool check(lua_State* L, int index = -1) { + bool check(lua_State* L, int index = -lua_size>::value) { auto handler = no_panic; return check(L, index, handler); } @@ -223,7 +223,7 @@ namespace sol { } template - inline decltype(auto) check_get(lua_State* L, int index = -1) { + inline decltype(auto) check_get(lua_State* L, int index = -lua_size>::value) { auto handler = no_panic; return check_get(L, index, handler); } @@ -320,7 +320,7 @@ namespace sol { } template - inline decltype(auto) get(lua_State* L, int index = -1) { + inline decltype(auto) get(lua_State* L, int index = -lua_size>::value) { record tracking{}; return get(L, index, tracking); } diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index 68c21f4e..2462bff1 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -284,15 +284,14 @@ namespace sol { template struct pusher> { - template - static int push_with(lua_State* L, Args&&... args) { + template + static int push_with(lua_State* L, Key&& name, Args&&... args) { // A dumb pusher void* rawdata = lua_newuserdata(L, sizeof(T)); T* data = static_cast(rawdata); std::allocator alloc; alloc.construct(data, std::forward(args)...); if (with_meta) { - const auto name = &usertype_traits>::user_gc_metatable[0]; lua_CFunction cdel = stack_detail::alloc_destroy; // Make sure we have a plain GC set for this data if (luaL_newmetatable(L, name) != 0) { @@ -305,30 +304,42 @@ namespace sol { return 1; } - template >> = meta::enabler> + template , no_metatable_t, metatable_key_t>> = meta::enabler> static int push(lua_State* L, Arg&& arg, Args&&... args) { - return push_with(L, std::forward(arg), std::forward(args)...); + const auto name = &usertype_traits>::user_gc_metatable[0]; + return push_with(L, name, std::forward(arg), std::forward(args)...); } template static int push(lua_State* L, no_metatable_t, Args&&... args) { - return push_with(L, std::forward(args)...); + const auto name = &usertype_traits>::user_gc_metatable[0]; + return push_with(L, name, std::forward(args)...); + } + + template + static int push(lua_State* L, metatable_key_t, Key&& key, Args&&... args) { + const auto name = &key[0]; + return push_with(L, name, std::forward(args)...); } static int push(lua_State* L, const user& u) { - return push_with(L, u.value); + const auto name = &usertype_traits>::user_gc_metatable[0]; + return push_with(L, name, u.value); } static int push(lua_State* L, user&& u) { - return push_with(L, std::move(u.value)); + const auto name = &usertype_traits>::user_gc_metatable[0]; + return push_with(L, name, std::move(u.value)); } static int push(lua_State* L, no_metatable_t, const user& u) { - return push_with(L, u.value); + const auto name = &usertype_traits>::user_gc_metatable[0]; + return push_with(L, name, u.value); } static int push(lua_State* L, no_metatable_t, user&& u) { - return push_with(L, std::move(u.value)); + const auto name = &usertype_traits>::user_gc_metatable[0]; + return push_with(L, name, std::move(u.value)); } }; diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index 11484234..bec8dcb8 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -388,12 +388,16 @@ namespace sol { typedef typename umt_t::regs_t regs_t; static umt_t& make_cleanup(lua_State* L, umt_t&& umx) { + // ensure some sort of uniqueness + static int uniqueness = 0; + std::string uniquegcmetakey = usertype_traits::user_gc_metatable; + uniquegcmetakey.append(std::to_string(uniqueness++)); + const char* gcmetakey = &usertype_traits::gc_table[0]; + // Make sure userdata's memory is properly in lua first, // otherwise all the light userdata we make later will become invalid - + stack::push>(L, metatable_key, uniquegcmetakey, std::move(umx)); // Create the top level thing that will act as our deleter later on - const char* gcmetakey = &usertype_traits::gc_table[0]; - stack::push>(L, std::move(umx)); stack_reference umt(L, -1); stack::set_field(L, gcmetakey, umt); umt.pop();