Fix for Issue #35

Userdata now properly forwards arguments to constructor
get_call now properly has extra parameters to allow for forwarding items from the first call that are not popped
Added tests to cover new cases
This commit is contained in:
ThePhD 2014-06-27 01:25:57 -07:00
parent 05dcba2fac
commit d35de4a8fa
6 changed files with 107 additions and 18 deletions

3
.gitignore vendored
View File

@ -25,3 +25,6 @@ lib/liblua5.2.a
*.includes *.includes
*.pyc *.pyc
main.cpp main.cpp
lua-5.2.3/
build.ninja
main.ninja

40
sol/default_construct.hpp Normal file
View File

@ -0,0 +1,40 @@
// The MIT License (MIT)
// Copyright (c) 2013 Danny Y., Rapptz
// 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_DEFAULT_CONSTRUCTOR_HPP
#define SOL_DEFAULT_CONSTRUCTOR_HPP
#include <memory>
#include "traits.hpp"
namespace sol {
struct default_construct {
template <typename T, typename... Args>
void operator()(T&& obj, Args&&... args) const {
std::allocator<Unqualified<T>> alloc{};
alloc.construct(obj, std::forward<Args>(args)...);
}
};
} // sol
#endif // SOL_DEFAULT_CONSTRUCTOR_HPP

View File

@ -220,7 +220,7 @@ struct pusher {
template<typename U = Unqualified<T>, EnableIf<Not<has_begin_end<U>>, Not<std::is_base_of<reference, U>>, Not<std::is_integral<U>>, Not<std::is_floating_point<U>>> = 0> template<typename U = Unqualified<T>, EnableIf<Not<has_begin_end<U>>, Not<std::is_base_of<reference, U>>, Not<std::is_integral<U>>, Not<std::is_floating_point<U>>> = 0>
static void push(lua_State* L, T&& t) { static void push(lua_State* L, T&& t) {
detail::push_userdata<U>(L, userdata_traits<T*>::metatable, std::move(t)); detail::push_userdata<U>(L, userdata_traits<T>::metatable, std::move(t));
} }
}; };
@ -378,8 +378,8 @@ inline auto ltr_get(lua_State*, int, F&& f, types<Args...>, types<>, Vs&&... vs)
return f(std::forward<Vs>(vs)...); return f(std::forward<Vs>(vs)...);
} }
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args> template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
inline auto ltr_get(lua_State* L, int index, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) { inline auto ltr_get(lua_State* L, int index, F&& f, types<Args...>, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
return ltr_get(L, index + 1, std::forward<F>(f), t, types<Tail...>(), std::forward<Vs>(vs)..., stack::get<Head>(L, index)); return ltr_get(L, index + 1, std::forward<F>(f), types<Args...>(), types<Tail...>(), std::forward<Vs>(vs)..., stack::get<Head>(L, index));
} }
template<typename F, typename... Vs, typename... Args> template<typename F, typename... Vs, typename... Args>
@ -427,14 +427,14 @@ inline void push_reverse(lua_State* L, std::tuple<Args...>&& tuplen) {
detail::push_tuple(L, build_reverse_indices<sizeof...(Args)>(), std::move(tuplen)); detail::push_tuple(L, build_reverse_indices<sizeof...(Args)>(), std::move(tuplen));
} }
template<typename... Args, typename TFx> template<typename... Args, typename TFx, typename... Vs>
inline auto get_call(lua_State* L, int index, TFx&& fx, types<Args...> t) -> decltype(detail::ltr_get(L, index, std::forward<TFx>(fx), t, t)) { inline auto get_call(lua_State* L, int index, TFx&& fx, types<Args...> t, Vs&&... vs) -> decltype(detail::ltr_get(L, index, std::forward<TFx>(fx), t, t, std::forward<Vs>(vs)...)) {
return detail::ltr_get(L, index, std::forward<TFx>(fx), t, t); return detail::ltr_get(L, index, std::forward<TFx>(fx), t, t, std::forward<Vs>(vs)...);
} }
template<typename... Args, typename TFx> template<typename TFx, typename... Args, typename... Vs>
inline auto get_call(lua_State* L, TFx&& fx, types<Args...> t) -> decltype(get_call(L, 1, std::forward<TFx>(fx), t)) { inline auto get_call(lua_State* L, TFx&& fx, types<Args...> t, Vs&&... vs) -> decltype(get_call(L, 1, std::forward<TFx>(fx), t, std::forward<Vs>(vs)...)) {
return get_call(L, 1, std::forward<TFx>(fx), t); return get_call(L, 1, std::forward<TFx>(fx), t, std::forward<Vs>(vs)...);
} }
template<typename... Args, typename TFx> template<typename... Args, typename TFx>

View File

