M O R E B R E A K I N G C H A N G E S

- constant_automagic_enrollments use compile-time flags to avoid crappy shenanigans with linker-unavailable methods
This commit is contained in:
ThePhD 2021-01-21 03:26:42 -05:00
parent f7d8e1e822
commit c032cda56e
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
10 changed files with 284 additions and 48 deletions

View File

@ -547,8 +547,8 @@ namespace sol {
std::bitset<64>& properties;
automagic_enrollments& enrollments;
properties_enrollment_allowed(int& times, std::bitset<64>& props, automagic_enrollments& enroll)
: times_through(times), properties(props), enrollments(enroll) {
properties_enrollment_allowed(int& times_through_, std::bitset<64>& properties_, automagic_enrollments& enrollments_)
: times_through(times_through_), properties(properties_), enrollments(enrollments_) {
}
bool operator()(meta_function mf) const {

View File

@ -34,14 +34,24 @@ namespace sol {
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;
constant_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, automagic_flags enrollment_flags>
usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, constant_automagic_enrollments<enrollment_flags> enrollments) {
int mt_index = u_detail::register_usertype<Class, enrollment_flags>(this->lua_state(), std::move(enrollments));
usertype<Class> mt(this->lua_state(), -mt_index);
lua_pop(this->lua_state(), 1);
set(std::forward<Key>(key), mt);
return mt;
}
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));
int mt_index = u_detail::register_usertype<Class, automagic_flags::all>(this->lua_state(), std::move(enrollments));
usertype<Class> mt(this->lua_state(), -mt_index);
lua_pop(this->lua_state(), 1);
set(std::forward<Key>(key), mt);
@ -51,7 +61,10 @@ namespace sol {
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;
constexpr automagic_flags enrollment_flags = meta::any_same_v<no_construction, meta::unqualified_t<Arg>, meta::unqualified_t<Args>...>
? clear_flags(automagic_flags::all, automagic_flags::default_constructor)
: automagic_flags::all;
constant_automagic_enrollments<enrollment_flags> 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));

View File

