Change how proxies are done for the sake of efficiency.

This commit is contained in:
ThePhD 2019-09-15 00:43:44 -04:00
parent b2c22ea8fe
commit bafac3abbd
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
20 changed files with 456 additions and 284 deletions

View File

@ -17,7 +17,7 @@ The library is header-only for easy integration with projects.
## Documentation
Find it [here](http://sol2.rtfd.io/). A run-through kind of tutorial is [here](http://sol2.readthedocs.io/en/latest/tutorial/all-the-things.html)! The API documentation goes over most cases (particularly, the "api/usertype" and "api/proxy" and "api/function" sections) that should still get you off your feet and going, and there's an examples directory [here](https://github.com/ThePhD/sol2/tree/develop/examples) as well.
Find it [here](http://sol2.rtfd.io/). A run-through kind of tutorial is [here](http://sol2.readthedocs.io/en/latest/tutorial/all-the-things.html)! The API documentation goes over most cases (particularly, the "api/usertype" and "api/table_proxy" and "api/function" sections) that should still get you off your feet and going, and there's an examples directory [here](https://github.com/ThePhD/sol2/tree/develop/examples) as well.
## Sneak Peek

View File

@ -19,7 +19,7 @@ int main () {
lua.open_libraries(sol::lib::base);
lua.script(code);
// produces proxy, implicitly converts to std::string, quietly destroys proxy
// produces table_proxy, implicitly converts to std::string, quietly destroys table_proxy
std::string arf_string = lua["bark"]["woof"][2];
// lazy-evaluation of tables

View File

@ -59,7 +59,7 @@ namespace sol {
template <typename>
struct proxy_base;
template <typename, typename>
struct proxy;
struct table_proxy;
template <bool, typename>
class basic_table_core;

View File

@ -682,12 +682,12 @@ namespace sol {
}
template <typename T>
proxy<global_table&, detail::proxy_key_t<T>> operator[](T&& key) {
table_proxy<global_table&, detail::proxy_key_t<T>> operator[](T&& key) {
return global[std::forward<T>(key)];
}
template <typename T>
proxy<const global_table&, detail::proxy_key_t<T>> operator[](T&& key) const {
table_proxy<const global_table&, detail::proxy_key_t<T>> operator[](T&& key) const {
return global[std::forward<T>(key)];
}

View File

@ -24,7 +24,7 @@
#ifndef SOL_TABLE_CORE_HPP
#define SOL_TABLE_CORE_HPP
#include "proxy.hpp"
#include "table_proxy.hpp"
#include "stack.hpp"
#include "function_types.hpp"
#include "table_iterator.hpp"
@ -575,17 +575,17 @@ namespace sol {
template <typename T>
auto operator[](T&& key) & {
return proxy<basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));
return table_proxy<basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));
}
template <typename T>
auto operator[](T&& key) const& {
return proxy<const basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));
return table_proxy<const basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));
}
template <typename T>
auto operator[](T&& key) && {
return proxy<basic_table_core, detail::proxy_key_t<T>>(std::move(*this), std::forward<T>(key));
return table_proxy<basic_table_core, detail::proxy_key_t<T>>(std::move(*this), std::forward<T>(key));
}
template <typename Sig, typename Key, typename... Args>

View File

