Skip to content

Commit

Permalink
ObserverAutoPtr: use observer factory of the specified type
Browse files Browse the repository at this point in the history
  • Loading branch information
congard committed Sep 2, 2024
1 parent 51c101f commit 36c9f32
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 18 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ set(TULZ_OBSERVER_SOURCES
include/tulz/observer/ObserverAutoPtr.h
include/tulz/observer/EternalObserver.h
include/tulz/observer/detail/ObserverFactory.h
include/tulz/observer/EternalObserverFactory.h)
include/tulz/observer/EternalObserverFactory.h
include/tulz/observer/EternalObserverAutoPtr.h)

set(TULZ_THREADING_SOURCES
include/tulz/threading/Runnable.h
Expand Down
13 changes: 13 additions & 0 deletions include/tulz/observer/EternalObserverAutoPtr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef TULZ_ETERNALOBSERVERAUTOPTR_H
#define TULZ_ETERNALOBSERVERAUTOPTR_H

#include <tulz/observer/ObserverAutoPtr.h>
#include <tulz/observer/EternalObserver.h>
#include <tulz/observer/EternalObserverFactory.h>

namespace tulz {
template<typename ...Args>
using EternalObserverAutoPtr = ObserverAutoPtr<EternalObserver, Args...>;
}

#endif //TULZ_ETERNALOBSERVERAUTOPTR_H
29 changes: 16 additions & 13 deletions include/tulz/observer/ObserverAutoPtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#define TULZ_OBSERVERAUTOPTR_H

#include <tulz/observer/Observer.h>
#include <tulz/observer/EternalObserver.h>

#include <concepts>

Expand All @@ -13,43 +12,47 @@ namespace tulz {
* The `ObserverAutoPtr` class accepts three different types of objects:
*
* 1. Invocable objects: When an invocable object (e.g., lambda, function, functor) is provided,
* a new default observer will be created.
* a new default observer will be created using the factory of provided ObserverType.
* 2. Unique pointers of derived observers: If a unique pointer to a derived observer type is passed,
* the ownership will be transferred to the `ObserverAutoPtr`.
* 3. Raw pointers of derived observers: When a raw pointer to a derived observer object is given,
* the ownership will be transferred to the `ObserverAutoPtr`.
*
* @tparam ObserverType The observer which factory will be used in case 1.
* @tparam Args The template parameter pack representing the types of arguments for the observer.
*/
template<typename ...Args>
template<template<typename...> class ObserverType, typename ...Args>
class ObserverAutoPtr {
public:
using BaseObserver = Observer<Args...>;
using DefaultObserver = EternalObserver<Args...>;
using Ptr = std::unique_ptr<BaseObserver>;
using BaseObserver_t = Observer<Args...>;
using Observer_t = ObserverType<Args...>;
using Ptr_t = std::unique_ptr<BaseObserver_t>;

public:
template<typename T>
ObserverAutoPtr(T &&val) requires std::invocable<T, Args...>
: m_ptr(std::make_unique<DefaultObserver>(std::forward<T>(val))) {}
requires std::invocable<T, Args...> ||
std::invocable<T, typename Observer_t::SelfView, Args...>
ObserverAutoPtr(T &&val)
: m_ptr(typename Observer_t::Factory{}(std::forward<T>(val))) {}

template<typename T>
ObserverAutoPtr(std::unique_ptr<T> ptr) requires std::derived_from<T, BaseObserver>
requires std::derived_from<T, BaseObserver_t>
ObserverAutoPtr(std::unique_ptr<T> ptr)
: m_ptr(std::move(ptr)) {}

ObserverAutoPtr(BaseObserver *ptr)
ObserverAutoPtr(BaseObserver_t *ptr)
: m_ptr(ptr) {}

Ptr operator*() {
Ptr_t operator*() {
return std::move(m_ptr);
}

Ptr pointer() {
Ptr_t pointer() {
return std::move(m_ptr);
}

private:
Ptr m_ptr;
Ptr_t m_ptr;
};
}

Expand Down
4 changes: 2 additions & 2 deletions include/tulz/observer/Subject.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <stdexcept>

#include "Observer.h"
#include "ObserverAutoPtr.h"
#include "EternalObserverAutoPtr.h"
#include "Subscription.h"

namespace tulz {
Expand All @@ -16,7 +16,7 @@ class Subject {
using Subscription_t = Subscription<Args...>;
using Observer_t = Observer<Args...>;
using ObserverPtr_t = ObserverPtr<Args...>;
using ObserverAutoPtr_t = ObserverAutoPtr<Args...>;
using ObserverAutoPtr_t = EternalObserverAutoPtr<Args...>;

public:
Subject() = default;
Expand Down
7 changes: 5 additions & 2 deletions include/tulz/observer/routing/SubjectRouter.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define TULZ_SUBJECTROUTER_H

#include <tulz/observer/Subject.h>
#include <tulz/observer/ObserverAutoPtr.h>
#include <tulz/observer/EternalObserverAutoPtr.h>
#include <tulz/observer/routing/RoutingKey.h>

#include <memory>
Expand All @@ -18,6 +18,9 @@ class TULZ_API SubjectRouter {

using DefaultSubject_t = Subject_t<>;

template<typename ...Args>
using ObserverAutoPtr_t = EternalObserverAutoPtr<Args...>;

public:
SubjectRouter();

Expand Down Expand Up @@ -50,7 +53,7 @@ class TULZ_API SubjectRouter {
*/
template<typename ...Args, typename O>
Subscription<Args...> subscribe(const RoutingKey &key, O &&observer) {
return m_rootNode.subscribe(key, *ObserverAutoPtr<Args...>(std::forward<O>(observer)));
return m_rootNode.subscribe(key, *ObserverAutoPtr_t<Args...>(std::forward<O>(observer)));
}

/**
Expand Down
28 changes: 28 additions & 0 deletions tests/tulz/observer/EternalObserverTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <tulz/observer/Subject.h>
#include <tulz/observer/EternalObserver.h>
#include <tulz/observer/EternalObserverFactory.h>
#include <tulz/observer/EternalObserverAutoPtr.h>

using namespace tulz;

Expand Down Expand Up @@ -51,3 +52,30 @@ TEST(EternalObserverTest, ProducedByFactory) {

ASSERT_EQ(value, 1);
}

TEST(EternalObserverTest, ProduceByAutoPtrThenInvalidate) {
Subject subject;
int counter {0};

auto produce = [](EternalObserverAutoPtr<> observer) {
return *observer;
};

using Observer = EternalObserver<>;
auto observer = produce([&counter](Observer::SelfView self) {
++counter;
self->invalidate();
});

auto subscription = subject.subscribe(std::move(observer));

ASSERT_TRUE(subscription.getObserver()->isValid());

subject.notify();

ASSERT_FALSE(subscription.isValid());

subject.notify();

ASSERT_EQ(counter, 1);
}

0 comments on commit 36c9f32

Please sign in to comment.