more luajit compatibility fixes - works with Lua 5.1, 5.2, 5.3

additional tests to make sure pass-by-value and copy semantics work as intended
new proxy_base class to reduce code duplication
update function / protected_function usage (to solve starwing's issue while keeping code as clean as possible)
This commit is contained in:
ThePhD 2016-02-01 03:27:06 -05:00
parent 27f09fbb35
commit 1d93f560f2
33 changed files with 426 additions and 266 deletions

3
.gitignore vendored
View File

@ -40,3 +40,6 @@ luajit-2.0.4/
*.creator.user.*
lua-5.3.1/
main2.cpp
lua-5.3.2/
lua-5.2.4/
bench/

View File

@ -13,11 +13,11 @@ static sol::state prepare_cpp_function_state( ) {
return lua;
}
struct sol_fast_function_result_cpp_bench {
struct sol_protected_function_result_cpp_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_cpp_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::fast_function r = lua[ "r" ];
sol::protected_function r = lua[ "r" ];
int value = r( );
return value;
};
@ -25,11 +25,11 @@ struct sol_fast_function_result_cpp_bench {
}
};
struct sol_fast_direct_cpp_bench {
struct sol_protected_call_cpp_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_cpp_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::fast_function r = lua[ "r" ];
sol::protected_function r = lua[ "r" ];
int value = r.call<int>( );
return value;
};
@ -49,7 +49,7 @@ struct sol_function_result_cpp_bench {
}
};
struct sol_direct_cpp_bench {
struct sol_call_cpp_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_cpp_function_state( );
auto measurement = [ & ] ( int run_index ) {
@ -61,7 +61,7 @@ struct sol_direct_cpp_bench {
}
};
struct c_direct_cpp_bench {
struct c_call_cpp_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_cpp_function_state( );
lua_State* L = lua.lua_state( );
@ -82,11 +82,11 @@ void bench_cpp_function( const std::string& dir, std::string& configurationname,
cfg.title = "sol::function (C++ source) (" + configurationname + " " + platformname + ")";
cfg.samples = 100;
nonius::benchmark benchmarks [] = {
nonius::benchmark( "fast_function - function_result", sol_fast_function_result_cpp_bench( ) ),
nonius::benchmark( "fast_function - call<>", sol_fast_direct_cpp_bench( ) ),
nonius::benchmark( "protected_function - function_result", sol_protected_function_result_cpp_bench( ) ),
nonius::benchmark( "protected_function - call<>", sol_protected_call_cpp_bench( ) ),
nonius::benchmark( "function - function_result", sol_function_result_cpp_bench( ) ),
nonius::benchmark( "function - call<>", sol_direct_cpp_bench( ) ),
nonius::benchmark( "plain C", c_direct_cpp_bench( ) ),
nonius::benchmark( "function - call<>", sol_call_cpp_bench( ) ),
nonius::benchmark( "plain C", c_call_cpp_bench( ) ),
};
nonius::go( cfg, std::begin( benchmarks ), std::end( benchmarks ), nonius::html_reporter( ) );
}

View File

@ -13,30 +13,6 @@ end
return lua;
}
struct sol_fast_function_result_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::fast_function r = lua[ "r" ];
int value = r( );
return value;
};
meter.measure( measurement );
}
};
struct sol_fast_direct_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::fast_function r = lua[ "r" ];
int value = r.call<int>( );
return value;
};
meter.measure( measurement );
}
};
struct sol_function_result_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
@ -49,7 +25,7 @@ struct sol_function_result_lua_bench {
}
};
struct sol_direct_lua_bench {
struct sol_call_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
auto measurement = [ & ] ( int run_index ) {
@ -61,6 +37,30 @@ struct sol_direct_lua_bench {
}
};
struct sol_protected_function_result_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::protected_function r = lua[ "r" ];
int value = r( );
return value;
};
meter.measure( measurement );
}
};
struct sol_protected_call_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::protected_function r = lua[ "r" ];
int value = r.call<int>( );
return value;
};
meter.measure( measurement );
}
};
struct c_direct_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
@ -81,11 +81,11 @@ void bench_lua_function( const std::string& dir, std::string& configurationname
cfg.output_file = dir + "sol.functions (lua source) - " + configurationname + " " + platformname + ".html";
cfg.title = "sol::function (lua source) (" + configurationname + " " + platformname + ")";
cfg.samples = 100;
nonius::benchmark benchmarks [] = {
nonius::benchmark( "fast_function - function_result", sol_fast_function_result_lua_bench( ) ),
nonius::benchmark( "fast_function - call<>", sol_fast_direct_lua_bench( ) ),
nonius::benchmark( "function - function_result", sol_function_result_lua_bench( ) ),
nonius::benchmark( "function - call<>", sol_direct_lua_bench( ) ),
nonius::benchmark benchmarks[] = {
nonius::benchmark("function - function_result", sol_function_result_lua_bench()),
nonius::benchmark("function - call<>", sol_call_lua_bench()),
nonius::benchmark("protected_function - function_result", sol_protected_function_result_lua_bench()),
nonius::benchmark("protected_function - call<>", sol_protected_call_lua_bench()),
nonius::benchmark( "plain C", c_direct_lua_bench( ) ),
};
nonius::go( cfg, std::begin( benchmarks ), std::end( benchmarks ), nonius::html_reporter( ) );

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Danny Y., Rapptz
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
@ -28,88 +28,13 @@
#include "function_types.hpp"
#include "usertype_traits.hpp"
#include "resolve.hpp"
#include "function_result.hpp"
#include <cstdint>
#include <functional>
#include <memory>
namespace sol {
class function_result {
private:
lua_State* L;
int index;
int returncount;
int popcount;
call_error error;
template <typename T, std::size_t I>
stack::get_return<T> get(types<T>, indices<I>) const {
return stack::get<T>(L, index);
}
template <typename... Ret, std::size_t... I>
stack::get_return<Ret...> get(types<Ret...>, indices<I...>) const {
auto r = std::make_tuple(stack::get<Ret>(L, index + I)...);
return r;
}
public:
function_result() = default;
function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_error error = call_error::ok): L(L), index(index), returncount(returncount), popcount(popcount), error(error) {
}
function_result(const function_result&) = default;
function_result& operator=(const function_result&) = default;
function_result(function_result&& o) : L(o.L), index(o.index), returncount(o.returncount), error(o.error) {
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
o.L = nullptr;
o.index = 0;
o.returncount = 0;
o.popcount = 0;
o.error = call_error::runtime;
}
function_result& operator=(function_result&& o) {
L = o.L;
index = o.index;
returncount = o.returncount;
error = o.error;
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
o.L = nullptr;
o.index = 0;
o.returncount = 0;
o.popcount = 0;
o.error = call_error::runtime;
return *this;
}
bool valid() const {
return error == call_error::ok;
}
template<typename T>
T get() const {
tuple_types<Unqualified<T>> tr;
return get(tr, tr);
}
operator std::string() const {
return get<std::string>();
}
template<typename T, EnableIf<Not<std::is_same<Unqualified<T>, const char*>>, Not<std::is_same<Unqualified<T>, char>>, Not<std::is_same<Unqualified<T>, std::string>>, Not<std::is_same<Unqualified<T>, std::initializer_list<char>>>> = 0>
operator T () const {
return get<T>();
}
~function_result() {
stack::remove(L, index, popcount);
}
};
class fast_function : public reference {
class function : public reference {
private:
void luacall( std::ptrdiff_t argcount, std::ptrdiff_t resultcount ) const {
lua_callk( lua_state( ), static_cast<int>( argcount ), static_cast<int>( resultcount ), 0, nullptr );
@ -117,7 +42,7 @@ private:
template<std::size_t... I, typename... Ret>
std::tuple<Ret...> invoke( indices<I...>, types<Ret...>, std::ptrdiff_t n ) const {
luacall( n, sizeof...( Ret ), h );
luacall( n, sizeof...( Ret ) );
int nreturns = static_cast<int>( sizeof...( Ret ) );
int stacksize = lua_gettop( lua_state( ) );
int firstreturn = std::max( 0, stacksize - nreturns ) + 1;
@ -139,35 +64,22 @@ private:
function_result invoke( indices<>, types<>, std::ptrdiff_t n ) const {
int stacksize = lua_gettop( lua_state( ) );
int firstreturn = std::max( 0, stacksize - static_cast<int>( n ) - 1 );
int poststacksize = 0;
int returncount = 0;
try {
luacall( n, LUA_MULTRET );
poststacksize = lua_gettop( lua_state( ) );
returncount = poststacksize - firstreturn;
}
// Handle C++ errors thrown from C++ functions bound inside of lua
catch ( const std::exception& error ) {
stack::push( lua_state( ), error.what( ) );
return function_result( lua_state( ), firstreturn, 0, 1, call_error::runtime );
}
catch ( ... ) {
throw;
}
int firstreturn = std::max( 1, stacksize - static_cast<int>( n ) );
luacall( n, LUA_MULTRET );
int poststacksize = lua_gettop( lua_state( ) );
int returncount = poststacksize - firstreturn;
return function_result( lua_state( ), firstreturn, returncount, returncount, call_error::ok );
}
public:
fast_function( ) = default;
fast_function( lua_State* L, int index = -1 ) : reference( L, index ) {
function( ) = default;
function( lua_State* L, int index = -1 ) : reference( L, index ) {
type_assert( L, index, type::function );
}
fast_function( const fast_function& ) = default;
fast_function& operator=( const fast_function& ) = default;
fast_function( fast_function&& ) = default;
fast_function& operator=( fast_function&& ) = default;
function( const function& ) = default;
function& operator=( const function& ) = default;
function( function&& ) = default;
function& operator=( function&& ) = default;
template<typename... Args>
function_result operator()( Args&&... args ) const {
@ -176,7 +88,7 @@ public:
template<typename... Ret, typename... Args>
auto operator()( types<Ret...>, Args&&... args ) const
-> decltype( invoke( types<Ret...>( ), types<Ret...>( ), 0, std::declval<handler&>( ) ) ) {
-> decltype( invoke( types<Ret...>( ), types<Ret...>( ), 0 ) ) {
return call<Ret...>( std::forward<Args>( args )... );
}
@ -190,7 +102,7 @@ public:
}
};
class safe_function : public reference {
class protected_function : public reference {
private:
static reference& handler_storage() {
static sol::reference h;
@ -252,21 +164,21 @@ private:
function_result invoke(indices<>, types<>, std::ptrdiff_t n, handler& h) const {
bool handlerpushed = error_handler.valid();
int stacksize = lua_gettop(lua_state());
int firstreturn = std::max(0, stacksize - static_cast<int>(n) - 1);
int firstreturn = std::max(1, stacksize - static_cast<int>(n) - 1);
int returncount = 0;
call_error code = call_error::ok;
try {
code = static_cast<call_error>(luacall(n, LUA_MULTRET, h));
int poststacksize = lua_gettop( lua_state( ) );
int poststacksize = lua_gettop(lua_state());
returncount = poststacksize - firstreturn;
}
// Handle C++ errors thrown from C++ functions bound inside of lua
catch (const std::exception& error) {
code = call_error::runtime;
h.stackindex = 0;
stack::push(lua_state(), error.what());
return function_result( lua_state( ), firstreturn, 0, 1, call_error::runtime );
firstreturn = lua_gettop(lua_state());
return function_result(lua_state(), firstreturn, 0, 1, call_error::runtime);
}
catch (...) {
throw;
@ -277,14 +189,14 @@ private:
public:
sol::reference error_handler;
safe_function() = default;
safe_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) {
protected_function() = default;
protected_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) {
type_assert(L, index, type::function);
}
safe_function(const safe_function&) = default;
safe_function& operator=(const safe_function&) = default;
safe_function( safe_function&& ) = default;
safe_function& operator=( safe_function&& ) = default;
protected_function(const protected_function&) = default;
protected_function& operator=(const protected_function&) = default;
protected_function( protected_function&& ) = default;
protected_function& operator=( protected_function&& ) = default;
template<typename... Args>
function_result operator()(Args&&... args) const {

103
sol/function_result.hpp Normal file
View File

@ -0,0 +1,103 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// 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.
#ifndef SOL_FUNCTION_RESULT_HPP
#define SOL_FUNCTION_RESULT_HPP
#include "reference.hpp"
#include "tuple.hpp"
#include "stack.hpp"
#include "proxy_base.hpp"
namespace sol {
struct function_result : public proxy_base<function_result> {
private:
lua_State* L;
int index;
int returncount;
int popcount;
call_error error;
template <typename T, std::size_t I>
stack::get_return<T> get(types<T>, indices<I>) const {
return stack::get<T>(L, index);
}
template <typename... Ret, std::size_t... I>
stack::get_return<Ret...> get(types<Ret...>, indices<I...>) const {
return stack::get_return<Ret...>(stack::get<Ret>(L, index + I)...);
}
public:
function_result() = default;
function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_error error = call_error::ok): L(L), index(index), returncount(returncount), popcount(popcount), error(error) {
}
function_result(const function_result&) = default;
function_result& operator=(const function_result&) = default;
function_result(function_result&& o) : L(o.L), index(o.index), returncount(o.returncount), error(o.error) {
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
o.L = nullptr;
o.index = 0;
o.returncount = 0;
o.popcount = 0;
o.error = call_error::runtime;
}
function_result& operator=(function_result&& o) {
L = o.L;
index = o.index;
returncount = o.returncount;
error = o.error;
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
o.L = nullptr;
o.index = 0;
o.returncount = 0;
o.popcount = 0;
o.error = call_error::runtime;
return *this;
}
bool valid() const {
return error == call_error::ok;
}
template<typename T>
T get() const {
tuple_types<Unqualified<T>> tr;
return get(tr, tr);
}
template <typename K>
decltype(auto) operator[](K&& key) const {
return get<table>()[std::forward<K>(key)];
}
~function_result() {
stack::remove(L, index, popcount);
}
};
} // sol
#endif // SOL_FUNCTION_RESULT_HPP

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
@ -25,10 +25,11 @@
#include "traits.hpp"
#include "object.hpp"
#include "function.hpp"
#include "proxy_base.hpp"
namespace sol {
template<typename Table, typename Key>
struct proxy {
struct proxy : public proxy_base<proxy<Table, Key>> {
private:
Table tbl;
If<std::is_array<Unqualified<Key>>, Key&, Unqualified<Key>> key;
@ -67,20 +68,6 @@ public:
return tbl.template get<T>( key );
}
operator std::string() const {
return get<std::string>();
}
template<typename T, EnableIf<Not<is_string_constructible<T>>, is_lua_primitive<T>> = 0>
operator T ( ) const {
return get<T>( );
}
template<typename T, EnableIf<Not<is_string_constructible<T>>, Not<is_lua_primitive<T>>> = 0>
operator T& ( ) const {
return get<T&>( );
}
template <typename K>
decltype(auto) operator[](K&& key) const {
return get<table>()[std::forward<K>(key)];

51
sol/proxy_base.hpp Normal file
View File

@ -0,0 +1,51 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// 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.
#ifndef SOL_PROXY_BASE_HPP
#define SOL_PROXY_BASE_HPP
#include "reference.hpp"
#include "tuple.hpp"
#include "stack.hpp"
namespace sol {
template <typename Super>
struct proxy_base {
operator std::string() const {
const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
return super.template get<std::string>();
}
template<typename T, EnableIf<Not<is_string_constructible<T>>, is_proxy_primitive<Unqualified<T>>> = 0>
operator T ( ) const {
const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
return super.template get<T>( );
}
template<typename T, EnableIf<Not<is_string_constructible<T>>, Not<is_proxy_primitive<Unqualified<T>>>> = 0>
operator T& ( ) const {
const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
return super.template get<T&>( );
}
};
} // sol
#endif // SOL_PROXY_BASE_HPP

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
@ -25,14 +25,18 @@
#include "types.hpp"
namespace sol {
namespace detail {
namespace stack {
template <typename T>
struct push_pop {
T t;
push_pop (T x) : t(x) { t.push(); }
~push_pop() { t.pop(); }
};
} // detail
template <typename T>
push_pop<T> push_popper(T&& x) {
return push_pop<T>(std::forward<T>(x));
};
} // stack
class reference {
private:

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
@ -150,7 +150,7 @@ inline void lua_setglobali(lua_State* L, lua_Integer n) {
#else
lua_pushglobaltable(L);
lua_pushinteger(L, n);
lua_pushvalue(L, -3)
lua_pushvalue(L, -3);
lua_settable(L, -3);
lua_pop(L, 2); // remove table, and the copy of the value
#endif

View File

@ -150,19 +150,19 @@ public:
return globals.get<Args...>(std::forward<Keys>(keys)...);
}
template<typename T, typename U>
state_view& set(T&& key, U&& value) {
globals.set(std::forward<T>(key), std::forward<U>(value));
template<typename... Tn>
state_view& set(Tn&&... argn) {
globals.set(std::forward<Tn>(argn)...);
return *this;
}
template<typename T>
SOL_DEPRECATED table& set_userdata(usertype<T>& user) {
SOL_DEPRECATED state_view& set_userdata(usertype<T>& user) {
return set_usertype(user);
}
template<typename Key, typename T>
SOL_DEPRECATED table& set_userdata(Key&& key, usertype<T>& user) {
SOL_DEPRECATED state_view& set_userdata(Key&& key, usertype<T>& user) {
return set_usertype(std::forward<Key>(key), user);
}

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
@ -49,8 +49,9 @@ class table_core : public reference {
return stack::pop<T>(lua_state());
}
template<typename T, typename Key, DisableIf<Not<std::is_void<Key>>, Bool<top_level>> = 0>
template<typename T, typename Key, DisableIf<Bool<top_level>, Not<std::is_void<Key>>> = 0>
decltype(auto) single_get( Key&& key ) const {
auto pp = stack::push_popper(*this);
stack::push( lua_state( ), std::forward<Key>( key ) );
lua_gettable( lua_state( ), -2 );
return stack::pop<T>( lua_state( ) );
@ -78,8 +79,9 @@ class table_core : public reference {
lua_setglobal( lua_state( ), &key[0] );
}
template<typename Key, typename Value, DisableIf<Not<std::is_void<Key>>, Bool<top_level>> = 0>
template<typename Key, typename Value, DisableIf<Bool<top_level>, Not<std::is_void<Key>>> = 0>
void single_set(Key&& key, Value&& value) {
auto pp = stack::push_popper(*this);
stack::push(lua_state(), std::forward<Key>(key));
stack::push(lua_state(), std::forward<Value>(value));
lua_settable(lua_state(), -3);
@ -87,8 +89,8 @@ class table_core : public reference {
template<typename Pairs, std::size_t... I>
void tuple_set( indices<I...>, Pairs&& pairs ) {
using swallow = int[];
swallow{ 0, ( single_set(std::get<I * 2>(pairs), std::get<I * 2 + 1>(pairs)) , 0)..., 0 };
using swallow = int[];
swallow{ 0, ( single_set(std::get<I * 2>(pairs), std::get<I * 2 + 1>(pairs)) , 0)..., 0 };
}
#if SOL_LUA_VERSION < 502
@ -105,14 +107,12 @@ public:
template<typename... Ret, typename... Keys>
decltype(auto) get( Keys&&... keys ) const {
auto pp = detail::push_pop<const table_core&>(*this);
return tuple_get( types<Ret...>( ), build_indices<sizeof...( Ret )>( ), std::forward_as_tuple(std::forward<Keys>(keys)...));
}
template<typename... Tn>
table_core& set( Tn&&... argn ) {
auto pp = detail::push_pop<const table_core&>(*this);
tuple_set(build_indices<sizeof...(Tn) / 2>(), std::forward_as_tuple(std::forward<Tn>(argn)...));
tuple_set(build_indices<sizeof...(Tn) / 2>(), std::forward_as_tuple(std::forward<Tn>(argn)...));
return *this;
}
@ -136,21 +136,19 @@ public:
if ( top_level ) {
stack::push( lua_state( ), user );
lua_setglobal( lua_state( ), &key[ 0 ] );
pop( );
}
else {
push( );
auto pp = stack::push_popper( *this );
stack::push( lua_state( ), std::forward<Key>( key ) );
stack::push( lua_state( ), user );
lua_settable( lua_state( ), -3 );
pop( );
}
return *this;
}
template<typename Fx>
void for_each( Fx&& fx ) const {
push( );
auto pp = stack::push_popper( *this );
stack::push( lua_state( ), nil );
while ( lua_next( this->lua_state( ), -2 ) ) {
sol::object key( lua_state( ), -2 );
@ -158,14 +156,11 @@ public:
fx( key, value );
lua_pop( lua_state( ), 1 );
}
pop( );
}
size_t size( ) const {
push( );
size_t result = lua_rawlen( lua_state( ), -1 );
pop( );
return result;
auto pp = stack::push_popper( *this );
return lua_rawlen(lua_state(), -1);
}
template<typename T>
@ -238,11 +233,10 @@ private:
template<typename... Sig, typename... Args, typename Key, DisableIf<Not<std::is_arithmetic<Unqualified<Key>>>, Bool<top_level>> = 0>
void set_resolved_function( Key&& key, Args&&... args ) {
push( );
auto pp = stack::push_popper( *this );
int tabletarget = lua_gettop( lua_state( ) );
stack::push<function_sig_t<Sig...>>( lua_state( ), std::forward<Args>( args )... );
lua_setfield( lua_state( ), tabletarget, &key[ 0 ] );
pop( );
}
};
} // sol

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
@ -44,7 +44,7 @@ struct unwrap {
template<typename T>
struct unwrap<std::reference_wrapper<T>> {
typedef typename std::add_lvalue_reference<T>::type type;
typedef T type;
};
template<typename T>
@ -321,7 +321,7 @@ auto unwrapper(T&& item) -> decltype(std::forward<T>(item)) {
}
template<typename Arg>
Unwrap<Arg> unwrapper(std::reference_wrapper<Arg> arg) {
Arg& unwrapper(std::reference_wrapper<Arg> arg) {
return arg.get();
}

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
@ -93,9 +93,6 @@ struct constructors {};
const auto default_constructor = constructors<types<>>{};
template <typename T>
using ref = std::reference_wrapper<T>;
} // sol
#endif // SOL_TUPLE_HPP

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
@ -126,9 +126,8 @@ template <bool>
class table_core;
typedef table_core<false> table;
typedef table_core<true> global_table;
class fast_function;
class safe_function;
typedef safe_function function;
class function;
class protected_function;
class object;
template <typename T, typename = void>
@ -165,7 +164,7 @@ template <>
struct lua_type_of<function> : std::integral_constant<type, type::function> {};
template <>
struct lua_type_of<fast_function> : std::integral_constant<type, type::function> {};
struct lua_type_of<protected_function> : std::integral_constant<type, type::function> {};
template <typename Signature>
struct lua_type_of<std::function<Signature>> : std::integral_constant<type, type::function>{};
@ -195,6 +194,14 @@ struct lua_type_of<T, typename std::enable_if<std::is_enum<T>::value>::type> : s
template <typename T>
struct is_lua_primitive : std::integral_constant<bool, type::userdata != lua_type_of<Unqualified<T>>::value> { };
template <typename T>
struct is_proxy_primitive : is_lua_primitive<T> { };
template <typename T>
struct is_proxy_primitive<std::reference_wrapper<T>> : std::true_type { };
template <typename... Tn>
struct is_proxy_primitive<std::tuple<Tn...>> : std::true_type { };
} // sol
#endif // SOL_TYPES_HPP

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
// Copyright (c) 2013-2015 Rapptz and contributors
// Copyright (c) 2013-2016 Rapptz and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in

176
tests.cpp
View File

@ -198,7 +198,7 @@ struct giver {
};
TEST_CASE("simple/set_global", "Check if the set_global works properly.") {
TEST_CASE("simple/set", "Check if the set works properly.") {
sol::state lua;
lua.set("a", 9);
@ -207,10 +207,8 @@ TEST_CASE("simple/set_global", "Check if the set_global works properly.") {
lua.set("d", "hello");
REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
lua.set("e", std::string("hello"));
lua.set("e", std::string("hello"), "f", true);
REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
lua.set("f", true);
REQUIRE_NOTHROW(lua.script("if f ~= true then error('wrong value') end"));
}
@ -225,11 +223,11 @@ TEST_CASE("simple/get", "Tests if the get function works properly.") {
REQUIRE_NOTHROW(lua.get<sol::nil_t>("b"));
lua.script("d = 'hello'");
auto d = lua.get<std::string>("d");
REQUIRE(d == "hello");
lua.script("e = true");
auto e = lua.get<bool>("e");
std::string d;
bool e;
std::tie( d, e ) = lua.get<std::string, bool>("d", "e");
REQUIRE(d == "hello");
REQUIRE(e == true);
}
@ -265,7 +263,7 @@ TEST_CASE("simple/call_with_parameters", "Lua function is called with a few para
REQUIRE_NOTHROW(fvoid(1, 2, 3));
REQUIRE_NOTHROW(a = f.call<int>(1, 2, 3));
REQUIRE(a == 6);
REQUIRE_THROWS(a = f.call<int>(1, 2, "arf"));
REQUIRE_THROWS(a = f(1, 2, "arf"));
}
TEST_CASE("simple/call_c++_function", "C++ function is called from lua") {
@ -627,7 +625,7 @@ TEST_CASE("tables/usertype", "Show that we can create classes from usertype and
REQUIRE(cresult == 3);
}
TEST_CASE("tables/usertype constructors", "Show that we can create classes from usertype and use them with multiple destructors") {
TEST_CASE("tables/usertype constructors", "Show that we can create classes from usertype and use them with multiple constructors") {
sol::state lua;
@ -704,19 +702,25 @@ TEST_CASE("tables/usertype utility derived", "usertype classes must play nice wh
lua.set_usertype(baseusertype);
lua.script("base = Base.new(5)");
lua.script("print(base:get_num())");
REQUIRE_NOTHROW(lua.script("print(base:get_num())"));
sol::constructors<sol::types<int>> derivedctor;
sol::usertype<Derived> derivedusertype(derivedctor, "get_num", &Derived::get_num, "get_num_10", &Derived::get_num_10);
/*sol::constructors<sol::types<int>> derivedctor;
sol::usertype<Derived> derivedusertype(derivedctor,
"get_num_10", &Derived::get_num_10,
"get_num", &Derived::get_num
);
lua.set_usertype(derivedusertype);
lua.script("derived = Derived.new(7)");
lua.script("dgn10 = derived:get_num_10()\nprint(dgn10)");
lua.script("dgn = derived:get_num()\nprint(dgn)");
Derived& derived = lua["derived"];
lua.script("dgn = derived:get_num()\n"
"print(dgn)");
lua.script("dgn10 = derived:get_num_10()\n"
"print(dgn10)");
REQUIRE((lua.get<int>("dgn10") == 70));
REQUIRE((lua.get<int>("dgn") == 7));
REQUIRE((lua.get<int>("dgn") == 7));*/
}
TEST_CASE("tables/self-referential usertype", "usertype classes must play nice when C++ object types are requested for C++ code") {
@ -856,24 +860,11 @@ TEST_CASE("tables/issue-number-twenty-five", "Using pointers and references from
}
TEST_CASE("usertype/issue-number-thirty-five", "using value types created from lua-called C++ code, fixing user-defined types with constructors") {
struct Line {
Vec p1, p2;
Line() : p1{0, 0, 0}, p2{0, 0, 0} {}
Line(float x) : p1{x, x, x}, p2{x, x, x} {}
Line(const Vec& p1) : p1{p1}, p2{p1} {}
Line(Vec p1, Vec p2) : p1{p1}, p2{p2} {}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
sol::constructors<sol::types<>, sol::types<Vec>, sol::types<Vec, Vec>> lctor;
sol::usertype<Line> ludata(lctor);
lua.set_usertype("Line", ludata);
sol::constructors<sol::types<float, float, float>> ctor;
sol::usertype<Vec> udata(ctor, "normalized", &Vec::normalized, "length", &Vec::length);
lua.set_usertype(udata);
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n"
@ -971,20 +962,26 @@ TEST_CASE("references/get-set", "properly get and set with std::ref semantics. N
lua.new_usertype<vars>("vars",
"boop", &vars::boop);
vars var{};
vars rvar{};
lua.set("beep", var);
lua.set("rbeep", std::ref(rvar));
auto& my_var = lua.get<vars>("beep");
auto& ref_var = lua.get<sol::ref<vars>>("rbeep");
auto& ref_var = lua.get<std::reference_wrapper<vars>>("rbeep");
vars& proxy_my_var = lua["beep"];
std::reference_wrapper<vars> proxy_ref_var = lua["rbeep"];
var.boop = 2;
rvar.boop = 5;
// Was return as a value: var must be diferent from "beep"
REQUIRE_FALSE(std::addressof(var) == std::addressof(my_var));
REQUIRE_FALSE(std::addressof(proxy_my_var) == std::addressof(var));
REQUIRE((my_var.boop == 0));
REQUIRE(var.boop != my_var.boop);
// Reference should point back to the same type.
REQUIRE(std::addressof(ref_var) == std::addressof(rvar));
//REQUIRE(std::addressof(proxy_ref_var.get()) == std::addressof(rvar));
REQUIRE(rvar.boop == 5);
REQUIRE(rvar.boop == ref_var.boop);
}
@ -1003,7 +1000,7 @@ TEST_CASE("interop/null-to-nil-and-back", "nil should be the given type when a p
"assert(x == nil)"));
}
TEST_CASE( "functions/sol::function_result", "Function result should be the beefy return type for sol::function that allows for error checking and error handlers" ) {
TEST_CASE( "functions/function_result-protected_function", "Function result should be the beefy return type for sol::function that allows for error checking and error handlers" ) {
sol::state lua;
lua.open_libraries( sol::lib::base, sol::lib::debug );
@ -1032,8 +1029,8 @@ TEST_CASE( "functions/sol::function_result", "Function result should be the beef
+ "end"
);
sol::function func = lua[ "doom" ];
sol::function luafunc = lua[ "luadoom" ];
sol::protected_function func = lua[ "doom" ];
sol::protected_function luafunc = lua[ "luadoom" ];
sol::function luahandler = lua[ "handler" ];
sol::function cpphandler = lua[ "cpphandler" ];
func.error_handler = luahandler;
@ -1049,5 +1046,110 @@ TEST_CASE( "functions/sol::function_result", "Function result should be the beef
REQUIRE(!result2.valid());
errorstring = result2;
REQUIRE(errorstring == errormessage2);
}
TEST_CASE("functions/destructor-tests", "Show that proper copies / destruction happens") {
static int created = 0;
static int destroyed = 0;
static void* last_call = nullptr;
static void* static_call = reinterpret_cast<void*>(0x01);
typedef void(* fptr)();
struct x {
x() {++created;}
x(const x&) {++created;}
x(x&&) {++created;}
x& operator=(const x&) {++created; return *this;}
x& operator=(x&&) {++created; return *this;}
void func() {last_call = static_cast<void*>(this);};
~x () {++destroyed;}
};
struct y {
y() {++created;}
y(const x&) {++created;}
y(x&&) {++created;}
y& operator=(const x&) {return *this;}
y& operator=(x&&) {return *this;}
static void func() {last_call = static_call;};
void operator()() {func();}
operator fptr () { return func; }
~y () {++destroyed;}
};
// stateful functors/member functions should always copy unless specified
{
created = 0;
destroyed = 0;
last_call = nullptr;
{
sol::state lua;
x x1;
lua.set_function("x1copy", &x::func, x1);
lua.script("x1copy()");
REQUIRE(created == 2);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(last_call == &x1);
lua.set_function("x1ref", &x::func, std::ref(x1));
lua.script("x1ref()");
REQUIRE(created == 2);
REQUIRE(destroyed == 0);
REQUIRE(last_call == &x1);
}
REQUIRE(created == 2);
REQUIRE(destroyed == 2);
REQUIRE(created == destroyed);
}
// things convertible to a static function should _never_ be forced to make copies
// therefore, pass through untouched
{
created = 0;
destroyed = 0;
last_call = nullptr;
{
sol::state lua;
y y1;
lua.set_function("y1copy", y1);
lua.script("y1copy()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call);
last_call = nullptr;
lua.set_function("y1ref", std::ref(y1));
lua.script("y1ref()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
REQUIRE(created == destroyed);
}
}
TEST_CASE("usertype/destructor-tests", "Show that proper copies / destruction happens") {
static int created = 0;
static int destroyed = 0;
static void* last_call = nullptr;
struct x {
x() {++created;}
~x () {++destroyed;}
};
{
sol::state lua;
x x1;
x x2;
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
x& x1copyref = lua["x1copy"];
x& x2copyref = lua["x2copy"];
x& x1ref = lua["x1ref"];
REQUIRE(created == 4);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(last_call == &x1);
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
}
REQUIRE(created == 4);
REQUIRE(destroyed == 4);
REQUIRE(created == destroyed);
}