Refactoring the filter for supporting the factory

This commit is contained in:
samcake 2015-10-14 09:22:30 -07:00
parent fb4ff240ef
commit cb62527bf9
6 changed files with 218 additions and 52 deletions

View file

@ -11,11 +11,66 @@
#include <QtCore/QObject>
#include <QtScript/QScriptValue>
namespace controller {
#include <QJSonObject>
#include <QJSonArray>
Filter::Pointer Filter::parse(const QJsonObject& json) {
// FIXME parse the json object and determine the instance type to create
return Filter::Pointer();
#include "SharedUtil.h"
using namespace controller;
const QString JSON_FILTER_TYPE = QStringLiteral("type");
const QString JSON_FILTER_PARAMS = QStringLiteral("params");
Filter::Factory Filter::_factory;
Filter::Pointer Filter::parse(const QJsonObject& json) {
// The filter is an object, now let s check for type and potential arguments
Filter::Pointer filter;
auto filterType = json[JSON_FILTER_TYPE];
if (filterType.isString()) {
filter.reset(Filter::getFactory().create(filterType.toString().toStdString()));
if (filter) {
// Filter is defined, need to read the parameters and validate
auto parameters = json[JSON_FILTER_PARAMS];
if (parameters.isArray()) {
if (filter->parseParameters(parameters.toArray())) {
}
}
return filter;
}
}
return Filter::Pointer();
}
Filter::Factory::ClassEntry<ScaleFilter> ScaleFilter::_factoryEntry;
bool ScaleFilter::parseParameters(const QJsonArray& parameters) {
if (parameters.size() > 1) {
_scale = parameters[0].toDouble();
}
return true;
}
Filter::Factory::ClassEntry<PulseFilter> PulseFilter::_factoryEntry;
float PulseFilter::apply(float value) const {
float result = 0.0;
if (0.0 != value) {
float now = secTimestampNow();
float delta = now - _lastEmitTime;
if (delta >= _interval) {
_lastEmitTime = now;
result = value;
}
}
return result;
}
bool PulseFilter::parseParameters(const QJsonArray& parameters) {
return false;
}

View file

@ -14,13 +14,49 @@
#include <memory>
#include <numeric>
#include <functional>
#include <map>
#include <QtCore/QEasingCurve>
class QJsonObject;
class QJsonArray;
namespace controller {
/*
template <class T> class Factory {
public:
template <class T> class Entry {
public:
virtual T* create() = 0;
};
template <class T, class S> class DefaultEntry{
public:
T* create() { return new S(); }
};
using EntryMap = std::map<std::string, std::unique_ptr<Entry<T>>>;
void registerEntry(const std::string& name, std::unique_ptr<Entry<T>>& entry) {
if (entry) {
_entries[name] = entry;
}
}
T* create(const std::string& name) const {
auto& entryIt = _entries.find(name);
if (entryIt != _entries.end()) {
return (*entryIt).second->create();
}
return nullptr;
}
protected:
EntryMap _entries;
};
*/
// Encapsulates part of a filter chain
class Filter {
public:
@ -30,18 +66,71 @@ namespace controller {
using List = std::list<Pointer>;
using Lambda = std::function<float(float)>;
static Filter::Pointer parse(const QJsonObject& json);
};
// Factory features
virtual bool parseParameters(const QJsonArray& parameters) = 0;
class Factory {
public:
class Entry {
public:
virtual Filter* create() = 0;
Entry() = default;
virtual ~Entry() = default;
};
template <class T> class ClassEntry {
public:
virtual Filter* create() { return (Filter*) new T(); }
ClassEntry() = default;
virtual ~ClassEntry() = default;
};
using EntryMap = std::map<std::string, std::shared_ptr<Entry>>;
void registerEntry(const std::string& name, const std::shared_ptr<Entry>& entry) {
if (entry) {
_entries.insert(EntryMap::value_type(name, entry));
}
}
Filter* create(const std::string& name) const {
auto& entryIt = _entries.find(name);
if (entryIt != _entries.end()) {
return (*entryIt).second->create();
}
return nullptr;
}
protected:
EntryMap _entries;
};
static Filter::Pointer parse(const QJsonObject& json);
static Factory& getFactory() { return _factory; }
protected:
static Factory _factory;
};
}
#define REGISTER_FILTER_CLASS(classEntry) static Filter::Factory::ClassEntry<classEntry> _factoryEntry;
namespace controller {
class LambdaFilter : public Filter {
public:
// LambdaFilter() {}
LambdaFilter(Lambda f) : _function(f) {};
virtual float apply(float value) const {
return _function(value);
}
virtual bool parseParameters(const QJsonArray& parameters) { return true; }
// REGISTER_FILTER_CLASS(LambdaFilter);
private:
Lambda _function;
};
@ -50,17 +139,21 @@ namespace controller {
public:
};
class ScaleFilter : public Filter {
public:
ScaleFilter() {}
ScaleFilter(float scale): _scale(scale) {}
//class ScaleFilter : public Filter {
//public:
// ScaleFilter(float scale);
// virtual float apply(float scale) const override {
// return value * _scale;
// }
virtual float apply(float value) const override {
return value * _scale;
}
virtual bool parseParameters(const QJsonArray& parameters);
//private:
// const float _scale;
//};
REGISTER_FILTER_CLASS(ScaleFilter);
private:
float _scale = 1.0f;
};
//class AbstractRangeFilter : public Filter {
//public:
@ -84,6 +177,23 @@ namespace controller {
// const float _interval;
//};
class PulseFilter : public Filter {
public:
REGISTER_FILTER_CLASS(PulseFilter);
PulseFilter() {}
PulseFilter(float interval) : _interval(interval) {}
virtual float apply(float value) const override;
virtual bool parseParameters(const QJsonArray& parameters);
private:
mutable float _lastEmitTime{ -std::numeric_limits<float>::max() };
float _interval = 1.0f;
};
////class DeadzoneFilter : public AbstractRangeFilter {
////public:
//// DeadzoneFilter(float min, float max = 1.0f);

View file

@ -11,8 +11,8 @@
#include <QtCore/QHash>
#include <QtCore/QDebug>
#include <QJSONObject>
#include <qjsonarray.h>
#include <QJSonObject>
#include <QJSonArray>
#include "RouteBuilderProxy.h"
#include "../NewControllerScriptingInterface.h"
@ -71,8 +71,6 @@ void MappingBuilderProxy::parseRoute(const QJsonValue& json) {
auto route = dynamic_cast<RouteBuilderProxy*>(newRoute);
route->filters(jsonChannel[JSON_CHANNEL_FILTERS]);
route->to(jsonChannel[JSON_CHANNEL_TO]);
return
}
}
}
@ -87,6 +85,3 @@ QObject* MappingBuilderProxy::from(const QJsonValue& json) {
}
Filter::List MappingBuilderProxy::parseFilters(const QJsonValue& json) const {
return Filter::List();
}

View file

@ -17,6 +17,7 @@
class QJSValue;
class QScriptValue;
class QJsonValue;
namespace controller {

View file

@ -9,6 +9,9 @@
#include <QtCore/QDebug>
#include <QJSonObject>
#include <QJSonArray>
#include <GLMHelpers.h>
#include "MappingBuilderProxy.h"
@ -61,9 +64,7 @@ QObject* RouteBuilderProxy::clamp(float min, float max) {
}
QObject* RouteBuilderProxy::scale(float multiplier) {
addFilter([=](float value) {
return value * multiplier;
});
addFilter(Filter::Pointer(new ScaleFilter(multiplier)));
return this;
}
@ -99,39 +100,12 @@ QObject* RouteBuilderProxy::constrainToPositiveInteger() {
}
class PulseFilter : public Filter {
public:
PulseFilter(float interval) : _interval(interval) {}
virtual float apply(float value) const override {
float result = 0.0;
if (0.0 != value) {
float now = secTimestampNow();
float delta = now - _lastEmitTime;
if (delta >= _interval) {
_lastEmitTime = now;
result = value;
}
}
return result;
}
private:
mutable float _lastEmitTime{ -std::numeric_limits<float>::max() };
const float _interval;
};
QObject* RouteBuilderProxy::pulse(float interval) {
Filter::Pointer filter = std::make_shared<PulseFilter>(interval);
addFilter(filter);
return this;
}
void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda);
addFilter(filterPointer);
@ -141,4 +115,34 @@ void RouteBuilderProxy::addFilter(Filter::Pointer filter) {
_route->_filters.push_back(filter);
}
QObject* RouteBuilderProxy::filters(const QJsonValue& json) {
// We expect an array of objects to define the filters
if (json.isArray()) {
const auto& jsonFilters = json.toArray();
for (auto jsonFilter : jsonFilters) {
if (jsonFilter.isObject()) {
// The filter is an object, now let s check for type and potential arguments
Filter::Pointer filter = Filter::parse(jsonFilter.toObject());
if (filter) {
addFilter(filter);
}
}
}
}
return this;
}
void RouteBuilderProxy::to(const QJsonValue& json) {
if (json.isString()) {
return to(_parent.endpointFor(_parent.inputFor(json.toString())));
} else if (json.isObject()) {
// Endpoint is defined as an object, we expect a js function then
return to(nullptr);
}
}
}

View file

@ -16,6 +16,7 @@
class QJSValue;
class QScriptValue;
class QJsonValue;
namespace controller {