@ -26,6 +26,9 @@
#include <type_traits> #include <type_traits>
namespace sol { namespace sol {
template <typename T>
struct identity { typedef T type; };
template<class T, class...> template<class T, class...>
struct are_same : std::true_type { }; struct are_same : std::true_type { };

View File

@ -25,6 +25,7 @@
#include "state.hpp" #include "state.hpp"
#include "function_types.hpp" #include "function_types.hpp"
#include "userdata_traits.hpp" #include "userdata_traits.hpp"
#include "default_construct.hpp"
#include <vector> #include <vector>
#include <array> #include <array>
#include <algorithm> #include <algorithm>
@ -56,11 +57,8 @@ private:
struct constructor { struct constructor {
template<typename... Args> template<typename... Args>
static void do_constructor(lua_State* L, T* obj, call_syntax syntax, int, types<Args...>) { static void do_constructor(lua_State* L, T* obj, call_syntax syntax, int, types<Args...>) {
auto fx = [&obj] (Args&&... args) -> void { default_construct fx{};
std::allocator<T> alloc{}; stack::get_call(L, 1 + static_cast<int>(syntax), fx, types<Args...>(), obj);
alloc.construct(obj, std::forward<Args>(args)...);
};
stack::get_call(L, 1 + static_cast<int>(syntax), fx, types<Args...>());
} }
static void match_constructor(lua_State*, T*, call_syntax, int) { static void match_constructor(lua_State*, T*, call_syntax, int) {
@ -83,7 +81,7 @@ private:
void* udata = lua_newuserdata(L, sizeof(T)); void* udata = lua_newuserdata(L, sizeof(T));
T* obj = static_cast<T*>(udata); T* obj = static_cast<T*>(udata);
match_constructor(L, obj, syntax, argcount - static_cast<int>(syntax), typename std::common_type<TTypes>::type()...); match_constructor(L, obj, syntax, argcount - static_cast<int>(syntax), typename identity<TTypes>::type()...);
if (luaL_newmetatable(L, std::addressof(meta[0])) == 1) { if (luaL_newmetatable(L, std::addressof(meta[0])) == 1) {

View File

@ -636,10 +636,14 @@ TEST_CASE("tables/issue-number-twenty-five", "Using pointers and references from
return x; return x;
} }
test* clone() { test* pget() {
return this; return this;
} }
test create_get() {
return *this;
}
int fun(int x) { int fun(int x) {
return x * 10; return x * 10;
} }
@ -647,10 +651,10 @@ TEST_CASE("tables/issue-number-twenty-five", "Using pointers and references from
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_userdata<test>("test", "set", &test::set, "get", &test::get, "clone", &test::clone, "fun", &test::fun); lua.new_userdata<test>("test", "set", &test::set, "get", &test::get, "pointer_get", &test::pget, "fun", &test::fun, "create_get", &test::create_get);
REQUIRE_NOTHROW(lua.script("x = test.new()\n" REQUIRE_NOTHROW(lua.script("x = test.new()\n"
"x:set():get()")); "x:set():get()"));
REQUIRE_NOTHROW(lua.script("y = x:clone()")); REQUIRE_NOTHROW(lua.script("y = x:pointer_get()"));
REQUIRE_NOTHROW(lua.script("y:set():get()")); REQUIRE_NOTHROW(lua.script("y:set():get()"));
REQUIRE_NOTHROW(lua.script("y:fun(10)")); REQUIRE_NOTHROW(lua.script("y:fun(10)"));
REQUIRE_NOTHROW(lua.script("x:fun(10)")); REQUIRE_NOTHROW(lua.script("x:fun(10)"));
@ -659,3 +663,44 @@ TEST_CASE("tables/issue-number-twenty-five", "Using pointers and references from
REQUIRE_NOTHROW(lua.script("assert(y:set():get() == y:set():get(), '...')")); REQUIRE_NOTHROW(lua.script("assert(y:set():get() == y:set():get(), '...')"));
REQUIRE_NOTHROW(lua.script("assert(y:set():get() == 10, '...')")); REQUIRE_NOTHROW(lua.script("assert(y:set():get() == 10, '...')"));
} }
TEST_CASE("userdata/issue-number-thirty-five", "using value types created from lua-called C++ code, fixing user-defined types with constructors") {
struct Vec {
float x, y, z;
Vec(float x, float y, float z) : x{x}, y{y}, z{z} {}
float length() {
return sqrtf(x*x + y*y + z*z);
}
Vec normalized() {
float invS = 1 / length();
return {x * invS, y * invS, z * invS};
}
};
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::userdata<Line> ludata("Line", lctor);
lua.set_userdata(ludata);
sol::constructors<sol::types<float, float, float>> ctor;
sol::userdata<Vec> udata("Vec", ctor,
"normalized", &Vec::normalized,
"length", &Vec::length);
lua.set_userdata(udata);
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n"
"print(v:length())"));
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n"
"print(v:normalized():length())" ));
}