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;
}
} // 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
#endif // SOL_FORWARD_DETAIL_HPP

View File

@ -1,4 +1,4 @@
// sol3
// sol3
// The MIT License (MIT)
@ -37,6 +37,7 @@
#include "forward_detail.hpp"
#include <vector>
#include <bitset>
#include <forward_list>
#include <string>
#include <algorithm>
@ -51,6 +52,8 @@ namespace sol {
template <typename T>
struct as_table_tag {};
using lua_reg_table = luaL_Reg[64];
using unique_destructor = void (*)(void*);
using unique_tag = detail::inheritance_unique_cast_function;
@ -340,7 +343,7 @@ namespace sol {
return false;
}
allocated_size -= sizeof(T*);
adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + sizeof(T*));
dx_adjusted = align(std::alignment_of<unique_destructor>::value, sizeof(unique_destructor), adjusted, allocated_size);
if (dx_adjusted == nullptr) {
@ -348,7 +351,7 @@ namespace sol {
return false;
}
allocated_size -= sizeof(unique_destructor);
adjusted = static_cast<void*>(static_cast<char*>(dx_adjusted) + sizeof(unique_destructor));
id_adjusted = align(std::alignment_of<unique_tag>::value, sizeof(unique_tag), adjusted, allocated_size);
@ -357,7 +360,7 @@ namespace sol {
return false;
}
allocated_size -= sizeof(unique_tag);
adjusted = static_cast<void*>(static_cast<char*>(id_adjusted) + sizeof(unique_tag));
data_adjusted = align(std::alignment_of<Real>::value, sizeof(Real), adjusted, allocated_size);
if (data_adjusted == nullptr) {
@ -488,6 +491,200 @@ namespace sol {
void reserve(std::basic_string<T, Tr, Al>& arr, std::size_t 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 stack {

View File

@ -75,7 +75,7 @@ namespace stack {
// do the actual object. Things that are std::ref or plain T* are stored as
// just the sizeof(T*), and nothing else.
T* obj = detail::usertype_allocate<T>(L);
std::allocator<T> alloc {};
std::allocator<T> alloc{};
std::allocator_traits<std::allocator<T>>::construct(alloc, obj, std::forward<Args>(args)...);
f();
return 1;
@ -130,7 +130,7 @@ namespace stack {
struct pusher {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
return pusher<detail::as_value_tag<T>> {}.push(L, std::forward<Args>(args)...);
return pusher<detail::as_value_tag<T>>{}.push(L, std::forward<Args>(args)...);
}
};
@ -138,7 +138,7 @@ namespace stack {
struct pusher<T*, meta::disable_if_t<meta::any<is_container<meta::unqualified_t<T>>, std::is_function<meta::unqualified_t<T>>, is_lua_reference<meta::unqualified_t<T>>>::value>> {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
return pusher<detail::as_pointer_tag<T>> {}.push(L, std::forward<Args>(args)...);
return pusher<detail::as_pointer_tag<T>>{}.push(L, std::forward<Args>(args)...);
}
};
@ -173,11 +173,11 @@ namespace stack {
detail::default_construct::construct(mem, std::forward<Args>(args)...);
*pref = unique_usertype_traits<T>::get(*mem);
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;
auto prop_fx = [](meta_function) { return true; };
u_detail::insert_default_registrations<P>(l, index, prop_fx);
u_detail::make_destructor<T>(l, index);
detail::indexed_insert insert_fx(l, index);
detail::insert_default_registrations<P>(insert_fx, detail::property_always_true);
l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() };
luaL_setfuncs(L, l, 0);
}
lua_setmetatable(L, -2);
@ -334,7 +334,7 @@ namespace stack {
template <typename T>
struct pusher<nested<T>, std::enable_if_t<is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> {
static int push(lua_State* L, const T& tablecont) {
pusher<detail::as_table_tag<T>> p {};
pusher<detail::as_table_tag<T>> p{};
// silence annoying VC++ warning
(void)p;
return p.push(std::true_type(), L, tablecont);
@ -344,7 +344,7 @@ namespace stack {
template <typename T>
struct pusher<nested<T>, std::enable_if_t<!is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> {
static int push(lua_State* L, const T& tablecont) {
pusher<meta::unqualified_t<T>> p {};
pusher<meta::unqualified_t<T>> p{};
// silence annoying VC++ warning
(void)p;
return p.push(L, tablecont);
@ -354,7 +354,7 @@ namespace stack {
template <typename T>
struct pusher<std::initializer_list<T>> {
static int push(lua_State* L, const std::initializer_list<T>& il) {
pusher<detail::as_table_tag<std::initializer_list<T>>> p {};
pusher<detail::as_table_tag<std::initializer_list<T>>> p{};
// silence annoying VC++ warning
(void)p;
return p.push(L, il);
@ -497,7 +497,7 @@ namespace stack {
static int push_with(lua_State* L, Key&& name, Args&&... args) {
// A dumb pusher
T* data = detail::user_allocate<T>(L);
std::allocator<T> alloc {};
std::allocator<T> alloc{};
std::allocator_traits<std::allocator<T>>::construct(alloc, data, std::forward<Args>(args)...);
if (with_meta) {
// Make sure we have a plain GC set for this data
@ -584,25 +584,25 @@ namespace stack {
template <>
struct pusher<char*> {
static int push_sized(lua_State* L, const char* str, std::size_t len) {
pusher<const char*> p {};
pusher<const char*> p{};
(void)p;
return p.push_sized(L, str, len);
}
static int push(lua_State* L, const char* str) {
pusher<const char*> p {};
pusher<const char*> p{};
(void)p;
return p.push(L, str);
}
static int push(lua_State* L, const char* strb, const char* stre) {
pusher<const char*> p {};
pusher<const char*> p{};
(void)p;
return p.push(L, strb, stre);
}
static int push(lua_State* L, const char* str, std::size_t len) {
pusher<const char*> p {};
pusher<const char*> p{};
(void)p;
return p.push(L, str, len);
}
@ -711,19 +711,19 @@ namespace stack {
template <>
struct pusher<wchar_t*> {
static int push(lua_State* L, const wchar_t* str) {
pusher<const wchar_t*> p {};
pusher<const wchar_t*> p{};
(void)p;
return p.push(L, str);
}
static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) {
pusher<const wchar_t*> p {};
pusher<const wchar_t*> p{};
(void)p;
return p.push(L, strb, stre);
}
static int push(lua_State* L, const wchar_t* str, std::size_t len) {
pusher<const wchar_t*> p {};
pusher<const wchar_t*> p{};
(void)p;
return p.push(L, str, len);
}
@ -791,19 +791,19 @@ namespace stack {
template <>
struct pusher<char16_t*> {
static int push(lua_State* L, const char16_t* str) {
pusher<const char16_t*> p {};
pusher<const char16_t*> p{};
(void)p;
return p.push(L, str);
}
static int push(lua_State* L, const char16_t* strb, const char16_t* stre) {
pusher<const char16_t*> p {};
pusher<const char16_t*> p{};
(void)p;
return p.push(L, strb, stre);
}
static int push(lua_State* L, const char16_t* str, std::size_t len) {
pusher<const char16_t*> p {};
pusher<const char16_t*> p{};
(void)p;
return p.push(L, str, len);
}
@ -869,19 +869,19 @@ namespace stack {
template <>
struct pusher<char32_t*> {
static int push(lua_State* L, const char32_t* str) {
pusher<const char32_t*> p {};
pusher<const char32_t*> p{};
(void)p;
return p.push(L, str);
}
static int push(lua_State* L, const char32_t* strb, const char32_t* stre) {
pusher<const char32_t*> p {};
pusher<const char32_t*> p{};
(void)p;
return p.push(L, strb, stre);
}
static int push(lua_State* L, const char32_t* str, std::size_t len) {
pusher<const char32_t*> p {};
pusher<const char32_t*> p{};
(void)p;
return p.push(L, str, len);
}
@ -960,7 +960,7 @@ namespace stack {
template <std::size_t... I, typename T>
static int push(std::index_sequence<I...>, lua_State* L, T&& t) {
int pushcount = 0;
(void)detail::swallow { 0, (pushcount += stack::push(L, detail::forward_get<I>(t)), 0)... };
(void)detail::swallow{ 0, (pushcount += stack::push(L, detail::forward_get<I>(t)), 0)... };
return pushcount;
}

View File

@ -30,16 +30,41 @@
namespace sol {
typedef table_core<false> table;
template <bool top_level, typename base_type>
template <typename Class, typename Key, typename... Args>
usertype<Class> basic_table_core<top_level, base_type>::new_usertype(Key&& key, Args&&... args) {
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));
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;
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);
mt.
set(std::forward<Key>(key), 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 Key, typename 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;
uts.set(std::forward<Key>(key), std::forward<Value>(value));
}
else {
base_t::set(std::forward<Key>(key), std::forward<Value>(value));
}
}
namespace stack {

View File

@ -366,7 +366,13 @@ namespace sol {
}
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>
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>;
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>
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>
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>
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>
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>
struct lua_type_of : detail::lua_type_of<T> {
typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_;
};
template <typename T>
inline constexpr type lua_type_of_v = lua_type_of<T>::value;
template <typename T>
struct lua_size : std::integral_constant<int, 1> {
typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_;
@ -1059,6 +1065,9 @@ namespace sol {
template <typename... Args>
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 {
template <typename...>
struct void_ { typedef void type; };
@ -1211,7 +1220,7 @@ namespace sol {
using any_is_constructor = meta::any<is_constructor<meta::unqualified_t<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>
struct is_destructor : std::false_type {};
@ -1220,13 +1229,30 @@ namespace sol {
struct is_destructor<destructor_wrapper<Fx>> : std::true_type {};
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 check_destructor_tag {};
struct verified_tag {
} const verified {};
} // 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
#endif // SOL_TYPES_HPP

View File

@ -42,6 +42,16 @@ namespace sol {
using base_t::pop;
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>
void set(Key&& key, Value&& value) {
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) {
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{
{ "at", &at_call },
{ "get", &real_get_call },

View File

@ -66,78 +66,6 @@ namespace sol {
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) {
return s;
}
@ -183,81 +111,6 @@ namespace sol {
inline int is_indexer(call_construction) {
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 stack { namespace stack_detail {
@ -274,15 +127,11 @@ namespace sol {
void operator()() const {
if (luaL_newmetatable(L, key) == 1) {
luaL_Reg l[64] {};
detail::lua_reg_table l{};
int index = 0;
auto prop_fx = [](meta_function) { return true; };
auto insert_fx = [&l, &index](meta_function mf, lua_CFunction f) {
l[index] = luaL_Reg { to_string(mf).c_str(), f };
++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>() };
detail::indexed_insert insert_fx(l, index);
detail::insert_default_registrations<P>(insert_fx, detail::property_always_true);
l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<P>() };
luaL_setfuncs(L, l, 0);
// __type table
@ -290,7 +139,7 @@ namespace sol {
const std::string& name = detail::demangle<T>();
lua_pushlstring(L, name.c_str(), name.size());
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_setfield(L, -2, "is");
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 type_table;
reference gc_names_table;
reference metametatable;
reference named_metatable;
std::bitset<64> properties;
index_call_storage base_index;
index_call_storage base_new_index;
@ -166,7 +166,7 @@ namespace u_detail {
bool is_using_new_index;
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.index = index_target_fail;
base_index.new_index = index_target_fail;
@ -339,8 +339,8 @@ namespace u_detail {
}
else {
if (submetatable_type == submetatable::named) {
stack::set_field(L, metatable_key, metametatable, t.stack_index());
stack_reference stack_metametatable(L, -metametatable.push());
stack::set_field(L, metatable_key, named_metatable, t.stack_index());
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::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();
@ -433,19 +433,19 @@ namespace u_detail {
using KeyU = meta::unwrap_unqualified_t<Key>;
using Binding = binding<KeyU, ValueU, T>;
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));
Binding& b = *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);
stack::push(L, nullptr);
stack::push(L, b.data());
lua_CFunction target_func = &b.call<false, false>;
lua_pushcclosure(L, target_func, 2);
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)) {
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));
stack_table usertype_storage_metatable(L, -usertype_storage_metatabe_count);
// 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
stack::set_field(L, metatable_key, usertype_storage_metatable, usertype_storage_ref.stack_index());
usertype_storage_metatable.pop();
@ -638,7 +638,7 @@ namespace u_detail {
}
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_const_traits = usertype_traits<const 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
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, "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();
// 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());
}
auto prop_fx = [&](meta_function mf) {
return !storage.properties[static_cast<int>(mf)];
};
auto prop_fx = properties_enrollment_allowed(storage.properties, enrollments);
auto insert_fx = [&](meta_function mf, lua_CFunction reg) {
stack::set_field(L, mf, reg, t.stack_index());
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
// 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());
// fancy new_indexing when using the named table
stack::set_field<false, true>(L, metatable_key, storage.metametatable, t.stack_index());
stack_reference stack_metametatable(L, -storage.metametatable.push());
stack::set_field<false, true>(L, metatable_key, storage.named_metatable, t.stack_index());
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::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();
@ -819,7 +817,7 @@ namespace u_detail {
// can only use set AFTER we initialize all the metatables
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()>());
}
}

View File

@ -1119,16 +1119,6 @@ TEST_CASE("containers/non_copyable", "make sure non-copyable types in containers
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);
REQUIRE_FALSE(pfr.valid());
}

View File

@ -170,36 +170,6 @@ end
sol::function f = lua.safe_script(R"(
return function(e)
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;
{
@ -443,27 +413,6 @@ TEST_CASE("gc/usertypes", "show that proper copies / destruction happens for use
REQUIRE(created == 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") {
@ -492,21 +441,6 @@ TEST_CASE("gc/double-deletion tests", "make sure usertypes are properly destruct
)", sol::script_pass_on_error);
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) {
lua["testCrash"]();
}
@ -554,34 +488,6 @@ TEST_CASE("gc/shared_ptr regression", "metatables should not screw over unique u
REQUIRE(created == 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") {
@ -603,24 +509,6 @@ TEST_CASE("gc/double deleter guards", "usertype metatables internally must not r
};
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") {

View File

@ -27,6 +27,58 @@
#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") {
struct A {
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") {
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::usertype<TestClass00> s_TestUsertype00(
sol::usertype<TestClass00> s_TestUsertype00 = lua.new_usertype<TestClass00>("TestClass00",
sol::call_constructor, sol::constructors<sol::types<>>(),
"Thing", &TestClass00::Thing);
lua.set_usertype("TestClass00", s_TestUsertype00);
sol::usertype<TestClass01> s_TestUsertype01(
sol::usertype<TestClass01> s_TestUsertype01 = lua.new_usertype<TestClass01>("TestClass01",
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass00&>>(),
sol::base_classes, sol::bases<TestClass00>(),
"a", &TestClass01::a);
lua.set_usertype("TestClass01", s_TestUsertype01);
sol::usertype<TestClass02> s_TestUsertype02(
sol::usertype<TestClass02> s_TestUsertype02 = lua.new_usertype<TestClass02>("TestClass02",
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
sol::base_classes, sol::bases<TestClass01, TestClass00>(),
"b", &TestClass02::b);
lua.set_usertype("TestClass02", s_TestUsertype02);
sol::usertype<TestClass03> s_TestUsertype03(
sol::usertype<TestClass03> s_TestUsertype03 = lua.new_usertype<TestClass03>("TestClass03",
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>(),
"c", &TestClass03::c);
lua.set_usertype("TestClass03", s_TestUsertype03);
auto result1 = lua.safe_script(R"(
tc0 = TestClass00()
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") {
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::simple_usertype<TestClass00> s_TestUsertype00(lua,
sol::usertype<TestClass00> s_TestUsertype00 = lua.new_usertype<TestClass00>("TestClass00",
sol::call_constructor, sol::constructors<sol::types<>>(),
"Thing", &TestClass00::Thing);
lua.set_usertype("TestClass00", s_TestUsertype00);
sol::simple_usertype<TestClass01> s_TestUsertype01(lua,
sol::usertype<TestClass01> s_TestUsertype01 = lua.new_usertype<TestClass01>("TestClass01",
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass00&>>(),
sol::base_classes, sol::bases<TestClass00>(),
"a", &TestClass01::a);
lua.set_usertype("TestClass01", s_TestUsertype01);
sol::simple_usertype<TestClass02> s_TestUsertype02(lua,
sol::usertype<TestClass02> s_TestUsertype02 = lua.new_usertype<TestClass02>("TestClass02",
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
sol::base_classes, sol::bases<TestClass01, TestClass00>(),
"b", &TestClass02::b);
lua.set_usertype("TestClass02", s_TestUsertype02);
sol::simple_usertype<TestClass03> s_TestUsertype03(lua,
sol::usertype<TestClass03> s_TestUsertype03 = lua.new_usertype<TestClass03>("TestClass03",
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>(),
"c", &TestClass03::c);
lua.set_usertype("TestClass03", s_TestUsertype03);
auto result1 = lua.safe_script(R"(
tc0 = TestClass00()
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<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
{
auto result1 = lua.safe_script("assert(t1 == t1)"
@ -240,15 +193,6 @@ TEST_CASE("operators/call", "test call operator generation") {
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 {
@ -316,16 +260,6 @@ TEST_CASE("operators/stringable", "test std::ostream stringability") {
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") {
@ -349,15 +283,6 @@ TEST_CASE("operators/adl_stringable", "test adl to_string stringability") {
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") {
@ -381,15 +306,6 @@ TEST_CASE("operators/inside::adl_stringable2", "test adl to_string stringability
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") {
@ -413,15 +329,6 @@ TEST_CASE("operators/member_stringable", "test member to_string stringability")
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") {
@ -506,13 +413,4 @@ TEST_CASE("operators/length", "test that size is automatically bound to the leng
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") {
sol::state lua;
sol::usertype<fuser> lc{ "add", &fuser::add, "add2", &fuser::add2 };
lua.set_usertype(lc);
sol::usertype<fuser> lc = lua.new_usertype<fuser>("fuser", "add", &fuser::add, "add2", &fuser::add2);
lua.safe_script(
"a = fuser:new()\n"
@ -346,8 +345,10 @@ TEST_CASE("usertype/usertype-constructors", "Show that we can create classes fro
sol::state lua;
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);
lua.set_usertype(lc);
sol::usertype<crapola::fuser> lc = lua.new_usertype<crapola::fuser>("fuser",
con,
"add", &crapola::fuser::add,
"add2", &crapola::fuser::add2);
lua.safe_script(
"a = fuser.new(2)\n"
@ -414,9 +415,7 @@ TEST_CASE("usertype/usertype-utility-derived", "usertype classes must play nice
sol::state lua;
lua.open_libraries(sol::lib::base);
sol::constructors<sol::types<int>> basector;
sol::usertype<Base> baseusertype(basector, "get_num", &Base::get_num);
lua.set_usertype(baseusertype);
sol::usertype<Base> baseusertype = lua.new_usertype<Base>("Base", basector, "get_num", &Base::get_num);
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::usertype<Derived> derivedusertype(derivedctor,
sol::usertype<Derived> derivedusertype = lua.new_usertype<Derived>("Derived", derivedctor,
"get_num_10", &Derived::get_num_10,
"get_num", &Derived::get_num);
lua.set_usertype(derivedusertype);
lua.safe_script("derived = Derived.new(7)");
lua.safe_script(
"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);
sol::constructors<sol::types<float, float, float>> ctor;
sol::usertype<Vec> udata(ctor, "normalized", &Vec::normalized, "length", &Vec::length);
lua.set_usertype(udata);
sol::usertype<Vec> udata = lua.new_usertype<Vec>("Vec", ctor, "normalized", &Vec::normalized, "length", &Vec::length);
{
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::usertype<Vec> udata(ctor,
sol::usertype<Vec> udata = lua.new_usertype<Vec>("Vec",
ctor,
"normalized", &Vec::normalized,
"length", &Vec::length);
lua.set_usertype(udata);
// 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;
lua.open_libraries(sol::lib::base);
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,
"y", &Vec::y,
"z", &Vec::z,
"normalized", &Vec::normalized,
"length", &Vec::length);
lua.set_usertype(udata);
REQUIRE_NOTHROW(lua.safe_script(
"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,
"__tostring", [](const giver& t) {
return std::to_string(t.a) + ": giving value";
})
.get<sol::table>("giver")
.set_function("stuff", giver::stuff);
});
lua.get<sol::table>("giver").set_function("stuff", giver::stuff);
{
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") {
struct vec2 {
struct vec2x {
float x = 0, y = 0;
};
sol::state lua;
lua.new_simple_usertype<vec2>("vec2",
sol::call_constructor, sol::factories([]() { return vec2{}; }, [](vec2 const& v) -> vec2 { return v; }, [](sol::variadic_args va) {
vec2 res{};
lua.new_usertype<vec2x>("vec2x",
sol::call_constructor, sol::factories([]() { return vec2x{}; }, [](vec2x const& v) -> vec2x { return v; }, [](sol::variadic_args va) {
vec2x res{};
if (va.size() == 1) {
res.x = 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; }));
REQUIRE_NOTHROW([&]() {
lua.safe_script("v0 = vec2();");
lua.safe_script("v1 = vec2(1);");
lua.safe_script("v2 = vec2(1, 2);");
lua.safe_script("v3 = vec2(v2)");
lua.safe_script("v0 = vec2x();");
lua.safe_script("v1 = vec2x(1);");
lua.safe_script("v2 = vec2x(1, 2);");
lua.safe_script("v3 = vec2x(v2)");
}());
vec2& v0 = lua["v0"];
vec2& v1 = lua["v1"];
vec2& v2 = lua["v2"];
vec2& v3 = lua["v3"];
vec2x& v0 = lua["v0"];
vec2x& v1 = lua["v1"];
vec2x& v2 = lua["v2"];
vec2x& v3 = lua["v3"];
REQUIRE(v0.x == 0);
REQUIRE(v0.y == 0);