Skip to content

Commit

Permalink
meta: safer empty meta_data/meta_func
Browse files Browse the repository at this point in the history
  • Loading branch information
skypjack committed Jan 7, 2025
1 parent 7262858 commit acdd212
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 19 deletions.
3 changes: 2 additions & 1 deletion TODO
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ TODO:
* sparse_set shrink_to_fit argument for sparse array shrink policy (none, empty, deep, whatever)
* any cdynamic to support const ownership construction
* track meta context on meta elements
* safer meta_data/meta_func (no blind indirections)
* safer meta_type (no blind indirections)
* no context-less meta_any{} from meta objects if possible
33 changes: 15 additions & 18 deletions src/entt/meta/meta.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@ struct meta_data {
template<typename Type>
// NOLINTNEXTLINE(modernize-use-nodiscard)
bool set(meta_handle instance, Type &&value) const {
return node.set && node.set(meta_handle{*ctx, std::move(instance)}, meta_any{*ctx, std::forward<Type>(value)});
return (node.set != nullptr) && node.set(meta_handle{*ctx, std::move(instance)}, meta_any{*ctx, std::forward<Type>(value)});
}

/**
Expand All @@ -883,7 +883,7 @@ struct meta_data {
* @return A wrapper containing the value of the underlying variable.
*/
[[nodiscard]] meta_any get(meta_handle instance) const {
return node.get(*ctx, meta_handle{*ctx, std::move(instance)});
return (node.set != nullptr) ? node.get(*ctx, meta_handle{*ctx, std::move(instance)}) : meta_any{};
}

/**
Expand Down Expand Up @@ -1005,7 +1005,7 @@ struct meta_func {
* @return A wrapper containing the returned value, if any.
*/
meta_any invoke(meta_handle instance, meta_any *const args, const size_type sz) const {
return sz == arity() ? node.invoke(*ctx, meta_handle{*ctx, std::move(instance)}, args) : meta_any{meta_ctx_arg, *ctx};
return ((node.invoke != nullptr) && (sz == arity())) ? node.invoke(*ctx, meta_handle{*ctx, std::move(instance)}, args) : meta_any{};
}

/**
Expand All @@ -1018,8 +1018,7 @@ struct meta_func {
template<typename... Args>
// NOLINTNEXTLINE(modernize-use-nodiscard)
meta_any invoke(meta_handle instance, Args &&...args) const {
std::array<meta_any, sizeof...(Args)> arguments{meta_any{*ctx, std::forward<Args>(args)}...};
return invoke(std::move(instance), arguments.data(), sizeof...(Args));
return (ctx != nullptr) ? invoke(std::move(instance), std::array<meta_any, sizeof...(Args)>{meta_any{*ctx, std::forward<Args>(args)}...}.data(), sizeof...(Args)) : meta_any{};
}

/*! @copydoc meta_data::traits */
Expand All @@ -1038,7 +1037,7 @@ struct meta_func {
* @return The next overload of the given function, if any.
*/
[[nodiscard]] meta_func next() const {
return node.next ? meta_func{*ctx, *node.next} : meta_func{};
return (node.next != nullptr) ? meta_func{*ctx, *node.next} : meta_func{};
}

/**
Expand Down Expand Up @@ -1380,7 +1379,7 @@ class meta_type {
return node.default_constructor(*ctx);
}

return meta_any{meta_ctx_arg, *ctx};
return meta_any{};
}

/**
Expand All @@ -1391,8 +1390,7 @@ class meta_type {
*/
template<typename... Args>
[[nodiscard]] meta_any construct(Args &&...args) const {
std::array<meta_any, sizeof...(Args)> arguments{meta_any{*ctx, std::forward<Args>(args)}...};
return construct(arguments.data(), sizeof...(Args));
return (ctx != nullptr) ? construct(std::array<meta_any, sizeof...(Args)>{meta_any{*ctx, std::forward<Args>(args)}...}.data(), sizeof...(Args)) : meta_any{};
}

/**
Expand All @@ -1402,7 +1400,7 @@ class meta_type {
* @return A wrapper that references the given instance.
*/
[[nodiscard]] meta_any from_void(void *elem, bool transfer_ownership = false) const {
return ((elem != nullptr) && (node.from_void != nullptr)) ? node.from_void(*ctx, elem, transfer_ownership ? elem : nullptr) : meta_any{meta_ctx_arg, *ctx};
return ((elem != nullptr) && (node.from_void != nullptr)) ? node.from_void(*ctx, elem, transfer_ownership ? elem : nullptr) : meta_any{};
}

/**
Expand All @@ -1411,7 +1409,7 @@ class meta_type {
* @return A wrapper that references the given instance.
*/
[[nodiscard]] meta_any from_void(const void *elem) const {
return ((elem != nullptr) && (node.from_void != nullptr)) ? node.from_void(*ctx, nullptr, elem) : meta_any{meta_ctx_arg, *ctx};
return ((elem != nullptr) && (node.from_void != nullptr)) ? node.from_void(*ctx, nullptr, elem) : meta_any{};
}

/**
Expand All @@ -1438,7 +1436,7 @@ class meta_type {
}
}

return meta_any{meta_ctx_arg, *ctx};
return meta_any{};
}

/**
Expand All @@ -1452,8 +1450,7 @@ class meta_type {
template<typename... Args>
// NOLINTNEXTLINE(modernize-use-nodiscard)
meta_any invoke(const id_type id, meta_handle instance, Args &&...args) const {
std::array<meta_any, sizeof...(Args)> arguments{meta_any{*ctx, std::forward<Args>(args)}...};
return invoke(id, std::move(instance), arguments.data(), sizeof...(Args));
return (ctx != nullptr) ? invoke(id, std::move(instance), std::array<meta_any, sizeof...(Args)>{meta_any{*ctx, std::forward<Args>(args)}...}.data(), sizeof...(Args)) : meta_any{};
}

/**
Expand All @@ -1479,7 +1476,7 @@ class meta_type {
*/
[[nodiscard]] meta_any get(const id_type id, meta_handle instance) const {
const auto candidate = data(id);
return candidate ? candidate.get(std::move(instance)) : meta_any{meta_ctx_arg, *ctx};
return candidate ? candidate.get(std::move(instance)) : meta_any{};
}

/*! @copydoc meta_data::traits */
Expand Down Expand Up @@ -1550,7 +1547,7 @@ bool meta_any::set(const id_type id, Type &&value) {
}

[[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const {
return internal::try_convert(internal::meta_context::from(*ctx), node, type.info(), type.is_arithmetic() || type.is_enum(), storage.data(), [this, &type]([[maybe_unused]] const void *instance, auto &&...args) {
return internal::try_convert(internal::meta_context::from(*ctx), node, type.info(), type.is_arithmetic() || type.is_enum(), storage.data(), [this, &type]([[maybe_unused]] const void *instance, [[maybe_unused]] auto &&...args) {
if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, internal::meta_type_node> || ...)) {
return (args.from_void(*ctx, nullptr, instance), ...);
} else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, internal::meta_conv_node> || ...)) {
Expand Down Expand Up @@ -1582,15 +1579,15 @@ inline bool meta_any::assign(meta_any &&other) {
}

[[nodiscard]] inline meta_type meta_data::type() const noexcept {
return meta_type{*ctx, node.type(internal::meta_context::from(*ctx))};
return (ctx != nullptr) ? meta_type{*ctx, node.type(internal::meta_context::from(*ctx))} : meta_type{};
}

[[nodiscard]] inline meta_type meta_data::arg(const size_type index) const noexcept {
return index < arity() ? node.arg(*ctx, index) : meta_type{};
}

[[nodiscard]] inline meta_type meta_func::ret() const noexcept {
return meta_type{*ctx, node.ret(internal::meta_context::from(*ctx))};
return (ctx != nullptr) ? meta_type{*ctx, node.ret(internal::meta_context::from(*ctx))} : meta_type{};
}

[[nodiscard]] inline meta_type meta_func::arg(const size_type index) const noexcept {
Expand Down
16 changes: 16 additions & 0 deletions test/entt/meta/meta_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,22 @@ struct MetaData: ::testing::Test {

using MetaDataDeathTest = MetaData;

TEST_F(MetaData, SafeWhenEmpty) {
entt::meta_data data{};

ASSERT_FALSE(data);
ASSERT_EQ(data, entt::meta_data{});
ASSERT_EQ(data.arity(), 0u);
ASSERT_FALSE(data.is_const());
ASSERT_FALSE(data.is_static());
ASSERT_EQ(data.type(), entt::meta_type{});
ASSERT_FALSE(data.set({}, 0));
ASSERT_FALSE(data.get({}));
ASSERT_EQ(data.arg(0u), entt::meta_type{});
ASSERT_EQ(data.traits<test::meta_traits>(), test::meta_traits::none);
ASSERT_EQ(static_cast<const char *>(data.custom()), nullptr);
}

TEST_F(MetaData, UserTraits) {
using namespace entt::literals;

Expand Down
21 changes: 21 additions & 0 deletions test/entt/meta/meta_func.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,27 @@ struct MetaFunc: ::testing::Test {

using MetaFuncDeathTest = MetaFunc;

TEST_F(MetaFunc, SafeWhenEmpty) {
entt::meta_func func{};
entt::meta_any *args = nullptr;

ASSERT_FALSE(func);
ASSERT_EQ(func, entt::meta_func{});
ASSERT_EQ(func.arity(), 0u);
ASSERT_FALSE(func.is_const());
ASSERT_FALSE(func.is_static());
ASSERT_EQ(func.ret(), entt::meta_type{});
ASSERT_EQ(func.arg(0u), entt::meta_type{});
ASSERT_EQ(func.arg(1u), entt::meta_type{});
ASSERT_FALSE(func.invoke({}, args, 0u));
ASSERT_FALSE(func.invoke({}, args, 1u));
ASSERT_FALSE(func.invoke({}));
ASSERT_FALSE(func.invoke({}, 'c'));
ASSERT_EQ(func.traits<test::meta_traits>(), test::meta_traits::none);
ASSERT_EQ(static_cast<const char *>(func.custom()), nullptr);
ASSERT_EQ(func.next(), entt::meta_func{});
}

TEST_F(MetaFunc, UserTraits) {
using namespace entt::literals;

Expand Down

0 comments on commit acdd212

Please sign in to comment.