update tests (which compile, but now all fail)

This commit is contained in:
ThePhD 2018-11-18 13:06:01 -05:00
parent e74ce68163
commit 9b47849110
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
17 changed files with 414 additions and 605 deletions

View File

@ -50,16 +50,6 @@ namespace sol {
struct undefined_metatable; struct undefined_metatable;
} }
} // namespace stack::stack_detail } // namespace stack::stack_detail
namespace u_detail {
template <typename T, typename Regs, typename Fx>
void insert_default_registrations(Regs& l, int& index, Fx&& fx);
template <typename T, typename Regs, meta::enable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> = meta::enabler>
void make_destructor(Regs& l, int& index);
template <typename T, typename Regs, meta::disable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> = meta::enabler>
void make_destructor(Regs& l, int& index);
} // namespace u_detail
} // namespace sol } // namespace sol
#endif // SOL_FORWARD_DETAIL_HPP #endif // SOL_FORWARD_DETAIL_HPP

View File

@ -37,6 +37,7 @@
#include "forward_detail.hpp" #include "forward_detail.hpp"
#include <vector> #include <vector>
#include <bitset>
#include <forward_list> #include <forward_list>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
@ -51,6 +52,8 @@ namespace sol {
template <typename T> template <typename T>
struct as_table_tag {}; struct as_table_tag {};
using lua_reg_table = luaL_Reg[64];
using unique_destructor = void (*)(void*); using unique_destructor = void (*)(void*);
using unique_tag = detail::inheritance_unique_cast_function; using unique_tag = detail::inheritance_unique_cast_function;
@ -488,6 +491,200 @@ namespace sol {
void reserve(std::basic_string<T, Tr, Al>& arr, std::size_t hint) { void reserve(std::basic_string<T, Tr, Al>& arr, std::size_t hint) {
arr.reserve(hint); arr.reserve(hint);
} }
template <typename T>
inline lua_CFunction make_destructor() {
if constexpr (std::is_destructible_v<T>) {
if constexpr (is_unique_usertype_v<T>) {
return &unique_destruct<T>;
}
else if constexpr (!std::is_pointer_v<T>) {
return &usertype_alloc_destruct<T>;
}
}
else {
return &cannot_destruct<T>;
}
}
struct no_comp {
template <typename A, typename B>
bool operator()(A&&, B&&) const {
return false;
}
};
template <typename T>
inline int is_check(lua_State* L) {
return stack::push(L, stack::check<T>(L, 1, &no_panic));
}
template <typename T>
inline int member_default_to_string(std::true_type, lua_State* L) {
decltype(auto) ts = stack::get<T>(L, 1).to_string();
return stack::push(L, std::forward<decltype(ts)>(ts));
}
template <typename T>
inline int member_default_to_string(std::false_type, lua_State* L) {
return luaL_error(L, "cannot perform to_string on '%s': no 'to_string' overload in namespace, 'to_string' member function, or operator<<(ostream&, ...) present", detail::demangle<T>().data());
}
template <typename T>
inline int adl_default_to_string(std::true_type, lua_State* L) {
using namespace std;
decltype(auto) ts = to_string(stack::get<T>(L, 1));
return stack::push(L, std::forward<decltype(ts)>(ts));
}
template <typename T>
inline int adl_default_to_string(std::false_type, lua_State* L) {
return member_default_to_string<T>(meta::supports_to_string_member<T>(), L);
}
template <typename T>
inline int oss_default_to_string(std::true_type, lua_State* L) {
std::ostringstream oss;
oss << stack::unqualified_get<T>(L, 1);
return stack::push(L, oss.str());
}
template <typename T>
inline int oss_default_to_string(std::false_type, lua_State* L) {
return adl_default_to_string<T>(meta::supports_adl_to_string<T>(), L);
}
template <typename T>
inline int default_to_string(lua_State* L) {
return oss_default_to_string<T>(meta::supports_ostream_op<T>(), L);
}
template <typename T, typename Op>
int comparsion_operator_wrap(lua_State* L) {
auto maybel = stack::unqualified_check_get<T&>(L, 1);
if (maybel) {
auto mayber = stack::unqualified_check_get<T&>(L, 2);
if (mayber) {
auto& l = *maybel;
auto& r = *mayber;
if (std::is_same<no_comp, Op>::value) {
return stack::push(L, detail::ptr(l) == detail::ptr(r));
}
else {
Op op;
return stack::push(L, (detail::ptr(l) == detail::ptr(r)) || op(detail::deref(l), detail::deref(r)));
}
}
}
return stack::push(L, false);
}
template <typename T, typename IFx, typename Fx>
inline void insert_default_registrations(IFx&& ifx, Fx&& fx) {
if constexpr (is_automagical<T>::value) {
if (fx(meta_function::less_than)) {
if constexpr (meta::supports_op_less<T>::value) {
lua_CFunction f = &comparsion_operator_wrap<T, std::less<>>;
ifx(meta_function::less_than, f);
}
}
if (fx(meta_function::less_than_or_equal_to)) {
if constexpr (meta::supports_op_less_equal<T>::value) {
lua_CFunction f = &comparsion_operator_wrap<T, std::less_equal<>>;
ifx(meta_function::less_than_or_equal_to, f);
}
}
if (fx(meta_function::equal_to)) {
if constexpr (meta::supports_op_equal<T>::value) {
lua_CFunction f = &comparsion_operator_wrap<T, std::equal_to<>>;
ifx(meta_function::equal_to, f);
}
}
if (fx(meta_function::pairs)) {
ifx(meta_function::pairs, &usertype_container<as_container_t<T>>::pairs_call);
}
if (fx(meta_function::length)) {
if constexpr (meta::has_size<const T>::value) {
#if defined(__clang__)
ifx(meta_function::length, &c_call<decltype(&T::size), &T::size>);
#else
typedef decltype(std::declval<T const>().size()) R;
using sz_func = R (T::*)() const;
lua_CFunction f = &c_call<decltype(static_cast<sz_func>(&T::size)), static_cast<sz_func>(&T::size)>;
ifx(meta_function::length, f);
#endif
}
else if constexpr (meta::has_size<T>::value) {
#if defined(__clang__)
ifx(meta_function::length, &c_call<decltype(&T::size), &T::size>);
#else
typedef decltype(std::declval<T>().size()) R;
using sz_func = R (T::*)();
ifx(meta_function::length, &c_call<decltype(static_cast<sz_func>(&T::size)), static_cast<sz_func>(&T::size)>);
#endif
}
}
if (fx(meta_function::to_string)) {
if constexpr (is_to_stringable<T>::value) {
lua_CFunction f = &detail::static_trampoline<&default_to_string<T>>;
ifx(meta_function::to_string, f);
}
}
if (fx(meta_function::call_function)) {
if constexpr (meta::has_deducible_signature<T>::value) {
lua_CFunction f = &c_call<decltype(&T::operator()), &T::operator()>;
ifx(meta_function::call_function, f);
}
}
}
}
inline bool property_always_true(meta_function) {
return true;
}
struct properties_enrollment_allowed {
std::bitset<64>& properties;
automagic_enrollments& enrollments;
properties_enrollment_allowed(std::bitset<64>& props, automagic_enrollments& enroll)
: properties(props), enrollments(enroll) {
}
bool operator()(meta_function mf) const {
bool p = properties[static_cast<int>(mf)];
switch (mf) {
case meta_function::length:
return enrollments.length_operator && !p;
case meta_function::pairs:
return enrollments.pairs_operator && !p;
case meta_function::call:
return enrollments.call_operator && !p;
case meta_function::less_than:
return enrollments.less_than_operator && !p;
case meta_function::less_than_or_equal_to:
return enrollments.less_than_or_equal_to_operator && !p;
case meta_function::equal_to:
return enrollments.equal_to_operator && !p;
default:
break;
}
return !p;
}
};
struct indexed_insert {
lua_reg_table& l;
int& index;
indexed_insert(lua_reg_table& cont, int& idx)
: l(cont), index(idx) {
}
void operator()(meta_function mf, lua_CFunction f) {
l[index] = luaL_Reg{ to_string(mf).c_str(), f };
++index;
}
};
} // namespace detail } // namespace detail
namespace stack { namespace stack {

View File

@ -173,11 +173,11 @@ namespace stack {
detail::default_construct::construct(mem, std::forward<Args>(args)...); detail::default_construct::construct(mem, std::forward<Args>(args)...);
*pref = unique_usertype_traits<T>::get(*mem); *pref = unique_usertype_traits<T>::get(*mem);
if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) { if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) {
luaL_Reg l[32] {}; detail::lua_reg_table l{};
int index = 0; int index = 0;
auto prop_fx = [](meta_function) { return true; }; detail::indexed_insert insert_fx(l, index);
u_detail::insert_default_registrations<P>(l, index, prop_fx); detail::insert_default_registrations<P>(insert_fx, detail::property_always_true);
u_detail::make_destructor<T>(l, index); l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() };
luaL_setfuncs(L, l, 0); luaL_setfuncs(L, l, 0);
} }
lua_setmetatable(L, -2); lua_setmetatable(L, -2);

View File

@ -30,16 +30,41 @@
namespace sol { namespace sol {
typedef table_core<false> table; typedef table_core<false> table;
template <bool top_level, typename base_type> template <bool is_global, typename base_type>
template <typename Class, typename Key, typename... Args> template <typename Class, typename Key>
usertype<Class> basic_table_core<top_level, base_type>::new_usertype(Key&& key, Args&&... args) { usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key) {
int mt_index = u_detail::register_usertype<Class>(this->lua_state(), detail::any_is_constructor_v<Args...> ? optional<no_construction>() : optional<no_construction>(no_constructor)); automagic_enrollments enrollments;
return this->new_usertype<Class>(std::forward<Key>(key), std::move(enrollments));
}
template <bool is_global, typename base_type>
template <typename Class, typename Key>
usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, automagic_enrollments enrollments) {
int mt_index = u_detail::register_usertype<Class>(this->lua_state(), std::move(enrollments));
usertype<Class> mt(this->lua_state(), -mt_index); usertype<Class> mt(this->lua_state(), -mt_index);
mt.
set(std::forward<Key>(key), mt); set(std::forward<Key>(key), mt);
return mt; return mt;
} }
template <bool is_global, typename base_type>
template <typename Class, typename Key, typename Arg, typename... Args, typename>
usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, Arg&& arg, Args&&... args) {
automagic_enrollments enrollments;
enrollments.default_constructor = !detail::any_is_constructor_v<Arg, Args...>;
enrollments.destructor = !detail::any_is_destructor_v<Arg, Args...>;
usertype<Class> ut = this->new_usertype<Class>(std::forward<Key>(key), std::move(enrollments));
static_assert(sizeof...(Args) % 2 == static_cast<std::size_t>(!detail::any_is_constructor_v<Arg>),
"you must pass an even number of arguments to new_usertype after first passing a constructor");
if constexpr (detail::any_is_constructor_v<Arg>) {
ut.set(meta_function::construct, std::forward<Arg>(arg));
ut.tuple_set(std::make_index_sequence<(sizeof...(Args)) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...));
}
else {
ut.tuple_set(std::make_index_sequence<(sizeof...(Args) + 1) / 2>(), std::forward_as_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...));
}
return ut;
}
template <typename base_type> template <typename base_type>
template <typename Key, typename Value> template <typename Key, typename Value>
void basic_metatable<base_type>::set(Key&& key, Value&& value) { void basic_metatable<base_type>::set(Key&& key, Value&& value) {
@ -48,6 +73,9 @@ namespace sol {
u_detail::usertype_storage_base& uts = *maybe_uts; u_detail::usertype_storage_base& uts = *maybe_uts;
uts.set(std::forward<Key>(key), std::forward<Value>(value)); uts.set(std::forward<Key>(key), std::forward<Value>(value));
} }
else {
base_t::set(std::forward<Key>(key), std::forward<Value>(value));
}
} }
namespace stack { namespace stack {

View File

@ -366,7 +366,13 @@ namespace sol {
} }
template <typename Class, typename Key> template <typename Class, typename Key>
usertype<Class> new_usertype(Key&& key, optional<no_construction> no_constructor = nullopt); usertype<Class> new_usertype(Key&& key);
template <typename Class, typename Key>
usertype<Class> new_usertype(Key&& key, automagic_enrollments enrollment);
template <typename Class, typename Key, typename Arg, typename... Args, typename = std::enable_if_t<!std::is_same_v<meta::unqualified_t<Arg>, automagic_enrollments>>>
usertype<Class> new_usertype(Key&& key, Arg&& arg, Args&&... args);
template <bool read_only = true, typename... Args> template <bool read_only = true, typename... Args>
table new_enum(const string_view& name, Args&&... args) { table new_enum(const string_view& name, Args&&... args) {

View File

@ -550,13 +550,13 @@ namespace sol {
using has_insert_after = meta::boolean<meta_detail::has_insert_after_test<T>::value>; using has_insert_after = meta::boolean<meta_detail::has_insert_after_test<T>::value>;
template <typename T> template <typename T>
using has_size = meta::boolean<meta_detail::has_size_test<T>::value || meta_detail::has_size_test<const T>::value>; using has_size = meta::boolean<meta_detail::has_size_test<T>::value>;
template <typename T> template <typename T>
struct is_associative : meta::all<has_key_type<T>, has_key_value_pair<T>, has_mapped_type<T>> {}; using is_associative = meta::all<has_key_type<T>, has_key_value_pair<T>, has_mapped_type<T>>;
template <typename T> template <typename T>
struct is_lookup : meta::all<has_key_type<T>, has_value_type<T>> {}; using is_lookup = meta::all<has_key_type<T>, has_value_type<T>>;
template <typename T> template <typename T>
struct is_matched_lookup : meta_detail::is_matched_lookup_impl<T, is_lookup<T>::value> {}; struct is_matched_lookup : meta_detail::is_matched_lookup_impl<T, is_lookup<T>::value> {};

View File

@ -1043,11 +1043,17 @@ namespace sol {
template <typename T> template <typename T>
struct is_unique_usertype : std::integral_constant<bool, unique_usertype_traits<T>::value> {}; struct is_unique_usertype : std::integral_constant<bool, unique_usertype_traits<T>::value> {};
template <typename T>
inline constexpr bool is_unique_usertype_v = is_unique_usertype<T>::value;
template <typename T> template <typename T>
struct lua_type_of : detail::lua_type_of<T> { struct lua_type_of : detail::lua_type_of<T> {
typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_;
}; };
template <typename T>
inline constexpr type lua_type_of_v = lua_type_of<T>::value;
template <typename T> template <typename T>
struct lua_size : std::integral_constant<int, 1> { struct lua_size : std::integral_constant<int, 1> {
typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_;
@ -1059,6 +1065,9 @@ namespace sol {
template <typename... Args> template <typename... Args>
struct lua_size<std::tuple<Args...>> : std::integral_constant<int, detail::accumulate<int, 0, lua_size, Args...>::value> {}; struct lua_size<std::tuple<Args...>> : std::integral_constant<int, detail::accumulate<int, 0, lua_size, Args...>::value> {};
template <typename T>
inline constexpr int lua_size_v = lua_size<T>::value;
namespace detail { namespace detail {
template <typename...> template <typename...>
struct void_ { typedef void type; }; struct void_ { typedef void type; };
@ -1211,7 +1220,7 @@ namespace sol {
using any_is_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>; using any_is_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>;
template <typename... Args> template <typename... Args>
using any_is_constructor_v = any_is_constructor<Args...>::value; inline constexpr bool any_is_constructor_v = any_is_constructor<Args...>::value;
template <typename T> template <typename T>
struct is_destructor : std::false_type {}; struct is_destructor : std::false_type {};
@ -1220,13 +1229,30 @@ namespace sol {
struct is_destructor<destructor_wrapper<Fx>> : std::true_type {}; struct is_destructor<destructor_wrapper<Fx>> : std::true_type {};
template <typename... Args> template <typename... Args>
using has_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>; using any_is_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>;
template <typename... Args>
inline constexpr bool any_is_destructor_v = any_is_destructor<Args...>::value;
struct add_destructor_tag {}; struct add_destructor_tag {};
struct check_destructor_tag {}; struct check_destructor_tag {};
struct verified_tag { struct verified_tag {
} const verified {}; } const verified {};
} // namespace detail } // namespace detail
struct automagic_enrollments {
bool default_constructor = true;
bool destructor = true;
bool pairs_operator = true;
bool to_string_operator = true;
bool call_operator = true;
bool less_than_operator = true;
bool less_than_or_equal_to_operator = true;
bool length_operator = true;
bool equal_to_operator = true;
};
} // namespace sol } // namespace sol
#endif // SOL_TYPES_HPP #endif // SOL_TYPES_HPP

View File

@ -42,6 +42,16 @@ namespace sol {
using base_t::pop; using base_t::pop;
using base_t::push; using base_t::push;
template <std::size_t... I, typename... Args>
void tuple_set(std::index_sequence<I...>, std::tuple<Args...>&& args) {
using args_tuple = std::tuple<Args...>&&;
optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(this->lua_state());
if (maybe_uts) {
u_detail::usertype_storage<T>& uts = *maybe_uts;
detail::swallow{ 0, (uts.set(this->lua_state(), std::get<I * 2>(std::forward<args_tuple>(args)), std::get<I * 2 + 1>(std::forward<args_tuple>(args))), 0)... };
}
}
template <typename Key, typename Value> template <typename Key, typename Value>
void set(Key&& key, Value&& value) { void set(Key&& key, Value&& value) {
optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(this->lua_state()); optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(this->lua_state());

View File

@ -45,7 +45,7 @@ namespace sol {
} }
static int real_index_call(lua_State* L) { static int real_index_call(lua_State* L) {
typedef detail::map_t<std::string, lua_CFunction> call_map; typedef detail::unordered_map<std::string, lua_CFunction> call_map;
static const call_map calls{ static const call_map calls{
{ "at", &at_call }, { "at", &at_call },
{ "get", &real_get_call }, { "get", &real_get_call },

View File

@ -66,78 +66,6 @@ namespace sol {
named named
}; };
struct no_comp {
template <typename A, typename B>
bool operator()(A&&, B&&) const {
return false;
}
};
template <typename T>
inline int is_check(lua_State* L) {
return stack::push(L, stack::check<T>(L, 1, &no_panic));
}
template <typename T>
inline int member_default_to_string(std::true_type, lua_State* L) {
decltype(auto) ts = stack::get<T>(L, 1).to_string();
return stack::push(L, std::forward<decltype(ts)>(ts));
}
template <typename T>
inline int member_default_to_string(std::false_type, lua_State* L) {
return luaL_error(L, "cannot perform to_string on '%s': no 'to_string' overload in namespace, 'to_string' member function, or operator<<(ostream&, ...) present", detail::demangle<T>().data());
}
template <typename T>
inline int adl_default_to_string(std::true_type, lua_State* L) {
using namespace std;
decltype(auto) ts = to_string(stack::get<T>(L, 1));
return stack::push(L, std::forward<decltype(ts)>(ts));
}
template <typename T>
inline int adl_default_to_string(std::false_type, lua_State* L) {
return member_default_to_string<T>(meta::supports_to_string_member<T>(), L);
}
template <typename T>
inline int oss_default_to_string(std::true_type, lua_State* L) {
std::ostringstream oss;
oss << stack::unqualified_get<T>(L, 1);
return stack::push(L, oss.str());
}
template <typename T>
inline int oss_default_to_string(std::false_type, lua_State* L) {
return adl_default_to_string<T>(meta::supports_adl_to_string<T>(), L);
}
template <typename T>
inline int default_to_string(lua_State* L) {
return oss_default_to_string<T>(meta::supports_ostream_op<T>(), L);
}
template <typename T, typename Op>
int comparsion_operator_wrap(lua_State* L) {
auto maybel = stack::unqualified_check_get<T&>(L, 1);
if (maybel) {
auto mayber = stack::unqualified_check_get<T&>(L, 2);
if (mayber) {
auto& l = *maybel;
auto& r = *mayber;
if (std::is_same<no_comp, Op>::value) {
return stack::push(L, detail::ptr(l) == detail::ptr(r));
}
else {
Op op;
return stack::push(L, (detail::ptr(l) == detail::ptr(r)) || op(detail::deref(l), detail::deref(r)));
}
}
}
return stack::push(L, false);
}
inline auto make_string_view(string_view s) { inline auto make_string_view(string_view s) {
return s; return s;
} }
@ -183,81 +111,6 @@ namespace sol {
inline int is_indexer(call_construction) { inline int is_indexer(call_construction) {
return 0; return 0;
} }
template <typename T>
lua_CFunction make_destructor() {
if constexpr (std::is_destructible_v<T>) {
if constexpr (is_unique_usertype<T>::value) {
return &detail::unique_destruct<T>;
}
else if constexpr (!std::is_pointer_v<T>) {
return &detail::usertype_alloc_destruct<T>;
}
}
else {
return &detail::cannot_destruct<T>;
}
}
template <typename T, typename IFx, typename Fx>
void insert_default_registrations(IFx&& ifx, Fx&& fx) {
if constexpr (is_automagical<T>::value) {
if (fx(meta_function::less_than)) {
if constexpr (meta::supports_op_less<T>::value) {
lua_CFunction f = &comparsion_operator_wrap<T, std::less<>>;
ifx(meta_function::less_than, f);
}
}
if (fx(meta_function::less_than_or_equal_to)) {
if constexpr (meta::supports_op_less_equal<T>::value) {
lua_CFunction f = &comparsion_operator_wrap<T, std::less_equal<>>;
ifx(meta_function::less_than_or_equal_to, f);
}
}
if (fx(meta_function::equal_to)) {
if constexpr (meta::supports_op_equal<T>::value) {
lua_CFunction f = &comparsion_operator_wrap<T, std::equal_to<>>;
ifx(meta_function::equal_to, f);
}
}
if (fx(meta_function::pairs)) {
ifx(meta_function::pairs, &usertype_container<as_container_t<T>>::pairs_call);
}
if (fx(meta_function::length)) {
if constexpr (meta::has_size<T>::value) {
#if defined(__clang__)
ifx(meta_function::length, &c_call<decltype(&T::size), &T::size>);
#else
typedef decltype(std::declval<T>().size()) R;
using sz_func = R (T::*)();
ifx(meta_function::length, &c_call<decltype(static_cast<sz_func>(&T::size)), static_cast<sz_func>(&T::size)>);
#endif
}
else if constexpr (meta::has_size<const T>::value) {
#if defined(__clang__)
ifx(meta_function::length, &c_call<decltype(&T::size), &T::size>);
#else
typedef decltype(std::declval<T>().size()) R;
using sz_func = R (T::*)() const;
lua_CFunction f = &c_call<decltype(static_cast<sz_func>(&T::size)), static_cast<sz_func>(&T::size)>;
ifx(meta_function::length, f);
#endif
}
}
if (fx(meta_function::to_string)) {
if constexpr (is_to_stringable<T>::value) {
lua_CFunction f = &detail::static_trampoline<&default_to_string<T>>;
ifx(meta_function::to_string, f);
}
}
if (fx(meta_function::call_function)) {
if constexpr (meta::has_deducible_signature<T>::value) {
lua_CFunction f = &c_call<decltype(&T::operator()), &T::operator()>;
ifx(meta_function::call_function, f);
}
}
}
}
} // namespace u_detail } // namespace u_detail
namespace stack { namespace stack_detail { namespace stack { namespace stack_detail {
@ -274,15 +127,11 @@ namespace sol {
void operator()() const { void operator()() const {
if (luaL_newmetatable(L, key) == 1) { if (luaL_newmetatable(L, key) == 1) {
luaL_Reg l[64] {}; detail::lua_reg_table l{};
int index = 0; int index = 0;
auto prop_fx = [](meta_function) { return true; }; detail::indexed_insert insert_fx(l, index);
auto insert_fx = [&l, &index](meta_function mf, lua_CFunction f) { detail::insert_default_registrations<P>(insert_fx, detail::property_always_true);
l[index] = luaL_Reg { to_string(mf).c_str(), f }; l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<P>() };
++index;
};
u_detail::insert_default_registrations<P>(insert_fx, prop_fx);
l[index] = luaL_Reg { to_string(meta_function::garbage_collect).c_str(), u_detail::make_destructor<P>() };
luaL_setfuncs(L, l, 0); luaL_setfuncs(L, l, 0);
// __type table // __type table
@ -290,7 +139,7 @@ namespace sol {
const std::string& name = detail::demangle<T>(); const std::string& name = detail::demangle<T>();
lua_pushlstring(L, name.c_str(), name.size()); lua_pushlstring(L, name.c_str(), name.size());
lua_setfield(L, -2, "name"); lua_setfield(L, -2, "name");
lua_CFunction is_func = &u_detail::is_check<T>; lua_CFunction is_func = &detail::is_check<T>;
lua_pushcclosure(L, is_func, 0); lua_pushcclosure(L, is_func, 0);
lua_setfield(L, -2, "is"); lua_setfield(L, -2, "is");
lua_setfield(L, -2, to_string(meta_function::type).c_str()); lua_setfield(L, -2, to_string(meta_function::type).c_str());

View File

@ -158,7 +158,7 @@ namespace u_detail {
reference named_index_table; reference named_index_table;
reference type_table; reference type_table;
reference gc_names_table; reference gc_names_table;
reference metametatable; reference named_metatable;
std::bitset<64> properties; std::bitset<64> properties;
index_call_storage base_index; index_call_storage base_index;
index_call_storage base_new_index; index_call_storage base_new_index;
@ -166,7 +166,7 @@ namespace u_detail {
bool is_using_new_index; bool is_using_new_index;
usertype_storage_base(lua_State* L) usertype_storage_base(lua_State* L)
: storage(), string_keys(), auxiliary_keys(), value_index_table(), reference_index_table(), unique_index_table(), const_reference_index_table(), type_table(make_reference(L, create)), gc_names_table(make_reference(L, create)), metametatable(make_reference(L, create)), properties(), base_index(), base_new_index(), is_using_index(false), is_using_new_index(false) { : storage(), string_keys(), auxiliary_keys(), value_index_table(), reference_index_table(), unique_index_table(), const_reference_index_table(), type_table(make_reference(L, create)), gc_names_table(make_reference(L, create)), named_metatable(make_reference(L, create)), properties(), base_index(), base_new_index(), is_using_index(false), is_using_new_index(false) {
base_index.binding_data = nullptr; base_index.binding_data = nullptr;
base_index.index = index_target_fail; base_index.index = index_target_fail;
base_index.new_index = index_target_fail; base_index.new_index = index_target_fail;
@ -339,8 +339,8 @@ namespace u_detail {
} }
else { else {
if (submetatable_type == submetatable::named) { if (submetatable_type == submetatable::named) {
stack::set_field(L, metatable_key, metametatable, t.stack_index()); stack::set_field(L, metatable_key, named_metatable, t.stack_index());
stack_reference stack_metametatable(L, -metametatable.push()); stack_reference stack_metametatable(L, -named_metatable.push());
stack::set_field<false, true>(L, meta_function::index, make_closure(uts::meta_index_call, nullptr, make_light(*this), make_light(this_base), nullptr, toplevel_magic), stack_metametatable.stack_index()); stack::set_field<false, true>(L, meta_function::index, make_closure(uts::meta_index_call, nullptr, make_light(*this), make_light(this_base), nullptr, toplevel_magic), stack_metametatable.stack_index());
stack::set_field<false, true>(L, meta_function::new_index, make_closure(uts::meta_new_index_call, nullptr, make_light(*this), make_light(this_base), nullptr, toplevel_magic), stack_metametatable.stack_index()); stack::set_field<false, true>(L, meta_function::new_index, make_closure(uts::meta_new_index_call, nullptr, make_light(*this), make_light(this_base), nullptr, toplevel_magic), stack_metametatable.stack_index());
stack_metametatable.pop(); stack_metametatable.pop();
@ -433,19 +433,19 @@ namespace u_detail {
using KeyU = meta::unwrap_unqualified_t<Key>; using KeyU = meta::unwrap_unqualified_t<Key>;
using Binding = binding<KeyU, ValueU, T>; using Binding = binding<KeyU, ValueU, T>;
using is_var_bind = is_variable_binding<ValueU>; using is_var_bind = is_variable_binding<ValueU>;
if constexpr (std::is_same_v<Key, call_construction>) { if constexpr (std::is_same_v<KeyU, call_construction>) {
std::unique_ptr<Binding> p_binding = std::make_unique<Binding>(std::forward<Value>(value)); std::unique_ptr<Binding> p_binding = std::make_unique<Binding>(std::forward<Value>(value));
Binding& b = *p_binding; Binding& b = *p_binding;
this->storage.push_back(std::move(p_binding)); this->storage.push_back(std::move(p_binding));
this->named_index_table.push(); this->named_metatable.push();
absolute_index metametatable_index(L, -1); absolute_index metametatable_index(L, -1);
stack::push(L, nullptr); stack::push(L, nullptr);
stack::push(L, b.data()); stack::push(L, b.data());
lua_CFunction target_func = &b.call<false, false>; lua_CFunction target_func = &b.call<false, false>;
lua_pushcclosure(L, target_func, 2); lua_pushcclosure(L, target_func, 2);
lua_setfield(L, metametatable_index, to_string(meta_function::call).c_str()); lua_setfield(L, metametatable_index, to_string(meta_function::call).c_str());
this->named_index_table.pop(); this->named_metatable.pop();
} }
else if constexpr ((meta::is_string_constructible<KeyU>::value || std::is_same_v<KeyU, meta_function>)&&(!is_lua_reference_or_proxy<ValueU>::value && !is_lua_reference_or_proxy<KeyU>::value)) { else if constexpr ((meta::is_string_constructible<KeyU>::value || std::is_same_v<KeyU, meta_function>)&&(!is_lua_reference_or_proxy<ValueU>::value && !is_lua_reference_or_proxy<KeyU>::value)) {
std::unique_ptr<Binding> p_binding = std::make_unique<Binding>(std::forward<Value>(value)); std::unique_ptr<Binding> p_binding = std::make_unique<Binding>(std::forward<Value>(value));
@ -553,7 +553,7 @@ namespace u_detail {
int usertype_storage_metatabe_count = stack::push(L, new_table(0, 1)); int usertype_storage_metatabe_count = stack::push(L, new_table(0, 1));
stack_table usertype_storage_metatable(L, -usertype_storage_metatabe_count); stack_table usertype_storage_metatable(L, -usertype_storage_metatabe_count);
// set the destruction routine on the metatable // set the destruction routine on the metatable
stack::set_field(L, meta_function::garbage_collect, detail::user_alloc_destruct<T>, usertype_storage_metatable.stack_index()); stack::set_field(L, meta_function::garbage_collect, detail::user_alloc_destruct<usertype_storage<T>>, usertype_storage_metatable.stack_index());
// set the metatable on the usertype storage userdata // set the metatable on the usertype storage userdata
stack::set_field(L, metatable_key, usertype_storage_metatable, usertype_storage_ref.stack_index()); stack::set_field(L, metatable_key, usertype_storage_metatable, usertype_storage_ref.stack_index());
usertype_storage_metatable.pop(); usertype_storage_metatable.pop();
@ -638,7 +638,7 @@ namespace u_detail {
} }
template <typename T> template <typename T>
inline int register_usertype(lua_State* L, optional<no_construction> no_default_constructor = nullopt) { inline int register_usertype(lua_State* L, automagic_enrollments enrollments = {}) {
using u_traits = usertype_traits<T>; using u_traits = usertype_traits<T>;
using u_const_traits = usertype_traits<const T>; using u_const_traits = usertype_traits<const T>;
using u_unique_traits = usertype_traits<detail::unique_usertype<T>>; using u_unique_traits = usertype_traits<detail::unique_usertype<T>>;
@ -704,7 +704,7 @@ namespace u_detail {
// STEP 4: add some useful information to the type table // STEP 4: add some useful information to the type table
stack_reference stacked_type_table(L, -storage.type_table.push()); stack_reference stacked_type_table(L, -storage.type_table.push());
stack::set_field(L, "name", detail::demangle<T>(), stacked_type_table.stack_index()); stack::set_field(L, "name", detail::demangle<T>(), stacked_type_table.stack_index());
stack::set_field(L, "is", &u_detail::is_check<T>, stacked_type_table.stack_index()); stack::set_field(L, "is", &detail::is_check<T>, stacked_type_table.stack_index());
stacked_type_table.pop(); stacked_type_table.pop();
// STEP 5: create and hook up metatable, // STEP 5: create and hook up metatable,
@ -781,14 +781,12 @@ namespace u_detail {
stack::set_field(L, detail::base_class_cast_key(), (void*)&detail::inheritance<T>::type_cast, t.stack_index()); stack::set_field(L, detail::base_class_cast_key(), (void*)&detail::inheritance<T>::type_cast, t.stack_index());
} }
auto prop_fx = [&](meta_function mf) { auto prop_fx = properties_enrollment_allowed(storage.properties, enrollments);
return !storage.properties[static_cast<int>(mf)];
};
auto insert_fx = [&](meta_function mf, lua_CFunction reg) { auto insert_fx = [&](meta_function mf, lua_CFunction reg) {
stack::set_field(L, mf, reg, t.stack_index()); stack::set_field(L, mf, reg, t.stack_index());
storage.properties[static_cast<int>(mf)] = true; storage.properties[static_cast<int>(mf)] = true;
}; };
u_detail::insert_default_registrations<T>(insert_fx, prop_fx); detail::insert_default_registrations<T>(insert_fx, prop_fx);
// There are no variables, so serialize the fast function stuff // There are no variables, so serialize the fast function stuff
// be sure to reset the index stuff to the non-fast version // be sure to reset the index stuff to the non-fast version
@ -800,8 +798,8 @@ namespace u_detail {
stack::set_field(L, meta_function::gc_names, storage.gc_names_table, t.stack_index()); stack::set_field(L, meta_function::gc_names, storage.gc_names_table, t.stack_index());
// fancy new_indexing when using the named table // fancy new_indexing when using the named table
stack::set_field<false, true>(L, metatable_key, storage.metametatable, t.stack_index()); stack::set_field<false, true>(L, metatable_key, storage.named_metatable, t.stack_index());
stack_reference stack_metametatable(L, -storage.metametatable.push()); stack_reference stack_metametatable(L, -storage.named_metatable.push());
stack::set_field<false, true>(L, meta_function::index, make_closure(uts::meta_index_call, nullptr, make_light(storage), make_light(base_storage), nullptr, toplevel_magic), stack_metametatable.stack_index()); stack::set_field<false, true>(L, meta_function::index, make_closure(uts::meta_index_call, nullptr, make_light(storage), make_light(base_storage), nullptr, toplevel_magic), stack_metametatable.stack_index());
stack::set_field<false, true>(L, meta_function::new_index, make_closure(uts::meta_new_index_call, nullptr, make_light(storage), make_light(base_storage), nullptr, toplevel_magic), stack_metametatable.stack_index()); stack::set_field<false, true>(L, meta_function::new_index, make_closure(uts::meta_new_index_call, nullptr, make_light(storage), make_light(base_storage), nullptr, toplevel_magic), stack_metametatable.stack_index());
stack_metametatable.pop(); stack_metametatable.pop();
@ -819,7 +817,7 @@ namespace u_detail {
// can only use set AFTER we initialize all the metatables // can only use set AFTER we initialize all the metatables
if constexpr (std::is_default_constructible_v<T>) { if constexpr (std::is_default_constructible_v<T>) {
if (no_default_constructor == nullopt) { if (enrollments.default_constructor) {
storage.set(L, meta_function::construct, constructors<T()>()); storage.set(L, meta_function::construct, constructors<T()>());
} }
} }

View File

@ -1119,16 +1119,6 @@ TEST_CASE("containers/non_copyable", "make sure non-copyable types in containers
lua["v"] = std::vector<non_copyable>{}; lua["v"] = std::vector<non_copyable>{};
auto pfr = lua.safe_script("t = test.new() t.b = v", sol::script_pass_on_error);
REQUIRE_FALSE(pfr.valid());
}
SECTION("simple") {
sol::state lua;
lua.new_simple_usertype<test>("test",
"b", sol::readonly(&test::b));
lua["v"] = std::vector<non_copyable>{};
auto pfr = lua.safe_script("t = test.new() t.b = v", sol::script_pass_on_error); auto pfr = lua.safe_script("t = test.new() t.b = v", sol::script_pass_on_error);
REQUIRE_FALSE(pfr.valid()); REQUIRE_FALSE(pfr.valid());
} }

View File

@ -170,36 +170,6 @@ end
sol::function f = lua.safe_script(R"( sol::function f = lua.safe_script(R"(
return function(e) return function(e)
end end
)");
gc_entity* target = nullptr;
{
gc_entity e;
target = &e;
{
f(e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(&e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(std::ref(e)); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
}
REQUIRE(entities.size() == 1);
REQUIRE(entities.back() == target);
}
SECTION("simple") {
entities.clear();
sol::state lua;
lua.open_libraries();
lua.new_simple_usertype<gc_entity>("entity");
sol::function f = lua.safe_script(R"(
return function(e)
end
)"); )");
gc_entity* target = nullptr; gc_entity* target = nullptr;
{ {
@ -443,27 +413,6 @@ TEST_CASE("gc/usertypes", "show that proper copies / destruction happens for use
REQUIRE(created == 4); REQUIRE(created == 4);
REQUIRE(destroyed == 4); REQUIRE(destroyed == 4);
} }
SECTION("simple") {
created = 0;
destroyed = 0;
{
sol::state lua;
lua.new_simple_usertype<x>("x");
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(std::addressof(x1) == std::addressof(x1ref));
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
}
REQUIRE(created == 4);
REQUIRE(destroyed == 4);
}
} }
TEST_CASE("gc/double-deletion tests", "make sure usertypes are properly destructed and don't double-delete memory or segfault") { TEST_CASE("gc/double-deletion tests", "make sure usertypes are properly destructed and don't double-delete memory or segfault") {
@ -492,21 +441,6 @@ TEST_CASE("gc/double-deletion tests", "make sure usertypes are properly destruct
)", sol::script_pass_on_error); )", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
for (int i = 0; i < 1000; ++i) {
lua["testCrash"]();
}
}
SECTION("simple") {
lua.new_simple_usertype<crash_class>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>());
auto result1 = lua.safe_script(R"(
function testCrash()
local x = CrashClass()
end
)", sol::script_pass_on_error);
REQUIRE(result1.valid());
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
lua["testCrash"](); lua["testCrash"]();
} }
@ -554,34 +488,6 @@ TEST_CASE("gc/shared_ptr regression", "metatables should not screw over unique u
REQUIRE(created == 1); REQUIRE(created == 1);
REQUIRE(destroyed == 1); REQUIRE(destroyed == 1);
} }
SECTION("simple") {
created = 0;
destroyed = 0;
{
std::list<std::shared_ptr<test>> tests;
sol::state lua;
lua.open_libraries();
lua.new_simple_usertype<test>("test",
"create", [&]() -> std::shared_ptr<test> {
tests.push_back(std::make_shared<test>());
return tests.back();
});
REQUIRE(created == 0);
REQUIRE(destroyed == 0);
auto result1 = lua.safe_script("x = test.create()", sol::script_pass_on_error);
REQUIRE(result1.valid());
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty());
std::shared_ptr<test>& x = lua["x"];
std::size_t xuse = x.use_count();
std::size_t tuse = tests.back().use_count();
REQUIRE(xuse == tuse);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
} }
TEST_CASE("gc/double deleter guards", "usertype metatables internally must not rely on C++ state") { TEST_CASE("gc/double deleter guards", "usertype metatables internally must not rely on C++ state") {
@ -603,24 +509,6 @@ TEST_CASE("gc/double deleter guards", "usertype metatables internally must not r
}; };
REQUIRE_NOTHROW(routine()); REQUIRE_NOTHROW(routine());
} }
SECTION("simple") {
struct sc_a {
int xv;
};
struct sc_b {
int yv;
};
auto routine = []() {
sol::state lua;
lua.new_simple_usertype<sc_a>("c_a", "x", &sc_a::xv);
lua.new_simple_usertype<sc_b>("c_b", "y", &sc_b::yv);
lua = sol::state();
lua.new_simple_usertype<sc_a>("c_a", "x", &sc_a::xv);
lua.new_simple_usertype<sc_b>("c_b", "y", &sc_b::yv);
lua = sol::state();
};
REQUIRE_NOTHROW(routine());
}
} }
TEST_CASE("gc/alignment", "test that allocation is always on aligned boundaries, no matter the wrapper / type") { TEST_CASE("gc/alignment", "test that allocation is always on aligned boundaries, no matter the wrapper / type") {

View File

@ -27,6 +27,58 @@
#include <iostream> #include <iostream>
class TestClass00 {
public:
int Thing() const {
return 123;
}
};
class TestClass01 : public TestClass00 {
public:
TestClass01()
: a(1) {
}
TestClass01(const TestClass00& other)
: a(other.Thing()) {
}
int a;
};
class TestClass02 : public TestClass01 {
public:
TestClass02()
: b(2) {
}
TestClass02(const TestClass01& other)
: b(other.a) {
}
TestClass02(const TestClass00& other)
: b(other.Thing()) {
}
int b;
};
class TestClass03 : public TestClass02 {
public:
TestClass03()
: c(2) {
}
TestClass03(const TestClass02& other)
: c(other.b) {
}
TestClass03(const TestClass01& other)
: c(other.a) {
}
TestClass03(const TestClass00& other)
: c(other.Thing()) {
}
int c;
};
TEST_CASE("inheritance/basic", "test that metatables are properly inherited") { TEST_CASE("inheritance/basic", "test that metatables are properly inherited") {
struct A { struct A {
int a = 5; int a = 5;
@ -82,87 +134,28 @@ TEST_CASE("inheritance/basic", "test that metatables are properly inherited") {
} }
TEST_CASE("inheritance/multi base", "test that multiple bases all work and overloading for constructors works with them") { TEST_CASE("inheritance/multi base", "test that multiple bases all work and overloading for constructors works with them") {
class TestClass00 {
public:
int Thing() const {
return 123;
}
};
class TestClass01 : public TestClass00 {
public:
TestClass01()
: a(1) {
}
TestClass01(const TestClass00& other)
: a(other.Thing()) {
}
int a;
};
class TestClass02 : public TestClass01 {
public:
TestClass02()
: b(2) {
}
TestClass02(const TestClass01& other)
: b(other.a) {
}
TestClass02(const TestClass00& other)
: b(other.Thing()) {
}
int b;
};
class TestClass03 : public TestClass02 {
public:
TestClass03()
: c(2) {
}
TestClass03(const TestClass02& other)
: c(other.b) {
}
TestClass03(const TestClass01& other)
: c(other.a) {
}
TestClass03(const TestClass00& other)
: c(other.Thing()) {
}
int c;
};
sol::state lua; sol::state lua;
sol::usertype<TestClass00> s_TestUsertype00( sol::usertype<TestClass00> s_TestUsertype00 = lua.new_usertype<TestClass00>("TestClass00",
sol::call_constructor, sol::constructors<sol::types<>>(), sol::call_constructor, sol::constructors<sol::types<>>(),
"Thing", &TestClass00::Thing); "Thing", &TestClass00::Thing);
lua.set_usertype("TestClass00", s_TestUsertype00); sol::usertype<TestClass01> s_TestUsertype01 = lua.new_usertype<TestClass01>("TestClass01",
sol::usertype<TestClass01> s_TestUsertype01(
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass00&>>(), sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass00&>>(),
sol::base_classes, sol::bases<TestClass00>(), sol::base_classes, sol::bases<TestClass00>(),
"a", &TestClass01::a); "a", &TestClass01::a);
lua.set_usertype("TestClass01", s_TestUsertype01); sol::usertype<TestClass02> s_TestUsertype02 = lua.new_usertype<TestClass02>("TestClass02",
sol::usertype<TestClass02> s_TestUsertype02(
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(), sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
sol::base_classes, sol::bases<TestClass01, TestClass00>(), sol::base_classes, sol::bases<TestClass01, TestClass00>(),
"b", &TestClass02::b); "b", &TestClass02::b);
lua.set_usertype("TestClass02", s_TestUsertype02); sol::usertype<TestClass03> s_TestUsertype03 = lua.new_usertype<TestClass03>("TestClass03",
sol::usertype<TestClass03> s_TestUsertype03(
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass02&>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(), sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass02&>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
sol::base_classes, sol::bases<TestClass02, TestClass01, TestClass00>(), sol::base_classes, sol::bases<TestClass02, TestClass01, TestClass00>(),
"c", &TestClass03::c); "c", &TestClass03::c);
lua.set_usertype("TestClass03", s_TestUsertype03);
auto result1 = lua.safe_script(R"( auto result1 = lua.safe_script(R"(
tc0 = TestClass00() tc0 = TestClass00()
tc2 = TestClass02(tc0) tc2 = TestClass02(tc0)
@ -185,87 +178,28 @@ tc3 = TestClass03(tc1)
} }
TEST_CASE("inheritance/simple multi base", "test that multiple bases all work and overloading for constructors works with them") { TEST_CASE("inheritance/simple multi base", "test that multiple bases all work and overloading for constructors works with them") {
class TestClass00 {
public:
int Thing() const {
return 123;
}
};
class TestClass01 : public TestClass00 {
public:
TestClass01()
: a(1) {
}
TestClass01(const TestClass00& other)
: a(other.Thing()) {
}
int a;
};
class TestClass02 : public TestClass01 {
public:
TestClass02()
: b(2) {
}
TestClass02(const TestClass01& other)
: b(other.a) {
}
TestClass02(const TestClass00& other)
: b(other.Thing()) {
}
int b;
};
class TestClass03 : public TestClass02 {
public:
TestClass03()
: c(2) {
}
TestClass03(const TestClass02& other)
: c(other.b) {
}
TestClass03(const TestClass01& other)
: c(other.a) {
}
TestClass03(const TestClass00& other)
: c(other.Thing()) {
}
int c;
};
sol::state lua; sol::state lua;
sol::simple_usertype<TestClass00> s_TestUsertype00(lua, sol::usertype<TestClass00> s_TestUsertype00 = lua.new_usertype<TestClass00>("TestClass00",
sol::call_constructor, sol::constructors<sol::types<>>(), sol::call_constructor, sol::constructors<sol::types<>>(),
"Thing", &TestClass00::Thing); "Thing", &TestClass00::Thing);
lua.set_usertype("TestClass00", s_TestUsertype00); sol::usertype<TestClass01> s_TestUsertype01 = lua.new_usertype<TestClass01>("TestClass01",
sol::simple_usertype<TestClass01> s_TestUsertype01(lua,
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass00&>>(), sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass00&>>(),
sol::base_classes, sol::bases<TestClass00>(), sol::base_classes, sol::bases<TestClass00>(),
"a", &TestClass01::a); "a", &TestClass01::a);
lua.set_usertype("TestClass01", s_TestUsertype01); sol::usertype<TestClass02> s_TestUsertype02 = lua.new_usertype<TestClass02>("TestClass02",
sol::simple_usertype<TestClass02> s_TestUsertype02(lua,
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(), sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
sol::base_classes, sol::bases<TestClass01, TestClass00>(), sol::base_classes, sol::bases<TestClass01, TestClass00>(),
"b", &TestClass02::b); "b", &TestClass02::b);
lua.set_usertype("TestClass02", s_TestUsertype02); sol::usertype<TestClass03> s_TestUsertype03 = lua.new_usertype<TestClass03>("TestClass03",
sol::simple_usertype<TestClass03> s_TestUsertype03(lua,
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass02&>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(), sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass02&>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
sol::base_classes, sol::bases<TestClass02, TestClass01, TestClass00>(), sol::base_classes, sol::bases<TestClass02, TestClass01, TestClass00>(),
"c", &TestClass03::c); "c", &TestClass03::c);
lua.set_usertype("TestClass03", s_TestUsertype03);
auto result1 = lua.safe_script(R"( auto result1 = lua.safe_script(R"(
tc0 = TestClass00() tc0 = TestClass00()
tc2 = TestClass02(tc0) tc2 = TestClass02(tc0)

View File

@ -120,53 +120,6 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
lua.new_usertype<U>("U"); lua.new_usertype<U>("U");
lua.new_usertype<V>("V"); lua.new_usertype<V>("V");
// Can only compare identity here
{
auto result1 = lua.safe_script("assert(t1 == t1)"
"assert(t2 == t2)"
"assert(t3 == t3)", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
{
auto result1 = lua.safe_script("assert(t1 == t2)"
"assert(not (t1 == t3))"
"assert(not (t2 == t3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
// Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient)
{
auto result1 = lua.safe_script("assert(u1 == u1)"
"assert(u2 == u2)"
"assert(u3 == u3)", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
{
auto result1 = lua.safe_script("assert(not (u1 == u2))"
"assert(u1 == u3)"
"assert(not (u2 == u3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
// Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient)
{
auto result1 = lua.safe_script("assert(v1 == v1)"
"assert(v2 == v2)"
"assert(v3 == v3)", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
{
auto result1 = lua.safe_script("assert(not (v1 == v2))"
"assert(v1 == v3)"
"assert(not (v2 == v3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
}
SECTION("simple") {
lua.new_simple_usertype<T>("T");
lua.new_simple_usertype<U>("U");
lua.new_simple_usertype<V>("V");
// Can only compare identity here // Can only compare identity here
{ {
auto result1 = lua.safe_script("assert(t1 == t1)" auto result1 = lua.safe_script("assert(t1 == t1)"
@ -240,15 +193,6 @@ TEST_CASE("operators/call", "test call operator generation") {
REQUIRE(v == 11); REQUIRE(v == 11);
} }
} }
SECTION("simple") {
lua.new_simple_usertype<callable>("callable");
{
lua.safe_script("obj = callable.new()");
lua.safe_script("v = obj(2, 'bark woof')");
int v = lua["v"];
REQUIRE(v == 11);
}
}
} }
struct stringable { struct stringable {
@ -316,16 +260,6 @@ TEST_CASE("operators/stringable", "test std::ostream stringability") {
REQUIRE(stringable::last_print_ptr == &obj); REQUIRE(stringable::last_print_ptr == &obj);
} }
} }
SECTION("simple") {
lua.new_simple_usertype<stringable>("stringable");
{
auto result1 = lua.safe_script(R"(obj = stringable.new()
print(obj))", sol::script_pass_on_error);
REQUIRE(result1.valid());
stringable& obj = lua["obj"];
REQUIRE(stringable::last_print_ptr == &obj);
}
}
} }
TEST_CASE("operators/adl_stringable", "test adl to_string stringability") { TEST_CASE("operators/adl_stringable", "test adl to_string stringability") {
@ -349,15 +283,6 @@ TEST_CASE("operators/adl_stringable", "test adl to_string stringability") {
REQUIRE(adl_stringable::last_print_ptr == &obj); REQUIRE(adl_stringable::last_print_ptr == &obj);
} }
} }
SECTION("simple") {
lua.new_simple_usertype<adl_stringable>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
adl_stringable& obj = lua["obj"];
REQUIRE(adl_stringable::last_print_ptr == &obj);
}
}
} }
TEST_CASE("operators/inside::adl_stringable2", "test adl to_string stringability from inside a namespace") { TEST_CASE("operators/inside::adl_stringable2", "test adl to_string stringability from inside a namespace") {
@ -381,15 +306,6 @@ TEST_CASE("operators/inside::adl_stringable2", "test adl to_string stringability
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj); REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
} }
} }
SECTION("simple") {
lua.new_simple_usertype<inside::adl_stringable2>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
inside::adl_stringable2& obj = lua["obj"];
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
}
}
} }
TEST_CASE("operators/member_stringable", "test member to_string stringability") { TEST_CASE("operators/member_stringable", "test member to_string stringability") {
@ -413,15 +329,6 @@ TEST_CASE("operators/member_stringable", "test member to_string stringability")
REQUIRE(member_stringable::last_print_ptr == &obj); REQUIRE(member_stringable::last_print_ptr == &obj);
} }
} }
SECTION("simple") {
lua.new_simple_usertype<member_stringable>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
member_stringable& obj = lua["obj"];
REQUIRE(member_stringable::last_print_ptr == &obj);
}
}
} }
TEST_CASE("operators/container-like", "test that generic begin/end and iterator are automatically bound") { TEST_CASE("operators/container-like", "test that generic begin/end and iterator are automatically bound") {
@ -506,13 +413,4 @@ TEST_CASE("operators/length", "test that size is automatically bound to the leng
REQUIRE(s == 6); REQUIRE(s == 6);
} }
} }
SECTION("simple") {
lua.new_simple_usertype<sizable>("sizable");
{
lua.safe_script("obj = sizable.new()");
lua.safe_script("s = #obj");
std::size_t s = lua["s"];
REQUIRE(s == 6);
}
}
} }

View File

@ -317,8 +317,7 @@ struct alignas(16) weird_aligned_wrapper {
TEST_CASE("usertype/usertype", "Show that we can create classes from usertype and use them") { TEST_CASE("usertype/usertype", "Show that we can create classes from usertype and use them") {
sol::state lua; sol::state lua;
sol::usertype<fuser> lc{ "add", &fuser::add, "add2", &fuser::add2 }; sol::usertype<fuser> lc = lua.new_usertype<fuser>("fuser", "add", &fuser::add, "add2", &fuser::add2);
lua.set_usertype(lc);
lua.safe_script( lua.safe_script(
"a = fuser:new()\n" "a = fuser:new()\n"
@ -346,8 +345,10 @@ TEST_CASE("usertype/usertype-constructors", "Show that we can create classes fro
sol::state lua; sol::state lua;
sol::constructors<sol::types<>, sol::types<int>, sol::types<int, int>> con; sol::constructors<sol::types<>, sol::types<int>, sol::types<int, int>> con;
sol::usertype<crapola::fuser> lc(con, "add", &crapola::fuser::add, "add2", &crapola::fuser::add2); sol::usertype<crapola::fuser> lc = lua.new_usertype<crapola::fuser>("fuser",
lua.set_usertype(lc); con,
"add", &crapola::fuser::add,
"add2", &crapola::fuser::add2);
lua.safe_script( lua.safe_script(
"a = fuser.new(2)\n" "a = fuser.new(2)\n"
@ -414,9 +415,7 @@ TEST_CASE("usertype/usertype-utility-derived", "usertype classes must play nice
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
sol::constructors<sol::types<int>> basector; sol::constructors<sol::types<int>> basector;
sol::usertype<Base> baseusertype(basector, "get_num", &Base::get_num); sol::usertype<Base> baseusertype = lua.new_usertype<Base>("Base", basector, "get_num", &Base::get_num);
lua.set_usertype(baseusertype);
lua.safe_script("base = Base.new(5)"); lua.safe_script("base = Base.new(5)");
{ {
@ -425,12 +424,10 @@ TEST_CASE("usertype/usertype-utility-derived", "usertype classes must play nice
} }
sol::constructors<sol::types<int>> derivedctor; sol::constructors<sol::types<int>> derivedctor;
sol::usertype<Derived> derivedusertype(derivedctor, sol::usertype<Derived> derivedusertype = lua.new_usertype<Derived>("Derived", derivedctor,
"get_num_10", &Derived::get_num_10, "get_num_10", &Derived::get_num_10,
"get_num", &Derived::get_num); "get_num", &Derived::get_num);
lua.set_usertype(derivedusertype);
lua.safe_script("derived = Derived.new(7)"); lua.safe_script("derived = Derived.new(7)");
lua.safe_script( lua.safe_script(
"dgn = derived:get_num()\n" "dgn = derived:get_num()\n"
@ -532,8 +529,7 @@ TEST_CASE("usertype/issue-number-thirty-five", "using value types created from l
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
sol::constructors<sol::types<float, float, float>> ctor; sol::constructors<sol::types<float, float, float>> ctor;
sol::usertype<Vec> udata(ctor, "normalized", &Vec::normalized, "length", &Vec::length); sol::usertype<Vec> udata = lua.new_usertype<Vec>("Vec", ctor, "normalized", &Vec::normalized, "length", &Vec::length);
lua.set_usertype(udata);
{ {
auto result = lua.safe_script( auto result = lua.safe_script(
@ -555,11 +551,11 @@ TEST_CASE("usertype/lua-stored-usertype", "ensure usertype values can be stored
{ {
sol::constructors<sol::types<float, float, float>> ctor; sol::constructors<sol::types<float, float, float>> ctor;
sol::usertype<Vec> udata(ctor, sol::usertype<Vec> udata = lua.new_usertype<Vec>("Vec",
ctor,
"normalized", &Vec::normalized, "normalized", &Vec::normalized,
"length", &Vec::length); "length", &Vec::length);
lua.set_usertype(udata);
// usertype dies, but still usable in lua! // usertype dies, but still usable in lua!
} }
@ -583,13 +579,13 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
sol::constructors<sol::types<float, float, float>> ctor; sol::constructors<sol::types<float, float, float>> ctor;
sol::usertype<Vec> udata(ctor, sol::usertype<Vec> udata = lua.new_usertype<Vec>("Vec",
ctor,
"x", &Vec::x, "x", &Vec::x,
"y", &Vec::y, "y", &Vec::y,
"z", &Vec::z, "z", &Vec::z,
"normalized", &Vec::normalized, "normalized", &Vec::normalized,
"length", &Vec::length); "length", &Vec::length);
lua.set_usertype(udata);
REQUIRE_NOTHROW(lua.safe_script( REQUIRE_NOTHROW(lua.safe_script(
"v = Vec.new(1, 2, 3)\n" "v = Vec.new(1, 2, 3)\n"
@ -639,9 +635,8 @@ TEST_CASE("usertype/nonmember-functions", "let users set non-member functions th
"gief", &giver::gief, "gief", &giver::gief,
"__tostring", [](const giver& t) { "__tostring", [](const giver& t) {
return std::to_string(t.a) + ": giving value"; return std::to_string(t.a) + ": giving value";
}) });
.get<sol::table>("giver") lua.get<sol::table>("giver").set_function("stuff", giver::stuff);
.set_function("stuff", giver::stuff);
{ {
auto result = lua.safe_script("giver.stuff()", sol::script_pass_on_error); auto result = lua.safe_script("giver.stuff()", sol::script_pass_on_error);

View File

@ -210,15 +210,15 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
} }
TEST_CASE("variadics/fallback_constructor", "ensure constructor matching behaves properly in the presence of variadic fallbacks") { TEST_CASE("variadics/fallback_constructor", "ensure constructor matching behaves properly in the presence of variadic fallbacks") {
struct vec2 { struct vec2x {
float x = 0, y = 0; float x = 0, y = 0;
}; };
sol::state lua; sol::state lua;
lua.new_simple_usertype<vec2>("vec2", lua.new_usertype<vec2x>("vec2x",
sol::call_constructor, sol::factories([]() { return vec2{}; }, [](vec2 const& v) -> vec2 { return v; }, [](sol::variadic_args va) { sol::call_constructor, sol::factories([]() { return vec2x{}; }, [](vec2x const& v) -> vec2x { return v; }, [](sol::variadic_args va) {
vec2 res{}; vec2x res{};
if (va.size() == 1) { if (va.size() == 1) {
res.x = va[0].get<float>(); res.x = va[0].get<float>();
res.y = va[0].get<float>(); res.y = va[0].get<float>();
@ -233,16 +233,16 @@ TEST_CASE("variadics/fallback_constructor", "ensure constructor matching behaves
return res; })); return res; }));
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.safe_script("v0 = vec2();"); lua.safe_script("v0 = vec2x();");
lua.safe_script("v1 = vec2(1);"); lua.safe_script("v1 = vec2x(1);");
lua.safe_script("v2 = vec2(1, 2);"); lua.safe_script("v2 = vec2x(1, 2);");
lua.safe_script("v3 = vec2(v2)"); lua.safe_script("v3 = vec2x(v2)");
}()); }());
vec2& v0 = lua["v0"]; vec2x& v0 = lua["v0"];
vec2& v1 = lua["v1"]; vec2x& v1 = lua["v1"];
vec2& v2 = lua["v2"]; vec2x& v2 = lua["v2"];
vec2& v3 = lua["v3"]; vec2x& v3 = lua["v3"];
REQUIRE(v0.x == 0); REQUIRE(v0.x == 0);
REQUIRE(v0.y == 0); REQUIRE(v0.y == 0);