From 805cec7caf243ef756dd576a1e85f79eee28bdb4 Mon Sep 17 00:00:00 2001 From: Mat Sutcliffe Date: Tue, 26 Feb 2019 01:51:54 +0000 Subject: [PATCH] Issue #15 Classes for sharing a single value object, built on top of the lower level API --- src/blackmisc/sharedstate/scalarjournal.cpp | 37 ++++++++++ src/blackmisc/sharedstate/scalarjournal.h | 65 ++++++++++++++++ src/blackmisc/sharedstate/scalarmutator.cpp | 28 +++++++ src/blackmisc/sharedstate/scalarmutator.h | 66 +++++++++++++++++ src/blackmisc/sharedstate/scalarobserver.cpp | 46 ++++++++++++ src/blackmisc/sharedstate/scalarobserver.h | 78 ++++++++++++++++++++ 6 files changed, 320 insertions(+) create mode 100644 src/blackmisc/sharedstate/scalarjournal.cpp create mode 100644 src/blackmisc/sharedstate/scalarjournal.h create mode 100644 src/blackmisc/sharedstate/scalarmutator.cpp create mode 100644 src/blackmisc/sharedstate/scalarmutator.h create mode 100644 src/blackmisc/sharedstate/scalarobserver.cpp create mode 100644 src/blackmisc/sharedstate/scalarobserver.h diff --git a/src/blackmisc/sharedstate/scalarjournal.cpp b/src/blackmisc/sharedstate/scalarjournal.cpp new file mode 100644 index 000000000..281a81801 --- /dev/null +++ b/src/blackmisc/sharedstate/scalarjournal.cpp @@ -0,0 +1,37 @@ +/* Copyright (C) 2020 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, + * or distributed except according to the terms contained in the LICENSE file. + */ + +//! \file + +#include "blackmisc/sharedstate/scalarjournal.h" +#include "blackmisc/sharedstate/datalink.h" + +namespace BlackMisc +{ + namespace SharedState + { + void CGenericScalarJournal::initialize(IDataLink *dataLink) + { + dataLink->publish(m_mutator.data()); + dataLink->subscribe(m_observer.data()); + m_observer->setEventSubscription(CVariant::from(CAnyMatch())); + m_mutator->postEvent(m_value); + } + + CVariant CGenericScalarJournal::handleRequest(const CVariant ¶m) + { + Q_UNUSED(param) + return m_value; + } + + void CGenericScalarJournal::handleEvent(const CVariant ¶m) + { + m_value = param; + } + } +} diff --git a/src/blackmisc/sharedstate/scalarjournal.h b/src/blackmisc/sharedstate/scalarjournal.h new file mode 100644 index 000000000..0789fcbea --- /dev/null +++ b/src/blackmisc/sharedstate/scalarjournal.h @@ -0,0 +1,65 @@ +/* Copyright (C) 2020 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, + * or distributed except according to the terms contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_SHAREDSTATE_SCALARJOURNAL_H +#define BLACKMISC_SHAREDSTATE_SCALARJOURNAL_H + +#include "blackmisc/sharedstate/activemutator.h" +#include "blackmisc/sharedstate/passiveobserver.h" +#include "blackmisc/variant.h" +#include "blackmisc/blackmiscexport.h" +#include +#include + +namespace BlackMisc +{ + namespace SharedState + { + class IDataLink; + + /*! + * Non-template base class for CScalarJournal. + */ + class BLACKMISC_EXPORT CGenericScalarJournal : public QObject + { + Q_OBJECT + + public: + //! Publish using the given transport mechanism. + void initialize(IDataLink *); + + protected: + //! Constructor. + CGenericScalarJournal(QObject *parent) : QObject(parent) {} + + private: + CVariant handleRequest(const CVariant ¶m); + void handleEvent(const CVariant ¶m); + + QSharedPointer m_mutator = CActiveMutator::create(this, &CGenericScalarJournal::handleRequest); + QSharedPointer m_observer = CPassiveObserver::create(this, &CGenericScalarJournal::handleEvent); + CVariant m_value; + }; + + /*! + * Base class for an object that shares state with a corresponding CScalarObserver subclass object. + * \tparam T Datatype encapsulating the state to be shared. + */ + template + class CScalarJournal : public CGenericScalarJournal + { + protected: + //! Constructor. + CScalarJournal(QObject *parent) : CGenericScalarJournal(parent) {} + }; + } +} + +#endif diff --git a/src/blackmisc/sharedstate/scalarmutator.cpp b/src/blackmisc/sharedstate/scalarmutator.cpp new file mode 100644 index 000000000..ac2f80181 --- /dev/null +++ b/src/blackmisc/sharedstate/scalarmutator.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2017 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, + * or distributed except according to the terms contained in the LICENSE file. + */ + +//! \file + +#include "blackmisc/sharedstate/scalarmutator.h" +#include "blackmisc/sharedstate/datalink.h" + +namespace BlackMisc +{ + namespace SharedState + { + void CGenericScalarMutator::initialize(IDataLink *dataLink) + { + dataLink->publish(m_mutator.data()); + } + + void CGenericScalarMutator::setValue(const CVariant &value) + { + m_mutator->postEvent(value); + } + } +} diff --git a/src/blackmisc/sharedstate/scalarmutator.h b/src/blackmisc/sharedstate/scalarmutator.h new file mode 100644 index 000000000..af9b9f57c --- /dev/null +++ b/src/blackmisc/sharedstate/scalarmutator.h @@ -0,0 +1,66 @@ +/* Copyright (C) 2017 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, + * or distributed except according to the terms contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_SHAREDSTATE_SCALARMUTATOR_H +#define BLACKMISC_SHAREDSTATE_SCALARMUTATOR_H + +#include "blackmisc/sharedstate/passivemutator.h" +#include "blackmisc/variant.h" +#include "blackmisc/blackmiscexport.h" +#include +#include + +namespace BlackMisc +{ + namespace SharedState + { + class IDataLink; + + /*! + * Non-template base class for CScalarMutator. + */ + class BLACKMISC_EXPORT CGenericScalarMutator : public QObject + { + Q_OBJECT + + public: + //! Publish using the given transport mechanism. + void initialize(IDataLink *); + + protected: + //! Constructor. + CGenericScalarMutator(QObject *parent) : QObject(parent) {} + + //! Set scalar value as variant. + void setValue(const CVariant &value); + + private: + QSharedPointer m_mutator = CPassiveMutator::create(this); + }; + + /*! + * Base class for an object that shares state with a corresponding CScalarObserver subclass object. + * \tparam T Datatype encapsulating the state to be shared. + */ + template + class CScalarMutator : public CGenericScalarMutator + { + protected: + //! Constructor. + CScalarMutator(QObject *parent) : CGenericScalarMutator(parent) {} + + public: + //! Set scalar value. + void setValue(const T &value) { CGenericScalarMutator::setValue(CVariant::from(value)); } + }; + } +} + +#endif diff --git a/src/blackmisc/sharedstate/scalarobserver.cpp b/src/blackmisc/sharedstate/scalarobserver.cpp new file mode 100644 index 000000000..1ebcadb93 --- /dev/null +++ b/src/blackmisc/sharedstate/scalarobserver.cpp @@ -0,0 +1,46 @@ +/* Copyright (C) 2017 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, + * or distributed except according to the terms contained in the LICENSE file. + */ + +//! \file + +#include "blackmisc/sharedstate/scalarobserver.h" +#include "blackmisc/sharedstate/datalink.h" + +namespace BlackMisc +{ + namespace SharedState + { + void CGenericScalarObserver::initialize(IDataLink *dataLink) + { + dataLink->subscribe(m_observer.data()); + m_observer->setEventSubscription(CVariant::from(CAnyMatch())); + connect(dataLink->watcher(), &CDataLinkConnectionWatcher::connected, this, &CGenericScalarObserver::reconstruct); + if (dataLink->watcher()->isConnected()) { reconstruct(); } + } + + void CGenericScalarObserver::reconstruct() + { + m_observer->requestAsync({}, [this](const CVariant &value) { handleEvent(value); }); + } + + CVariant CGenericScalarObserver::value() const + { + QMutexLocker lock(&m_valueMutex); + return m_value; + } + + void CGenericScalarObserver::handleEvent(const CVariant ¶m) + { + QMutexLocker lock(&m_valueMutex); + if (m_value == param) { return; } + m_value = param; + lock.unlock(); + onGenericValueChanged(param); + } + } +} diff --git a/src/blackmisc/sharedstate/scalarobserver.h b/src/blackmisc/sharedstate/scalarobserver.h new file mode 100644 index 000000000..42a92f76a --- /dev/null +++ b/src/blackmisc/sharedstate/scalarobserver.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2017 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, + * or distributed except according to the terms contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_SHAREDSTATE_SCALAROBSERVER_H +#define BLACKMISC_SHAREDSTATE_SCALAROBSERVER_H + +#include "blackmisc/sharedstate/activeobserver.h" +#include "blackmisc/variant.h" +#include "blackmisc/blackmiscexport.h" +#include +#include + +namespace BlackMisc +{ + namespace SharedState + { + class IDataLink; + + /*! + * Non-template base class for CScalarObserver. + */ + class BLACKMISC_EXPORT CGenericScalarObserver : public QObject + { + Q_OBJECT + + public: + //! Subscribe using the given transport mechanism. + void initialize(IDataLink *); + + protected: + //! Constructor. + CGenericScalarObserver(QObject *parent) : QObject(parent) {} + + //! Get scalar value as variant. + CVariant value() const; + + private: + void reconstruct(); + void handleEvent(const CVariant ¶m); + virtual void onGenericValueChanged(const CVariant &value) = 0; + + QSharedPointer m_observer = CActiveObserver::create(this, &CGenericScalarObserver::handleEvent); + mutable QMutex m_valueMutex; + CVariant m_value; + }; + + /*! + * Base class for an object that shares state with a corresponding CScalarMutator subclass object. + * \tparam T Datatype encapsulating the state to be shared. + */ + template + class CScalarObserver : public CGenericScalarObserver + { + protected: + //! Constructor. + CScalarObserver(QObject *parent) : CGenericScalarObserver(parent) {} + + public: + //! Get scalar value. + T value() const { return CGenericScalarObserver::value().template to(); } + + private: + //! Called when the scalar value changes. + virtual void onValueChanged(const T &value) = 0; + + virtual void onGenericValueChanged(const CVariant &value) override final { onValueChanged(value.to()); } + }; + } +} + +#endif