@ -21,8 +21,8 @@
// 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_HPP
#define SOL_PROXY_HPP
#ifndef SOL_TABLE_PROXY_HPP
#define SOL_TABLE_PROXY_HPP
#include "traits.hpp"
#include "function.hpp"
@ -32,12 +32,12 @@
namespace sol {
template <typename Table, typename Key>
struct proxy : public proxy_base<proxy<Table, Key>> {
struct table_proxy : public proxy_base<table_proxy<Table, Key>> {
private:
using key_type = detail::proxy_key_t<Key>;
template <typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) const & {
decltype(auto) tuple_get(std::index_sequence<I...>) const& {
return tbl.template traverse_get<T>(std::get<I>(key)...);
}
@ -74,36 +74,35 @@ namespace sol {
key_type key;
template <typename T>
proxy(Table table, T&& k)
: tbl(table), key(std::forward<T>(k)) {
table_proxy(Table table, T&& k) : tbl(table), key(std::forward<T>(k)) {
}
template <typename T>
proxy& set(T&& item) & {
table_proxy& set(T&& item) & {
tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
return *this;
}
template <typename T>
proxy&& set(T&& item) && {
table_proxy&& set(T&& item) && {
tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
return std::move(*this);
}
template <typename... Args>
proxy& set_function(Args&&... args) & {
table_proxy& set_function(Args&&... args) & {
tbl.set_function(key, std::forward<Args>(args)...);
return *this;
}
template <typename... Args>
proxy&& set_function(Args&&... args) && {
table_proxy&& set_function(Args&&... args) && {
tbl.set_function(std::move(key), std::forward<Args>(args)...);
return std::move(*this);
}
template <typename T>
proxy& operator=(T&& other) & {
table_proxy& operator=(T&& other) & {
using Tu = meta::unwrap_unqualified_t<T>;
if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {
return set_function(std::forward<T>(other));
@ -114,7 +113,7 @@ namespace sol {
}
template <typename T>
proxy&& operator=(T&& other) && {
table_proxy&& operator=(T&& other) && {
using Tu = meta::unwrap_unqualified_t<T>;
if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {
return std::move(*this).set_function(std::forward<T>(other));
@ -125,17 +124,17 @@ namespace sol {
}
template <typename T>
proxy& operator=(std::initializer_list<T> other) & {
table_proxy& operator=(std::initializer_list<T> other) & {
return set(std::move(other));
}
template <typename T>
proxy&& operator=(std::initializer_list<T> other) && {
table_proxy&& operator=(std::initializer_list<T> other) && {
return std::move(*this).set(std::move(other));
}
template <typename T>
decltype(auto) get() const & {
decltype(auto) get() const& {
using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
return tuple_get<T>(idx_seq());
}
@ -165,7 +164,7 @@ namespace sol {
return static_cast<T>(std::forward<D>(otherwise));
}
template <typename T>
decltype(auto) get_or_create() {
return get_or_create<T>(new_table());
@ -182,29 +181,28 @@ namespace sol {
template <typename K>
decltype(auto) operator[](K&& k) const& {
auto keys = meta::tuplefy(key, std::forward<K>(k));
return proxy<Table, decltype(keys)>(tbl, std::move(keys));
return table_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename K>
decltype(auto) operator[](K&& k) & {
auto keys = meta::tuplefy(key, std::forward<K>(k));
return proxy<Table, decltype(keys)>(tbl, std::move(keys));
return table_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename K>
decltype(auto) operator[](K&& k) && {
auto keys = meta::tuplefy(std::move(key), std::forward<K>(k));
return proxy<Table, decltype(keys)>(tbl, std::move(keys));
return table_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
#if !defined(__clang__) && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000
// MSVC is ass sometimes
return get<function>().call<Ret...>(std::forward<Args>(args)...);
#else
return get<function>().template call<Ret...>(std::forward<Args>(args)...);
#endif
lua_State* L = this->lua_state();
push(L);
int idx = lua_gettop(L);
stack_aligned_function func(L, idx);
return func.call<Ret...>(std::forward<Args>(args)...);
}
template <typename... Args>
@ -224,7 +222,22 @@ namespace sol {
}
int push(lua_State* L) const noexcept {
return get<reference>().push(L);
if constexpr (std::is_same_v<meta::unqualified_t<Table>, global_table> || is_stack_table_v<meta::unqualified_t<Table>>) {
auto pp = stack::push_pop<true>(tbl);
int top_index = lua_gettop(L);
stack::get_field<true>(lua_state(), key, -1);
lua_replace(L, top_index + 1);
lua_settop(L, top_index + 1);
}
else {
auto pp = stack::push_pop<false>(tbl);
int tableindex = pp.index_of(tbl);
int aftertableindex = lua_gettop(L);
stack::get_field<false>(lua_state(), key, tableindex);
lua_replace(L, tableindex);
lua_settop(L, aftertableindex + 1);
}
return 1;
}
type get_type() const {
@ -242,7 +255,7 @@ namespace sol {
return tbl.lua_state();
}
proxy& force() {
table_proxy& force() {
if (!this->valid()) {
this->set(new_table());
}
@ -251,46 +264,46 @@ namespace sol {
};
template <typename Table, typename Key, typename T>
inline bool operator==(T&& left, const proxy<Table, Key>& right) {
inline bool operator==(T&& left, const table_proxy<Table, Key>& right) {
using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<G>>() == left;
}
template <typename Table, typename Key, typename T>
inline bool operator==(const proxy<Table, Key>& right, T&& left) {
inline bool operator==(const table_proxy<Table, Key>& right, T&& left) {
using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<G>>() == left;
}
template <typename Table, typename Key, typename T>
inline bool operator!=(T&& left, const proxy<Table, Key>& right) {
inline bool operator!=(T&& left, const table_proxy<Table, Key>& right) {
using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<G>>() != left;
}
template <typename Table, typename Key, typename T>
inline bool operator!=(const proxy<Table, Key>& right, T&& left) {
inline bool operator!=(const table_proxy<Table, Key>& right, T&& left) {
using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<G>>() != left;
}
template <typename Table, typename Key>
inline bool operator==(lua_nil_t, const proxy<Table, Key>& right) {
inline bool operator==(lua_nil_t, const table_proxy<Table, Key>& right) {
return !right.valid();
}
template <typename Table, typename Key>
inline bool operator==(const proxy<Table, Key>& right, lua_nil_t) {
inline bool operator==(const table_proxy<Table, Key>& right, lua_nil_t) {
return !right.valid();
}
template <typename Table, typename Key>
inline bool operator!=(lua_nil_t, const proxy<Table, Key>& right) {
inline bool operator!=(lua_nil_t, const table_proxy<Table, Key>& right) {
return right.valid();
}
template <typename Table, typename Key>
inline bool operator!=(const proxy<Table, Key>& right, lua_nil_t) {
inline bool operator!=(const table_proxy<Table, Key>& right, lua_nil_t) {
return right.valid();
}
@ -312,13 +325,12 @@ namespace sol {
namespace stack {
template <typename Table, typename Key>
struct unqualified_pusher<proxy<Table, Key>> {
static int push(lua_State* L, const proxy<Table, Key>& p) {
reference r = p;
return r.push(L);
struct unqualified_pusher<table_proxy<Table, Key>> {
static int push(lua_State* L, const table_proxy<Table, Key>& p) {
return p.push(L);
}
};
} // namespace stack
} // namespace sol
#endif // SOL_PROXY_HPP
#endif // SOL_TABLE_PROXY_HPP

View File

@ -422,7 +422,7 @@ namespace sol {
struct as_container_t {
private:
T value_;
public:
using type = T;
@ -504,7 +504,7 @@ namespace sol {
return std::move(value_);
}
const T& value() const & {
const T& value() const& {
return value_;
}
};
@ -867,16 +867,14 @@ namespace sol {
}
template <typename T>
struct is_lua_reference : std::integral_constant<bool,
std::is_base_of_v<reference, T> || std::is_base_of_v<main_reference, T>
|| std::is_base_of_v<stack_reference, T>> {};
struct is_lua_reference
: std::integral_constant<bool, std::is_base_of_v<reference, T> || std::is_base_of_v<main_reference, T> || std::is_base_of_v<stack_reference, T>> {};
template <typename T>
inline constexpr bool is_lua_reference_v = is_lua_reference<T>::value;
template <typename T>
struct is_lua_reference_or_proxy
: std::integral_constant<bool, is_lua_reference_v<T> || meta::is_specialization_of_v<T, proxy>> {};
struct is_lua_reference_or_proxy : std::integral_constant<bool, is_lua_reference_v<T> || meta::is_specialization_of_v<T, table_proxy>> {};
template <typename T>
inline constexpr bool is_lua_reference_or_proxy_v = is_lua_reference_or_proxy<T>::value;
@ -901,7 +899,8 @@ namespace sol {
template <typename T>
struct is_container
: std::integral_constant<bool,
!std::is_same_v<state_view, T> && !std::is_same_v<state, T> && !meta::is_initializer_list_v<T> && !meta::is_string_like_v<T> && !meta::is_string_literal_array_v<T> && !is_transparent_argument_v<T> && !is_lua_reference_v<T> && (meta::has_begin_end_v<T> || std::is_array_v<T>)> {
!std::is_same_v<state_view,
T> && !std::is_same_v<state, T> && !meta::is_initializer_list_v<T> && !meta::is_string_like_v<T> && !meta::is_string_literal_array_v<T> && !is_transparent_argument_v<T> && !is_lua_reference_v<T> && (meta::has_begin_end_v<T> || std::is_array_v<T>)> {
};
template <typename T>
@ -1098,7 +1097,8 @@ namespace sol {
struct lua_type_of<T*> : std::integral_constant<type, type::userdata> {};
template <typename T>
struct lua_type_of<T, std::enable_if_t<std::is_arithmetic_v<T> || std::is_same_v<T, lua_Number> || std::is_same_v<T, lua_Integer>>> : std::integral_constant<type, type::number> {};
struct lua_type_of<T, std::enable_if_t<std::is_arithmetic_v<T> || std::is_same_v<T, lua_Number> || std::is_same_v<T, lua_Integer>>>
: std::integral_constant<type, type::number> {};
template <typename T>
struct lua_type_of<T, std::enable_if_t<std::is_enum_v<T>>> : std::integral_constant<type, type::number> {};
@ -1114,8 +1114,7 @@ namespace sol {
#endif // SOL_CXX17_FEATURES
template <typename T>
struct lua_type_of<nested<T>>
: meta::conditional_t<::sol::is_container_v<T>, std::integral_constant<type, type::table>, lua_type_of<T>> {};
struct lua_type_of<nested<T>> : meta::conditional_t<::sol::is_container_v<T>, std::integral_constant<type, type::table>, lua_type_of<T>> {};
template <typename C, C v, template <typename...> class V, typename... Args>
struct accumulate : std::integral_constant<C, v> {};
@ -1172,11 +1171,10 @@ namespace sol {
template <typename T>
struct is_lua_primitive
: std::integral_constant<bool,
type::userdata != lua_type_of_v<T>
|| ((type::userdata == lua_type_of_v<T>) && detail::has_internal_marker_v<lua_type_of<T>>
&& !detail::has_internal_marker_v<lua_size<T>>)
|| is_lua_reference_v<T> || meta::is_specialization_of_v<T, std::tuple>
|| meta::is_specialization_of_v<T, std::pair>> {};
type::userdata
!= lua_type_of_v<
T> || ((type::userdata == lua_type_of_v<T>)&&detail::has_internal_marker_v<lua_type_of<T>> && !detail::has_internal_marker_v<lua_size<T>>)
|| is_lua_reference_or_proxy_v<T> || meta::is_specialization_of_v<T, std::tuple> || meta::is_specialization_of_v<T, std::pair>> {};
template <typename T>
constexpr inline bool is_lua_primitive_v = is_lua_primitive<T>::value;
@ -1265,6 +1263,16 @@ namespace sol {
template <typename T>
inline constexpr bool is_table_v = is_table<T>::value;
template <typename T>
struct is_stack_table : std::false_type {};
template <bool x, typename T>
struct is_stack_table<basic_table_core<x, T>> : std::integral_constant<bool, std::is_base_of_v<stack_reference, T>> {};
template <typename T>
struct is_stack_table<basic_lua_table<T>> : std::integral_constant<bool, std::is_base_of_v<stack_reference, T>> {};
template <typename T>
inline constexpr bool is_stack_table_v = is_stack_table<T>::value;
template <typename T>
struct is_function : std::false_type {};
template <typename T, bool aligned>
@ -1300,7 +1308,8 @@ namespace sol {
template <typename T>
struct is_automagical
: std::integral_constant<bool,
std::is_array_v<meta::unqualified_t<T>> || !std::is_same_v<meta::unqualified_t<T>, state> || !std::is_same_v<meta::unqualified_t<T>, state_view>> {};
std::is_array_v<meta::unqualified_t<T>> || !std::is_same_v<meta::unqualified_t<T>, state> || !std::is_same_v<meta::unqualified_t<T>, state_view>> {
};
template <typename T>
inline type type_of() {

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2019-09-08 23:53:48.445628 UTC
// This header was generated with sol v3.0.3 (revision 29c03ea)
// Generated 2019-09-15 04:36:38.687873 UTC
// This header was generated with sol v3.0.3 (revision b2c22ea)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
@ -281,7 +281,7 @@ namespace sol {
template <typename>
struct proxy_base;
template <typename, typename>
struct proxy;
struct table_proxy;
template <bool, typename>
class basic_table_core;

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2019-09-08 23:53:47.830273 UTC
// This header was generated with sol v3.0.3 (revision 29c03ea)
// Generated 2019-09-15 04:36:35.549872 UTC
// This header was generated with sol v3.0.3 (revision b2c22ea)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -307,7 +307,7 @@ namespace sol {
template <typename>
struct proxy_base;
template <typename, typename>
struct proxy;
struct table_proxy;
template <bool, typename>
class basic_table_core;
@ -6649,7 +6649,7 @@ namespace sol {
struct as_container_t {
private:
T value_;
public:
using type = T;
@ -6731,7 +6731,7 @@ namespace sol {
return std::move(value_);
}
const T& value() const & {
const T& value() const& {
return value_;
}
};
@ -7094,16 +7094,14 @@ namespace sol {
}
template <typename T>
struct is_lua_reference : std::integral_constant<bool,
std::is_base_of_v<reference, T> || std::is_base_of_v<main_reference, T>
|| std::is_base_of_v<stack_reference, T>> {};
struct is_lua_reference
: std::integral_constant<bool, std::is_base_of_v<reference, T> || std::is_base_of_v<main_reference, T> || std::is_base_of_v<stack_reference, T>> {};
template <typename T>
inline constexpr bool is_lua_reference_v = is_lua_reference<T>::value;
template <typename T>
struct is_lua_reference_or_proxy
: std::integral_constant<bool, is_lua_reference_v<T> || meta::is_specialization_of_v<T, proxy>> {};
struct is_lua_reference_or_proxy : std::integral_constant<bool, is_lua_reference_v<T> || meta::is_specialization_of_v<T, table_proxy>> {};
template <typename T>
inline constexpr bool is_lua_reference_or_proxy_v = is_lua_reference_or_proxy<T>::value;
@ -7128,7 +7126,8 @@ namespace sol {
template <typename T>
struct is_container
: std::integral_constant<bool,
!std::is_same_v<state_view, T> && !std::is_same_v<state, T> && !meta::is_initializer_list_v<T> && !meta::is_string_like_v<T> && !meta::is_string_literal_array_v<T> && !is_transparent_argument_v<T> && !is_lua_reference_v<T> && (meta::has_begin_end_v<T> || std::is_array_v<T>)> {
!std::is_same_v<state_view,
T> && !std::is_same_v<state, T> && !meta::is_initializer_list_v<T> && !meta::is_string_like_v<T> && !meta::is_string_literal_array_v<T> && !is_transparent_argument_v<T> && !is_lua_reference_v<T> && (meta::has_begin_end_v<T> || std::is_array_v<T>)> {
};
template <typename T>
@ -7325,7 +7324,8 @@ namespace sol {
struct lua_type_of<T*> : std::integral_constant<type, type::userdata> {};
template <typename T>
struct lua_type_of<T, std::enable_if_t<std::is_arithmetic_v<T> || std::is_same_v<T, lua_Number> || std::is_same_v<T, lua_Integer>>> : std::integral_constant<type, type::number> {};
struct lua_type_of<T, std::enable_if_t<std::is_arithmetic_v<T> || std::is_same_v<T, lua_Number> || std::is_same_v<T, lua_Integer>>>
: std::integral_constant<type, type::number> {};
template <typename T>
struct lua_type_of<T, std::enable_if_t<std::is_enum_v<T>>> : std::integral_constant<type, type::number> {};
@ -7341,8 +7341,7 @@ namespace sol {
#endif // SOL_CXX17_FEATURES
template <typename T>
struct lua_type_of<nested<T>>
: meta::conditional_t<::sol::is_container_v<T>, std::integral_constant<type, type::table>, lua_type_of<T>> {};
struct lua_type_of<nested<T>> : meta::conditional_t<::sol::is_container_v<T>, std::integral_constant<type, type::table>, lua_type_of<T>> {};
template <typename C, C v, template <typename...> class V, typename... Args>
struct accumulate : std::integral_constant<C, v> {};
@ -7399,11 +7398,10 @@ namespace sol {
template <typename T>
struct is_lua_primitive
: std::integral_constant<bool,
type::userdata != lua_type_of_v<T>
|| ((type::userdata == lua_type_of_v<T>) && detail::has_internal_marker_v<lua_type_of<T>>
&& !detail::has_internal_marker_v<lua_size<T>>)
|| is_lua_reference_v<T> || meta::is_specialization_of_v<T, std::tuple>
|| meta::is_specialization_of_v<T, std::pair>> {};
type::userdata
!= lua_type_of_v<
T> || ((type::userdata == lua_type_of_v<T>)&&detail::has_internal_marker_v<lua_type_of<T>> && !detail::has_internal_marker_v<lua_size<T>>)
|| is_lua_reference_or_proxy_v<T> || meta::is_specialization_of_v<T, std::tuple> || meta::is_specialization_of_v<T, std::pair>> {};
template <typename T>
constexpr inline bool is_lua_primitive_v = is_lua_primitive<T>::value;
@ -7492,6 +7490,16 @@ namespace sol {
template <typename T>
inline constexpr bool is_table_v = is_table<T>::value;
template <typename T>
struct is_stack_table : std::false_type {};
template <bool x, typename T>
struct is_stack_table<basic_table_core<x, T>> : std::integral_constant<bool, std::is_base_of_v<stack_reference, T>> {};
template <typename T>
struct is_stack_table<basic_lua_table<T>> : std::integral_constant<bool, std::is_base_of_v<stack_reference, T>> {};
template <typename T>
inline constexpr bool is_stack_table_v = is_stack_table<T>::value;
template <typename T>
struct is_function : std::false_type {};
template <typename T, bool aligned>
@ -7526,7 +7534,8 @@ namespace sol {
template <typename T>
struct is_automagical
: std::integral_constant<bool,
std::is_array_v<meta::unqualified_t<T>> || !std::is_same_v<meta::unqualified_t<T>, state> || !std::is_same_v<meta::unqualified_t<T>, state_view>> {};
std::is_array_v<meta::unqualified_t<T>> || !std::is_same_v<meta::unqualified_t<T>, state> || !std::is_same_v<meta::unqualified_t<T>, state_view>> {
};
template <typename T>
inline type type_of() {
@ -22335,17 +22344,17 @@ namespace sol {
// beginning of sol/table_core.hpp
// beginning of sol/proxy.hpp
// beginning of sol/table_proxy.hpp
namespace sol {
template <typename Table, typename Key>
struct proxy : public proxy_base<proxy<Table, Key>> {
struct table_proxy : public proxy_base<table_proxy<Table, Key>> {
private:
using key_type = detail::proxy_key_t<Key>;
template <typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) const & {
decltype(auto) tuple_get(std::index_sequence<I...>) const& {
return tbl.template traverse_get<T>(std::get<I>(key)...);
}
@ -22382,36 +22391,35 @@ namespace sol {
key_type key;
template <typename T>
proxy(Table table, T&& k)
: tbl(table), key(std::forward<T>(k)) {
table_proxy(Table table, T&& k) : tbl(table), key(std::forward<T>(k)) {
}
template <typename T>
proxy& set(T&& item) & {
table_proxy& set(T&& item) & {
tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
return *this;
}
template <typename T>
proxy&& set(T&& item) && {
table_proxy&& set(T&& item) && {
tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
return std::move(*this);
}
template <typename... Args>
proxy& set_function(Args&&... args) & {
table_proxy& set_function(Args&&... args) & {
tbl.set_function(key, std::forward<Args>(args)...);
return *this;
}
template <typename... Args>
proxy&& set_function(Args&&... args) && {
table_proxy&& set_function(Args&&... args) && {
tbl.set_function(std::move(key), std::forward<Args>(args)...);
return std::move(*this);
}
template <typename T>
proxy& operator=(T&& other) & {
table_proxy& operator=(T&& other) & {
using Tu = meta::unwrap_unqualified_t<T>;
if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {
return set_function(std::forward<T>(other));
@ -22422,7 +22430,7 @@ namespace sol {
}
template <typename T>
proxy&& operator=(T&& other) && {
table_proxy&& operator=(T&& other) && {
using Tu = meta::unwrap_unqualified_t<T>;
if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {
return std::move(*this).set_function(std::forward<T>(other));
@ -22433,17 +22441,17 @@ namespace sol {
}
template <typename T>
proxy& operator=(std::initializer_list<T> other) & {
table_proxy& operator=(std::initializer_list<T> other) & {
return set(std::move(other));
}
template <typename T>
proxy&& operator=(std::initializer_list<T> other) && {
table_proxy&& operator=(std::initializer_list<T> other) && {
return std::move(*this).set(std::move(other));
}
template <typename T>
decltype(auto) get() const & {
decltype(auto) get() const& {
using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
return tuple_get<T>(idx_seq());
}
@ -22489,29 +22497,28 @@ namespace sol {
template <typename K>
decltype(auto) operator[](K&& k) const& {
auto keys = meta::tuplefy(key, std::forward<K>(k));
return proxy<Table, decltype(keys)>(tbl, std::move(keys));
return table_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename K>
decltype(auto) operator[](K&& k) & {
auto keys = meta::tuplefy(key, std::forward<K>(k));
return proxy<Table, decltype(keys)>(tbl, std::move(keys));
return table_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename K>
decltype(auto) operator[](K&& k) && {
auto keys = meta::tuplefy(std::move(key), std::forward<K>(k));
return proxy<Table, decltype(keys)>(tbl, std::move(keys));
return table_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
#if !defined(__clang__) && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000
// MSVC is ass sometimes
return get<function>().call<Ret...>(std::forward<Args>(args)...);
#else
return get<function>().template call<Ret...>(std::forward<Args>(args)...);
#endif
lua_State* L = this->lua_state();
push(L);
int idx = lua_gettop(L);
stack_aligned_function func(L, idx);
return func.call<Ret...>(std::forward<Args>(args)...);
}
template <typename... Args>
@ -22531,7 +22538,22 @@ namespace sol {
}
int push(lua_State* L) const noexcept {
return get<reference>().push(L);
if constexpr (std::is_same_v<meta::unqualified_t<Table>, global_table> || is_stack_table_v<meta::unqualified_t<Table>>) {
auto pp = stack::push_pop<true>(tbl);
int top_index = lua_gettop(L);
stack::get_field<true>(lua_state(), key, -1);
lua_replace(L, top_index + 1);
lua_settop(L, top_index + 1);
}
else {
auto pp = stack::push_pop<false>(tbl);
int tableindex = pp.index_of(tbl);
int aftertableindex = lua_gettop(L);
stack::get_field<false>(lua_state(), key, tableindex);
lua_replace(L, tableindex);
lua_settop(L, aftertableindex + 1);
}
return 1;
}
type get_type() const {
@ -22549,7 +22571,7 @@ namespace sol {
return tbl.lua_state();
}
proxy& force() {
table_proxy& force() {
if (!this->valid()) {
this->set(new_table());
}
@ -22558,46 +22580,46 @@ namespace sol {
};
template <typename Table, typename Key, typename T>
inline bool operator==(T&& left, const proxy<Table, Key>& right) {
inline bool operator==(T&& left, const table_proxy<Table, Key>& right) {
using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<G>>() == left;
}
template <typename Table, typename Key, typename T>
inline bool operator==(const proxy<Table, Key>& right, T&& left) {
inline bool operator==(const table_proxy<Table, Key>& right, T&& left) {
using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<G>>() == left;
}
template <typename Table, typename Key, typename T>
inline bool operator!=(T&& left, const proxy<Table, Key>& right) {
inline bool operator!=(T&& left, const table_proxy<Table, Key>& right) {
using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<G>>() != left;
}
template <typename Table, typename Key, typename T>
inline bool operator!=(const proxy<Table, Key>& right, T&& left) {
inline bool operator!=(const table_proxy<Table, Key>& right, T&& left) {
using G = decltype(stack::get<T>(nullptr, 0));
return right.template get<optional<G>>() != left;
}
template <typename Table, typename Key>
inline bool operator==(lua_nil_t, const proxy<Table, Key>& right) {
inline bool operator==(lua_nil_t, const table_proxy<Table, Key>& right) {
return !right.valid();
}
template <typename Table, typename Key>
inline bool operator==(const proxy<Table, Key>& right, lua_nil_t) {
inline bool operator==(const table_proxy<Table, Key>& right, lua_nil_t) {
return !right.valid();
}
template <typename Table, typename Key>
inline bool operator!=(lua_nil_t, const proxy<Table, Key>& right) {
inline bool operator!=(lua_nil_t, const table_proxy<Table, Key>& right) {
return right.valid();
}
template <typename Table, typename Key>
inline bool operator!=(const proxy<Table, Key>& right, lua_nil_t) {
inline bool operator!=(const table_proxy<Table, Key>& right, lua_nil_t) {
return right.valid();
}
@ -22619,16 +22641,15 @@ namespace sol {
namespace stack {
template <typename Table, typename Key>
struct unqualified_pusher<proxy<Table, Key>> {
static int push(lua_State* L, const proxy<Table, Key>& p) {
reference r = p;
return r.push(L);
struct unqualified_pusher<table_proxy<Table, Key>> {
static int push(lua_State* L, const table_proxy<Table, Key>& p) {
return p.push(L);
}
};
} // namespace stack
} // namespace sol
// end of sol/proxy.hpp
// end of sol/table_proxy.hpp
// beginning of sol/table_iterator.hpp
@ -23266,17 +23287,17 @@ namespace sol {
template <typename T>
auto operator[](T&& key) & {
return proxy<basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));
return table_proxy<basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));
}
template <typename T>
auto operator[](T&& key) const& {
return proxy<const basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));
return table_proxy<const basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));
}
template <typename T>
auto operator[](T&& key) && {
return proxy<basic_table_core, detail::proxy_key_t<T>>(std::move(*this), std::forward<T>(key));
return table_proxy<basic_table_core, detail::proxy_key_t<T>>(std::move(*this), std::forward<T>(key));
}
template <typename Sig, typename Key, typename... Args>
@ -25005,12 +25026,12 @@ namespace sol {
}
template <typename T>
proxy<global_table&, detail::proxy_key_t<T>> operator[](T&& key) {
table_proxy<global_table&, detail::proxy_key_t<T>> operator[](T&& key) {
return global[std::forward<T>(key)];
}
template <typename T>
proxy<const global_table&, detail::proxy_key_t<T>> operator[](T&& key) const {
table_proxy<const global_table&, detail::proxy_key_t<T>> operator[](T&& key) const {
return global[std::forward<T>(key)];
}

View File

@ -23,4 +23,4 @@
#include "sol_defines.hpp"
#include <sol/proxy.hpp>
#include <sol/table_proxy.hpp>

View File

@ -217,7 +217,7 @@ TEST_CASE("simple/get_or", "check if table.get_or works correctly") {
REQUIRE(bark == 55.6);
}
TEST_CASE("simple/proxy get_or", "check if proxy.get_or works correctly") {
TEST_CASE("simple/table_proxy get_or", "check if table_proxy.get_or works correctly") {
sol::state lua;
auto bob_table = lua.create_table("bob");

View File

@ -37,13 +37,24 @@
#include <set>
#include <unordered_set>
inline namespace sol2_test_container_table {
template <typename T>
struct as_table_callable {
T* ptr;
as_table_callable(T& ref_) : ptr(&ref_) {
}
auto operator()() const {
return sol::as_table(*ptr);
}
};
} // namespace sol2_test_container_table
TEST_CASE("containers/vector table roundtrip", "make sure vectors can be round-tripped") {
sol::state lua;
std::vector<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.set_function("f", as_table_callable<std::vector<int>>(v));
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::vector<int>> x = lua["x"];
@ -54,9 +65,7 @@ TEST_CASE("containers/vector table roundtrip", "make sure vectors can be round-t
TEST_CASE("containers/deque table roundtrip", "make sure deques can be round-tripped") {
sol::state lua;
std::deque<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.set_function("f", as_table_callable<std::deque<int>>(v));
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::deque<int>> x = lua["x"];
@ -67,9 +76,7 @@ TEST_CASE("containers/deque table roundtrip", "make sure deques can be round-tri
TEST_CASE("containers/array table roundtrip", "make sure arrays can be round-tripped") {
sol::state lua;
std::array<int, 3> v{ { 1, 2, 3 } };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.set_function("f", as_table_callable<std::array<int, 3>>(v));
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::array<int, 3>> x = lua["x"];
@ -80,9 +87,7 @@ TEST_CASE("containers/array table roundtrip", "make sure arrays can be round-tri
TEST_CASE("containers/list table roundtrip", "make sure lists can be round-tripped") {
sol::state lua;
std::list<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.set_function("f", as_table_callable<std::list<int>>(v));
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::list<int>> x = lua["x"];
@ -93,9 +98,7 @@ TEST_CASE("containers/list table roundtrip", "make sure lists can be round-tripp
TEST_CASE("containers/forward_list table roundtrip", "make sure forward_lists can be round-tripped") {
sol::state lua;
std::forward_list<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.set_function("f", as_table_callable<std::forward_list<int>>(v));
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::forward_list<int>> x = lua["x"];
@ -106,9 +109,7 @@ TEST_CASE("containers/forward_list table roundtrip", "make sure forward_lists ca
TEST_CASE("containers/map table roundtrip", "make sure maps can be round-tripped") {
sol::state lua;
std::map<std::string, int> v{ { "a", 1 }, { "b", 2 }, { "c", 3 } };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.set_function("f", as_table_callable<std::map<std::string, int>>(v));
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::map<std::string, int>> x = lua["x"];
@ -119,9 +120,7 @@ TEST_CASE("containers/map table roundtrip", "make sure maps can be round-tripped
TEST_CASE("containers/unordered_map table roundtrip", "make sure unordered_maps can be round-tripped") {
sol::state lua;
std::unordered_map<std::string, int> v{ { "a", 1 }, { "b", 2 }, { "c", 3 } };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.set_function("f", as_table_callable<std::unordered_map<std::string, int>>(v));
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::unordered_map<std::string, int>> x = lua["x"];
@ -132,9 +131,7 @@ TEST_CASE("containers/unordered_map table roundtrip", "make sure unordered_maps
TEST_CASE("containers/unordered_set table roundtrip", "make sure unordered_sets can be round-tripped") {
sol::state lua;
std::unordered_set<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.set_function("f", as_table_callable<std::unordered_set<int>>(v));
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::unordered_set<int>> x = lua["x"];
@ -145,9 +142,7 @@ TEST_CASE("containers/unordered_set table roundtrip", "make sure unordered_sets
TEST_CASE("containers/set table roundtrip", "make sure sets can be round-tripped") {
sol::state lua;
std::set<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.set_function("f", as_table_callable<std::set<int>>(v));
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::set<int>> x = lua["x"];

View File

@ -37,13 +37,24 @@
#include <set>
#include <unordered_set>
inline namespace sol2_test_containers {
struct returns_callable {
std::vector<int>* ptr;
returns_callable(std::vector<int>& ref_) : ptr(&ref_) {
}
std::vector<int>& operator()() const {
REQUIRE(ptr->size() == 3);
return *ptr;
}
};
} // namespace sol2_test_containers
TEST_CASE("containers/returns", "make sure that even references to vectors are being serialized as tables") {
sol::state lua;
std::vector<int> v{ 1, 2, 3 };
auto f = [&]() -> std::vector<int>& {
REQUIRE(v.size() == 3);
return v;
};
returns_callable f(v);
lua.set_function("f", f);
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());

View File

@ -1,4 +1,4 @@
// sol3
// sol3
// The MIT License (MIT)
@ -25,6 +25,39 @@
#include <catch.hpp>
inline namespace sol2_test_coroutines {
struct coroutine_thread_runner_state {
sol::state_view* prunner_thread_state;
coroutine_thread_runner_state(sol::state_view& ref_) : prunner_thread_state(&ref_) {
}
auto operator()() const {
sol::state_view& runner_thread_state = *prunner_thread_state;
sol::coroutine cr = runner_thread_state["loop"];
sol::stack::push(runner_thread_state, 50);
sol::stack::push(runner_thread_state, 25);
int r = cr();
return r;
}
};
struct coroutine_thread_runner {
sol::thread* prunner_thread;
coroutine_thread_runner(sol::thread& ref_) : prunner_thread(&ref_) {
}
auto operator()() const {
sol::thread& runner_thread = *prunner_thread;
sol::state_view th_state = runner_thread.state();
sol::coroutine cr = th_state["loop"];
int r = cr();
return r;
}
};
} // namespace sol2_test_coroutines
struct coro_h {
int x = 500;
int func() {
@ -151,13 +184,11 @@ TEST_CASE("coroutines/transfer", "test that things created inside of a coroutine
for (std::size_t tries = 0; tries < 200; ++tries) {
sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries();
{
sol::function f2;
lua["f"] = [&lua, &f2](sol::object t) {
f2 = sol::function(lua, t);
};
lua["f"] = [&lua, &f2](sol::object t) { f2 = sol::function(lua, t); };
{
auto code = R"(
i = 0
@ -241,10 +272,13 @@ co = nil
lua.open_libraries(sol::lib::coroutine, sol::lib::base);
lua.new_usertype<coro_test>("coro_test",
sol::constructors<coro_test(sol::this_state, std::string)>(),
"store", &coro_test::store,
"copy_store", &coro_test::copy_store,
"get", &coro_test::get);
sol::constructors<coro_test(sol::this_state, std::string)>(),
"store",
&coro_test::store,
"copy_store",
&coro_test::copy_store,
"get",
&coro_test::get);
auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid());
@ -299,8 +333,7 @@ co = nil
std::string identifier;
sol::reference obj;
coro_test_implicit(sol::this_state L, std::string id)
: identifier(id), obj(L, sol::lua_nil) {
coro_test_implicit(sol::this_state L, std::string id) : identifier(id), obj(L, sol::lua_nil) {
}
void store(sol::table ref) {
@ -325,10 +358,13 @@ co = nil
lua.open_libraries(sol::lib::coroutine, sol::lib::base);
lua.new_usertype<coro_test_implicit>("coro_test",
sol::constructors<coro_test_implicit(sol::this_state, std::string)>(),
"store", &coro_test_implicit::store,
"copy_store", &coro_test_implicit::copy_store,
"get", &coro_test_implicit::get);
sol::constructors<coro_test_implicit(sol::this_state, std::string)>(),
"store",
&coro_test_implicit::store,
"copy_store",
&coro_test_implicit::copy_store,
"get",
&coro_test_implicit::get);
auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid());
@ -382,10 +418,13 @@ collectgarbage()
lua.open_libraries(sol::lib::coroutine, sol::lib::base);
lua.new_usertype<coro_test_implicit>("coro_test",
sol::constructors<coro_test_implicit(sol::this_state, std::string)>(),
"store", &coro_test_implicit::store,
"copy_store", &coro_test_implicit::copy_store,
"get", &coro_test_implicit::get);
sol::constructors<coro_test_implicit(sol::this_state, std::string)>(),
"store",
&coro_test_implicit::store,
"copy_store",
&coro_test_implicit::copy_store,
"get",
&coro_test_implicit::get);
auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid());
@ -404,7 +443,8 @@ collectgarbage()
REQUIRE(s == "SOME_TABLE");
}
TEST_CASE("coroutines/coroutine.create protection", "ensure that a thread picked up from coroutine.create does not throw off the lua stack entirely when called from C++") {
TEST_CASE("coroutines/coroutine.create protection",
"ensure that a thread picked up from coroutine.create does not throw off the lua stack entirely when called from C++") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
@ -425,12 +465,7 @@ loop_th = coroutine.create(loop)
REQUIRE(r.valid());
sol::thread runner_thread = lua["loop_th"];
auto test_resume = [&runner_thread]() {
sol::state_view th_state = runner_thread.state();
sol::coroutine cr = th_state["loop"];
int r = cr();
return r;
};
coroutine_thread_runner test_resume(runner_thread);
lua.set_function("test_resume", std::ref(test_resume));
@ -480,13 +515,7 @@ end
// Resume from lua via thread and coroutine
sol::thread runner_thread = lua["loop_th"];
sol::state_view runner_thread_state = runner_thread.state();
auto test_resume = [&runner_thread_state]() {
sol::coroutine cr = runner_thread_state["loop"];
sol::stack::push(runner_thread_state, 50);
sol::stack::push(runner_thread_state, 25);
int r = cr();
return r;
};
coroutine_thread_runner_state test_resume(runner_thread_state);
lua.set_function("test_resume", std::ref(test_resume));
// Resume via getting a sol::function from the state
@ -504,7 +533,7 @@ end
int v1 = test_resume();
int s1 = runner_thread_state.stack_top();
int v2;
{
{
auto result = lua.safe_script("return test_resume()", sol::script_pass_on_error);
REQUIRE(result.valid());
v2 = result;
@ -598,9 +627,7 @@ TEST_CASE("coroutines/yielding", "test that a sol3 bound function can yield when
lua["hobj"] = &hobj;
lua.new_usertype<coro_h>("coro_h",
"h", sol::yielding(&coro_h::func)
);
lua.new_usertype<coro_h>("coro_h", "h", sol::yielding(&coro_h::func));
sol::string_view code = R"(
co4 = coroutine.create(function()

View File

@ -117,6 +117,21 @@ namespace sol {
} // namespace stack
} // namespace sol
inline namespace sol2_test_customizations_private {
struct boolean_set_true {
bool* pTwoThingsWorks;
boolean_set_true(bool& ref_) : pTwoThingsWorks(&ref_) {
}
void operator()(two_things) const {
bool& TwoThingsWorks = *pTwoThingsWorks;
TwoThingsWorks = true;
}
};
} // namespace sol2_test_customizations_private
TEST_CASE("customization/split struct", "using the old customization points to handle different kinds of classes") {
sol::state lua;
@ -166,8 +181,8 @@ TEST_CASE("customization/usertype", "using the old customization points to handl
TEST_CASE("customization/overloading", "using multi-size customized types in an overload") {
bool TwoThingsWorks = false, OverloadWorks = false;
sol::state lua;
lua["test_two_things"] = [&](two_things) { TwoThingsWorks = true; };
lua["test_overload"] = sol::overload([&](two_things) { OverloadWorks = true; }, [] {});
lua["test_two_things"] = boolean_set_true(TwoThingsWorks);
lua["test_overload"] = sol::overload(boolean_set_true(OverloadWorks), [] {});
lua.script(
"test_two_things(0, true)\n"

View File

@ -1,4 +1,4 @@
// sol3
// sol3
// The MIT License (MIT)
@ -27,6 +27,64 @@
#include <iostream>
inline namespace sol2_test_environments {
struct check_g_env {
sol::state* plua;
sol::environment* penv_g;
check_g_env(sol::state& lua, sol::environment& env_g) : plua(&lua), penv_g(&env_g) {
}
void operator()(sol::function target) const {
sol::state& lua = *plua;
sol::environment& env_g = *penv_g;
sol::stack_guard luasg(lua);
sol::environment target_env = sol::get_environment(target);
int test_env_g = env_g["test"];
int test_target_env = target_env["test"];
REQUIRE(test_env_g == test_target_env);
REQUIRE(test_env_g == 5);
REQUIRE(env_g == target_env);
}
};
struct check_f_env {
sol::state* plua;
sol::environment* penv_f;
check_f_env(sol::state& lua, sol::environment& env_f) : plua(&lua), penv_f(&env_f) {
}
void operator()(sol::function target) const {
sol::state& lua = *plua;
sol::environment& env_f = *penv_f;
sol::stack_guard luasg(lua);
sol::environment target_env(sol::env_key, target);
int test_env_f = env_f["test"];
int test_target_env = target_env["test"];
REQUIRE(test_env_f == test_target_env);
REQUIRE(test_env_f == 31);
REQUIRE(env_f == target_env);
}
};
struct check_h_env {
sol::state* plua;
check_h_env(sol::state& lua) : plua(&lua) {
}
void operator()(sol::function target) const {
sol::state& lua = *plua;
sol::stack_guard luasg(lua);
sol::environment target_env = sol::get_environment(target);
// cannot strictly test
// if it's the global table, because different lua runtimes
// give different envs when there is no env
}
};
} // namespace sol2_test_environments
TEST_CASE("environments/get", "Envronments can be taken out of things like Lua functions properly") {
sol::state lua;
sol::stack_guard luasg(lua);
@ -61,37 +119,15 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
auto result3 = lua.safe_script("h = function() end", sol::script_pass_on_error);
REQUIRE(result3.valid());
lua.set_function("check_f_env",
[&lua, &env_f](sol::object target) {
sol::stack_guard luasg(lua);
sol::environment target_env(sol::env_key, target);
int test_env_f = env_f["test"];
int test_target_env = target_env["test"];
REQUIRE(test_env_f == test_target_env);
REQUIRE(test_env_f == 31);
REQUIRE(env_f == target_env);
});
lua.set_function("check_g_env",
[&lua, &env_g](sol::function target) {
sol::stack_guard luasg(lua);
sol::environment target_env = sol::get_environment(target);
int test_env_g = env_g["test"];
int test_target_env = target_env["test"];
REQUIRE(test_env_g == test_target_env);
REQUIRE(test_env_g == 5);
REQUIRE(env_g == target_env);
});
lua.set_function("check_h_env",
[&lua](sol::function target) {
sol::stack_guard luasg(lua);
sol::environment target_env = sol::get_environment(target);
});
lua.set_function("check_f_env", check_f_env(lua, env_f));
lua.set_function("check_g_env", check_g_env(lua, env_g));
lua.set_function("check_h_env", check_h_env(lua));
auto checkf = lua.safe_script("check_f_env(f)");
auto checkf = lua.safe_script("check_f_env(f)", sol::script_pass_on_error);
REQUIRE(checkf.valid());
auto checkg = lua.safe_script("check_g_env(g)");
auto checkg = lua.safe_script("check_g_env(g)", sol::script_pass_on_error);
REQUIRE(checkg.valid());
auto checkh = lua.safe_script("check_h_env(h)");
auto checkh = lua.safe_script("check_h_env(h)", sol::script_pass_on_error);
REQUIRE(checkh.valid());
}

View File

@ -239,7 +239,7 @@ end )",
REQUIRE(v->v == 29);
}
TEST_CASE("functions/pair and tuple and proxy tests", "Check if sol::reference and sol::proxy can be passed to functions as arguments") {
TEST_CASE("functions/pair and tuple and table_proxy tests", "Check if sol::reference and sol::table_proxy can be passed to functions as arguments") {
sol::state lua;
sol::stack_guard luasg(lua);

View File

@ -1,4 +1,4 @@
// sol3
// sol3
// The MIT License (MIT)
@ -28,16 +28,44 @@
#include <cstdint>
#include <limits>
inline namespace sol2_test_large_integer {
inline bool bool_roundtrip(bool num) {
REQUIRE(num == true);
return num;
}
inline void trigger_passthrough_crash(sol::state& lua) {
sol::protected_function pf = lua["f"];
auto result = pf(0xFFFFFFFFFFFFFFFFull);
(void)result;
}
template <typename T>
inline T intT_passthrough(T num) {
return num;
}
template <typename T>
inline T intT_roundtrip(T num) {
REQUIRE(num == std::numeric_limits<T>::max());
return num;
}
inline std::uint64_t int53_roundtrip(std::uint64_t num) {
REQUIRE(num == 0x1FFFFFFFFFFFFFull);
return num;
}
} // namespace sol2_test_large_integer
TEST_CASE("large_integer/bool", "pass bool integral value to and from lua") {
sol::state lua;
lua.open_libraries();
lua.set_function("f", [&](bool num) {
REQUIRE(num == true);
return num;
});
auto result1 = lua.safe_script("x = f(true)\n"
"assert(x == true)", sol::script_pass_on_error);
REQUIRE(result1.valid());
lua.set_function("f", bool_roundtrip);
sol::optional<sol::error> result1 = lua.safe_script(
"x = f(true)\n"
"assert(x == true)",
sol::script_pass_on_error);
REQUIRE_FALSE(result1.has_value());
sol::object x = lua["x"];
REQUIRE(x.is<bool>());
REQUIRE(x.as<bool>() == true);
@ -52,12 +80,11 @@ TEST_CASE("large_integers/unsigned32", "pass large unsigned 32bit values to and
using T = std::uint32_t;
sol::state lua;
lua.open_libraries();
lua.set_function("f", [&](T num) -> T {
REQUIRE(num == 0xFFFFFFFF);
return num;
});
auto result1 = lua.safe_script("x = f(0xFFFFFFFF)\n"
"assert(x == 0xFFFFFFFF)", sol::script_pass_on_error);
lua.set_function("f", intT_roundtrip<T>);
auto result1 = lua.safe_script(
"x = f(0xFFFFFFFF)\n"
"assert(x == 0xFFFFFFFF)",
sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::object x = lua["x"];
REQUIRE(x.is<T>());
@ -68,12 +95,10 @@ TEST_CASE("large_integer/unsigned53", "pass large unsigned 53bit value to and fr
using T = std::uint64_t;
sol::state lua;
lua.open_libraries();
lua.set_function("f", [&](T num) -> T {
REQUIRE(num == 0x1FFFFFFFFFFFFFull);
return num;
});
auto result1 = lua.safe_script("x = f(0x1FFFFFFFFFFFFF)\n"
"assert(x == 0x1FFFFFFFFFFFFF)");
lua.set_function("f", int53_roundtrip);
auto result1 = lua.safe_script(
"x = f(0x1FFFFFFFFFFFFF)\n"
"assert(x == 0x1FFFFFFFFFFFFF)");
REQUIRE(result1.valid());
sol::object x = lua["x"];
REQUIRE(x.is<T>());
@ -83,32 +108,19 @@ TEST_CASE("large_integer/unsigned53", "pass large unsigned 53bit value to and fr
TEST_CASE("large_integer/unsigned64", "pass too large unsigned 64bit value to lua") {
using T = std::int64_t;
sol::state lua;
lua.set_function("f", [&](T num) -> T {
return num;
});
REQUIRE_THROWS([&lua]() {
sol::protected_function pf = lua["f"];
auto result = pf(0xFFFFFFFFFFFFFFFFull);
}());
lua.set_function("f", intT_passthrough<T>);
REQUIRE_THROWS(trigger_passthrough_crash(lua));
}
TEST_CASE("large_integer/double", "pass negative and large positive values as signed and unsigned from and to lua") {
sol::state lua;
lua.open_libraries();
lua.set_function("s32", [&](std::int32_t num) {
return num;
});
lua.set_function("s64", [&](std::int64_t num) {
return num;
});
lua.set_function("u32", [&](std::uint32_t num) {
return num;
});
lua.set_function("u64", [&](std::uint64_t num) {
return num;
});
lua.set_function("s32", intT_passthrough<std::int32_t>);
lua.set_function("s64", intT_passthrough<std::int64_t>);
lua.set_function("u32", intT_passthrough<std::uint32_t>);
lua.set_function("u64", intT_passthrough<std::uint64_t>);
{
//signed 32bit
// signed 32bit
auto result1 = lua.safe_script("x = s32(-1)", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("assert(x == -1)", sol::script_pass_on_error);
@ -125,7 +137,7 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si
REQUIRE(x.as<std::uint32_t>() == 0xFFFFFFFF);
}
//unsigned 32bit
// unsigned 32bit
{
auto result1 = lua.safe_script("x = u32(0xFFFFFFFF)", sol::script_pass_on_error);
REQUIRE(result1.valid());
@ -141,7 +153,7 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si
REQUIRE(x.is<std::uint32_t>());
REQUIRE(x.as<std::uint32_t>() == 0xFFFFFFFF);
}
//signed 64bit
// signed 64bit
{
auto result1 = lua.safe_script("x = s64(-1)", sol::script_pass_on_error);
REQUIRE(result1.valid());

View File

@ -238,7 +238,8 @@ TEST_CASE("tables/optional move", "ensure pushing a sol::optional<T> rvalue corr
sol::state sol_state;
struct move_only {
int secret_code;
move_only(int sc) : secret_code(sc) {}
move_only(int sc) : secret_code(sc) {
}
move_only(const move_only&) = delete;
move_only(move_only&&) = default;
@ -248,3 +249,36 @@ TEST_CASE("tables/optional move", "ensure pushing a sol::optional<T> rvalue corr
sol_state["requires_move"] = sol::optional<move_only>(move_only(0x4D));
REQUIRE(sol_state["requires_move"].get<move_only>().secret_code == 0x4D);
}
TEST_CASE("table/stack table size", "make sure size() works correctly on stack tables") {
sol::state lua;
sol::stack_guard luasg(lua);
sol::stack_table t(lua, sol::create);
t[1] = 42;
auto sz1 = t.size();
REQUIRE(sz1 == 1);
sol::stack::push(lua, "some string");
auto sz2 = t.size();
REQUIRE(sz2 == 1);
std::string s = sol::stack::pop<std::string>(lua);
REQUIRE(s == "some string");
sol::table t2 = sol::stack::pop<sol::table>(lua);
auto sz3 = t2.size();
REQUIRE(sz1 == sz3);
REQUIRE(sz1 == sz2);
}
TEST_CASE("table/proxy call", "test proxy calls put the variable in the right place") {
sol::state lua;
sol::stack_guard luasg(lua);
{
sol::stack_guard tsg(lua);
lua["t"] = std::initializer_list<std::pair<int, std::string_view>>{ { 1, "borf" }, { 2, "bjork" }, { 3, "waf" } };
}
{
sol::stack_guard fsg(lua);
lua["f"] = [](std::string bjork) { REQUIRE(bjork == std::string("borf")); };
}
auto prox = lua["t"][1];
lua["f"](prox);
}

View File

@ -27,7 +27,7 @@
#include <iostream>
TEST_CASE("tables/proxy override_value", "allow override_value by way of key") {
TEST_CASE("tables/table_proxy override_value", "allow override_value by way of key") {
sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base, sol::lib::io);
@ -59,7 +59,7 @@ TEST_CASE("tables/insertion override", "allow override all non-table values plus
REQUIRE(*b_totally_there == 500);
REQUIRE_FALSE(static_cast<bool>(totally_not_there));
}
SECTION("proxy") {
SECTION("table_proxy") {
sol::state lua;
sol::stack_guard luasg(lua);
@ -77,7 +77,7 @@ TEST_CASE("tables/insertion override", "allow override all non-table values plus
REQUIRE(*b_totally_there == 500);
REQUIRE_FALSE(static_cast<bool>(totally_not_there));
}
SECTION("complex proxy") {
SECTION("complex table_proxy") {
sol::state lua;
sol::stack_guard luasg(lua);
@ -104,7 +104,7 @@ TEST_CASE("tables/insertion update_if_empty", "allow updating a value only if it
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == 357);
}
SECTION("proxy") {
SECTION("table_proxy") {
sol::state lua;
sol::stack_guard luasg(lua);
@ -120,7 +120,7 @@ TEST_CASE("tables/insertion update_if_empty", "allow updating a value only if it
REQUIRE(static_cast<bool>(totally_there_still));
REQUIRE(*totally_there_still == 357);
}
SECTION("proxy invoker") {
SECTION("table_proxy invoker") {
sol::state lua;
sol::stack_guard luasg(lua);
@ -165,7 +165,7 @@ TEST_CASE("tables/get create_if_nil", "create tables all the way down") {
REQUIRE(static_cast<bool>(totally_created));
REQUIRE(static_cast<bool>(totally_there));
}
SECTION("proxy non-optional") {
SECTION("table_proxy non-optional") {
sol::state lua;
sol::stack_guard luasg_outer(lua);
@ -181,7 +181,7 @@ TEST_CASE("tables/get create_if_nil", "create tables all the way down") {
}
}
SECTION("proxy") {
SECTION("table_proxy") {
sol::state lua;
sol::stack_guard luasg(lua);