Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2022-03-19 12:57:40 +0300
committerJacques Lucke <jacques@blender.org>2022-03-19 12:57:40 +0300
commit8711483632823524019a6cc95575c5a4ba5aa831 (patch)
tree76c2f8355d0fce66f4f9e35b5ec1282960e51209 /source/blender/blenlib/BLI_cpp_type.hh
parent3e16f3b3ef4b8f385b30fe4a1e00860620f610ee (diff)
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.
Diffstat (limited to 'source/blender/blenlib/BLI_cpp_type.hh')
-rw-r--r--source/blender/blenlib/BLI_cpp_type.hh73
1 files changed, 73 insertions, 0 deletions
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) {
+ callback(fn);
+ }
+ else {
+ /* Call the non-templated `operator()` of the given function object. */
+ fn();
+ }
+ }
+
+ template<typename T> struct type_tag {
+ using type = T;
+ };
+
+ private:
+ template<typename Fn> struct TypeTagExecutor {
+ const Fn &fn;
+
+ template<typename T> void operator()() const
+ {
+ fn(type_tag<T>{});
+ }
+
+ void operator()() const
+ {
+ fn(type_tag<void>{});
+ }
+ };
+
+ public:
+ /**
+ * Similar to #to_static_type but is easier to use with a lambda function. The function is
+ * expected to take a single `auto type_tag` parameter. To extract the static type, use:
+ * `using T = typename decltype(type_tag)::type;`
+ *
+ * If the current #CPPType is not in #Types, the type tag is `void`.
+ */
+ template<typename... Types, typename Fn> void to_static_type_tag(const Fn &fn) const
+ {
+ TypeTagExecutor<Fn> executor{fn};
+ this->to_static_type<Types...>(executor);
+ }
};
} // namespace blender