From cb62527bf93a1b32dcce94095a38583f163b4412 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 14 Oct 2015 09:22:30 -0700 Subject: [PATCH] Refactoring the filter for supporting the factory --- .../controllers/src/controllers/Filter.cpp | 63 ++++++++- .../controllers/src/controllers/Filter.h | 132 ++++++++++++++++-- .../controllers/impl/MappingBuilderProxy.cpp | 9 +- .../controllers/impl/MappingBuilderProxy.h | 1 + .../controllers/impl/RouteBuilderProxy.cpp | 64 +++++---- .../src/controllers/impl/RouteBuilderProxy.h | 1 + 6 files changed, 218 insertions(+), 52 deletions(-) diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp index 17715eceff..b7175f1716 100644 --- a/libraries/controllers/src/controllers/Filter.cpp +++ b/libraries/controllers/src/controllers/Filter.cpp @@ -11,11 +11,66 @@ #include #include -namespace controller { +#include +#include - 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::_factoryEntry; + +bool ScaleFilter::parseParameters(const QJsonArray& parameters) { + if (parameters.size() > 1) { + _scale = parameters[0].toDouble(); + } + return true; +} + +Filter::Factory::ClassEntry 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; +} diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h index f3978e2c0a..425bba7512 100644 --- a/libraries/controllers/src/controllers/Filter.h +++ b/libraries/controllers/src/controllers/Filter.h @@ -14,13 +14,49 @@ #include #include #include +#include #include class QJsonObject; +class QJsonArray; + namespace controller { + /* + template class Factory { + public: + template class Entry { + public: + virtual T* create() = 0; + }; + + template class DefaultEntry{ + public: + T* create() { return new S(); } + }; + + using EntryMap = std::map>>; + + void registerEntry(const std::string& name, std::unique_ptr>& 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; using Lambda = std::function; - 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 ClassEntry { + public: + virtual Filter* create() { return (Filter*) new T(); } + + ClassEntry() = default; + virtual ~ClassEntry() = default; + }; + + using EntryMap = std::map>; + + void registerEntry(const std::string& name, const std::shared_ptr& 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 _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::max() }; + float _interval = 1.0f; + }; + ////class DeadzoneFilter : public AbstractRangeFilter { ////public: //// DeadzoneFilter(float min, float max = 1.0f); diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp index 71a8a417fd..9080555cac 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp @@ -11,8 +11,8 @@ #include #include -#include -#include +#include +#include #include "RouteBuilderProxy.h" #include "../NewControllerScriptingInterface.h" @@ -71,8 +71,6 @@ void MappingBuilderProxy::parseRoute(const QJsonValue& json) { auto route = dynamic_cast(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(); -} diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h index d0101b95a7..799fc99399 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h @@ -17,6 +17,7 @@ class QJSValue; class QScriptValue; +class QJsonValue; namespace controller { diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp index e6b67e9ca6..d606b52608 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp @@ -9,6 +9,9 @@ #include +#include +#include + #include #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::max() }; - const float _interval; -}; - - QObject* RouteBuilderProxy::pulse(float interval) { Filter::Pointer filter = std::make_shared(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); + } + +} + } diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h index a62a465700..573e841e85 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -16,6 +16,7 @@ class QJSValue; class QScriptValue; +class QJsonValue; namespace controller {