@ -529,11 +529,14 @@ namespace sol {
template <typename Class, typename Key>
usertype<Class> new_usertype(Key&& key);
template <typename Class, typename Key, automagic_flags enrollment_flags>
usertype<Class> new_usertype(Key&& key, constant_automagic_enrollments<enrollment_flags> enrollment);
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>>>
typename = std::enable_if_t<!std::is_base_of_v<automagic_enrollments, meta::unqualified_t<Arg>>>>
usertype<Class> new_usertype(Key&& key, Arg&& arg, Args&&... args);
template <bool read_only = true, typename... Args>

View File

@ -1401,6 +1401,56 @@ namespace sol {
template <typename T>
inline constexpr bool is_lua_c_function_v = is_lua_c_function<T>::value;
enum class automagic_flags : unsigned {
none = 0x000u,
default_constructor = 0x001,
destructor = 0x002u,
pairs_operator = 0x004u,
to_string_operator = 0x008u,
call_operator = 0x010u,
less_than_operator = 0x020u,
less_than_or_equal_to_operator = 0x040u,
length_operator = 0x080u,
equal_to_operator = 0x100u,
all = default_constructor | destructor | pairs_operator | to_string_operator | call_operator | less_than_operator | less_than_or_equal_to_operator
| length_operator | equal_to_operator
};
inline constexpr automagic_flags operator|(automagic_flags left, automagic_flags right) noexcept {
return static_cast<automagic_flags>(
static_cast<std::underlying_type_t<automagic_flags>>(left) | static_cast<std::underlying_type_t<automagic_flags>>(right));
}
inline constexpr automagic_flags operator&(automagic_flags left, automagic_flags right) noexcept {
return static_cast<automagic_flags>(
static_cast<std::underlying_type_t<automagic_flags>>(left) & static_cast<std::underlying_type_t<automagic_flags>>(right));
}
inline constexpr automagic_flags& operator|=(automagic_flags& left, automagic_flags right) noexcept {
left = left | right;
return left;
}
inline constexpr automagic_flags& operator&=(automagic_flags& left, automagic_flags right) noexcept {
left = left & right;
return left;
}
template <typename Left, typename Right>
constexpr bool has_flag(Left left, Right right) noexcept {
return (left & right) == right;
}
template <typename Left, typename Right>
constexpr bool has_any_flag(Left left, Right right) noexcept {
return (left & right) != static_cast<Left>(static_cast<std::underlying_type_t<Left>>(0));
}
template <typename Left, typename Right>
constexpr auto clear_flags(Left left, Right right) noexcept {
return static_cast<Left>(static_cast<std::underlying_type_t<Left>>(left) & ~static_cast<std::underlying_type_t<Right>>(right));
}
struct automagic_enrollments {
bool default_constructor = true;
bool destructor = true;
@ -1413,6 +1463,8 @@ namespace sol {
bool equal_to_operator = true;
};
template <automagic_flags compile_time_defaults = automagic_flags::all>
struct constant_automagic_enrollments : public automagic_enrollments { };
} // namespace sol

View File

@ -940,7 +940,7 @@ namespace sol { namespace u_detail {
stack::set_field<true>(L, gcmetakey, lua_nil);
}
template <typename T>
template <typename T, automagic_flags enrollment_flags>
inline int register_usertype(lua_State* L_, automagic_enrollments enrollments_ = {}) {
using u_traits = usertype_traits<T>;
using u_const_traits = usertype_traits<const T>;
@ -1144,7 +1144,7 @@ namespace sol { namespace u_detail {
storage.for_each_table(L_, for_each_backing_metatable);
// 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> && has_flag(enrollment_flags, automagic_flags::default_constructor)) {
if (enrollments_.default_constructor) {
storage.set(L_, meta_function::construct, constructors<T()>());
}

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2021-01-21 07:19:50.241796 UTC
// This header was generated with sol v3.2.3 (revision e892aa34)
// Generated 2021-01-21 08:26:13.647505 UTC
// This header was generated with sol v3.2.3 (revision f7d8e1e8)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_CONFIG_HPP

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2021-01-21 07:19:50.218794 UTC
// This header was generated with sol v3.2.3 (revision e892aa34)
// Generated 2021-01-21 08:26:13.622520 UTC
// This header was generated with sol v3.2.3 (revision f7d8e1e8)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2021-01-21 07:19:49.610795 UTC
// This header was generated with sol v3.2.3 (revision e892aa34)
// Generated 2021-01-21 08:26:12.913504 UTC
// This header was generated with sol v3.2.3 (revision f7d8e1e8)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -8102,6 +8102,56 @@ namespace sol {
template <typename T>
inline constexpr bool is_lua_c_function_v = is_lua_c_function<T>::value;
enum class automagic_flags : unsigned {
none = 0x000u,
default_constructor = 0x001,
destructor = 0x002u,
pairs_operator = 0x004u,
to_string_operator = 0x008u,
call_operator = 0x010u,
less_than_operator = 0x020u,
less_than_or_equal_to_operator = 0x040u,
length_operator = 0x080u,
equal_to_operator = 0x100u,
all = default_constructor | destructor | pairs_operator | to_string_operator | call_operator | less_than_operator | less_than_or_equal_to_operator
| length_operator | equal_to_operator
};
inline constexpr automagic_flags operator|(automagic_flags left, automagic_flags right) noexcept {
return static_cast<automagic_flags>(
static_cast<std::underlying_type_t<automagic_flags>>(left) | static_cast<std::underlying_type_t<automagic_flags>>(right));
}
inline constexpr automagic_flags operator&(automagic_flags left, automagic_flags right) noexcept {
return static_cast<automagic_flags>(
static_cast<std::underlying_type_t<automagic_flags>>(left) & static_cast<std::underlying_type_t<automagic_flags>>(right));
}
inline constexpr automagic_flags& operator|=(automagic_flags& left, automagic_flags right) noexcept {
left = left | right;
return left;
}
inline constexpr automagic_flags& operator&=(automagic_flags& left, automagic_flags right) noexcept {
left = left & right;
return left;
}
template <typename Left, typename Right>
constexpr bool has_flag(Left left, Right right) noexcept {
return (left & right) == right;
}
template <typename Left, typename Right>
constexpr bool has_any_flag(Left left, Right right) noexcept {
return (left & right) != static_cast<Left>(static_cast<std::underlying_type_t<Left>>(0));
}
template <typename Left, typename Right>
constexpr auto clear_flags(Left left, Right right) noexcept {
return static_cast<Left>(static_cast<std::underlying_type_t<Left>>(left) & ~static_cast<std::underlying_type_t<Right>>(right));
}
struct automagic_enrollments {
bool default_constructor = true;
bool destructor = true;
@ -8114,6 +8164,9 @@ namespace sol {
bool equal_to_operator = true;
};
template <automagic_flags compile_time_defaults = automagic_flags::all>
struct constant_automagic_enrollments : public automagic_enrollments { };
} // namespace sol
// end of sol/types.hpp
@ -10824,8 +10877,8 @@ namespace sol {
std::bitset<64>& properties;
automagic_enrollments& enrollments;
properties_enrollment_allowed(int& times, std::bitset<64>& props, automagic_enrollments& enroll)
: times_through(times), properties(props), enrollments(enroll) {
properties_enrollment_allowed(int& times_through_, std::bitset<64>& properties_, automagic_enrollments& enrollments_)
: times_through(times_through_), properties(properties_), enrollments(enrollments_) {
}
bool operator()(meta_function mf) const {
@ -23614,7 +23667,7 @@ namespace sol { namespace u_detail {
stack::set_field<true>(L, gcmetakey, lua_nil);
}
template <typename T>
template <typename T, automagic_flags enrollment_flags>
inline int register_usertype(lua_State* L_, automagic_enrollments enrollments_ = {}) {
using u_traits = usertype_traits<T>;
using u_const_traits = usertype_traits<const T>;
@ -23816,7 +23869,7 @@ namespace sol { namespace u_detail {
storage.for_each_table(L_, for_each_backing_metatable);
// 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> && has_flag(enrollment_flags, automagic_flags::default_constructor)) {
if (enrollments_.default_constructor) {
storage.set(L_, meta_function::construct, constructors<T()>());
}
@ -25145,11 +25198,14 @@ namespace sol {
template <typename Class, typename Key>
usertype<Class> new_usertype(Key&& key);
template <typename Class, typename Key, automagic_flags enrollment_flags>
usertype<Class> new_usertype(Key&& key, constant_automagic_enrollments<enrollment_flags> enrollment);
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>>>
typename = std::enable_if_t<!std::is_base_of_v<automagic_enrollments, meta::unqualified_t<Arg>>>>
usertype<Class> new_usertype(Key&& key, Arg&& arg, Args&&... args);
template <bool read_only = true, typename... Args>
@ -25696,14 +25752,24 @@ namespace sol {
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;
constant_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, automagic_flags enrollment_flags>
usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, constant_automagic_enrollments<enrollment_flags> enrollments) {
int mt_index = u_detail::register_usertype<Class, enrollment_flags>(this->lua_state(), std::move(enrollments));
usertype<Class> mt(this->lua_state(), -mt_index);
lua_pop(this->lua_state(), 1);
set(std::forward<Key>(key), mt);
return mt;
}
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));
int mt_index = u_detail::register_usertype<Class, automagic_flags::all>(this->lua_state(), std::move(enrollments));
usertype<Class> mt(this->lua_state(), -mt_index);
lua_pop(this->lua_state(), 1);
set(std::forward<Key>(key), mt);
@ -25713,7 +25779,10 @@ namespace sol {
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;
constexpr automagic_flags enrollment_flags = meta::any_same_v<no_construction, meta::unqualified_t<Arg>, meta::unqualified_t<Args>...>
? clear_flags(automagic_flags::all, automagic_flags::default_constructor)
: automagic_flags::all;
constant_automagic_enrollments<enrollment_flags> 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));

View File

@ -27,28 +27,39 @@
#include <catch.hpp>
inline namespace sol2_test_usertypes_constructors {
struct matrix_xf {
float a, b;
struct matrix_xf {
float a, b;
static matrix_xf from_lua_table(sol::table t) {
matrix_xf m;
m.a = t[1][1];
m.b = t[1][2];
return m;
}
};
static matrix_xf from_lua_table(sol::table t) {
matrix_xf m;
m.a = t[1][1];
m.b = t[1][2];
return m;
}
};
struct matrix_xi {
int a, b;
struct matrix_xi {
int a, b;
static matrix_xi from_lua_table(sol::table t) {
matrix_xi m;
m.a = t[1][1];
m.b = t[1][2];
return m;
}
};
static matrix_xi from_lua_table(sol::table t) {
matrix_xi m;
m.a = t[1][1];
m.b = t[1][2];
return m;
}
};
struct constructor_cheat {
int val;
constexpr constructor_cheat() noexcept;
constexpr constructor_cheat(int val_) noexcept : val(val_) {
}
};
} // namespace sol2_test_usertypes_constructors
TEST_CASE("usertype/call_constructor", "make sure lua types can be constructed with function call constructors") {
sol::state lua;
@ -204,3 +215,16 @@ TEST_CASE("usertype/constructor list", "Show that we can create classes from use
REQUIRE((y.as<int>() == 7));
REQUIRE((z.as<int>() == 9));
}
TEST_CASE("usertype/no_constructor", "make sure if no constructor is present, do not fix anything") {
sol::state lua;
lua.open_libraries(sol::lib::base);
auto ut = lua.new_usertype<constructor_cheat>("constructor_cheat", sol::no_constructor);
ut["val"] = &constructor_cheat::val;
lua["heck"] = constructor_cheat(1);
sol::optional<sol::error> maybe_error = lua.safe_script("assert(heck.val == 1)", &sol::script_pass_on_error);
REQUIRE_FALSE(maybe_error.has_value());
}

View File

@ -27,16 +27,58 @@
#include <catch.hpp>
struct overloading_test {
int print(int i) {
INFO("Integer print: " << i);
return 500 + i;
inline namespace sol2_test_usertypes_overload {
struct overloading_test {
int print(int i) {
INFO("Integer print: " << i);
return 500 + i;
}
int print() {
INFO("No param print.");
return 500;
}
};
class TestClass1 {
public:
TestClass1(void) {
}
~TestClass1(void) {
}
public:
void* Get(const uint32_t) {
return this;
}
void* Get(const std::string_view&) {
return this;
}
};
class TestClass2 {
public:
TestClass2(void) {
}
~TestClass2(void) {
}
public:
void* Get(const uint32_t) {
return this;
}
void* Get(const std::string_view&) {
return this;
}
};
sol::object lua_TestClass2_GetByIndex(const sol::this_state& s, TestClass2* tc, const uint32_t index) {
return sol::make_object(s, tc);
}
int print() {
INFO("No param print.");
return 500;
sol::object lua_TestClass2_GetByName(const sol::this_state& s, TestClass2* tc, const std::string_view& name) {
return sol::make_object(s, tc);
}
};
} // namespace sol2_test_usertypes_overload
TEST_CASE("usertype/overloading", "Check if overloading works properly for usertypes") {
sol::state lua;
@ -89,3 +131,36 @@ TEST_CASE("usertype/overloading_values", "ensure overloads handle properly") {
REQUIRE(res4 == 524);
std::cout << "----- end of 8" << std::endl;
}
TEST_CASE("usertypes/overloading with transparent arguments", "ensure transparent arguments bound with usertypes don't change arity counts in overloads") {
sol::state lua;
lua.open_libraries(sol::lib::base);
auto t1 = lua.new_usertype<TestClass1>(u8"TestClass1", sol::no_constructor);
t1.set_function(
u8"Get", sol::overload(sol::resolve<void*(const uint32_t)>(&TestClass1::Get), sol::resolve<void*(const std::string_view&)>(&TestClass1::Get)));
auto t2 = lua.new_usertype<TestClass2>(u8"TestClass2", sol::no_constructor);
t2.set_function(u8"Get", sol::overload(lua_TestClass2_GetByIndex, lua_TestClass2_GetByName));
TestClass1 test1;
TestClass2 test2;
lua["testObj1"] = test1;
lua["testObj2"] = test2;
sol::optional<sol::error> maybe_error = lua.safe_script(R"(
local test1 = testObj1:Get(0);
local test2 = testObj1:Get('test');
assert(test1 ~= nil, 'test1 failed');
assert(test2 ~= nil, 'test2 failed');
print('test1 ok!');
local test3 = testObj2:Get(0);
local test4 = testObj2:Get('test');
assert(test3 ~= nil, 'test3 failed');
assert(test4 ~= nil, 'test4 failed');
print('test2 ok!');
)",
&sol::script_pass_on_error);
REQUIRE_FALSE(maybe_error.has_value());
}