[Bf-blender-cvs] [87114836328] master: BLI: generalize converting CPPType to static type

Jacques Lucke noreply at git.blender.org
Sat Mar 19 10:57:59 CET 2022


Commit: 8711483632823524019a6cc95575c5a4ba5aa831
Author: Jacques Lucke
Date:   Sat Mar 19 10:57:40 2022 +0100
Branches: master
https://developer.blender.org/rB8711483632823524019a6cc95575c5a4ba5aa831

BLI: generalize converting CPPType to static type

Previously, the conversion was done manually for a fixed set of types.
Now, there is a more general utility that can be used in other contexts
(outside of geometry nodes attribute processing) as well.

===================================================================

M	source/blender/blenkernel/BKE_attribute_access.hh
M	source/blender/blenkernel/BKE_attribute_math.hh
M	source/blender/blenkernel/BKE_customdata.h
M	source/blender/blenkernel/intern/attribute_access.cc
M	source/blender/blenkernel/intern/customdata.cc
M	source/blender/blenlib/BLI_cpp_type.hh
M	source/blender/blenlib/intern/cpp_type.cc
M	source/blender/blenlib/tests/BLI_cpp_type_test.cc

===================================================================

diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index 36f29c7fbb7..8d449a124ec 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -164,8 +164,6 @@ using AttributeForeachCallback = blender::FunctionRef<bool(
 
 namespace blender::bke {
 
-const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
-CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
 CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types);
 /**
  * Domains with a higher "information density" have a higher priority,
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
index 9e97979fde9..3075c0689e9 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -8,71 +8,34 @@
 #include "BLI_math_vector.h"
 #include "BLI_math_vector.hh"
 
-#include "DNA_customdata_types.h"
+#include "BKE_customdata.h"
 
 namespace blender::attribute_math {
 
 /**
- * Utility function that simplifies calling a templated function based on a custom data type.
+ * Utility function that simplifies calling a templated function based on a run-time data type.
  */
 template<typename Func>
-inline void convert_to_static_type(const CustomDataType data_type, const Func &func)
+inline void convert_to_static_type(const CPPType &cpp_type, const Func &func)
 {
-  switch (data_type) {
-    case CD_PROP_FLOAT:
-      func(float());
-      break;
-    case CD_PROP_FLOAT2:
-      func(float2());
-      break;
-    case CD_PROP_FLOAT3:
-      func(float3());
-      break;
-    case CD_PROP_INT32:
-      func(int());
-      break;
-    case CD_PROP_BOOL:
-      func(bool());
-      break;
-    case CD_PROP_INT8:
-      func(int8_t());
-      break;
-    case CD_PROP_COLOR:
-      func(ColorGeometry4f());
-      break;
-    default:
-      BLI_assert_unreachable();
-      break;
-  }
+  cpp_type.to_static_type_tag<float, float2, float3, int, bool, int8_t, ColorGeometry4f>(
+      [&](auto type_tag) {
+        using T = typename decltype(type_tag)::type;
+        if constexpr (std::is_same_v<T, void>) {
+          /* It's expected that the given cpp type is one of the supported once. */
+          BLI_assert_unreachable();
+        }
+        else {
+          func(T());
+        }
+      });
 }
 
 template<typename Func>
-inline void convert_to_static_type(const CPPType &cpp_type, const Func &func)
+inline void convert_to_static_type(const CustomDataType data_type, const Func &func)
 {
-  if (cpp_type.is<float>()) {
-    func(float());
-  }
-  else if (cpp_type.is<float2>()) {
-    func(float2());
-  }
-  else if (cpp_type.is<float3>()) {
-    func(float3());
-  }
-  else if (cpp_type.is<int>()) {
-    func(int());
-  }
-  else if (cpp_type.is<bool>()) {
-    func(bool());
-  }
-  else if (cpp_type.is<int8_t>()) {
-    func(int8_t());
-  }
-  else if (cpp_type.is<ColorGeometry4f>()) {
-    func(ColorGeometry4f());
-  }
-  else {
-    BLI_assert_unreachable();
-  }
+  const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(data_type);
+  convert_to_static_type(cpp_type, func);
 }
 
 /* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 940dc3c4f6c..911f4aab394 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -751,3 +751,12 @@ void CustomData_debug_info_from_layers(const struct CustomData *data,
 #ifdef __cplusplus
 }
 #endif
+
+#ifdef __cplusplus
+#  include "BLI_cpp_type.hh"
+
+namespace blender::bke {
+const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
+CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
+}  // namespace blender::bke
+#endif
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 50e35c3c7c2..8fbab8dde25 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -54,55 +54,6 @@ std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_i
   return stream;
 }
 
-const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
-{
-  switch (type) {
-    case CD_PROP_FLOAT:
-      return &CPPType::get<float>();
-    case CD_PROP_FLOAT2:
-      return &CPPType::get<float2>();
-    case CD_PROP_FLOAT3:
-      return &CPPType::get<float3>();
-    case CD_PROP_INT32:
-      return &CPPType::get<int>();
-    case CD_PROP_COLOR:
-      return &CPPType::get<ColorGeometry4f>();
-    case CD_PROP_BOOL:
-      return &CPPType::get<bool>();
-    case CD_PROP_INT8:
-      return &CPPType::get<int8_t>();
-    default:
-      return nullptr;
-  }
-  return nullptr;
-}
-
-CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
-{
-  if (type.is<float>()) {
-    return CD_PROP_FLOAT;
-  }
-  if (type.is<float2>()) {
-    return CD_PROP_FLOAT2;
-  }
-  if (type.is<float3>()) {
-    return CD_PROP_FLOAT3;
-  }
-  if (type.is<int>()) {
-    return CD_PROP_INT32;
-  }
-  if (type.is<ColorGeometry4f>()) {
-    return CD_PROP_COLOR;
-  }
-  if (type.is<bool>()) {
-    return CD_PROP_BOOL;
-  }
-  if (type.is<int8_t>()) {
-    return CD_PROP_INT8;
-  }
-  return static_cast<CustomDataType>(-1);
-}
-
 static int attribute_data_type_complexity(const CustomDataType data_type)
 {
   switch (data_type) {
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index b348e18a6a8..251d73dc315 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -18,9 +18,11 @@
 #include "DNA_meshdata_types.h"
 
 #include "BLI_bitmap.h"
+#include "BLI_color.hh"
 #include "BLI_endian_switch.h"
 #include "BLI_math.h"
 #include "BLI_math_color_blend.h"
+#include "BLI_math_vector.hh"
 #include "BLI_mempool.h"
 #include "BLI_path_util.h"
 #include "BLI_string.h"
@@ -5234,3 +5236,56 @@ void CustomData_debug_info_from_layers(const CustomData *data, const char *inden
 }
 
 #endif /* NDEBUG */
+
+namespace blender::bke {
+
+const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
+{
+  switch (type) {
+    case CD_PROP_FLOAT:
+      return &CPPType::get<float>();
+    case CD_PROP_FLOAT2:
+      return &CPPType::get<float2>();
+    case CD_PROP_FLOAT3:
+      return &CPPType::get<float3>();
+    case CD_PROP_INT32:
+      return &CPPType::get<int>();
+    case CD_PROP_COLOR:
+      return &CPPType::get<ColorGeometry4f>();
+    case CD_PROP_BOOL:
+      return &CPPType::get<bool>();
+    case CD_PROP_INT8:
+      return &CPPType::get<int8_t>();
+    default:
+      return nullptr;
+  }
+  return nullptr;
+}
+
+CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
+{
+  if (type.is<float>()) {
+    return CD_PROP_FLOAT;
+  }
+  if (type.is<float2>()) {
+    return CD_PROP_FLOAT2;
+  }
+  if (type.is<float3>()) {
+    return CD_PROP_FLOAT3;
+  }
+  if (type.is<int>()) {
+    return CD_PROP_INT32;
+  }
+  if (type.is<ColorGeometry4f>()) {
+    return CD_PROP_COLOR;
+  }
+  if (type.is<bool>()) {
+    return CD_PROP_BOOL;
+  }
+  if (type.is<int8_t>()) {
+    return CD_PROP_INT8;
+  }
+  return static_cast<CustomDataType>(-1);
+}
+
+}  // namespace blender::bke
diff --git a/source/blender/blenlib/BLI_cpp_type.hh b/source/blender/blenlib/BLI_cpp_type.hh
index ae6a87b4b68..881408f460b 100644
--- a/source/blender/blenlib/BLI_cpp_type.hh
+++ b/source/blender/blenlib/BLI_cpp_type.hh
@@ -22,6 +22,7 @@
  *   - If the code is not performance sensitive, it usually makes sense to use #CPPType instead.
  * - Sometimes a combination can make sense. Optimized code can be be generated at compile-time for
  *   some types, while there is a fallback code path using #CPPType for all other types.
+ *   #CPPType::to_static_type allows dispatching between both versions based on the type.
  *
  * Under some circumstances, #CPPType serves a similar role as #std::type_info. However, #CPPType
  * has much more utility because it contains methods for actually working with instances of the
@@ -71,6 +72,7 @@
 
 #include "BLI_hash.hh"
 #include "BLI_index_mask.hh"
+#include "BLI_map.hh"
 #include "BLI_math_base.h"
 #include "BLI_string_ref.hh"
 #include "BLI_utility_mixins.hh"
@@ -643,6 +645,77 @@ class CPPType : NonCopyable, NonMovable {
   {
     return this == &CPPType::get<std::decay_t<T>>();
   }
+
+  /**
+   * Convert a #CPPType that is only known at run-time, to a static type that is known at
+   * compile-time. This allows the compiler to optimize a function for specific types, while all
+   * other types can still use a generic fallback function.
+   *
+   * \param Types The types that code should be generated for.
+   * \param fn The function object to call. This is expected to have a templated `operator()` and a
+   *   non-templated `operator()`. The templated version will be called if the current #CPPType
+   *   matches any of the given types. Otherwise, the non-templated function is called.
+   */
+  template<typename... Types, typename Fn> void to_static_type(const Fn &fn) const
+  {
+    using Callback = void (*)(const Fn &fn);
+
+    /* Build a lookup table to avoid having to compare the current #CPPType with every type in
+     * #Types one after another. */
+    static const Map<const CPPType *, Callback> callback_map = []() {
+      Map<const CPPType *, Callback> callback_map;
+      /* This adds an entry in the map for every type in #Types. */
+      (callback_map.add_new(&CPPType::get<Types>(),
+                            [](const Fn &fn) {
+                              /* Call the templated `operator()` of the given function object. */
+                              fn.template operator()<Types>();
+                            }),
+       ...);
+      return callback_map;
+    }();
+
+    const Callback callback = callback_map.lookup_default(this, nullptr);
+    if (callback != nullptr) {
+      cal

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list