[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