Issue #15 Classes for sharing a value list,

also built on top of the lower level API

Compared to the scalar classes they support features specific to lists.
This means they don't need to resend the whole list each time a value is appended.
This commit is contained in:
Mat Sutcliffe
2019-02-26 01:51:58 +00:00
parent 805cec7caf
commit 46caf4640b
6 changed files with 364 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
/* 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/listjournal.h"
#include "blackmisc/sharedstate/datalink.h"
namespace BlackMisc
{
namespace SharedState
{
void CGenericListJournal::initialize(IDataLink *dataLink)
{
dataLink->publish(m_mutator.data());
dataLink->subscribe(m_observer.data());
m_observer->setEventSubscription(CVariant::from(CAnyMatch()));
}
CVariant CGenericListJournal::handleRequest(const CVariant &filter)
{
CVariantList copy = m_value;
if (filter.isValid())
{
copy.removeIf([&filter](const CVariant &v) { return ! filter.matches(v); });
}
return CVariant::from(copy);
}
void CGenericListJournal::handleEvent(const CVariant &param)
{
m_value.push_back(param);
}
}
}

View File

@@ -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_LISTJOURNAL_H
#define BLACKMISC_SHAREDSTATE_LISTJOURNAL_H
#include "blackmisc/sharedstate/activemutator.h"
#include "blackmisc/sharedstate/passiveobserver.h"
#include "blackmisc/variantlist.h"
#include "blackmisc/blackmiscexport.h"
#include <QObject>
#include <QMutex>
namespace BlackMisc
{
namespace SharedState
{
class IDataLink;
/*!
* Non-template base class for CListJournal.
*/
class BLACKMISC_EXPORT CGenericListJournal : public QObject
{
Q_OBJECT
public:
//! Publish using the given transport mechanism.
void initialize(IDataLink *);
protected:
//! Constructor.
CGenericListJournal(QObject *parent) : QObject(parent) {}
private:
CVariant handleRequest(const CVariant &filter);
void handleEvent(const CVariant &param);
QSharedPointer<CActiveMutator> m_mutator = CActiveMutator::create(this, &CGenericListJournal::handleRequest);
QSharedPointer<CPassiveObserver> m_observer = CPassiveObserver::create(this, &CGenericListJournal::handleEvent);
CVariantList m_value;
};
/*!
* Base class for an object that shares state with a corresponding CListObserver subclass object.
* \tparam T Datatype encapsulating the state to be shared.
*/
template <typename T>
class CListJournal : public CGenericListJournal
{
protected:
//! Constructor.
CListJournal(QObject *parent) : CGenericListJournal(parent) {}
};
}
}
#endif

View File

@@ -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/listmutator.h"
#include "blackmisc/sharedstate/datalink.h"
namespace BlackMisc
{
namespace SharedState
{
void CGenericListMutator::initialize(IDataLink *dataLink)
{
dataLink->publish(m_mutator.data());
}
void CGenericListMutator::addElement(const CVariant &value)
{
m_mutator->postEvent(value);
}
}
}

View File

@@ -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_LISTMUTATOR_H
#define BLACKMISC_SHAREDSTATE_LISTMUTATOR_H
#include "blackmisc/sharedstate/passivemutator.h"
#include "blackmisc/variantlist.h"
#include "blackmisc/blackmiscexport.h"
#include <QObject>
#include <QMutex>
namespace BlackMisc
{
namespace SharedState
{
class IDataLink;
/*!
* Non-template base class for CListMutator.
*/
class BLACKMISC_EXPORT CGenericListMutator : public QObject
{
Q_OBJECT
public:
//! Publish using the given transport mechanism.
void initialize(IDataLink *);
protected:
//! Constructor.
CGenericListMutator(QObject *parent) : QObject(parent) {}
//! Add list element as variant.
void addElement(const CVariant &value);
private:
QSharedPointer<CPassiveMutator> m_mutator = CPassiveMutator::create(this);
};
/*!
* Base class for an object that shares state with a corresponding CListObserver subclass object.
* \tparam T Datatype encapsulating the state to be shared.
*/
template <typename T>
class CListMutator : public CGenericListMutator
{
protected:
//! Constructor.
CListMutator(QObject *parent) : CGenericListMutator(parent) {}
public:
//! Add list element.
void addElement(const typename T::value_type &value) { CGenericListMutator::addElement(CVariant::from(value)); }
};
}
}
#endif

View File

