aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/base/SelfResolvable.h125
-rw-r--r--test/base/CMakeLists.txt1
-rw-r--r--test/base/SelfResolvableTest.cpp82
3 files changed, 122 insertions, 86 deletions
diff --git a/include/cru/base/SelfResolvable.h b/include/cru/base/SelfResolvable.h
index 84fa54f6..308de486 100644
--- a/include/cru/base/SelfResolvable.h
+++ b/include/cru/base/SelfResolvable.h
@@ -1,7 +1,7 @@
#pragma once
+#include "Base.h"
#include <cassert>
-#include <functional>
#include <memory>
#include <type_traits>
@@ -16,70 +16,51 @@ class ObjectResolver {
friend class ObjectResolver;
private:
- template <typename U>
- using Accessor_ = std::function<U*(const std::shared_ptr<void*>&)>;
- using ThisAccessor_ = Accessor_<T>;
+ explicit ObjectResolver(std::shared_ptr<bool> destroyed, T* ptr)
+ : destroyed_(std::move(destroyed)), ptr_(ptr) {}
- explicit ObjectResolver(T* o)
- : shared_object_ptr_(new void*(o)),
- accessor_([](const std::shared_ptr<void*>& ptr) {
- return static_cast<T*>(*ptr);
- }) {}
- explicit ObjectResolver(std::shared_ptr<void*> ptr, ThisAccessor_ accessor)
- : shared_object_ptr_(std::move(ptr)), accessor_(std::move(accessor)) {}
+ public:
+ CRU_DEFAULT_COPY(ObjectResolver)
+ CRU_DEFAULT_MOVE(ObjectResolver)
template <typename U>
- static ThisAccessor_ CreateAccessor(Accessor_<U> parent_accessor) {
- return [parent_accessor =
- std::move(parent_accessor)](const std::shared_ptr<void*>& ptr) {
- return static_cast<T*>(parent_accessor(ptr));
- };
- }
-
- public:
- template <typename U,
- typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
ObjectResolver(const ObjectResolver<U>& other)
- : shared_object_ptr_(other.shared_object_ptr_),
- accessor_(CreateAccessor(other.accessor_)) {}
+ requires(std::is_convertible_v<U*, T*>)
+ : destroyed_(other.destroyed_), ptr_(static_cast<T*>(other.ptr_)) {}
- template <typename U,
- typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
+ template <typename U>
ObjectResolver(ObjectResolver<U>&& other)
- : shared_object_ptr_(std::move(other.shared_object_ptr_)),
- accessor_(CreateAccessor(std::move(other.accessor_))) {}
-
- ObjectResolver(const ObjectResolver&) = default;
- ObjectResolver& operator=(const ObjectResolver&) = default;
- ObjectResolver(ObjectResolver&&) = default;
- ObjectResolver& operator=(ObjectResolver&&) = default;
- ~ObjectResolver() = default;
-
- template <typename U,
- typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
- ObjectResolver& operator=(const ObjectResolver<U>& other) {
+ requires(std::is_convertible_v<U*, T*>)
+ : destroyed_(std::move(other.destroyed_)),
+ ptr_(static_cast<T*>(other.ptr_)) {}
+
+ template <typename U>
+ ObjectResolver& operator=(const ObjectResolver<U>& other)
+ requires(std::is_convertible_v<U*, T*>)
+ {
if (this != &other) {
- this->shared_object_ptr_ = other.shared_object_ptr_;
- this->accessor_ = CreateAccessor(other.accessor_);
+ this->destroyed_ = other.destroyed_;
+ this->ptr_ = static_cast<T*>(other.ptr_);
}
return *this;
}
- template <typename U,
- typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
- ObjectResolver& operator=(ObjectResolver<U>&& other) {
+ template <typename U>
+ ObjectResolver& operator=(ObjectResolver<U>&& other)
+ requires(std::is_convertible_v<U*, T*>)
+ {
if (this != &other) {
- this->shared_object_ptr_ = std::move(other.shared_object_ptr_);
- this->accessor_ = CreateAccessor(std::move(other.shared_object_ptr_));
+ this->destroyed_ = std::move(other.destroyed_);
+ this->ptr_ = static_cast<T*>(other.ptr_);
}
return *this;
}
- bool IsValid() const { return this->shared_object_ptr_ != nullptr; }
+ bool IsValid() const { return this->destroyed_ != nullptr; }
T* Resolve() const {
assert(IsValid());
- return this->accessor_(this->shared_object_ptr_);
+ return *destroyed_ ? nullptr : ptr_;
}
/**
@@ -87,21 +68,16 @@ class ObjectResolver {
*/
T* operator()() const { return Resolve(); }
- template <typename U,
- typename = std::enable_if_t<std::is_convertible_v<T*, U*>>>
- operator ObjectResolver<U>() const {
+ template <typename U>
+ operator ObjectResolver<U>() const
+ requires(std::is_convertible_v<T*, U*>)
+ {
return ObjectResolver<U>(*this);
}
private:
- void SetResolvedObject(T* o) {
- assert(IsValid());
- *this->shared_object_ptr_ = o;
- }
-
- private:
- std::shared_ptr<void*> shared_object_ptr_;
- std::function<T*(const std::shared_ptr<void*>&)> accessor_;
+ std::shared_ptr<bool> destroyed_;
+ T* ptr_;
};
/**
@@ -116,38 +92,15 @@ class ObjectResolver {
template <typename T>
class SelfResolvable {
public:
- SelfResolvable() : resolver_(CastToSubClass()) {}
- SelfResolvable(const SelfResolvable&) = delete;
- SelfResolvable& operator=(const SelfResolvable&) = delete;
-
- // Resolvers to old object will resolve to new object.
- SelfResolvable(SelfResolvable&& other)
- : resolver_(std::move(other.resolver_)) {
- this->resolver_.SetResolvedObject(CastToSubClass());
- }
-
- // Old resolvers for this object will resolve to nullptr.
- // Other's resolvers will now resolve to this.
- SelfResolvable& operator=(SelfResolvable&& other) {
- if (this != &other) {
- this->resolver_ = std::move(other.resolver_);
- this->resolver_.SetResolvedObject(CastToSubClass());
- }
- return *this;
- }
+ SelfResolvable() : destroyed_(new bool(false)) {}
+ CRU_DELETE_COPY(SelfResolvable)
+ virtual ~SelfResolvable() { *destroyed_ = true; }
- virtual ~SelfResolvable() {
- if (this->resolver_.IsValid()) {
- this->resolver_.SetResolvedObject(nullptr);
- }
+ ObjectResolver<T> CreateResolver() {
+ return ObjectResolver<T>(destroyed_, static_cast<T*>(this));
}
- ObjectResolver<T> CreateResolver() { return resolver_; }
-
- private:
- T* CastToSubClass() { return static_cast<T*>(this); }
-
private:
- ObjectResolver<T> resolver_;
+ std::shared_ptr<bool> destroyed_;
};
} // namespace cru
diff --git a/test/base/CMakeLists.txt b/test/base/CMakeLists.txt
index 6bae85d7..52f61a8c 100644
--- a/test/base/CMakeLists.txt
+++ b/test/base/CMakeLists.txt
@@ -1,6 +1,7 @@
add_executable(CruBaseTest
EventTest.cpp
PropertyTreeTest.cpp
+ SelfResolvableTest.cpp
StringUtilTest.cpp
SubProcessTest.cpp
TimerTest.cpp
diff --git a/test/base/SelfResolvableTest.cpp b/test/base/SelfResolvableTest.cpp
new file mode 100644
index 00000000..17d9309d
--- /dev/null
+++ b/test/base/SelfResolvableTest.cpp
@@ -0,0 +1,82 @@
+#include "cru/base/SelfResolvable.h"
+
+#include <catch2/catch_test_macros.hpp>
+
+#include <memory>
+
+namespace {
+class SelfResolvableTestClassBase {
+ public:
+ virtual ~SelfResolvableTestClassBase() = default;
+};
+
+class SelfResolvableTestClass
+ : public SelfResolvableTestClassBase,
+ public cru::SelfResolvable<SelfResolvableTestClass> {
+ public:
+ SelfResolvableTestClass() : ptr_(new int(123)) {}
+ ~SelfResolvableTestClass() override = default;
+
+ private:
+ std::shared_ptr<int> ptr_;
+};
+} // namespace
+
+TEST_CASE("SelfResolvable resolver should work.", "[self-resolvable]") {
+ SelfResolvableTestClass test_object;
+
+ auto resolver = test_object.CreateResolver();
+ REQUIRE(resolver.Resolve() == &test_object);
+
+ auto resolver_copy = resolver;
+ REQUIRE(resolver.Resolve() == &test_object);
+ REQUIRE(resolver_copy.Resolve() == &test_object);
+
+ auto resolver_move = std::move(resolver_copy);
+ REQUIRE(resolver.Resolve() == &test_object);
+ REQUIRE(resolver_copy.IsValid() == false);
+ REQUIRE(resolver_move.Resolve() == &test_object);
+}
+
+TEST_CASE("SelfResolvable object destructed should work.",
+ "[self-resolvable]") {
+ SelfResolvableTestClass* test_object = new SelfResolvableTestClass();
+
+ auto resolver = test_object->CreateResolver();
+ auto resolver_copy = resolver;
+
+ delete test_object;
+
+ REQUIRE(resolver.Resolve() == nullptr);
+ REQUIRE(resolver_copy.Resolve() == nullptr);
+
+ auto resolver_copy2 = resolver_copy;
+ REQUIRE(resolver_copy2.Resolve() == nullptr);
+
+ auto resolver_move = std::move(resolver_copy);
+ REQUIRE(resolver_copy.IsValid() == false);
+ REQUIRE(resolver_move.Resolve() == nullptr);
+}
+
+TEST_CASE("SelfResolvable should work for casted type.", "[self-resolvable]") {
+ auto test_object = new SelfResolvableTestClass();
+
+ cru::ObjectResolver<SelfResolvableTestClassBase> base_resolver =
+ test_object->CreateResolver();
+ auto resolver = test_object->CreateResolver();
+
+ REQUIRE(base_resolver.Resolve() == test_object);
+ REQUIRE(resolver.Resolve() == test_object);
+
+ auto base_resolver2 = base_resolver;
+ REQUIRE(base_resolver2.Resolve() == test_object);
+
+ auto base_resolver3 = std::move(base_resolver2);
+ REQUIRE(base_resolver3.Resolve() == test_object);
+
+ delete test_object;
+
+ REQUIRE(base_resolver.Resolve() == nullptr);
+ REQUIRE(base_resolver3.Resolve() == nullptr);
+ REQUIRE(resolver.Resolve() == nullptr);
+}