O-O-O-OVERHAAAAAUL no not really just bug fixes....

This commit is contained in:
ThePhD 2016-08-22 22:45:06 -04:00
parent a7423a5005
commit 5b65ea1460
18 changed files with 120 additions and 49 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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.

View File

@ -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!

View File

@ -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<T>``, ``sol::stack::pusher<T, C>``, ``sol::stack::getter<T, C>``, ``sol::stack::checker<T, sol::type t, C>``.
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<T>``, ``sol::stack::pusher<T, C>``, ``sol::stack::getter<T, C>``, ``sol::stack::checker<T, sol::type t, C>``.
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<two_things> : std::integral_constant<int, 2> {};
@ -32,9 +31,14 @@ These are structures, so you'll override them using a technique C++ calls *class
struct checker<two_things> {
template <typename Handler>
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<int>(L, index, handler)
&& stack::check<bool>(L, index + 1, handler);
bool success = stack::check<int>(L, absolute_index - 1, handler)
&& stack::check<bool>(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<two_things> {
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<int>(L, index);
int a = stack::get<int>(L, absolute_index - 1);
// Get the second element,
// in the +1 position from the first
bool b = stack::get<bool>(L, index + 1);
bool b = stack::get<bool>(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<two_things> {
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<extension_points>`, 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!

View File

@ -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<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
.. _github repository here: https://github.com/ThePhD/sol2
.. _Lua page on getting started: https://www.lua.org/start.html

View File

@ -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<all-the-things>` 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<all-the-things>` 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

View File

@ -1,6 +1,7 @@
#include <sol.hpp>
#include <iostream>
#include <cassert>
// 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;

View File

@ -29,6 +29,10 @@ height = 1080
screen.name = lua.get<std::string>("name");
screen.width = lua.get<int>("width");
screen.height = lua.get<int>("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;

View File

@ -2,6 +2,7 @@
#include <iostream>
#include <iomanip>
#include <cassert>
struct two_things {
int a;
@ -22,9 +23,14 @@ namespace sol {
struct checker<two_things> {
template <typename Handler>
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<int>(L, index, handler)
&& stack::check<bool>(L, index + 1, handler);
bool success = stack::check<int>(L, absolute_index + 1, handler)
&& stack::check<bool>(L, absolute_index, handler);
tracking.use(2);
return success;
}
@ -33,11 +39,12 @@ namespace sol {
template <>
struct getter<two_things> {
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<int>(L, index);
// Get the second element,
int a = stack::get<int>(L, absolute_index);
// Get the second element,
// in the +1 position from the first
bool b = stack::get<bool>(L, index + 1);
bool b = stack::get<bool>(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<two_things> {
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

View File

@ -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

View File

@ -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"
}

View File

@ -1,6 +1,7 @@
#include <sol.hpp>
#include <iostream>
#include <cassert>
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;

View File

@ -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)

View File

@ -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

View File

@ -206,7 +206,7 @@ namespace sol {
}
template <typename T>
bool check(lua_State* L, int index = -1) {
bool check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = no_panic;
return check<T>(L, index, handler);
}
@ -223,7 +223,7 @@ namespace sol {
}
template<typename T>
inline decltype(auto) check_get(lua_State* L, int index = -1) {
inline decltype(auto) check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = no_panic;
return check_get<T>(L, index, handler);
}
@ -320,7 +320,7 @@ namespace sol {
}
template<typename T>
inline decltype(auto) get(lua_State* L, int index = -1) {
inline decltype(auto) get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
record tracking{};
return get<T>(L, index, tracking);
}

View File

@ -284,15 +284,14 @@ namespace sol {
template<typename T>
struct pusher<user<T>> {
template <bool with_meta = true, typename... Args>
static int push_with(lua_State* L, Args&&... args) {
template <bool with_meta = true, typename Key, typename... Args>
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<T*>(rawdata);
std::allocator<T> alloc;
alloc.construct(data, std::forward<Args>(args)...);
if (with_meta) {
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable[0];
lua_CFunction cdel = stack_detail::alloc_destroy<T>;
// 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 <typename Arg, typename... Args, meta::disable<std::is_same<no_metatable_t, meta::unqualified_t<Arg>>> = meta::enabler>
template <typename Arg, typename... Args, meta::disable<meta::any_same<meta::unqualified_t<Arg>, 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>(arg), std::forward<Args>(args)...);
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable[0];
return push_with(L, name, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
template <typename... Args>
static int push(lua_State* L, no_metatable_t, Args&&... args) {
return push_with<false>(L, std::forward<Args>(args)...);
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable[0];
return push_with<false>(L, name, std::forward<Args>(args)...);
}
template <typename Key, typename... Args>
static int push(lua_State* L, metatable_key_t, Key&& key, Args&&... args) {
const auto name = &key[0];
return push_with<true>(L, name, std::forward<Args>(args)...);
}
static int push(lua_State* L, const user<T>& u) {
return push_with(L, u.value);
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable[0];
return push_with(L, name, u.value);
}
static int push(lua_State* L, user<T>&& u) {
return push_with(L, std::move(u.value));
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable[0];
return push_with(L, name, std::move(u.value));
}
static int push(lua_State* L, no_metatable_t, const user<T>& u) {
return push_with<false>(L, u.value);
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable[0];
return push_with<false>(L, name, u.value);
}
static int push(lua_State* L, no_metatable_t, user<T>&& u) {
return push_with<false>(L, std::move(u.value));
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable[0];
return push_with<false>(L, name, std::move(u.value));
}
};

View File

@ -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<T>::user_gc_metatable;
uniquegcmetakey.append(std::to_string(uniqueness++));
const char* gcmetakey = &usertype_traits<T>::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<user<umt_t>>(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<T>::gc_table[0];
stack::push<user<umt_t>>(L, std::move(umx));
stack_reference umt(L, -1);
stack::set_field<true>(L, gcmetakey, umt);
umt.pop();