Allow for checking whether or not a given proxy is valid.

This commit is contained in:
ThePhD 2016-03-25 05:27:19 -04:00
parent 4f99b99ee9
commit 68660a1bed
8 changed files with 142 additions and 4 deletions

View File

@ -3,7 +3,7 @@
You can adapt this file completely to your liking, but it should at least You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive. contain the root `toctree` directive.
Sol 2.0 Sol 2.1
======= =======
a fast, simple C++ and Lua Binding a fast, simple C++ and Lua Binding
---------------------------------- ----------------------------------

View File

@ -93,6 +93,12 @@ public:
decltype(auto) operator()(Args&&... args) { decltype(auto) operator()(Args&&... args) {
return call<>(std::forward<Args>(args)...); return call<>(std::forward<Args>(args)...);
} }
bool valid () const {
auto p = stack::probe_get_field<std::is_same<meta::Unqualified<Table>, global_table>::value>(tbl.lua_state(), key);
lua_pop(tbl.lua_state(), p.levels);
return p;
}
}; };
template<typename Table, typename Key, typename T> template<typename Table, typename Key, typename T>
@ -115,6 +121,26 @@ inline bool operator!=(const proxy<Table, Key>& right, T&& left) {
return right.template get<std::decay_t<T>>() != left; return right.template get<std::decay_t<T>>() != left;
} }
template<typename Table, typename Key>
inline bool operator==(nil_t left, const proxy<Table, Key>& right) {
return !right.valid();
}
template<typename Table, typename Key>
inline bool operator==(const proxy<Table, Key>& right, nil_t) {
return !right.valid();
}
template<typename Table, typename Key>
inline bool operator!=(nil_t, const proxy<Table, Key>& right) {
return right.valid();
}
template<typename Table, typename Key>
inline bool operator!=(const proxy<Table, Key>& right, nil_t) {
return right.valid();
}
namespace stack { namespace stack {
template <typename Table, typename Key> template <typename Table, typename Key>
struct pusher<proxy<Table, Key>> { struct pusher<proxy<Table, Key>> {

View File

@ -27,8 +27,6 @@
#include "stack.hpp" #include "stack.hpp"
namespace sol { namespace sol {
template <typename T>
struct idn { typedef T type; };
template <typename Super> template <typename Super>
struct proxy_base { struct proxy_base {
operator std::string() const { operator std::string() const {

View File

@ -29,6 +29,7 @@
#include "stack_push.hpp" #include "stack_push.hpp"
#include "stack_pop.hpp" #include "stack_pop.hpp"
#include "stack_field.hpp" #include "stack_field.hpp"
#include "stack_probe.hpp"
#include <cstring> #include <cstring>
#include <array> #include <array>

View File

@ -55,6 +55,8 @@ template<typename T, bool global = false, typename = void>
struct field_getter; struct field_getter;
template<typename T, bool global = false, typename = void> template<typename T, bool global = false, typename = void>
struct field_setter; struct field_setter;
template <typename T, bool global = false, typename = void>
struct probe_field_getter;
template<typename T, typename = void> template<typename T, typename = void>
struct getter; struct getter;
template<typename T, typename = void> template<typename T, typename = void>
@ -66,6 +68,15 @@ struct checker;
template<typename T, typename = void> template<typename T, typename = void>
struct check_getter; struct check_getter;
struct probe {
bool success;
int levels;
probe(bool s, int l) : success(s), levels(l) {}
operator bool() const { return success; };
};
namespace stack_detail { namespace stack_detail {
template <typename T> template <typename T>
struct strip { struct strip {
@ -93,6 +104,11 @@ inline decltype(auto) unchecked_get(lua_State* L, int index = -1) {
} }
} // stack_detail } // stack_detail
inline bool maybe_indexable(lua_State* L, int index = -1) {
type t = type_of(L, index);
return t == type::userdata || t == type::table;
}
template<typename T, typename... Args> template<typename T, typename... Args>
inline int push(lua_State* L, T&& t, Args&&... args) { inline int push(lua_State* L, T&& t, Args&&... args) {
return pusher<meta::Unqualified<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...); return pusher<meta::Unqualified<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
@ -168,6 +184,16 @@ void get_field(lua_State* L, Key&& key, int tableindex) {
field_getter<meta::Unqualified<Key>, global>{}.get(L, std::forward<Key>(key), tableindex); field_getter<meta::Unqualified<Key>, global>{}.get(L, std::forward<Key>(key), tableindex);
} }
template <bool global = false, typename Key>
probe probe_get_field(lua_State* L, Key&& key) {
return probe_field_getter<meta::Unqualified<Key>, global>{}.get(L, std::forward<Key>(key));
}
template <bool global = false, typename Key>
probe probe_get_field(lua_State* L, Key&& key, int tableindex) {
return probe_field_getter<meta::Unqualified<Key>, global>{}.get(L, std::forward<Key>(key), tableindex);
}
template <bool global = false, typename Key, typename Value> template <bool global = false, typename Key, typename Value>
void set_field(lua_State* L, Key&& key, Value&& value) { void set_field(lua_State* L, Key&& key, Value&& value) {
field_setter<meta::Unqualified<Key>, global>{}.set(L, std::forward<Key>(key), std::forward<Value>(value)); field_setter<meta::Unqualified<Key>, global>{}.set(L, std::forward<Key>(key), std::forward<Value>(value));

View File

@ -42,7 +42,6 @@ template <typename... Args, bool b, typename C>
struct field_getter<std::tuple<Args...>, b, C> { struct field_getter<std::tuple<Args...>, b, C> {
template <std::size_t... I, typename Keys> template <std::size_t... I, typename Keys>
void apply(std::index_sequence<I...>, lua_State* L, Keys&& keys, int tableindex) { void apply(std::index_sequence<I...>, lua_State* L, Keys&& keys, int tableindex) {
tableindex = lua_absindex(L, tableindex);
void(detail::swallow{ (get_field<I < 1 && b>(L, detail::forward_get<I>(keys), tableindex), 0)... }); void(detail::swallow{ (get_field<I < 1 && b>(L, detail::forward_get<I>(keys), tableindex), 0)... });
reference saved(L, -1); reference saved(L, -1);
lua_pop(L, static_cast<int>(sizeof...(I))); lua_pop(L, static_cast<int>(sizeof...(I)));
@ -51,6 +50,7 @@ struct field_getter<std::tuple<Args...>, b, C> {
template <typename Keys> template <typename Keys>
void get(lua_State* L, Keys&& keys, int tableindex = -2) { void get(lua_State* L, Keys&& keys, int tableindex = -2) {
tableindex = lua_absindex(L, tableindex);
apply(std::index_sequence_for<Args...>(), L, std::forward<Keys>(keys), tableindex); apply(std::index_sequence_for<Args...>(), L, std::forward<Keys>(keys), tableindex);
} }
}; };

65
sol/stack_probe.hpp Normal file
View File

@ -0,0 +1,65 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD 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_STACK_PROBE_HPP
#define SOL_STACK_PROBE_HPP
#include "stack_core.hpp"
#include "stack_field.hpp"
#include "stack_check.hpp"
namespace sol {
namespace stack {
template <typename T, bool b, typename>
struct probe_field_getter {
template <typename Key>
probe get(lua_State* L, Key&& key, int tableindex = -2) {
get_field<b>(L, std::forward<Key>(key), tableindex);
return probe(!check<nil_t>(L), 1);
}
};
template <typename... Args, bool b, typename C>
struct probe_field_getter<std::tuple<Args...>, b, C> {
template <std::size_t I, typename Keys>
probe apply(std::index_sequence<I>, int sofar, lua_State* L, Keys&& keys, int tableindex) {
get_field<I < 1 && b>(L, std::get<I>(keys), tableindex);
return probe(!check<nil_t>(L), sofar);
}
template <std::size_t I, std::size_t... In, typename Keys>
probe apply(std::index_sequence<I, In...>, int sofar, lua_State* L, Keys&& keys, int tableindex) {
get_field<I < 1 && b>(L, std::get<I>(keys), tableindex);
if (!maybe_indexable(L)) {
return probe(false, sofar);
}
return apply(std::index_sequence<In...>(), sofar + 1, L, std::forward<Keys>(keys), tableindex);
}
template <typename Keys>
probe get(lua_State* L, Keys&& keys, int tableindex = -2) {
return apply(std::index_sequence_for<Args...>(), 1, L, std::forward<Keys>(keys), tableindex);
}
};
} // stack
} // sol
#endif // SOL_STACK_PROBE_HPP

View File

@ -651,6 +651,28 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
REQUIRE_NOTHROW(assert1(lua.globals())); REQUIRE_NOTHROW(assert1(lua.globals()));
} }
TEST_CASE("tables/operator[]-valid", "Test if proxies on tables can lazily evaluate validity") {
sol::state lua;
bool isFullScreen = false;
auto fullscreennopers = lua["fullscreen"]["nopers"];
auto fullscreen = lua["fullscreen"];
REQUIRE_FALSE(fullscreennopers.valid());
REQUIRE_FALSE(fullscreen.valid());
lua["fullscreen"] = true;
REQUIRE_FALSE(fullscreennopers.valid());
REQUIRE(fullscreen.valid());
isFullScreen = lua["fullscreen"];
REQUIRE(isFullScreen);
lua["fullscreen"] = false;
REQUIRE_FALSE(fullscreennopers.valid());
REQUIRE(fullscreen.valid());
isFullScreen = lua["fullscreen"];
REQUIRE_FALSE(isFullScreen);
}
TEST_CASE("tables/usertype", "Show that we can create classes from usertype and use them") { TEST_CASE("tables/usertype", "Show that we can create classes from usertype and use them") {
sol::state lua; sol::state lua;