Core: new blenlib library for implicit-sharing #105994

Merged
Jacques Lucke merged 17 commits from JacquesLucke/blender:implicit-sharing into main 2023-03-28 13:58:02 +02:00
5 changed files with 26 additions and 22 deletions
Showing only changes of commit ab3fda1c58 - Show all commits

View File

@ -32,7 +32,7 @@ namespace blender::bke {
* because that is not available in C code. If possible, the #AutoAnonymousAttributeID wrapper * because that is not available in C code. If possible, the #AutoAnonymousAttributeID wrapper
* should be used to avoid manual reference counting in C++ code. * should be used to avoid manual reference counting in C++ code.
*/ */
class AnonymousAttributeID : public bCopyOnWriteMixin { class AnonymousAttributeID : public ImplicitShareMixin {
protected: protected:
std::string name_; std::string name_;
@ -54,7 +54,7 @@ class AnonymousAttributeID : public bCopyOnWriteMixin {
}; };
/** Wrapper for #AnonymousAttributeID that avoids manual reference counting. */ /** Wrapper for #AnonymousAttributeID that avoids manual reference counting. */
using AutoAnonymousAttributeID = COWUser<const AnonymousAttributeID>; using AutoAnonymousAttributeID = ImplicitSharePtr<const AnonymousAttributeID>;
/** /**
* A set of anonymous attribute names that is passed around in geometry nodes. * A set of anonymous attribute names that is passed around in geometry nodes.

View File

@ -43,7 +43,7 @@ class Instances;
* copy-on-write behavior to avoid read-only copies. It also integrates with attribute API, which * copy-on-write behavior to avoid read-only copies. It also integrates with attribute API, which
* generalizes storing and modifying generic information on a geometry. * generalizes storing and modifying generic information on a geometry.
*/ */
class GeometryComponent : public bCopyOnWriteMixin { class GeometryComponent : public blender::ImplicitShareMixin {
private: private:
GeometryComponentType type_; GeometryComponentType type_;
@ -101,7 +101,7 @@ inline constexpr bool is_geometry_component_v = std::is_base_of_v<GeometryCompon
*/ */
struct GeometrySet { struct GeometrySet {
private: private:
using GeometryComponentPtr = blender::COWUser<class GeometryComponent>; using GeometryComponentPtr = blender::ImplicitSharePtr<class GeometryComponent>;
/* Indexed by #GeometryComponentType. */ /* Indexed by #GeometryComponentType. */
std::array<GeometryComponentPtr, GEO_COMPONENT_TYPE_ENUM_SIZE> components_; std::array<GeometryComponentPtr, GEO_COMPONENT_TYPE_ENUM_SIZE> components_;

View File

@ -12,6 +12,8 @@
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BLI_utility_mixins.hh" #include "BLI_utility_mixins.hh"
namespace blender {
/** /**
* #bCopyOnWrite allows implementing copy-on-write behavior, i.e. it allows sharing read-only data * #bCopyOnWrite allows implementing copy-on-write behavior, i.e. it allows sharing read-only data
* between multiple independend systems (e.g. meshes). The data is only copied when it is shared * between multiple independend systems (e.g. meshes). The data is only copied when it is shared
@ -30,18 +32,18 @@
* #bCopyOnWrite is used in two ways: * #bCopyOnWrite is used in two ways:
* - It can be allocated separately from the referenced data as is typically the case with raw * - It can be allocated separately from the referenced data as is typically the case with raw
* arrays (e.g. for mesh attributes). * arrays (e.g. for mesh attributes).
* - It can be embedded into another struct. For that it's best to use #bCopyOnWriteMixin. * - It can be embedded into another struct. For that it's best to use #ImplicitShareMixin.
*/ */
struct bCopyOnWrite : blender::NonCopyable, blender::NonMovable { struct ImplicitShareInfo : blender::NonCopyable, blender::NonMovable {
private: private:
mutable std::atomic<int> users_; mutable std::atomic<int> users_;
public: public:
bCopyOnWrite(const int initial_users) : users_(initial_users) ImplicitShareInfo(const int initial_users) : users_(initial_users)
{ {
} }
virtual ~bCopyOnWrite() virtual ~ImplicitShareInfo()
{ {
BLI_assert(this->is_mutable()); BLI_assert(this->is_mutable());
} }
@ -67,7 +69,7 @@ struct bCopyOnWrite : blender::NonCopyable, blender::NonMovable {
BLI_assert(old_user_count >= 1); BLI_assert(old_user_count >= 1);
const bool was_last_user = old_user_count == 1; const bool was_last_user = old_user_count == 1;
if (was_last_user) { if (was_last_user) {
const_cast<bCopyOnWrite *>(this)->delete_self_with_data(); const_cast<ImplicitShareInfo *>(this)->delete_self_with_data();
} }
} }
@ -79,9 +81,9 @@ struct bCopyOnWrite : blender::NonCopyable, blender::NonMovable {
/** /**
* Makes it easy to embed copy-on-write behavior into a struct. * Makes it easy to embed copy-on-write behavior into a struct.
*/ */
JacquesLucke marked this conversation as resolved Outdated

This comment is a bit hard to follow, maybe replacing the subclass with something more specific would help (like saying the ptr class can be used with a class that derives from the mixin class).

This comment is a bit hard to follow, maybe replacing `the subclass` with something more specific would help (like saying the ptr class can be used with a class that derives from the mixin class).
struct bCopyOnWriteMixin : public bCopyOnWrite { struct ImplicitShareMixin : public ImplicitShareInfo {
public: public:
bCopyOnWriteMixin() : bCopyOnWrite(1) ImplicitShareMixin() : ImplicitShareInfo(1)
{ {
} }
@ -94,3 +96,5 @@ struct bCopyOnWriteMixin : public bCopyOnWrite {
virtual void delete_self() = 0; virtual void delete_self() = 0;
}; };
} // namespace blender

View File

@ -10,33 +10,33 @@
namespace blender { namespace blender {
template<typename T> class COWUser { template<typename T> class ImplicitSharePtr {
private: private:
T *data_ = nullptr; T *data_ = nullptr;
public: public:
COWUser() = default; ImplicitSharePtr() = default;
COWUser(T *data) : data_(data) ImplicitSharePtr(T *data) : data_(data)
{ {
} }
COWUser(const COWUser &other) : data_(other.data_) ImplicitSharePtr(const ImplicitSharePtr &other) : data_(other.data_)
{ {
this->add_user(data_); this->add_user(data_);
} }
COWUser(COWUser &&other) : data_(other.data_) ImplicitSharePtr(ImplicitSharePtr &&other) : data_(other.data_)
{ {
other.data_ = nullptr; other.data_ = nullptr;
} }
~COWUser() ~ImplicitSharePtr()
{ {
this->remove_user_and_delete_if_last(data_); this->remove_user_and_delete_if_last(data_);
} }
COWUser &operator=(const COWUser &other) ImplicitSharePtr &operator=(const ImplicitSharePtr &other)
{ {
if (this == &other) { if (this == &other) {
return *this; return *this;
@ -48,7 +48,7 @@ template<typename T> class COWUser {
return *this; return *this;
} }
COWUser &operator=(COWUser &&other) ImplicitSharePtr &operator=(ImplicitSharePtr &&other)
{ {
if (this == &other) { if (this == &other) {
return *this; return *this;
@ -122,7 +122,7 @@ template<typename T> class COWUser {
return get_default_hash(data_); return get_default_hash(data_);
} }
friend bool operator==(const COWUser &a, const COWUser &b) friend bool operator==(const ImplicitSharePtr &a, const ImplicitSharePtr &b)
{ {
return a.data_ == b.data_; return a.data_ == b.data_;
} }

View File

@ -226,8 +226,8 @@ struct GatherTasks {
/* Volumes only have very simple support currently. Only the first found volume is put into the /* Volumes only have very simple support currently. Only the first found volume is put into the
* output. */ * output. */
COWUser<const VolumeComponent> first_volume; ImplicitSharePtr<const VolumeComponent> first_volume;
COWUser<const GeometryComponentEditData> first_edit_data; ImplicitSharePtr<const GeometryComponentEditData> first_edit_data;
}; };
/** Current offsets while during the gather operation. */ /** Current offsets while during the gather operation. */