Collect properties from expression/condition trees.

Initial ground-work to support efficient updating of condition/expression results; allow collecting all the dependent property values from the hierarchy, so they can be observed. Also add a very small test-case for this.
This commit is contained in:
James Turner 2013-03-11 16:53:52 +00:00
parent 0dcb64dca3
commit 1a5467aec8
7 changed files with 212 additions and 16 deletions

View File

@ -0,0 +1,19 @@
#ifndef SG_MISC_TEST_MACROS_HXX
#define SG_MISC_TEST_MACROS_HXX
#define COMPARE(a, b) \
if ((a) != (b)) { \
std::cerr << "failed:" << #a << " != " << #b << std::endl; \
std::cerr << "\tgot:'" << a << "'" << std::endl; \
exit(1); \
}
#define VERIFY(a) \
if (!(a)) { \
std::cerr << "failed:" << #a << std::endl; \
exit(1); \
}
#endif // of SG_MISC_TEST_MACROS_HXX

View File

@ -35,6 +35,8 @@ public:
const char * propname );
virtual ~SGPropertyCondition ();
virtual bool test () const { return _node->getBoolValue(); }
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{ props.insert(_node.get()); }
private:
SGConstPropertyNode_ptr _node;
};
@ -63,6 +65,7 @@ public:
SGNotCondition (SGCondition * condition);
virtual ~SGNotCondition ();
virtual bool test () const;
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const;
private:
SGSharedPtr<SGCondition> _condition;
};
@ -82,6 +85,7 @@ public:
virtual bool test () const;
// transfer pointer ownership
virtual void addCondition (SGCondition * condition);
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const;
private:
std::vector<SGSharedPtr<SGCondition> > _conditions;
};
@ -101,6 +105,7 @@ public:
virtual bool test () const;
// transfer pointer ownership
virtual void addCondition (SGCondition * condition);
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const;
private:
std::vector<SGSharedPtr<SGCondition> > _conditions;
};
@ -135,6 +140,7 @@ public:
void setRightDExpression(SGExpressiond* dexp);
void setPrecisionDExpression(SGExpressiond* dexp);
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const;
private:
Type _type;
bool _reverse;
@ -195,6 +201,11 @@ SGNotCondition::test () const
return !(_condition->test());
}
void
SGNotCondition::collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{
_condition->collectDependentProperties(props);
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGAndCondition.
@ -225,6 +236,13 @@ SGAndCondition::addCondition (SGCondition * condition)
_conditions.push_back(condition);
}
void
SGAndCondition::collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{
for( size_t i = 0; i < _conditions.size(); i++ )
_conditions[i]->collectDependentProperties(props);
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGOrCondition.
@ -255,6 +273,13 @@ SGOrCondition::addCondition (SGCondition * condition)
_conditions.push_back(condition);
}
void
SGOrCondition::collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{
for( size_t i = 0; i < _conditions.size(); i++ )
_conditions[i]->collectDependentProperties(props);
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGComparisonCondition.
@ -421,7 +446,29 @@ SGComparisonCondition::setPrecisionDExpression(SGExpressiond* dexp)
{
_precision_property = new SGPropertyNode();
_precision_dexp = dexp;
}////////////////////////////////////////////////////////////////////////
}
void
SGComparisonCondition::collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{
if (_left_dexp)
_left_dexp->collectDependentProperties(props);
else
props.insert(_left_property);
if (_right_dexp)
_right_dexp->collectDependentProperties(props);
else
props.insert(_right_property);
if (_precision_dexp)
_precision_dexp->collectDependentProperties(props);
else if (_precision_property)
props.insert(_precision_property);
}
////////////////////////////////////////////////////////////////////////
// Read a condition and use it if necessary.
////////////////////////////////////////////////////////////////////////

View File

@ -10,6 +10,7 @@
#ifndef __SG_CONDITION_HXX
#define __SG_CONDITION_HXX
#include <set>
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
@ -34,6 +35,7 @@ public:
SGCondition ();
virtual ~SGCondition ();
virtual bool test () const = 0;
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const { }
};

View File

@ -57,4 +57,9 @@ add_executable(test_state_machine state_machine_test.cxx)
target_link_libraries(test_state_machine ${TEST_LIBS})
add_test(test_state_machine ${EXECUTABLE_OUTPUT_PATH}/test_state_machine)
add_executable(test_expressions expression_test.cxx)
target_link_libraries(test_expressions ${TEST_LIBS})
add_test(test_expressions ${EXECUTABLE_OUTPUT_PATH}/test_expressions)
endif(ENABLE_TESTS)

View File