@@ -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
#include "blackmisc/sharedstate/listobserver.h"
#include "blackmisc/sharedstate/datalink.h"
#include "blackmisc/variantlist.h"
namespace BlackMisc
{
namespace SharedState
{
void CGenericListObserver::initialize(IDataLink *dataLink)
{
dataLink->subscribe(m_observer.data());
m_watcher = dataLink->watcher();
connect(m_watcher, &CDataLinkConnectionWatcher::connected, this, &CGenericListObserver::reconstruct);
}
void CGenericListObserver::setFilter(const CVariant &filter)
{
m_observer->setEventSubscription(filter);
if (m_watcher && m_watcher->isConnected()) { reconstruct(); }
}
void CGenericListObserver::reconstruct()
{
m_observer->requestAsync(m_observer->eventSubscription(), [this](const CVariant &list)
{
QMutexLocker lock(&m_listMutex);
m_list = list.to<CVariantList>();
lock.unlock();
onGenericElementsReplaced(allValues());
});
}
CVariantList CGenericListObserver::allValues() const
{
QMutexLocker lock(&m_listMutex);
return m_list;
}
int CGenericListObserver::cleanValues()
{
QMutexLocker lock(&m_listMutex);
return m_list.removeIf([filter = m_observer->eventSubscription()](const CVariant &value)
{
return !value.matches(filter);
});
}
void CGenericListObserver::handleEvent(const CVariant &param)
{
QMutexLocker lock(&m_listMutex);
m_list.push_back(param);
lock.unlock();
onGenericElementAdded(param);
}
}
}

View File

@@ -0,0 +1,99 @@
/* 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_LISTOBSERVER_H
#define BLACKMISC_SHAREDSTATE_LISTOBSERVER_H
#include "blackmisc/sharedstate/activeobserver.h"
#include "blackmisc/sharedstate/datalink.h"
#include "blackmisc/variantlist.h"
#include "blackmisc/blackmiscexport.h"
#include <QObject>
#include <QMutex>
namespace BlackMisc
{
namespace SharedState
{
/*!
* Non-template base class for CListObserver.
*/
class BLACKMISC_EXPORT CGenericListObserver : public QObject
{
Q_OBJECT
protected:
//! Constructor.
CGenericListObserver(QObject *parent) : QObject(parent) {}
//! Subscribe using the given transport mechanism.
virtual void initialize(IDataLink *);
//! Set list filter as variant.
void setFilter(const CVariant &filter);
//! Get filtered list value as variant list.
CVariantList allValues() const;
//! Remove any old values that no longer match the filter.
int cleanValues();
private:
void reconstruct();
void handleEvent(const CVariant &param);
virtual void onGenericElementAdded(const CVariant &value) = 0;
virtual void onGenericElementsReplaced(const CVariantList &values) = 0;
QSharedPointer<CActiveObserver> m_observer = CActiveObserver::create(this, &CGenericListObserver::handleEvent);
CDataLinkConnectionWatcher *m_watcher = nullptr;
mutable QMutex m_listMutex;
CVariantList m_list;
};
/*!
* Base class for an object that shares state with a corresponding CListMutator subclass object.
* \tparam T Datatype encapsulating the state to be shared.
* \tparam U Datatype describing a filter to apply to the list.
*/
template <typename T, typename U = CAnyMatch>
class CListObserver : public CGenericListObserver
{
protected:
//! Constructor.
CListObserver(QObject *parent) : CGenericListObserver(parent) {}
public:
//! Subscribe using the given transport mechanism.
virtual void initialize(IDataLink *dataLink) override
{
CGenericListObserver::initialize(dataLink);
if (std::is_same<U, CAnyMatch>::value) { setFilter({}); }
}
//! Set filter to choose list elements.
void setFilter(const U &filter) { CGenericListObserver::setFilter(CVariant::from(filter)); }
//! Get list value containing all elements matching the filter.
T allValues() const { return CVariant::from(CGenericListObserver::allValues()).template to<T>(); }
//! Called when an element matching the filter is added to the list.
virtual void onElementAdded(const typename T::value_type &value) = 0;
//! Called when the whole list is updated wholesale.
virtual void onElementsReplaced(const T &values) = 0;
private:
virtual void onGenericElementAdded(const CVariant &value) override final { onElementAdded(value.to<typename T::value_type>()); }
virtual void onGenericElementsReplaced(const CVariantList &values) override final { onElementsReplaced(values.to<T>()); }
};
}
}
#endif