Sfoglia il codice sorgente

meta: try_convert to replace/merge can_convert and allow_cast

Michele Caini 2 anni fa
parent
commit
735e0af91a
3 ha cambiato i file con 30 aggiunte e 35 eliminazioni
  1. 0 1
      TODO
  2. 18 27
      src/entt/meta/meta.hpp
  3. 12 7
      src/entt/meta/node.hpp

+ 0 - 1
TODO

@@ -17,7 +17,6 @@ TODO (high prio):
 * view with entity storage: begin/end should return filtered iterators
 * update view doc: single vs multi type views are no longer a thing actually
 * meta container: add value type to resize
-* review allow_cast and can_convert, we can merge them in a single function probably
 * ===> TEST: review view tests after the last changes
 
 WIP:

+ 18 - 27
src/entt/meta/meta.hpp

@@ -1099,6 +1099,8 @@ private:
 
 /*! @brief Opaque wrapper for types. */
 class meta_type {
+    friend class meta_any;
+
     template<typename Func>
     [[nodiscard]] auto lookup(meta_any *const args, const typename internal::meta_type_node::size_type sz, [[maybe_unused]] bool constness, Func next) const {
         decltype(next()) candidate = nullptr;
@@ -1341,7 +1343,7 @@ public:
      * @return True if the conversion is allowed, false otherwise.
      */
     [[nodiscard]] bool can_convert(const meta_type &other) const noexcept {
-        return internal::can_convert(internal::meta_context::from(*ctx), node, other.node);
+        return internal::try_convert(internal::meta_context::from(*ctx), node, other.node, nullptr, [](const void *, auto &&...args) { return ((args, 1) + ... + 0u); });
     }
 
     /**
@@ -1621,33 +1623,22 @@ bool meta_any::set(const id_type id, Type &&value) {
 }
 
 [[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const {
-    if(node.info && *node.info == type.info()) {
-        return as_ref();
-    }
-
-    if(const auto *value = data(); node.details) {
-        if(auto it = node.details->conv.find(type.info().hash()); it != node.details->conv.cend()) {
-            return it->second.conv(*ctx, value);
-        }
-
-        for(auto &&curr: node.details->base) {
-            const auto &as_const = curr.second.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.second.cast(value));
-
-            if(auto other = as_const.allow_cast(type); other) {
-                return other;
-            }
+    return internal::try_convert(internal::meta_context::from(*ctx), node, type.node, data(), [this, &type](const void *instance, 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> || ...)) {
+            return (args.conv(*ctx, instance), ...);
+        } else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, decltype(internal::meta_type_node::conversion_helper)> || ...)) {
+            // exploits the fact that arithmetic types and enums are also default constructible
+            auto other = type.construct();
+            const auto value = (args(nullptr, instance), ...);
+            other.node.conversion_helper(other.data(), &value);
+            return other;
+        } else {
+            // forwards to force a compile-time error in case of available arguments
+            return meta_any{meta_ctx_arg, *ctx, std::forward<decltype(args)>(args)...};
         }
-    }
-
-    if(node.conversion_helper && (type.is_arithmetic() || type.is_enum())) {
-        // exploits the fact that arithmetic types and enums are also default constructible
-        auto other = type.construct();
-        const auto value = node.conversion_helper(nullptr, data());
-        other.node.conversion_helper(other.data(), &value);
-        return other;
-    }
-
-    return meta_any{meta_ctx_arg, *ctx};
+    });
 }
 
 inline bool meta_any::assign(const meta_any &other) {

+ 12 - 7
src/entt/meta/node.hpp

@@ -159,24 +159,29 @@ template<typename... Args>
     return nullptr;
 }
 
-[[nodiscard]] inline bool can_convert(const meta_context &context, const meta_type_node &from, const meta_type_node &to) noexcept {
-    if((from.info && *from.info == *to.info) || (from.conversion_helper && static_cast<bool>(to.traits & (meta_traits::is_arithmetic | meta_traits::is_enum)))) {
-        return true;
+template<typename Func>
+[[nodiscard]] inline auto try_convert(const meta_context &context, const meta_type_node &from, const meta_type_node &to, const void *instance, Func func) {
+    if(from.info && *from.info == *to.info) {
+        return func(instance, from);
     }
 
     if(from.details) {
         if(auto it = from.details->conv.find(to.info->hash()); it != from.details->conv.cend()) {
-            return true;
+            return func(instance, it->second);
         }
 
         for(auto &&curr: from.details->base) {
-            if(can_convert(context, curr.second.type(context), to)) {
-                return true;
+            if(auto other = try_convert(context, curr.second.type(context), to, curr.second.cast(instance), func); other) {
+                return other;
             }
         }
     }
 
-    return false;
+    if(from.conversion_helper && static_cast<bool>(to.traits & (meta_traits::is_arithmetic | meta_traits::is_enum))) {
+        return func(instance, from.conversion_helper);
+    }
+
+    return func(instance);
 }
 
 [[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {