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-01-03 18:55:45 +0300
committerJacques Lucke <jacques@blender.org>2022-01-03 18:55:45 +0300
commit1713a780c56b1c2fc1ba3e1b02fc6f860cd2604b (patch)
tree2c6037cd792c4cbb3e8dcb1e70ecaa47c4b7953e /source/blender
parente0ac932156b9b44190d5638f2c38d17af7770594 (diff)
progress
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh24
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc19
-rw-r--r--source/blender/blenlib/BLI_copy_on_write.h181
-rw-r--r--source/blender/blenlib/intern/copy_on_write.cc9
-rw-r--r--source/blender/geometry/intern/realize_instances.cc4
5 files changed, 201 insertions, 36 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 0f9c2c1062b..b3e757a83ba 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -23,6 +23,7 @@
#include <atomic>
#include <iostream>
+#include "BLI_copy_on_write.h"
#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
#include "BLI_function_ref.hh"
@@ -63,14 +64,13 @@ class GeometryComponent;
/**
* This is the base class for specialized geometry component types. A geometry component handles
- * a user count to allow avoiding duplication when it is wrapped with #UserCounter. It also handles
- * the attribute API, which generalizes storing and modifying generic information on a geometry.
+ * a user count to allow avoiding duplication when it is wrapped with #bCopyOnWrite. It also
+ * handles the attribute API, which generalizes storing and modifying generic information on a
+ * geometry.
*/
class GeometryComponent {
private:
- /* The reference count has two purposes. When it becomes zero, the component is freed. When it is
- * larger than one, the component becomes immutable. */
- mutable std::atomic<int> users_ = 1;
+ blender::bCopyOnWrite cow_;
GeometryComponentType type_;
public:
@@ -81,14 +81,22 @@ class GeometryComponent {
/* The returned component should be of the same type as the type this is called on. */
virtual GeometryComponent *copy() const = 0;
+ const blender::bCopyOnWrite &cow() const
+ {
+ return cow_;
+ }
+
+ void cow_delete_self() const
+ {
+ delete this;
+ }
+
/* Direct data is everything except for instances of objects/collections.
* If this returns true, the geometry set can be cached and is still valid after e.g. modifier
* evaluation ends. Instances can only be valid as long as the data they instance is valid. */
virtual bool owns_direct_data() const = 0;
virtual void ensure_owns_direct_data() = 0;
- void user_add() const;
- void user_remove() const;
bool is_mutable() const;
GeometryComponentType type() const;
@@ -310,7 +318,7 @@ inline constexpr bool is_geometry_component_v = std::is_base_of_v<GeometryCompon
*/
struct GeometrySet {
private:
- using GeometryComponentPtr = blender::UserCounter<class GeometryComponent>;
+ using GeometryComponentPtr = blender::COWUser<class GeometryComponent>;
/* Indexed by #GeometryComponentType. */
std::array<GeometryComponentPtr, GEO_COMPONENT_TYPE_ENUM_SIZE> components_;
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 06e0e78745b..5defda3aa63 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -69,24 +69,9 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ
return nullptr;
}
-void GeometryComponent::user_add() const
-{
- users_.fetch_add(1);
-}
-
-void GeometryComponent::user_remove() const
-{
- const int new_users = users_.fetch_sub(1) - 1;
- if (new_users == 0) {
- delete this;
- }
-}
-
bool GeometryComponent::is_mutable() const
{
- /* If the item is shared, it is read-only. */
- /* The user count can be 0, when this is called from the destructor. */
- return users_ <= 1;
+ return cow_.is_mutable();
}
GeometryComponentType GeometryComponent::type() const
@@ -168,7 +153,7 @@ void GeometrySet::keep_only(const blender::Span<GeometryComponentType> component
void GeometrySet::add(const GeometryComponent &component)
{
BLI_assert(!components_[component.type()]);
- component.user_add();
+ component.cow().user_add();
components_[component.type()] = const_cast<GeometryComponent *>(&component);
}
diff --git a/source/blender/blenlib/BLI_copy_on_write.h b/source/blender/blenlib/BLI_copy_on_write.h
index 838d4c38b0e..e1dba871207 100644
--- a/source/blender/blenlib/BLI_copy_on_write.h
+++ b/source/blender/blenlib/BLI_copy_on_write.h
@@ -20,7 +20,9 @@
* \ingroup bli
*/
+#include "BLI_assert.h"
#include "BLI_compiler_attrs.h"
+#include "BLI_utility_mixins.hh"
#include "DNA_copy_on_write.h"
@@ -31,11 +33,10 @@ extern "C" {
bCopyOnWrite *BLI_cow_new(int user_count);
void BLI_cow_free(const bCopyOnWrite *cow);
-void BLI_cow_init(const bCopyOnWrite *cow, int user_count);
+void BLI_cow_init(const bCopyOnWrite *cow);
bool BLI_cow_is_shared(const bCopyOnWrite *cow);
bool BLI_cow_is_mutable(const bCopyOnWrite *cow);
-bool BLI_cow_is_zero(const bCopyOnWrite *cow);
void BLI_cow_user_add(const bCopyOnWrite *cow);
bool BLI_cow_user_remove(const bCopyOnWrite *cow) ATTR_WARN_UNUSED_RESULT;
@@ -43,3 +44,179 @@ bool BLI_cow_user_remove(const bCopyOnWrite *cow) ATTR_WARN_UNUSED_RESULT;
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+
+namespace blender {
+
+class bCopyOnWrite : public ::bCopyOnWrite, private NonCopyable, NonMovable {
+ public:
+ bCopyOnWrite()
+ {
+ BLI_cow_init(this);
+ }
+
+ ~bCopyOnWrite()
+ {
+ BLI_assert(this->is_mutable());
+ }
+
+ bool is_shared() const
+ {
+ return BLI_cow_is_shared(this);
+ }
+
+ bool is_mutable() const
+ {
+ return BLI_cow_is_mutable(this);
+ }
+
+ void user_add() const
+ {
+ BLI_cow_user_add(this);
+ }
+
+ bool user_remove() const ATTR_WARN_UNUSED_RESULT
+ {
+ return BLI_cow_user_remove(this);
+ }
+};
+
+template<typename T> class COWUser {
+ private:
+ T *data_ = nullptr;
+
+ public:
+ COWUser() = default;
+
+ COWUser(T *data) : data_(data)
+ {
+ }
+
+ COWUser(const COWUser &other) : data_(other.data_)
+ {
+ this->user_add(data_);
+ }
+
+ COWUser(COWUser &&other) : data_(other.data_)
+ {
+ other.data_ = nullptr;
+ }
+
+ ~COWUser()
+ {
+ this->user_remove(data_);
+ }
+
+ COWUser &operator=(const COWUser &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->user_remove(data_);
+ data_ = other.data_;
+ this->user_add(data_);
+ return *this;
+ }
+
+ COWUser &operator=(COWUser &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->user_remove(data_);
+ data_ = other.data_;
+ other.data_ = nullptr;
+ return *this;
+ }
+
+ T *operator->()
+ {
+ BLI_assert(data_ != nullptr);
+ return data_;
+ }
+
+ const T *operator->() const
+ {
+ BLI_assert(data_ != nullptr);
+ return data_;
+ }
+
+ T &operator*()
+ {
+ BLI_assert(data_ != nullptr);
+ return *data_;
+ }
+
+ const T &operator*() const
+ {
+ BLI_assert(data_ != nullptr);
+ return *data_;
+ }
+
+ operator bool() const
+ {
+ return data_ != nullptr;
+ }
+
+ T *get()
+ {
+ return data_;
+ }
+
+ const T *get() const
+ {
+ return data_;
+ }
+
+ T *release()
+ {
+ T *data = data_;
+ data_ = nullptr;
+ return data;
+ }
+
+ void reset()
+ {
+ this->user_remove(data_);
+ data_ = nullptr;
+ }
+
+ bool has_value() const
+ {
+ return data_ != nullptr;
+ }
+
+ uint64_t hash() const
+ {
+ return get_default_hash(data_);
+ }
+
+ friend bool operator==(const COWUser &a, const COWUser &b)
+ {
+ return a.data_ == b.data_;
+ }
+
+ private:
+ static void user_add(T *data)
+ {
+ if (data != nullptr) {
+ data->cow().user_add();
+ }
+ }
+
+ static void user_remove(T *data)
+ {
+ if (data != nullptr) {
+ if (data->cow().user_remove()) {
+ data->cow_delete_self();
+ }
+ }
+ }
+};
+
+} // namespace blender
+
+#endif
diff --git a/source/blender/blenlib/intern/copy_on_write.cc b/source/blender/blenlib/intern/copy_on_write.cc
index c1fc7a7569b..4479db326b2 100644
--- a/source/blender/blenlib/intern/copy_on_write.cc
+++ b/source/blender/blenlib/intern/copy_on_write.cc
@@ -44,9 +44,9 @@ void BLI_cow_free(const bCopyOnWrite *cow)
MEM_freeN(const_cast<bCopyOnWrite *>(cow));
}
-void BLI_cow_init(const bCopyOnWrite *cow, int user_count)
+void BLI_cow_init(const bCopyOnWrite *cow)
{
- get_counter(cow) = user_count;
+ get_counter(cow) = 1;
}
bool BLI_cow_is_mutable(const bCopyOnWrite *cow)
@@ -59,11 +59,6 @@ bool BLI_cow_is_shared(const bCopyOnWrite *cow)
return cow->user_count >= 2;
}
-bool BLI_cow_is_zero(const bCopyOnWrite *cow)
-{
- return cow->user_count == 0;
-}
-
void BLI_cow_user_add(const bCopyOnWrite *cow)
{
atomic_fetch_and_add_int32(&get_counter(cow), 1);
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index 4022794d53f..16f0db3f430 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -191,7 +191,7 @@ struct GatherTasks {
/* Volumes only have very simple support currently. Only the first found volume is put into the
* output. */
- UserCounter<VolumeComponent> first_volume;
+ COWUser<VolumeComponent> first_volume;
};
/** Current offsets while during the gather operation. */
@@ -480,7 +480,7 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
case GEO_COMPONENT_TYPE_VOLUME: {
const VolumeComponent *volume_component = static_cast<const VolumeComponent *>(component);
if (!gather_info.r_tasks.first_volume) {
- volume_component->user_add();
+ volume_component->cow().user_add();
gather_info.r_tasks.first_volume = const_cast<VolumeComponent *>(volume_component);
}
break;