[Bf-blender-cvs] [a2d32960b4d] master: BLI: optimize constructing new virtual array

Jacques Lucke noreply at git.blender.org
Mon Apr 25 11:51:43 CEST 2022


Commit: a2d32960b4de78f545ce52e92185eefd3c93fde1
Author: Jacques Lucke
Date:   Mon Apr 25 11:51:22 2022 +0200
Branches: master
https://developer.blender.org/rBa2d32960b4de78f545ce52e92185eefd3c93fde1

BLI: optimize constructing new virtual array

Differential Revision: https://developer.blender.org/D14745

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

M	source/blender/blenlib/BLI_any.hh
M	source/blender/blenlib/BLI_generic_virtual_array.hh
M	source/blender/blenlib/BLI_virtual_array.hh
M	source/blender/blenlib/intern/generic_virtual_array.cc
M	source/blender/blenlib/tests/BLI_any_test.cc

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

diff --git a/source/blender/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh
index 4424ad29a21..875e7cce056 100644
--- a/source/blender/blenlib/BLI_any.hh
+++ b/source/blender/blenlib/BLI_any.hh
@@ -31,55 +31,37 @@ template<typename ExtraInfo> struct AnyTypeInfo {
   void (*destruct)(void *src);
   const void *(*get)(const void *src);
   ExtraInfo extra_info;
+};
 
-  /**
-   * Used when #T is stored directly in the inline buffer of the #Any.
-   */
-  template<typename T> static const AnyTypeInfo &get_for_inline()
-  {
-    static AnyTypeInfo funcs = {[](void *dst, const void *src) { new (dst) T(*(const T *)src); },
-                                [](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); },
-                                [](void *src) { ((T *)src)->~T(); },
-                                [](const void *src) { return src; },
-                                ExtraInfo::template get<T>()};
-    return funcs;
-  }
-
-  /**
-   * Used when #T can't be stored directly in the inline buffer and is stored in a #std::unique_ptr
-   * instead. In this scenario, the #std::unique_ptr is stored in the inline buffer.
-   */
-  template<typename T> static const AnyTypeInfo &get_for_unique_ptr()
-  {
-    using Ptr = std::unique_ptr<T>;
-    static AnyTypeInfo funcs = {
-        [](void *dst, const void *src) { new (dst) Ptr(new T(**(const Ptr *)src)); },
-        [](void *dst, void *src) { new (dst) Ptr(new T(std::move(**(Ptr *)src))); },
-        [](void *src) { ((Ptr *)src)->~Ptr(); },
-        [](const void *src) -> const void * { return &**(const Ptr *)src; },
-        ExtraInfo::template get<T>()};
-    return funcs;
-  }
+/**
+ * Used when #T is stored directly in the inline buffer of the #Any.
+ */
+template<typename ExtraInfo, typename T>
+static constexpr AnyTypeInfo<ExtraInfo> info_for_inline = {
+    [](void *dst, const void *src) { new (dst) T(*(const T *)src); },
+    [](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); },
+    [](void *src) { ((T *)src)->~T(); },
+    [](const void *src) { return src; },
+    ExtraInfo::template get<T>()};
 
