diff options
-rw-r--r-- | project2/common/if.cpp | 71 | ||||
-rw-r--r-- | project2/common/if.h | 9 | ||||
-rw-r--r-- | project2/common/rowProcessor.cpp | 2 | ||||
-rw-r--r-- | project2/common/rowProcessor.h | 3 | ||||
-rw-r--r-- | project2/common/scripts.h | 3 | ||||
-rw-r--r-- | project2/common/sourceObject.cpp | 30 | ||||
-rw-r--r-- | project2/common/sourceObject.h | 15 | ||||
-rw-r--r-- | project2/common/test.cpp | 5 | ||||
-rw-r--r-- | project2/common/test.h | 1 | ||||
-rw-r--r-- | project2/common/tests/compoundTest.cpp | 79 | ||||
-rw-r--r-- | project2/common/tests/compoundTest.h | 16 | ||||
-rw-r--r-- | project2/common/tests/isdistinct.cpp | 40 | ||||
-rw-r--r-- | project2/common/tests/isuniq.cpp | 48 | ||||
-rw-r--r-- | project2/common/variables-modlookup.cpp | 1 | ||||
-rw-r--r-- | project2/common/variables.cpp | 73 | ||||
-rw-r--r-- | project2/common/variables.h | 14 |
16 files changed, 315 insertions, 95 deletions
diff --git a/project2/common/if.cpp b/project2/common/if.cpp index b9db1db..c7f790e 100644 --- a/project2/common/if.cpp +++ b/project2/common/if.cpp @@ -9,13 +9,6 @@ DECLARE_LOADER("if", If); StaticMessageException(NoTestsToPerform, "No tests to perform"); -CompoundTest::CompoundTest(ScriptNodePtr s) : - SourceObject(s), - Test(s) -{ - s->script->loader.addLoadTarget(s, Storer::into<ElementLoader>(&tests)); -} - If::If(ScriptNodePtr e) : SourceObject(e), IHaveSubTasks(e), @@ -55,67 +48,3 @@ If::execute() const } } - -class All : public CompoundTest { - public: - All(ScriptNodePtr s) : - SourceObject(s), - CompoundTest(s) { - } - bool passes() const { - if (tests.empty()) { - throw NoTestsToPerform(); - } - return (std::find_if(tests.begin(), tests.end(), !boost::bind(&Test::passes, _1)) == tests.end()); - } -}; -DECLARE_LOADER("all", All); - -class Any : public CompoundTest { - public: - Any(ScriptNodePtr s) : - SourceObject(s), - CompoundTest(s) { - } - bool passes() const { - if (tests.empty()) { - throw NoTestsToPerform(); - } - return (std::find_if(tests.begin(), tests.end(), boost::bind(&Test::passes, _1)) != tests.end()); - } -}; -DECLARE_LOADER("any", Any); - -class None : public CompoundTest { - public: - None(ScriptNodePtr s) : - SourceObject(s), - CompoundTest(s) { - } - bool passes() const { - if (tests.empty()) { - throw NoTestsToPerform(); - } - return (std::find_if(tests.begin(), tests.end(), boost::bind(&Test::passes, _1)) == tests.end()); - } -}; -DECLARE_LOADER("none", None); - -class Not : public Test { - public: - Not(ScriptNodePtr s) : - SourceObject(s), - Test(s) - { - s->script->loader.addLoadTarget(s, Storer::into<ElementLoader>(&test)); - } - bool passes() const { - if (!test) { - throw NoTestsToPerform(); - } - return !test->passes(); - } - private: - TestPtr test; -}; -DECLARE_LOADER("not", Not); diff --git a/project2/common/if.h b/project2/common/if.h index bcf83cd..2496dc4 100644 --- a/project2/common/if.h +++ b/project2/common/if.h @@ -5,15 +5,6 @@ #include "view.h" #include "test.h" -class CompoundTest : public Test { - public: - CompoundTest(ScriptNodePtr); - - protected: - typedef ANONORDEREDSTORAGEOF(Test) Tests; - Tests tests; -}; - /// Project2 component to conditionally execute its children class If : public IHaveSubTasks, public View { public: diff --git a/project2/common/rowProcessor.cpp b/project2/common/rowProcessor.cpp index 541ff11..f83dfa7 100644 --- a/project2/common/rowProcessor.cpp +++ b/project2/common/rowProcessor.cpp @@ -7,6 +7,7 @@ #include <boost/algorithm/string/predicate.hpp> RowProcessor::RowProcessor(ScriptNodePtr p) : + SourceObject(p), IHaveParameters(p), recordSource(p->value("source").as<std::string>()), filter(p->value("filter", "").as<Glib::ustring>()), @@ -42,6 +43,7 @@ RowProcessor::execute() const } } Logger()->messagebf(LOG_DEBUG, "Executing from source '%s'", source->name); + ScopeObject onComplete(boost::bind(&SourceObject::send, this, Complete)); if (IRSE) { try { source->execute(filter, this); diff --git a/project2/common/rowProcessor.h b/project2/common/rowProcessor.h index cbbf6c3..a7e8544 100644 --- a/project2/common/rowProcessor.h +++ b/project2/common/rowProcessor.h @@ -12,8 +12,9 @@ class Presenter; /// Base class for Project2 components that work with row sets -class RowProcessor : public IHaveParameters { +class RowProcessor : public IHaveParameters, public virtual SourceObject { public: + enum EventIDs { Complete }; RowProcessor(ScriptNodePtr); void loadComplete(const CommonObjects *); diff --git a/project2/common/scripts.h b/project2/common/scripts.h index 0f1a1a6..ce2cf0e 100644 --- a/project2/common/scripts.h +++ b/project2/common/scripts.h @@ -55,6 +55,9 @@ class ScriptReader : public virtual IntrusivePtrBase { virtual bool isCurrent() const = 0; virtual time_t modifiedTime() const = 0; mutable LoaderBase loader; + + friend class SourceObject; + mutable std::map<std::string, SourceObject *> namedComponents; }; /// Base class to implement script reader modules diff --git a/project2/common/sourceObject.cpp b/project2/common/sourceObject.cpp index ef909b9..6f5bcc5 100644 --- a/project2/common/sourceObject.cpp +++ b/project2/common/sourceObject.cpp @@ -1,18 +1,24 @@ #include <pch.hpp> #include "sourceObject.h" +#include "exceptions.h" +#include "safeMapFind.h" unsigned int SourceObject::loadOrder = 1; +SimpleMessageException(ComponentNotFound); SourceObject::SourceObject(ScriptNodePtr p) : name(p ? p->value("name", "anon").as<std::string>() : "anon"), - order(loadOrder++) + order(loadOrder++), + script(p->script.get()) { LoaderBase::loadedObjects.insert(this); + script->namedComponents[name] = this; } SourceObject::SourceObject(const std::string & n) : name(n), - order(loadOrder++) + order(loadOrder++), + script(NULL) { LoaderBase::loadedObjects.insert(this); } @@ -27,3 +33,23 @@ SourceObject::loadComplete(const CommonObjects *) { } +void +SourceObject::send(int eventID) const +{ + for (Events::const_iterator i = events.lower_bound(eventID); i != events.upper_bound(eventID); i++) { + i->second(); + } +} + +void +SourceObject::registerFor(int eventID, const Event & event) const +{ + events.insert(Events::value_type(eventID, event)); +} + +SourceObject * +SourceObject::findComponent(const std::string & name) const +{ + return safeMapLookup<ComponentNotFound>(script->namedComponents, name); +} + diff --git a/project2/common/sourceObject.h b/project2/common/sourceObject.h index f8963ea..8529100 100644 --- a/project2/common/sourceObject.h +++ b/project2/common/sourceObject.h @@ -3,6 +3,7 @@ #include <boost/intrusive_ptr.hpp> #include <string> +#include <map> #include "intrusivePtrBase.h" #include "scriptLoader.h" #include "scripts_fwd.h" @@ -15,16 +16,30 @@ class CommonObjects; /// Base class for all Project2 components that can be placed in a Project2 script class SourceObject : public virtual IntrusivePtrBase { public: + typedef int EventID; + typedef boost::function<void()> Event; + typedef std::multimap<EventID, Event> Events; + SourceObject(ScriptNodePtr p); SourceObject(const std::string & name); virtual ~SourceObject() = 0; virtual void loadComplete(const CommonObjects *); + SourceObject * findComponent(const std::string & name) const; + + void registerFor(EventID eventID, const Event & event) const; + void send(EventID eventID) const; + const std::string name; const unsigned int order; + + private: static unsigned int loadOrder; + + mutable Events events; + const ScriptReader * const script; }; #endif diff --git a/project2/common/test.cpp b/project2/common/test.cpp index f4066af..427848a 100644 --- a/project2/common/test.cpp +++ b/project2/common/test.cpp @@ -5,3 +5,8 @@ Test::Test(ScriptNodePtr s) : { } +void +Test::reset() const +{ +} + diff --git a/project2/common/test.h b/project2/common/test.h index aa2709c..4f87c10 100644 --- a/project2/common/test.h +++ b/project2/common/test.h @@ -8,6 +8,7 @@ class Test : public virtual SourceObject { public: Test(ScriptNodePtr); virtual bool passes() const = 0; + virtual void reset() const; }; typedef boost::intrusive_ptr<const Test> TestPtr; diff --git a/project2/common/tests/compoundTest.cpp b/project2/common/tests/compoundTest.cpp new file mode 100644 index 0000000..c3babf7 --- /dev/null +++ b/project2/common/tests/compoundTest.cpp @@ -0,0 +1,79 @@ +#include <pch.hpp> +#include "compoundTest.h" +#include "../scriptLoader.h" +#include <boost/foreach.hpp> +#include <boost/bind.hpp> +#include <algorithm> + +StaticMessageException(NoTestsToPerform, "No tests to perform"); + +CompoundTest::CompoundTest(ScriptNodePtr s) : + SourceObject(s), + Test(s) +{ + s->script->loader.addLoadTarget(s, Storer::into<ElementLoader>(&tests)); +} + +class All : public CompoundTest { + public: + All(ScriptNodePtr s) : + SourceObject(s), + CompoundTest(s) { + } + bool passes() const { + if (tests.empty()) { + throw NoTestsToPerform(); + } + return (std::find_if(tests.begin(), tests.end(), !boost::bind(&Test::passes, _1)) == tests.end()); + } +}; +DECLARE_LOADER("all", All); + +class Any : public CompoundTest { + public: + Any(ScriptNodePtr s) : + SourceObject(s), + CompoundTest(s) { + } + bool passes() const { + if (tests.empty()) { + throw NoTestsToPerform(); + } + return (std::find_if(tests.begin(), tests.end(), boost::bind(&Test::passes, _1)) != tests.end()); + } +}; +DECLARE_LOADER("any", Any); + +class None : public CompoundTest { + public: + None(ScriptNodePtr s) : + SourceObject(s), + CompoundTest(s) { + } + bool passes() const { + if (tests.empty()) { + throw NoTestsToPerform(); + } + return (std::find_if(tests.begin(), tests.end(), boost::bind(&Test::passes, _1)) == tests.end()); + } +}; +DECLARE_LOADER("none", None); + +class Not : public Test { + public: + Not(ScriptNodePtr s) : + SourceObject(s), + Test(s) + { + s->script->loader.addLoadTarget(s, Storer::into<ElementLoader>(&test)); + } + bool passes() const { + if (!test) { + throw NoTestsToPerform(); + } + return !test->passes(); + } + private: + TestPtr test; +}; +DECLARE_LOADER("not", Not); diff --git a/project2/common/tests/compoundTest.h b/project2/common/tests/compoundTest.h new file mode 100644 index 0000000..38aadea --- /dev/null +++ b/project2/common/tests/compoundTest.h @@ -0,0 +1,16 @@ +#ifndef IF_H +#define IF_H + +#include "../test.h" + +class CompoundTest : public Test { + public: + CompoundTest(ScriptNodePtr); + + protected: + typedef ANONORDEREDSTORAGEOF(Test) Tests; + Tests tests; +}; + +#endif + diff --git a/project2/common/tests/isdistinct.cpp b/project2/common/tests/isdistinct.cpp new file mode 100644 index 0000000..b754d2d --- /dev/null +++ b/project2/common/tests/isdistinct.cpp @@ -0,0 +1,40 @@ +#include <pch.hpp> +#include "../test.h" +#include "../scriptLoader.h" +#include "../iHaveParameters.h" +#include "../rowProcessor.h" + +class IsDistinct : public Test, IHaveParameters { + public: + IsDistinct(ScriptNodePtr s) : + SourceObject(s), + Test(s), + IHaveParameters(s), + scope(s, "scope") + { + } + + void loadComplete(const CommonObjects *) + { + findComponent(scope())->registerFor(RowProcessor::Complete, boost::bind(&IsDistinct::reset, this)); + } + + bool passes() const { + Vars row; + BOOST_FOREACH(const Parameters::value_type & p, parameters) { + row.push_back(p.second()); + } + return previous.insert(row).second; + } + + void reset() const { + previous.clear(); + } + + private: + Variable scope; + typedef std::vector<VariableType> Vars; + typedef std::set<Vars> Rows; + mutable Rows previous; +}; +DECLARE_LOADER("isdistinct", IsDistinct); diff --git a/project2/common/tests/isuniq.cpp b/project2/common/tests/isuniq.cpp new file mode 100644 index 0000000..6966985 --- /dev/null +++ b/project2/common/tests/isuniq.cpp @@ -0,0 +1,48 @@ +#include <pch.hpp> +#include "../test.h" +#include "../scriptLoader.h" +#include "../iHaveParameters.h" +#include "../rowProcessor.h" + +class IsUniq : public Test, IHaveParameters { + public: + IsUniq(ScriptNodePtr s) : + SourceObject(s), + Test(s), + IHaveParameters(s), + scope(s, "scope") + { + } + + void loadComplete(const CommonObjects *) + { + findComponent(scope())->registerFor(RowProcessor::Complete, boost::bind(&IsUniq::reset, this)); + } + + bool passes() const { + if (previous.size() > 0) { + Vars row; + BOOST_FOREACH(const Parameters::value_type & p, parameters) { + row.push_back(p.second()); + } + std::swap(row, previous); + return row != previous; + } + else { + BOOST_FOREACH(const Parameters::value_type & p, parameters) { + previous.push_back(p.second()); + } + return true; + } + } + + void reset() const { + previous.clear(); + } + + private: + Variable scope; + typedef std::vector<VariableType> Vars; + mutable Vars previous; +}; +DECLARE_LOADER("isuniq", IsUniq); diff --git a/project2/common/variables-modlookup.cpp b/project2/common/variables-modlookup.cpp index 64ff93d..67d2924 100644 --- a/project2/common/variables-modlookup.cpp +++ b/project2/common/variables-modlookup.cpp @@ -31,6 +31,7 @@ class VariableLookup : public VariableImplDyn, public RowProcessor { } }; VariableLookup(ScriptNodePtr e) : + SourceObject(e), VariableImplDyn(e), RowProcessor(e), name(e->value("name").as<Glib::ustring>()) diff --git a/project2/common/variables.cpp b/project2/common/variables.cpp index 8515e44..4b42aa3 100644 --- a/project2/common/variables.cpp +++ b/project2/common/variables.cpp @@ -18,12 +18,6 @@ SimpleMessageException(UnknownVariableType); -bool -Null::operator<(const Null &) const -{ - return false; -} - Boolean::Boolean(bool v) : value(v) { } @@ -159,13 +153,13 @@ VariableType::VariableType(const VariableType & vt) : { } -template <class S> +template <class S, typename Op> class compi : public boost::static_visitor<bool> { public: compi(const S & s) : _s(s) { } bool operator()(const S & t) const { - return t < _s; + return Op()(t, _s); } template <class T> bool operator()(const T &) const @@ -176,13 +170,15 @@ class compi : public boost::static_visitor<bool> { private: const S & _s; }; + +template <template <class T> class Op> class comp : public boost::static_visitor<bool> { public: comp(const VariableType & a) : _a(a) { } template <class T> bool operator()(const T & t) const { - return boost::apply_visitor(compi<T>(t), _a); + return boost::apply_visitor(compi<T, Op<T>>(t), _a); } private: const VariableType & _a; @@ -195,7 +191,64 @@ VariableType::operator<(const VariableType & b) const return true; } if (this->which() == b.which()) { - return boost::apply_visitor(comp(*this), b); + return boost::apply_visitor(comp<std::less>(*this), b); + } + return false; +} + +bool +VariableType::operator==(const VariableType & b) const +{ + if (this->which() == b.which()) { + return boost::apply_visitor(comp<std::equal_to>(*this), b); + } + return false; +} + +bool +VariableType::operator<=(const VariableType & b) const +{ + if (this->which() < b.which()) { + return true; + } + if (this->which() == b.which()) { + return boost::apply_visitor(comp<std::less_equal>(*this), b); + } + return false; +} + +bool +VariableType::operator>(const VariableType & b) const +{ + if (this->which() > b.which()) { + return true; + } + if (this->which() == b.which()) { + return boost::apply_visitor(comp<std::greater>(*this), b); + } + return false; +} + +bool +VariableType::operator>=(const VariableType & b) const +{ + if (this->which() > b.which()) { + return true; + } + if (this->which() == b.which()) { + return boost::apply_visitor(comp<std::greater_equal>(*this), b); + } + return false; +} + +bool +VariableType::operator!=(const VariableType & b) const +{ + if (this->which() != b.which()) { + return true; + } + if (this->which() == b.which()) { + return boost::apply_visitor(comp<std::not_equal_to>(*this), b); } return false; } diff --git a/project2/common/variables.h b/project2/common/variables.h index 932da90..941d754 100644 --- a/project2/common/variables.h +++ b/project2/common/variables.h @@ -26,7 +26,12 @@ enum VT_typeID { class Null { public: - bool operator<(const Null &) const; + bool operator<(const Null &) const { return false; } + bool operator<=(const Null &) const { return false; } + bool operator>(const Null &) const { return false; } + bool operator>=(const Null &) const { return false; } + bool operator!=(const Null &) const { return false; } + bool operator==(const Null &) const { return true; } }; class Boolean { @@ -78,6 +83,11 @@ class VariableType : public _VT { static VT_typeID getTypeFromName(const std::string & src); bool operator<(const VariableType &) const; + bool operator<=(const VariableType &) const; + bool operator>(const VariableType &) const; + bool operator>=(const VariableType &) const; + bool operator==(const VariableType &) const; + bool operator!=(const VariableType &) const; operator const Glib::ustring &() const; operator const std::string &() const; @@ -97,7 +107,7 @@ class VariableType : public _VT { }; /// Base class for Project2 variable accessors -class VariableImpl : public IntrusivePtrBase { +class VariableImpl : public virtual IntrusivePtrBase { public: virtual VariableType value() const = 0; |