mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Merge pull request #11 from ThePhD/master
operator[] support, the right way
This commit is contained in:
commit
68fc9bf35e
129
sol/proxy.hpp
Normal file
129
sol/proxy.hpp
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include "traits.hpp"
|
||||||
|
#include "object.hpp"
|
||||||
|
#include "function.hpp"
|
||||||
|
|
||||||
|
namespace sol {
|
||||||
|
template <typename Table, typename Key>
|
||||||
|
struct proxy {
|
||||||
|
private:
|
||||||
|
Table& tbl;
|
||||||
|
Key& key;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
proxy(Table& table, T&& key) : tbl(table), key(std::forward<T>(key)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T get() const {
|
||||||
|
return tbl.get<T>(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
proxy& set(T&& item) {
|
||||||
|
tbl.set(key, std::forward<T>(item));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
proxy& set_function(Args&&... args) {
|
||||||
|
tbl.set_function(key, std::forward<Args>(args)...);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
EnableIf<Function<Unqualified<U>>> operator=(U&& other) {
|
||||||
|
tbl.set_function(key, std::forward<U>(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
DisableIf<Function<Unqualified<U>>> operator=(U&& other) {
|
||||||
|
tbl.set(key, std::forward<U>(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
operator nil_t () const {
|
||||||
|
return get<nil_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator object() const {
|
||||||
|
return get<object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator function() const {
|
||||||
|
return get<function>();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator std::string() const {
|
||||||
|
return get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
|
operator bool() const {
|
||||||
|
return get<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
|
operator double() const {
|
||||||
|
return get<double>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
|
operator float() const {
|
||||||
|
return get<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
|
operator int() const {
|
||||||
|
return get<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Ret, typename... Args>
|
||||||
|
typename multi_return<Ret...>::type call(Args&&... args) {
|
||||||
|
return tbl.get<function>(key)(types<Ret...>(), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Table, typename Key, typename T>
|
||||||
|
inline bool operator== (T&& left, const proxy<Table, Key>& right) {
|
||||||
|
return left == right.template get<Decay<T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Table, typename Key, typename T>
|
||||||
|
inline bool operator== (const proxy<Table, Key>& right, T&& left) {
|
||||||
|
return right.template get<Decay<T>>() == left;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Table, typename Key, typename T>
|
||||||
|
inline bool operator!= (T&& left, const proxy<Table, Key>& right) {
|
||||||
|
return right.template get<Decay<T>>() != left;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Table, typename Key, typename T>
|
||||||
|
inline bool operator!= (const proxy<Table, Key>& right, T&& left) {
|
||||||
|
return right.template get<Decay<T>>() != left;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // sol
|
|
@ -173,6 +173,16 @@ public:
|
||||||
table registry() const {
|
table registry() const {
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
proxy<table, T> operator[](T&& key) {
|
||||||
|
return global[std::forward<T>(key)];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
proxy<const table, T> operator[](T&& key) const {
|
||||||
|
return global[std::forward<T>(key)];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#ifndef SOL_TABLE_HPP
|
#ifndef SOL_TABLE_HPP
|
||||||
#define SOL_TABLE_HPP
|
#define SOL_TABLE_HPP
|
||||||
|
|
||||||
|
#include "proxy.hpp"
|
||||||
#include "stack.hpp"
|
#include "stack.hpp"
|
||||||
#include "lua_function.hpp"
|
#include "lua_function.hpp"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
@ -117,6 +118,17 @@ public:
|
||||||
push();
|
push();
|
||||||
return lua_rawlen(state(), -1);
|
return lua_rawlen(state(), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
proxy<table, T> operator[](T&& key) {
|
||||||
|
return proxy<table, T>(*this, std::forward<T>(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
proxy<const table, T> operator[](T&& key) const {
|
||||||
|
return proxy<const table, T>(*this, std::forward<T>(key));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename T, typename TFx>
|
template<typename T, typename TFx>
|
||||||
table& set_isfunction_fx(std::true_type, T&& key, TFx&& fx) {
|
table& set_isfunction_fx(std::true_type, T&& key, TFx&& fx) {
|
||||||
|
|
|
@ -56,6 +56,32 @@ struct multi_return<> : types<>{
|
||||||
template<bool B>
|
template<bool B>
|
||||||
using Bool = std::integral_constant<bool, B>;
|
using Bool = std::integral_constant<bool, B>;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template<typename T, bool isclass = std::is_class<Unqualified<T>>::value>
|
||||||
|
struct is_function_impl : std::is_function<typename std::remove_pointer<T>::type> { };
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_function_impl<T, true> {
|
||||||
|
using yes = char;
|
||||||
|
using no = struct { char s[2]; };
|
||||||
|
|
||||||
|
struct F { void operator()(); };
|
||||||
|
struct Derived : T, F { };
|
||||||
|
template<typename U, U> struct Check;
|
||||||
|
|
||||||
|
template<typename V>
|
||||||
|
static no test(Check<void (F::*)(), &V::operator()>*);
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
static yes test(...);
|
||||||
|
|
||||||
|
static const bool value = sizeof(test<Derived>(0)) == sizeof(yes);
|
||||||
|
};
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Function : Bool<detail::is_function_impl<T>::value> { };
|
||||||
|
|
||||||
template<typename TFuncSignature>
|
template<typename TFuncSignature>
|
||||||
struct function_traits;
|
struct function_traits;
|
||||||
|
|
||||||
|
|
105
tests.cpp
105
tests.cpp
|
@ -56,7 +56,7 @@ TEST_CASE("simple/get", "Tests if the get function works properly.") {
|
||||||
REQUIRE(e == true);
|
REQUIRE(e == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("simple/addition", "") {
|
TEST_CASE("simple/addition", "check if addition works and can be gotten through lua.get and lua.set") {
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
|
|
||||||
lua.set("b", 0.2);
|
lua.set("b", 0.2);
|
||||||
|
@ -66,7 +66,7 @@ TEST_CASE("simple/addition", "") {
|
||||||
REQUIRE(c == 9.2);
|
REQUIRE(c == 9.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("simple/if", "") {
|
TEST_CASE("simple/if", "check if if statements work through lua") {
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
|
|
||||||
std::string program = "if true then f = 0.1 else f = 'test' end";
|
std::string program = "if true then f = 0.1 else f = 'test' end";
|
||||||
|
@ -74,9 +74,10 @@ TEST_CASE("simple/if", "") {
|
||||||
auto f = lua.get<double>("f");
|
auto f = lua.get<double>("f");
|
||||||
|
|
||||||
REQUIRE(f == 0.1);
|
REQUIRE(f == 0.1);
|
||||||
|
REQUIRE((f == lua["f"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("simple/callWithParameters", "Lua function is called with a few parameters from C++") {
|
TEST_CASE("simple/call_with_parameters", "Lua function is called with a few parameters from C++") {
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
|
|
||||||
REQUIRE_NOTHROW(lua.script("function my_add(i, j, k) return i + j + k end"));
|
REQUIRE_NOTHROW(lua.script("function my_add(i, j, k) return i + j + k end"));
|
||||||
|
@ -90,7 +91,7 @@ TEST_CASE("simple/callWithParameters", "Lua function is called with a few parame
|
||||||
REQUIRE_THROWS(a = f.call<int>(1, 2, "arf"));
|
REQUIRE_THROWS(a = f.call<int>(1, 2, "arf"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("simple/callCppFunction", "C++ function is called from lua") {
|
TEST_CASE("simple/call_c++_function", "C++ function is called from lua") {
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
|
|
||||||
lua.set_function("plop_xyz", plop_xyz);
|
lua.set_function("plop_xyz", plop_xyz);
|
||||||
|
@ -99,7 +100,7 @@ TEST_CASE("simple/callCppFunction", "C++ function is called from lua") {
|
||||||
REQUIRE(lua.get<int>("x") == 11);
|
REQUIRE(lua.get<int>("x") == 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("simple/callLambda", "A C++ lambda is exposed to lua and called") {
|
TEST_CASE("simple/call_lambda", "A C++ lambda is exposed to lua and called") {
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
@ -111,7 +112,7 @@ TEST_CASE("simple/callLambda", "A C++ lambda is exposed to lua and called") {
|
||||||
REQUIRE(x == 1);
|
REQUIRE(x == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("advanced/callLambdaReturns", "Checks for lambdas returning values") {
|
TEST_CASE("advanced/get_and_call", "Checks for lambdas returning values after a get operation") {
|
||||||
const static std::string lol = "lol", str = "str";
|
const static std::string lol = "lol", str = "str";
|
||||||
const static std::tuple<int, float, double, std::string> heh_tuple = std::make_tuple(1, 6.28f, 3.14, std::string("heh"));
|
const static std::tuple<int, float, double, std::string> heh_tuple = std::make_tuple(1, 6.28f, 3.14, std::string("heh"));
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
|
@ -146,7 +147,42 @@ TEST_CASE("advanced/callLambdaReturns", "Checks for lambdas returning values") {
|
||||||
REQUIRE((lua.get<sol::function>("j").call<int, float, double, std::string>() == heh_tuple));
|
REQUIRE((lua.get<sol::function>("j").call<int, float, double, std::string>() == heh_tuple));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("advanced/callLambda2", "A C++ lambda is exposed to lua and called") {
|
TEST_CASE("advanced/operator[]_calls", "Checks for lambdas returning values using operator[]") {
|
||||||
|
const static std::string lol = "lol", str = "str";
|
||||||
|
const static std::tuple<int, float, double, std::string> heh_tuple = std::make_tuple(1, 6.28f, 3.14, std::string("heh"));
|
||||||
|
sol::state lua;
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(lua.set_function("a", [] { return 42; }));
|
||||||
|
REQUIRE(lua["a"].call<int>() == 42);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(lua.set_function("b", [] { return 42u; }));
|
||||||
|
REQUIRE(lua["b"].call<unsigned int>() == 42u);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(lua.set_function("c", [] { return 3.14; }));
|
||||||
|
REQUIRE(lua["c"].call<double>() == 3.14);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(lua.set_function("d", [] { return 6.28f; }));
|
||||||
|
REQUIRE(lua["d"].call<float>() == 6.28f);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(lua.set_function("e", [] { return "lol"; }));
|
||||||
|
REQUIRE(lua["e"].call<std::string>() == lol);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(lua.set_function("f", [] { return true; }));
|
||||||
|
REQUIRE(lua["f"].call<bool>());
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(lua.set_function("g", [] { return std::string("str"); }));
|
||||||
|
REQUIRE(lua["g"].call<std::string>() == str);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(lua.set_function("h", [] { }));
|
||||||
|
REQUIRE_NOTHROW(lua["h"].call());
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(lua.set_function("i", [] { return sol::nil; }));
|
||||||
|
REQUIRE(lua["i"].call<sol::nil_t>() == sol::nil);
|
||||||
|
REQUIRE_NOTHROW(lua.set_function("j", [] { return std::make_tuple(1, 6.28f, 3.14, std::string("heh")); }));
|
||||||
|
REQUIRE((lua["j"].call<int, float, double, std::string>() == heh_tuple));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("advanced/call_lambdas", "A C++ lambda is exposed to lua and called") {
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
@ -159,13 +195,13 @@ TEST_CASE("advanced/callLambda2", "A C++ lambda is exposed to lua and called") {
|
||||||
REQUIRE(x == 9);
|
REQUIRE(x == 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("negative/basicError", "Check if error handling works correctly") {
|
TEST_CASE("negative/basic_errors", "Check if error handling works correctly") {
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
|
|
||||||
REQUIRE_THROWS(lua.script("nil[5]"));
|
REQUIRE_THROWS(lua.script("nil[5]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("libraries", "Check if we can open libraries through sol") {
|
TEST_CASE("libraries", "Check if we can open libraries") {
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
REQUIRE_NOTHROW(lua.open_libraries(sol::lib::base, sol::lib::os));
|
REQUIRE_NOTHROW(lua.open_libraries(sol::lib::base, sol::lib::os));
|
||||||
}
|
}
|
||||||
|
@ -237,3 +273,54 @@ TEST_CASE("functions/return_order_and_multi_get", "Check if return order is in t
|
||||||
REQUIRE(tlua == triple);
|
REQUIRE(tlua == triple);
|
||||||
REQUIRE(tluaget == triple);
|
REQUIRE(tluaget == triple);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works properly") {
|
||||||
|
sol::state lua;
|
||||||
|
lua.open_libraries(sol::lib::base);
|
||||||
|
|
||||||
|
lua.script("foo = 20\nbar = \"hello world\"");
|
||||||
|
// basic retrieval
|
||||||
|
std::string bar = lua["bar"];
|
||||||
|
int foo = lua["foo"];
|
||||||
|
REQUIRE(bar == "hello world");
|
||||||
|
REQUIRE(foo == 20);
|
||||||
|
// test operator= for stringification
|
||||||
|
// errors due to ambiguous operators
|
||||||
|
bar = lua["bar"];
|
||||||
|
|
||||||
|
// basic setting
|
||||||
|
lua["bar"] = 20.4;
|
||||||
|
lua["foo"] = "goodbye";
|
||||||
|
|
||||||
|
// doesn't modify the actual values obviously.
|
||||||
|
REQUIRE(bar == "hello world");
|
||||||
|
REQUIRE(foo == 20);
|
||||||
|
|
||||||
|
// function setting
|
||||||
|
lua["test"] = plop_xyz;
|
||||||
|
REQUIRE_NOTHROW(lua.script("assert(test(10, 11, \"hello\") == 11)"));
|
||||||
|
|
||||||
|
// function retrieval
|
||||||
|
sol::function test = lua["test"];
|
||||||
|
REQUIRE(test.call<int>(10, 11, "hello") == 11);
|
||||||
|
|
||||||
|
// setting a lambda
|
||||||
|
lua["lamb"] = [](int x) {
|
||||||
|
return x * 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(lua.script("assert(lamb(220) == 440)"));
|
||||||
|
|
||||||
|
// function retrieval of a lambda
|
||||||
|
sol::function lamb = lua["lamb"];
|
||||||
|
REQUIRE(lamb.call<int>(220) == 440);
|
||||||
|
|
||||||
|
// test const table retrieval
|
||||||
|
auto assert1 = [](const sol::table& t) {
|
||||||
|
std::string a = t["foo"];
|
||||||
|
int b = t["bar"];
|
||||||
|
std::cout << a << ',' << b << '\n';
|
||||||
|
};
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(assert1(lua.global_table()));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user