-  /**
-   * Used when the #Any does not contain any type currently.
-   */
-  static const AnyTypeInfo &get_for_empty()
-  {
-    static AnyTypeInfo funcs = {[](void *UNUSED(dst), const void *UNUSED(src)) {},
-                                [](void *UNUSED(dst), void *UNUSED(src)) {},
-                                [](void *UNUSED(src)) {},
-                                [](const void *UNUSED(src)) -> const void * { return nullptr; },
-                                ExtraInfo{}};
-    return funcs;
-  }
-};
+/**
+ * Used when #T can't be stored directly in the inline buffer and is stored in a #std::unique_ptr
+ * instead. In this scenario, the #std::unique_ptr is stored in the inline buffer.
+ */
+template<typename T> using Ptr = std::unique_ptr<T>;
+template<typename ExtraInfo, typename T>
+static constexpr AnyTypeInfo<ExtraInfo> info_for_unique_ptr = {
+    [](void *dst, const void *src) { new (dst) Ptr<T>(new T(**(const Ptr<T> *)src)); },
+    [](void *dst, void *src) { new (dst) Ptr<T>(new T(std::move(**(Ptr<T> *)src))); },
+    [](void *src) { ((Ptr<T> *)src)->~Ptr<T>(); },
+    [](const void *src) -> const void * { return &**(const Ptr<T> *)src; },
+    ExtraInfo::template get<T>()};
 
 /**
  * Dummy extra info that is used when no additional type information should be stored in the #Any.
  */
 struct NoExtraInfo {
-  template<typename T> static NoExtraInfo get()
+  template<typename T> static constexpr NoExtraInfo get()
   {
     return {};
   }
@@ -119,8 +101,9 @@ class Any {
 
   /**
    * Information about the type that is currently stored.
+   * This is null when the #Any does not contain a value.
    */
-  const Info *info_ = &Info::get_for_empty();
+  const Info *info_ = nullptr;
 
  public:
   /** Only copy constructible types can be stored in #Any. */
@@ -148,10 +131,10 @@ class Any {
     using DecayT = std::decay_t<T>;
     static_assert(is_allowed_v<DecayT>);
     if constexpr (is_inline_v<DecayT>) {
-      return Info::template get_for_inline<DecayT>();
+      return detail::template info_for_inline<RealExtraInfo, DecayT>;
     }
     else {
-      return Info::template get_for_unique_ptr<DecayT>();
+      return detail::template info_for_unique_ptr<RealExtraInfo, DecayT>;
     }
   }
 
@@ -160,7 +143,9 @@ class Any {
 
   Any(const Any &other) : info_(other.info_)
   {
-    info_->copy_construct(&buffer_, &other.buffer_);
+    if (info_ != nullptr) {
+      info_->copy_construct(&buffer_, &other.buffer_);
+    }
   }
 
   /**
@@ -169,7 +154,9 @@ class Any {
    */
   Any(Any &&other) noexcept : info_(other.info_)
   {
-    info_->move_construct(&buffer_, &other.buffer_);
+    if (info_ != nullptr) {
+      info_->move_construct(&buffer_, &other.buffer_);
+    }
   }
 
   /**
@@ -178,18 +165,7 @@ class Any {
    */
   template<typename T, typename... Args> explicit Any(std::in_place_type_t<T>, Args &&...args)
   {
-    using DecayT = std::decay_t<T>;
-    static_assert(is_allowed_v<DecayT>);
-    info_ = &this->template get_info<DecayT>();
-    if constexpr (is_inline_v<DecayT>) {
-      /* Construct the value directly in the inline buffer. */
-      new (&buffer_) DecayT(std::forward<Args>(args)...);
-    }
-    else {
-      /* Construct the value in a new allocation and store a #std::unique_ptr to it in the inline
-       * buffer. */
-      new (&buffer_) std::unique_ptr<DecayT>(new DecayT(std::forward<Args>(args)...));
-    }
+    this->emplace_on_empty<T>(std::forward<Args>(args)...);
   }
 
   /**
@@ -202,7 +178,9 @@ class Any {
 
   ~Any()
   {
-    info_->destruct(&buffer_);
+    if (info_ != nullptr) {
+      info_->destruct(&buffer_);
+    }
   }
 
   /**
@@ -234,8 +212,10 @@ class Any {
   /** Destruct any existing value to make it empty. */
   void reset()
   {
-    info_->destruct(&buffer_);
-    info_ = &Info::get_for_empty();
+    if (info_ != nullptr) {
+      info_->destruct(&buffer_);
+    }
+    info_ = nullptr;
   }
 
   operator bool() const
@@ -245,7 +225,7 @@ class Any {
 
   bool has_value() const
   {
-    return info_ != &Info::get_for_empty();
+    return info_ != nullptr;
   }
 
   template<typename T, typename... Args> std::decay_t<T> &emplace(Args &&...args)
@@ -255,6 +235,26 @@ class Any {
     return this->get<T>();
   }
 
+  template<typename T, typename... Args> std::decay_t<T> &emplace_on_empty(Args &&...args)
+  {
+    BLI_assert(!this->has_value());
+    using DecayT = std::decay_t<T>;
+    static_assert(is_allowed_v<DecayT>);
+    info_ = &this->template get_info<DecayT>();
+    if constexpr (is_inline_v<DecayT>) {
+      /* Construct the value directly in the inline buffer. */
+      DecayT *stored_value = new (&buffer_) DecayT(std::forward<Args>(args)...);
+      return *stored_value;
+    }
+    else {
+      /* Construct the value in a new allocation and store a #std::unique_ptr to it in the inline
+       * buffer. */
+      std::unique_ptr<DecayT> *stored_value = new (&buffer_)
+          std::unique_ptr<DecayT>(new DecayT(std::forward<Args>(args)...));
+      return **stored_value;
+    }
+  }
+
   /** Return true when the value that is currently stored is a #T. */
   template<typename T> bool is() const
   {
@@ -264,12 +264,14 @@ class Any {
   /** Get a pointer to the stored value. */
   void *get()
   {
+    BLI_assert(info_ != nullptr);
     return const_cast<void *>(info_->get(&buffer_));
   }
 
   /** Get a pointer to the stored value. */
   const void *get() const
   {
+    BLI_assert(info_ != nullptr);
     return info_->get(&buffer_);
   }
 
@@ -298,6 +300,7 @@ class Any {
    */
   const RealExtraInfo &extra_info() const
   {
+    BLI_assert(info_ != nullptr);
     return info_->extra_info;
   }
 };
diff --git a/source/blender/blenlib/BLI_generic_virtual_array.hh b/source/blender/blenlib/BLI_generic_virtual_array.hh
index 2e756e912f9..d02760d9178 100644
--- a/source/blender/blenlib/BLI_generic_virtual_array.hh
+++ b/source/blender/blenlib/BLI_generic_virtual_array.hh
@@ -83,7 +83,7 @@ struct GVArrayAnyExtraInfo {
   const GVArrayImpl *(*get_varray)(const void *buffer) =
       [](const void *UNUSED(buffer)) -> const GVArrayImpl * { return nullptr; };
 
-  template<typename StorageT> static GVArrayAnyExtraInfo get();
+  template<typename StorageT> static constexpr GVArrayAnyExtraInfo get();
 };
 }  // namespace detail
 
@@ -810,7 +810,7 @@ inline bool GVArrayCommon::is_empty() const
  * \{ */
 
 namespace detail {
-template<typename StorageT> inline GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
+template<typename StorageT> constexpr GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
 {
   static_assert(std::is_base_of_v<GVArrayImpl, StorageT> ||
                 is_same_any_v<StorageT, const GVArrayImpl *, std::shared_ptr<const GVArrayImpl>>);
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index 453ca67b1e0..41a73b45853 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -564,10 +564,9 @@ template<typename T> struct VArrayAnyExtraInfo {
   /**
    * Gets the virtual array that is stored at the given pointer.
    */
-  const VArrayImpl<T> *(*get_varray)(const void *buffer) =
-      [](const void *UNUSED(buffer)) -> const VArrayImpl<T> * { return nullptr; };
+  const VArrayImpl<T> *(*get_varray)(const void *buffer);
 
-  template<typename StorageT> static VArrayAnyExtraInfo get()
+  template<typename StorageT> static constexpr VArrayAnyExtraInfo get()
   {
     /* These are the only allowed types in the #Any. */
     static_assert(
@@ -711,6 +710,9 @@ template<typename T> class VArrayCommon {
    * null. */
   const VArrayImpl<T> *impl_from_storage() const
   {
+    if (!storage_.has_value()) {
+      return nullptr;
+    }
     return storage_.extra_info().get_varray(storage_.get());
   }
 
diff --git a/source/blender/blenlib/intern/generic_virtual_array.cc b/source/blender/blenlib/intern/generic_virtual_array.cc
index e1a150c3f08..a3a17952a97 100644
--- a/source/blender/blenlib/intern/generic_virtual_array.cc
+++ b/source/blender/blenlib/intern/generic_virtual_array.cc
@@ -643,6 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list