@ -25,7 +25,8 @@
#include <string>
#include <vector>
#include <functional>
#include <set>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/math/interpolater.hxx>
@ -136,6 +137,8 @@ public:
{
return simgear::expression::TypeTraits<T>::typeTag;
}
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{ }
};
/// Constant value expression
@ -184,7 +187,9 @@ public:
_expression = _expression->simplify();
return SGExpression<T>::simplify();
}
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{ _expression->collectDependentProperties(props); }
protected:
SGUnaryExpression(SGExpression<T>* expression = 0)
{ setOperand(expression); }
@ -218,6 +223,12 @@ public:
return SGExpression<T>::simplify();
}
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{
_expressions[0]->collectDependentProperties(props);
_expressions[1]->collectDependentProperties(props);
}
protected:
SGBinaryExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
{ setOperand(0, expr0); setOperand(1, expr1); }
@ -266,6 +277,11 @@ public:
return SGExpression<T>::simplify();
}
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{
for (size_t i = 0; i < _expressions.size(); ++i)
_expressions[i]->collectDependentProperties(props);
}
protected:
SGNaryExpression()
{ }
@ -288,6 +304,9 @@ public:
{ _prop = prop; }
virtual void eval(T& value, const simgear::expression::Binding*) const
{ doEval(value); }
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{ props.insert(_prop.get()); }
private:
void doEval(float& value) const
{ if (_prop) value = _prop->getFloatValue(); }
@ -713,6 +732,12 @@ public:
return getOperand()->simplify();
return SGUnaryExpression<T>::simplify();
}
virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{
SGUnaryExpression<T>::collectDependentProperties(props);
_enable->collectDependentProperties(props);
}
using SGUnaryExpression<T>::getOperand;
private:

View File

@ -0,0 +1,110 @@
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#ifdef NDEBUG
// Always enable DEBUG mode in test application, otherwise "assert" test
// statements have no effect and don't actually test anything (catch 17 ;-) ).
#undef NDEBUG
#endif
#include <simgear/compiler.h>
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <simgear/misc/test_macros.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/structure/SGExpression.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
using namespace std;
using namespace simgear;
SGPropertyNode_ptr propertyTree;
void initPropTree()
{
const char* xml = "<?xml version=\"1.0\"?>"
"<PropertyList>"
"<group-a>"
"<foo>one</foo>"
"<bar>2</bar>"
"<zot>99</zot>"
"</group-a>"
"<group-b>"
"<thing-1 type=\"bool\">false</thing-1>"
"</group-b>"
"</PropertyList>";
propertyTree = new SGPropertyNode;
readProperties(xml, strlen(xml), propertyTree.ptr());
}
void testBasic()
{
}
void testParse()
{
initPropTree();
const char* xml = "<?xml version=\"1.0\"?>"
"<PropertyList>"
"<expression>"
"<and>"
"<greater-than>"
"<property>/group-a/bar</property>"
"<value>42</value>"
"</greater-than>"
"<less-than>"
"<property>/group-a/zot</property>"
"<value>50</value>"
"</less-than>"
"</and>"
"</expression>"
"</PropertyList>";
const char* xml2 = "<?xml version=\"1.0\"?>"
"<PropertyList>"
"<sqr>"
"<max>"
"<property>/group-a/bar</property>"
"<property>/group-a/zot</property>"
"<property>/group-b/thing-1</property>"
"</max>"
"</sqr>"
"</PropertyList>";
SGPropertyNode* desc = new SGPropertyNode;
readProperties(xml2, strlen(xml2), desc);
SGSharedPtr<SGExpressiond> expr = SGReadDoubleExpression(propertyTree, desc->getChild(0));
std::set<const SGPropertyNode*> deps;
expr->collectDependentProperties(deps);
COMPARE(deps.size(), 3);
SGPropertyNode* barProp = propertyTree->getNode("group-a/bar");
VERIFY(deps.find(barProp) != deps.end());
VERIFY(deps.find(propertyTree->getNode("group-a/zot")) != deps.end());
VERIFY(deps.find(propertyTree->getNode("group-b/thing-1")) != deps.end());
}
int main(int argc, char* argv[])
{
sglog().setLogLevels( SG_ALL, SG_INFO );
testBasic();
testParse();
cout << __FILE__ << ": All tests passed" << endl;
return EXIT_SUCCESS;
}

View File

@ -23,6 +23,7 @@
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/misc/test_macros.hxx>
using std::string;
using std::cout;
@ -57,19 +58,6 @@ public:
int dummy_cmd_state;
};
#define COMPARE(a, b) \
if ((a) != (b)) { \
cerr << "failed:" << #a << " != " << #b << endl; \
cerr << "\tgot:'" << a << "'" << endl; \
exit(1); \
}
#define VERIFY(a) \
if (!(a)) { \
cerr << "failed:" << #a << endl; \
exit(1); \
}
using namespace simgear;
#define BUILD_MACHINE_1() \