From 1a5467aec86437001faf009310c54c2b2a7851a6 Mon Sep 17 00:00:00 2001 From: James Turner Date: Mon, 11 Mar 2013 16:53:52 +0000 Subject: [PATCH 1/1] 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. --- simgear/misc/test_macros.hxx | 19 ++++ simgear/props/condition.cxx | 49 +++++++++- simgear/props/condition.hxx | 2 + simgear/structure/CMakeLists.txt | 5 ++ simgear/structure/SGExpression.hxx | 29 +++++- simgear/structure/expression_test.cxx | 110 +++++++++++++++++++++++ simgear/structure/state_machine_test.cxx | 14 +-- 7 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 simgear/misc/test_macros.hxx create mode 100644 simgear/structure/expression_test.cxx diff --git a/simgear/misc/test_macros.hxx b/simgear/misc/test_macros.hxx new file mode 100644 index 00000000..df154bcb --- /dev/null +++ b/simgear/misc/test_macros.hxx @@ -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 diff --git a/simgear/props/condition.cxx b/simgear/props/condition.cxx index 86f627f4..bfc1bf61 100644 --- a/simgear/props/condition.cxx +++ b/simgear/props/condition.cxx @@ -35,6 +35,8 @@ public: const char * propname ); virtual ~SGPropertyCondition (); virtual bool test () const { return _node->getBoolValue(); } + virtual void collectDependentProperties(std::set& 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& props) const; private: SGSharedPtr _condition; }; @@ -82,6 +85,7 @@ public: virtual bool test () const; // transfer pointer ownership virtual void addCondition (SGCondition * condition); + virtual void collectDependentProperties(std::set& props) const; private: std::vector > _conditions; }; @@ -101,6 +105,7 @@ public: virtual bool test () const; // transfer pointer ownership virtual void addCondition (SGCondition * condition); + virtual void collectDependentProperties(std::set& props) const; private: std::vector > _conditions; }; @@ -135,6 +140,7 @@ public: void setRightDExpression(SGExpressiond* dexp); void setPrecisionDExpression(SGExpressiond* dexp); + virtual void collectDependentProperties(std::set& props) const; private: Type _type; bool _reverse; @@ -195,6 +201,11 @@ SGNotCondition::test () const return !(_condition->test()); } +void +SGNotCondition::collectDependentProperties(std::set& 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& 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& 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& 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. //////////////////////////////////////////////////////////////////////// diff --git a/simgear/props/condition.hxx b/simgear/props/condition.hxx index f18e4b84..128cdfaf 100644 --- a/simgear/props/condition.hxx +++ b/simgear/props/condition.hxx @@ -10,6 +10,7 @@ #ifndef __SG_CONDITION_HXX #define __SG_CONDITION_HXX +#include #include #include @@ -34,6 +35,7 @@ public: SGCondition (); virtual ~SGCondition (); virtual bool test () const = 0; + virtual void collectDependentProperties(std::set& props) const { } }; diff --git a/simgear/structure/CMakeLists.txt b/simgear/structure/CMakeLists.txt index 2ce3646a..f7e29a76 100644 --- a/simgear/structure/CMakeLists.txt +++ b/simgear/structure/CMakeLists.txt @@ -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) diff --git a/simgear/structure/SGExpression.hxx b/simgear/structure/SGExpression.hxx index 1832c3a3..c5ef8761 100644 --- a/simgear/structure/SGExpression.hxx +++ b/simgear/structure/SGExpression.hxx @@ -25,7 +25,8 @@ #include #include #include - +#include + #include #include #include @@ -136,6 +137,8 @@ public: { return simgear::expression::TypeTraits::typeTag; } + virtual void collectDependentProperties(std::set& props) const + { } }; /// Constant value expression @@ -184,7 +187,9 @@ public: _expression = _expression->simplify(); return SGExpression::simplify(); } - + + virtual void collectDependentProperties(std::set& props) const + { _expression->collectDependentProperties(props); } protected: SGUnaryExpression(SGExpression* expression = 0) { setOperand(expression); } @@ -218,6 +223,12 @@ public: return SGExpression::simplify(); } + virtual void collectDependentProperties(std::set& props) const + { + _expressions[0]->collectDependentProperties(props); + _expressions[1]->collectDependentProperties(props); + } + protected: SGBinaryExpression(SGExpression* expr0, SGExpression* expr1) { setOperand(0, expr0); setOperand(1, expr1); } @@ -266,6 +277,11 @@ public: return SGExpression::simplify(); } + virtual void collectDependentProperties(std::set& 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& 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::simplify(); } + + virtual void collectDependentProperties(std::set& props) const + { + SGUnaryExpression::collectDependentProperties(props); + _enable->collectDependentProperties(props); + } using SGUnaryExpression::getOperand; private: diff --git a/simgear/structure/expression_test.cxx b/simgear/structure/expression_test.cxx new file mode 100644 index 00000000..f1ba16f6 --- /dev/null +++ b/simgear/structure/expression_test.cxx @@ -0,0 +1,110 @@ +#ifdef HAVE_CONFIG_H +# include +#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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace simgear; + +SGPropertyNode_ptr propertyTree; + +void initPropTree() +{ + const char* xml = "" + "" + "" + "one" + "2" + "99" + "" + "" + "false" + "" + ""; + + propertyTree = new SGPropertyNode; + readProperties(xml, strlen(xml), propertyTree.ptr()); +} + +void testBasic() +{ + +} + +void testParse() +{ + initPropTree(); + + const char* xml = "" + "" + "" + "" + "" + "/group-a/bar" + "42" + "" + "" + "/group-a/zot" + "50" + "" + "" + "" + ""; + + const char* xml2 = "" + "" + "" + "" + "/group-a/bar" + "/group-a/zot" + "/group-b/thing-1" + "" + "" + ""; + + SGPropertyNode* desc = new SGPropertyNode; + readProperties(xml2, strlen(xml2), desc); + + SGSharedPtr expr = SGReadDoubleExpression(propertyTree, desc->getChild(0)); + + std::set 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; +} + diff --git a/simgear/structure/state_machine_test.cxx b/simgear/structure/state_machine_test.cxx index 2d31d63d..0703ce62 100644 --- a/simgear/structure/state_machine_test.cxx +++ b/simgear/structure/state_machine_test.cxx @@ -23,6 +23,7 @@ #include #include #include +#include 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() \ -- 2.39.2