summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2013-02-12 00:36:09 +0000
committerrandomdan <randomdan@localhost>2013-02-12 00:36:09 +0000
commit0ec8f0b4ba05728b5c992bf8ec1731d5202fcc7c (patch)
tree105ec55059afe60cb7dff2484971245b91b04190
parentAdd support for writing dates in a custom format in XML presenter (diff)
downloadproject2-0ec8f0b4ba05728b5c992bf8ec1731d5202fcc7c.tar.bz2
project2-0ec8f0b4ba05728b5c992bf8ec1731d5202fcc7c.tar.xz
project2-0ec8f0b4ba05728b5c992bf8ec1731d5202fcc7c.zip
Basic eventing system
Component registration by script and name Fully comparable variable types Tidy up around tests IsDistinct and IsUniq row filters
-rw-r--r--project2/common/if.cpp71
-rw-r--r--project2/common/if.h9
-rw-r--r--project2/common/rowProcessor.cpp2
-rw-r--r--project2/common/rowProcessor.h3
-rw-r--r--project2/common/scripts.h3
-rw-r--r--project2/common/sourceObject.cpp30
-rw-r--r--project2/common/sourceObject.h15
-rw-r--r--project2/common/test.cpp5
-rw-r--r--project2/common/test.h1
-rw-r--r--project2/common/tests/compoundTest.cpp79
-rw-r--r--project2/common/tests/compoundTest.h16
-rw-r--r--project2/common/tests/isdistinct.cpp40
-rw-r--r--project2/common/tests/isuniq.cpp48
-rw-r--r--project2/common/variables-modlookup.cpp1
-rw-r--r--project2/common/variables.cpp73
-rw-r--r--project2/common/variables.h14
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;