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 <QtCore/QObject>
#include <QtScript/QScriptValue> #include <QtScript/QScriptValue>
namespace controller { #include <QJSonObject>
#include <QJSonArray>
Filter::Pointer Filter::parse(const QJsonObject& json) { #include "SharedUtil.h"
// FIXME parse the json object and determine the instance type to create
return Filter::Pointer(); 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 <memory>
#include <numeric> #include <numeric>
#include <functional> #include <functional>
#include <map>
#include <QtCore/QEasingCurve> #include <QtCore/QEasingCurve>
class QJsonObject; class QJsonObject;
class QJsonArray;
namespace controller { 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 // Encapsulates part of a filter chain
class Filter { class Filter {
public: public:
@ -30,18 +66,71 @@ namespace controller {
using List = std::list<Pointer>; using List = std::list<Pointer>;
using Lambda = std::function<float(float)>; 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 { class LambdaFilter : public Filter {
public: public:
// LambdaFilter() {}
LambdaFilter(Lambda f) : _function(f) {}; LambdaFilter(Lambda f) : _function(f) {};
virtual float apply(float value) const { virtual float apply(float value) const {
return _function(value); return _function(value);
} }
virtual bool parseParameters(const QJsonArray& parameters) { return true; }
// REGISTER_FILTER_CLASS(LambdaFilter);
private: private:
Lambda _function; Lambda _function;
}; };
@ -50,17 +139,21 @@ namespace controller {
public: public:
}; };
class ScaleFilter : public Filter {
public:
ScaleFilter() {}
ScaleFilter(float scale): _scale(scale) {}
//class ScaleFilter : public Filter { virtual float apply(float value) const override {
//public: return value * _scale;
// ScaleFilter(float scale); }
// virtual float apply(float scale) const override { virtual bool parseParameters(const QJsonArray& parameters);
// return value * _scale;
// }
//private: REGISTER_FILTER_CLASS(ScaleFilter);
// const float _scale; private:
//}; float _scale = 1.0f;
};
//class AbstractRangeFilter : public Filter { //class AbstractRangeFilter : public Filter {
//public: //public:
@ -84,6 +177,23 @@ namespace controller {
// const float _interval; // 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 { ////class DeadzoneFilter : public AbstractRangeFilter {
////public: ////public:
//// DeadzoneFilter(float min, float max = 1.0f); //// DeadzoneFilter(float min, float max = 1.0f);

View file

@ -11,8 +11,8 @@
#include <QtCore/QHash> #include <QtCore/QHash>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QJSONObject> #include <QJSonObject>
#include <qjsonarray.h> #include <QJSonArray>
#include "RouteBuilderProxy.h" #include "RouteBuilderProxy.h"
#include "../NewControllerScriptingInterface.h" #include "../NewControllerScriptingInterface.h"
@ -71,8 +71,6 @@ void MappingBuilderProxy::parseRoute(const QJsonValue& json) {
auto route = dynamic_cast<RouteBuilderProxy*>(newRoute); auto route = dynamic_cast<RouteBuilderProxy*>(newRoute);
route->filters(jsonChannel[JSON_CHANNEL_FILTERS]); route->filters(jsonChannel[JSON_CHANNEL_FILTERS]);
route->to(jsonChannel[JSON_CHANNEL_TO]); 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 QJSValue;
class QScriptValue; class QScriptValue;
class QJsonValue;
namespace controller { namespace controller {

View file

@ -9,6 +9,9 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QJSonObject>
#include <QJSonArray>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include "MappingBuilderProxy.h" #include "MappingBuilderProxy.h"
@ -61,9 +64,7 @@ QObject* RouteBuilderProxy::clamp(float min, float max) {
} }
QObject* RouteBuilderProxy::scale(float multiplier) { QObject* RouteBuilderProxy::scale(float multiplier) {
addFilter([=](float value) { addFilter(Filter::Pointer(new ScaleFilter(multiplier)));
return value * multiplier;
});
return this; 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) { QObject* RouteBuilderProxy::pulse(float interval) {
Filter::Pointer filter = std::make_shared<PulseFilter>(interval); Filter::Pointer filter = std::make_shared<PulseFilter>(interval);
addFilter(filter); addFilter(filter);
return this; return this;
} }
void RouteBuilderProxy::addFilter(Filter::Lambda lambda) { void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda); Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda);
addFilter(filterPointer); addFilter(filterPointer);
@ -141,4 +115,34 @@ void RouteBuilderProxy::addFilter(Filter::Pointer filter) {
_route->_filters.push_back(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 QJSValue;
class QScriptValue; class QScriptValue;
class QJsonValue;
namespace controller { namespace controller {