[Bf-blender-cvs] [7773e1c2af4] functions: better separation of concerns for shared objects

Jacques Lucke noreply at git.blender.org
Sun Feb 10 20:26:08 CET 2019


Commit: 7773e1c2af4da7c6cd7686277d9f00b9b2aa8af4
Author: Jacques Lucke
Date:   Wed Feb 6 14:45:29 2019 +0100
Branches: functions
https://developer.blender.org/rB7773e1c2af4da7c6cd7686277d9f00b9b2aa8af4

better separation of concerns for shared objects

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

A	source/blender/blenlib/BLI_shared.hpp
D	tests/gtests/blenlib/BLI_refcount_test.cc
A	tests/gtests/blenlib/BLI_shared_test.cc
M	tests/gtests/blenlib/CMakeLists.txt

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

diff --git a/source/blender/blenlib/BLI_shared.hpp b/source/blender/blenlib/BLI_shared.hpp
new file mode 100644
index 00000000000..93376ac4e26
--- /dev/null
+++ b/source/blender/blenlib/BLI_shared.hpp
@@ -0,0 +1,119 @@
+#include <atomic>
+#include <utility>
+
+namespace BLI {
+
+	template<typename T>
+	class RefCounted {
+	private:
+		T *m_object;
+		std::atomic<int> m_refcount;
+
+		~RefCounted() = default;
+
+	public:
+		RefCounted(T *object)
+			: m_object(object), m_refcount(1) {}
+
+		inline void incref()
+		{
+			std::atomic_fetch_add(&this->m_refcount, 1);
+		}
+
+		inline void decref()
+		{
+			int previous_value = std::atomic_fetch_sub(&this->m_refcount, 1);
+			if (previous_value == 1) {
+				delete this->m_object;
+				delete this;
+			}
+		}
+
+		int refcount() const
+		{
+			return this->m_refcount;
+		}
+
+		T *ptr() const
+		{
+			return this->m_object;
+		}
+	};
+
+	template<typename T>
+	class Shared {
+	private:
+		RefCounted<T> *m_object;
+
+		Shared() = delete;
+		Shared(RefCounted<T> *object)
+			: m_object(object) {}
+
+		inline void incref()
+		{
+			this->m_object->incref();
+		}
+
+		inline void decref()
+		{
+			this->m_object->decref();
+		}
+
+	public:
+		template<typename ...Args>
+		static Shared<T> New(Args&&... args)
+		{
+			T *actual_value = new T(std::forward<Args>(args)...);
+			RefCounted<T> *refcounted_value = new RefCounted<T>(actual_value);
+			return Shared<T>(refcounted_value);
+		}
+
+		Shared(const Shared &other)
+		{
+			this->m_object = other.m_object;
+			this->incref();
+		}
+
+		Shared(const Shared &&other)
+		{
+			this->m_object = other.m_object;
+			this->incref();
+		}
+
+		~Shared()
+		{
+			this->decref();
+		}
+
+		Shared &operator=(const Shared &other)
+		{
+			if (this->m_object == other->m_object) {
+				return *this;
+			}
+
+			this->decref();
+			this->m_object = other.m_object;
+			this->incref();
+			return *this;
+		}
+
+		Shared &operator=(const Shared &&other)
+		{
+			this->decref();
+			this->m_object = other.m_object;
+			this->incref();
+			return *this;
+		}
+
+		T *operator->() const
+		{
+			return this->m_object->ptr();
+		}
+
+		RefCounted<T> *refcounter() const
+		{
+			return this->m_object;
+		}
+	};
+
+} /* namespace BLI */
\ No newline at end of file
diff --git a/tests/gtests/blenlib/BLI_refcount_test.cc b/tests/gtests/blenlib/BLI_refcount_test.cc
deleted file mode 100644
index 54087d649cc..00000000000
--- a/tests/gtests/blenlib/BLI_refcount_test.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-#include "testing/testing.h"
-#include "BLI_refcount.hpp"
-
-#include <iostream>
-
-#define DEFAULT_VALUE 42
-
-class MyTestClass {
-public:
-	int m_value;
-	bool *m_alive = nullptr;
-
-	MyTestClass()
-		: m_value(DEFAULT_VALUE) {}
-
-	MyTestClass(int value)
-		: m_value(value) {}
-
-	MyTestClass(bool *alive)
-		: m_alive(alive)
-	{
-		*alive = true;
-	}
-
-	~MyTestClass()
-	{
-		if (this->m_alive) *this->m_alive = false;
-	}
-};
-
-using namespace BLI;
-
-using TestObj = RefCount<MyTestClass>;
-
-TEST(refcount, OneReferenceAfterConstruction)
-{
-	TestObj obj = TestObj::make();
-	ASSERT_EQ(obj.refcount(), 1);
-}
-
-TEST(refcount, IncRefIncreasesRefCount)
-{
-	TestObj obj = TestObj::make();
-	ASSERT_EQ(obj.refcount(), 1);
-	obj.incref();
-	ASSERT_EQ(obj.refcount(), 2);
-}
-
-TEST(refcount, DecRefDecreasesRefCount)
-{
-	TestObj obj = TestObj::make();
-	obj.incref();
-	ASSERT_EQ(obj.refcount(), 2);
-	obj.decref();
-	ASSERT_EQ(obj.refcount(), 1);
-}
-
-TEST(refcount, CopyConstructorIncreasesRefCount)
-{
-	TestObj obj1 = TestObj::make();
-	ASSERT_EQ(obj1.refcount(), 1);
-	TestObj obj2(obj1);
-	ASSERT_EQ(obj1.refcount(), 2);
-	ASSERT_EQ(obj2.refcount(), 2);
-}
-
-TEST(refcount, MoveConstructorKeepsRefCount)
-{
-	TestObj obj(TestObj::make());
-	ASSERT_EQ(obj.refcount(), 1);
-}
-
-TEST(refcount, DecreasedWhenScopeEnds)
-{
-	TestObj obj1 = TestObj::make();
-	ASSERT_EQ(obj1.refcount(), 1);
-	{
-		TestObj obj2 = obj1;
-		ASSERT_EQ(obj1.refcount(), 2);
-		ASSERT_EQ(obj2.refcount(), 2);
-	}
-	ASSERT_EQ(obj1.refcount(), 1);
-}
-
-TEST(refcount, DefaultConstructorCalled)
-{
-	TestObj obj = TestObj::make();
-	ASSERT_EQ(obj->m_value, DEFAULT_VALUE);
-}
-
-TEST(refcount, OtherConstructorCalled)
-{
-	TestObj obj = TestObj::make(123);
-	ASSERT_EQ(obj->m_value, 123);
-}
-
-TEST(refcount, DestructorCalled)
-{
-	bool alive = false;
-	{
-		TestObj obj = TestObj::make(&alive);
-		ASSERT_TRUE(alive);
-	}
-	ASSERT_FALSE(alive);
-}
\ No newline at end of file
diff --git a/tests/gtests/blenlib/BLI_shared_test.cc b/tests/gtests/blenlib/BLI_shared_test.cc
new file mode 100644
index 00000000000..9cf18ee4636
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_shared_test.cc
@@ -0,0 +1,124 @@
+#include "testing/testing.h"
+#include "BLI_shared.hpp"
+
+#include <iostream>
+
+#define DEFAULT_VALUE 42
+
+class MyTestClass {
+public:
+	int m_value;
+	bool *m_alive = nullptr;
+
+	MyTestClass()
+		: m_value(DEFAULT_VALUE) {}
+
+	MyTestClass(int value)
+		: m_value(value) {}
+
+	MyTestClass(bool *alive)
+		: m_alive(alive)
+	{
+		*alive = true;
+	}
+
+	~MyTestClass()
+	{
+		if (this->m_alive) *this->m_alive = false;
+	}
+};
+
+using namespace BLI;
+
+using SharedClass = Shared<MyTestClass>;
+using RefCountedClass = RefCounted<MyTestClass>;
+
+TEST(shared, OneReferenceAfterConstruction)
+{
+	SharedClass obj = SharedClass::New();
+	ASSERT_EQ(obj.refcounter()->refcount(), 1);
+}
+
+TEST(shared, CopyConstructorIncreasesRefCount)
+{
+	SharedClass obj1 = SharedClass::New();
+	ASSERT_EQ(obj1.refcounter()->refcount(), 1);
+	SharedClass obj2(obj1);
+	ASSERT_EQ(obj1.refcounter()->refcount(), 2);
+	ASSERT_EQ(obj2.refcounter()->refcount(), 2);
+}
+
+TEST(shared, MoveConstructorKeepsRefCount)
+{
+	SharedClass obj(SharedClass::New());
+	ASSERT_EQ(obj.refcounter()->refcount(), 1);
+}
+
+TEST(shared, DecreasedWhenScopeEnds)
+{
+	SharedClass obj1 = SharedClass::New();
+	ASSERT_EQ(obj1.refcounter()->refcount(), 1);
+	{
+		SharedClass obj2 = obj1;
+		ASSERT_EQ(obj1.refcounter()->refcount(), 2);
+		ASSERT_EQ(obj2.refcounter()->refcount(), 2);
+	}
+	ASSERT_EQ(obj1.refcounter()->refcount(), 1);
+}
+
+TEST(shared, DefaultConstructorCalled)
+{
+	SharedClass obj = SharedClass::New();
+	ASSERT_EQ(obj->m_value, DEFAULT_VALUE);
+}
+
+TEST(shared, OtherConstructorCalled)
+{
+	SharedClass obj = SharedClass::New(123);
+	ASSERT_EQ(obj->m_value, 123);
+}
+
+TEST(shared, DestructorCalled)
+{
+	bool alive = false;
+	{
+		SharedClass obj = SharedClass::New(&alive);
+		ASSERT_TRUE(alive);
+	}
+	ASSERT_FALSE(alive);
+}
+
+TEST(shared, CustomIncRef)
+{
+	RefCountedClass *obj = new RefCountedClass(new MyTestClass());
+	ASSERT_EQ(obj->refcount(), 1);
+	obj->incref();
+	ASSERT_EQ(obj->refcount(), 2);
+}
+
+TEST(shared, CustomDecRef)
+{
+	RefCountedClass *obj = new RefCountedClass(new MyTestClass());
+	obj->incref();
+	ASSERT_EQ(obj->refcount(), 2);
+	obj->decref();
+	ASSERT_EQ(obj->refcount(), 1);
+}
+
+TEST(shared, ExtractRefCounted)
+{
+	SharedClass obj = SharedClass::New();
+	RefCountedClass *ref = obj.refcounter();
+	ASSERT_EQ(obj.refcounter()->refcount(), 1);
+	ref->incref();
+	ASSERT_EQ(obj.refcounter()->refcount(), 2);
+}
+
+TEST(shared, DecRefToZero)
+{
+	bool alive = false;
+	RefCountedClass *obj = new RefCountedClass(new MyTestClass(&alive));
+	ASSERT_TRUE(alive);
+	obj->decref();
+	ASSERT_FALSE(alive);
+}
\ No newline at end of file
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index 466097fe364..40ed7658d5e 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -55,7 +55,7 @@ BLENDER_TEST(BLI_math_geom "bf_blenlib")
 BLENDER_TEST(BLI_memiter "bf_blenlib")
 BLENDER_TEST(BLI_path_util "${BLI_path_util_extra_libs}")
 BLENDER_TEST(BLI_polyfill_2d "bf_blenlib")
-BLENDER_TEST(BLI_refcount "bf_blenlib")
+BLENDER_TEST(BLI_shared "bf_blenlib")
 BLENDER_TEST(BLI_small_vector "bf_blenlib")
 BLENDER_TEST(BLI_small_set_vector "bf_blenlib")
 BLENDER_TEST(BLI_small_map "bf_blenlib")



More information about the Bf-blender-cvs mailing list