]> git.mxchange.org Git - simgear.git/blob - simgear/props/condition.cxx
Collect properties from expression/condition trees.
[simgear.git] / simgear / props / condition.cxx
1 // condition.cxx - Declarations and inline methods for property conditions.
2 //
3 // Written by David Megginson, started 2000.
4 // CLO May 2003 - Split out condition specific code.
5 //
6 // This file is in the Public Domain, and comes with no warranty.
7 //
8 // $Id$
9
10 #ifdef HAVE_CONFIG_H
11 #  include <simgear_config.h>
12 #endif
13
14 // #include <iostream>
15
16 #include <simgear/structure/exception.hxx>
17
18 #include "props.hxx"
19 #include "condition.hxx"
20
21 #include <simgear/structure/SGExpression.hxx>
22
23 using std::istream;
24 using std::ostream;
25 /**
26  * Condition for a single property.
27  *
28  * This condition is true only if the property returns a boolean
29  * true value.
30  */
31 class SGPropertyCondition : public SGCondition
32 {
33 public:
34   SGPropertyCondition ( SGPropertyNode *prop_root,
35                         const char * propname  );
36   virtual ~SGPropertyCondition ();
37   virtual bool test () const { return _node->getBoolValue(); }
38   virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
39     { props.insert(_node.get()); }
40 private:
41   SGConstPropertyNode_ptr _node;
42 };
43
44 /**
45  * Condition with constant value
46  *
47  */
48 class SGConstantCondition : public SGCondition
49 {
50 public:
51   SGConstantCondition (bool v) : _value(v) { ; }
52   virtual bool test () const { return _value; }
53 private:
54   bool _value;
55 };
56
57 /**
58  * Condition for a 'not' operator.
59  *
60  * This condition is true only if the child condition is false.
61  */
62 class SGNotCondition : public SGCondition
63 {
64 public:
65   SGNotCondition (SGCondition * condition);
66   virtual ~SGNotCondition ();
67   virtual bool test () const;
68   virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const;
69 private:
70   SGSharedPtr<SGCondition> _condition;
71 };
72
73
74 /**
75  * Condition for an 'and' group.
76  *
77  * This condition is true only if all of the conditions
78  * in the group are true.
79  */
80 class SGAndCondition : public SGCondition
81 {
82 public:
83   SGAndCondition ();
84   virtual ~SGAndCondition ();
85   virtual bool test () const;
86                                 // transfer pointer ownership
87   virtual void addCondition (SGCondition * condition);
88   virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const;
89 private:
90   std::vector<SGSharedPtr<SGCondition> > _conditions;
91 };
92
93
94 /**
95  * Condition for an 'or' group.
96  *
97  * This condition is true if at least one of the conditions in the
98  * group is true.
99  */
100 class SGOrCondition : public SGCondition
101 {
102 public:
103   SGOrCondition ();
104   virtual ~SGOrCondition ();
105   virtual bool test () const;
106                                 // transfer pointer ownership
107   virtual void addCondition (SGCondition * condition);
108   virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const;
109 private:
110   std::vector<SGSharedPtr<SGCondition> > _conditions;
111 };
112
113
114 /**
115  * Abstract base class for property comparison conditions.
116  */
117 class SGComparisonCondition : public SGCondition
118 {
119 public:
120   enum Type {
121     LESS_THAN,
122     GREATER_THAN,
123     EQUALS
124   };
125   SGComparisonCondition (Type type, bool reverse = false);
126   virtual ~SGComparisonCondition ();
127   virtual bool test () const;
128   virtual void setLeftProperty( SGPropertyNode *prop_root,
129                                 const char * propname );
130   virtual void setRightProperty( SGPropertyNode *prop_root,
131                                  const char * propname );
132   virtual void setPrecisionProperty( SGPropertyNode *prop_root,
133                                  const char * propname );
134   // will make a local copy
135   virtual void setLeftValue (const SGPropertyNode * value);
136   virtual void setRightValue (const SGPropertyNode * value);
137   virtual void setPrecisionValue (const SGPropertyNode * value);
138   
139   void setLeftDExpression(SGExpressiond* dexp);
140   void setRightDExpression(SGExpressiond* dexp);
141   void setPrecisionDExpression(SGExpressiond* dexp);
142   
143   virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const;
144 private:
145   Type _type;
146   bool _reverse;
147   SGPropertyNode_ptr _left_property;
148   SGPropertyNode_ptr _right_property;
149   SGPropertyNode_ptr _precision_property;
150   
151   SGSharedPtr<SGExpressiond> _left_dexp;
152   SGSharedPtr<SGExpressiond> _right_dexp;
153   SGSharedPtr<SGExpressiond> _precision_dexp;
154 };
155
156
157 ////////////////////////////////////////////////////////////////////////
158 // Implementation of SGCondition.
159 ////////////////////////////////////////////////////////////////////////
160
161 SGCondition::SGCondition ()
162 {
163 }
164
165 SGCondition::~SGCondition ()
166 {
167 }
168
169
170 ////////////////////////////////////////////////////////////////////////
171 // Implementation of SGPropertyCondition.
172 ////////////////////////////////////////////////////////////////////////
173
174 SGPropertyCondition::SGPropertyCondition ( SGPropertyNode *prop_root,
175                                            const char *propname )
176     : _node( prop_root->getNode(propname, true) )
177 {
178 }
179
180 SGPropertyCondition::~SGPropertyCondition ()
181 {
182 }
183
184
185 ////////////////////////////////////////////////////////////////////////
186 // Implementation of SGNotCondition.
187 ////////////////////////////////////////////////////////////////////////
188
189 SGNotCondition::SGNotCondition (SGCondition * condition)
190   : _condition(condition)
191 {
192 }
193
194 SGNotCondition::~SGNotCondition ()
195 {
196 }
197
198 bool
199 SGNotCondition::test () const
200 {
201   return !(_condition->test());
202 }
203
204 void
205 SGNotCondition::collectDependentProperties(std::set<const SGPropertyNode*>& props) const
206 {
207     _condition->collectDependentProperties(props);
208 }
209
210 ////////////////////////////////////////////////////////////////////////
211 // Implementation of SGAndCondition.
212 ////////////////////////////////////////////////////////////////////////
213
214 SGAndCondition::SGAndCondition ()
215 {
216 }
217
218 SGAndCondition::~SGAndCondition ()
219 {
220 }
221
222 bool
223 SGAndCondition::test () const
224 {
225   for( size_t i = 0; i < _conditions.size(); i++ )
226   {
227     if (!_conditions[i]->test())
228       return false;
229   }
230   return true;
231 }
232
233 void
234 SGAndCondition::addCondition (SGCondition * condition)
235 {
236   _conditions.push_back(condition);
237 }
238
239 void
240 SGAndCondition::collectDependentProperties(std::set<const SGPropertyNode*>& props) const
241 {
242   for( size_t i = 0; i < _conditions.size(); i++ )
243     _conditions[i]->collectDependentProperties(props);
244 }
245
246
247 ////////////////////////////////////////////////////////////////////////
248 // Implementation of SGOrCondition.
249 ////////////////////////////////////////////////////////////////////////
250
251 SGOrCondition::SGOrCondition ()
252 {
253 }
254
255 SGOrCondition::~SGOrCondition ()
256 {
257 }
258
259 bool
260 SGOrCondition::test () const
261 {
262   for( size_t i = 0; i < _conditions.size(); i++ )
263   {
264     if (_conditions[i]->test())
265       return true;
266   }
267   return false;
268 }
269
270 void
271 SGOrCondition::addCondition (SGCondition * condition)
272 {
273   _conditions.push_back(condition);
274 }
275
276 void
277 SGOrCondition::collectDependentProperties(std::set<const SGPropertyNode*>& props) const
278 {
279   for( size_t i = 0; i < _conditions.size(); i++ )
280     _conditions[i]->collectDependentProperties(props);
281 }
282
283
284 ////////////////////////////////////////////////////////////////////////
285 // Implementation of SGComparisonCondition.
286 ////////////////////////////////////////////////////////////////////////
287
288 template<typename T> 
289 static int doComp( T v1, T v2, T e )
290 {
291   T d = v1 - v2;
292   if( d < -e )
293     return SGComparisonCondition::LESS_THAN;
294   else if( d > e )
295     return SGComparisonCondition::GREATER_THAN;
296   else
297     return SGComparisonCondition::EQUALS;
298 }
299
300 static int
301 doComparison (const SGPropertyNode * left, const SGPropertyNode * right, const SGPropertyNode * precision )
302 {
303   using namespace simgear;
304   switch (left->getType()) {
305   case props::BOOL: {
306     bool v1 = left->getBoolValue();
307     bool v2 = right->getBoolValue();
308     if (v1 < v2)
309       return SGComparisonCondition::LESS_THAN;
310     else if (v1 > v2)
311       return SGComparisonCondition::GREATER_THAN;
312     else
313       return SGComparisonCondition::EQUALS;
314     break;
315   }
316   case props::INT:
317     return doComp<int>(left->getIntValue(), right->getIntValue(), 
318            precision ? std::abs(precision->getIntValue()/2) : 0 );
319
320   case props::LONG:
321     return doComp<long>(left->getLongValue(), right->getLongValue(), 
322            precision ? std::abs(precision->getLongValue()/2L) : 0L );
323
324   case props::FLOAT:
325     return doComp<float>(left->getFloatValue(), right->getFloatValue(), 
326            precision ? std::fabs(precision->getFloatValue()/2.0f) : 0.0f );
327
328   case props::DOUBLE:
329     return doComp<double>(left->getDoubleValue(), right->getDoubleValue(), 
330            precision ? std::fabs(precision->getDoubleValue()/2.0) : 0.0 );
331
332   case props::STRING:
333   case props::NONE:
334   case props::UNSPECIFIED: {
335     size_t l = precision ? precision->getLongValue() : string::npos;
336     string v1 = string(left->getStringValue()).substr(0,l);
337     string v2 = string(right->getStringValue()).substr(0,l);
338     if (v1 < v2)
339       return SGComparisonCondition::LESS_THAN;
340     else if (v1 > v2)
341       return SGComparisonCondition::GREATER_THAN;
342     else
343       return SGComparisonCondition::EQUALS;
344     break;
345   }
346   default:
347     throw sg_exception("condition: unrecognized node type in comparison");
348   }
349   
350   return 0;
351 }
352
353
354 SGComparisonCondition::SGComparisonCondition (Type type, bool reverse)
355   : _type(type),
356     _reverse(reverse)
357 {
358 }
359
360 SGComparisonCondition::~SGComparisonCondition ()
361 {
362 }
363
364 bool
365 SGComparisonCondition::test () const
366 {
367                                 // Always fail if incompletely specified
368   if (!_left_property || !_right_property)
369     return false;
370
371   // Get LESS_THAN, EQUALS, or GREATER_THAN
372   if (_left_dexp) {
373     _left_property->setDoubleValue(_left_dexp->getValue(NULL));
374   }
375   
376   if (_right_dexp) {
377     _right_property->setDoubleValue(_right_dexp->getValue(NULL));
378   }
379
380   if (_precision_dexp) {
381     _precision_property->setDoubleValue(_precision_dexp->getValue(NULL));
382   }
383         
384   int cmp = doComparison(_left_property, _right_property, _precision_property );
385   if (!_reverse)
386     return (cmp == _type);
387   else
388     return (cmp != _type);
389 }
390
391 void
392 SGComparisonCondition::setLeftProperty( SGPropertyNode *prop_root,
393                                         const char * propname )
394 {
395   _left_property = prop_root->getNode(propname, true);
396 }
397
398 void
399 SGComparisonCondition::setRightProperty( SGPropertyNode *prop_root,
400                                          const char * propname )
401 {
402   _right_property = prop_root->getNode(propname, true);
403 }
404
405 void
406 SGComparisonCondition::setPrecisionProperty( SGPropertyNode *prop_root,
407                                          const char * propname )
408 {
409   _precision_property = prop_root->getNode(propname, true);
410 }
411
412 void
413 SGComparisonCondition::setLeftValue (const SGPropertyNode *node)
414 {
415   _left_property = new SGPropertyNode(*node);
416 }
417
418 void
419 SGComparisonCondition::setPrecisionValue (const SGPropertyNode *node)
420 {
421   _precision_property = new SGPropertyNode(*node);
422 }
423
424 void
425 SGComparisonCondition::setRightValue (const SGPropertyNode *node)
426 {
427   _right_property = new SGPropertyNode(*node);
428 }
429
430 void
431 SGComparisonCondition::setLeftDExpression(SGExpressiond* dexp)
432 {
433   _left_property = new SGPropertyNode();
434   _left_dexp = dexp;
435 }
436
437 void
438 SGComparisonCondition::setRightDExpression(SGExpressiond* dexp)
439 {
440   _right_property = new SGPropertyNode();
441   _right_dexp = dexp;
442 }
443
444 void
445 SGComparisonCondition::setPrecisionDExpression(SGExpressiond* dexp)
446 {
447   _precision_property = new SGPropertyNode();
448   _precision_dexp = dexp;
449 }
450
451 void
452 SGComparisonCondition::collectDependentProperties(std::set<const SGPropertyNode*>& props) const
453 {
454   if (_left_dexp)
455     _left_dexp->collectDependentProperties(props);
456   else
457     props.insert(_left_property);
458   
459   if (_right_dexp)
460     _right_dexp->collectDependentProperties(props);
461   else
462     props.insert(_right_property);
463   
464   if (_precision_dexp)
465     _precision_dexp->collectDependentProperties(props);
466   else if (_precision_property)
467     props.insert(_precision_property);
468   
469 }
470
471 ////////////////////////////////////////////////////////////////////////
472 // Read a condition and use it if necessary.
473 ////////////////////////////////////////////////////////////////////////
474
475                                 // Forward declaration
476 static SGCondition * readCondition( SGPropertyNode *prop_root,
477                                     const SGPropertyNode *node );
478
479 static SGCondition *
480 readPropertyCondition( SGPropertyNode *prop_root,
481                        const SGPropertyNode *node )
482 {
483   return new SGPropertyCondition( prop_root, node->getStringValue() );
484 }
485
486 static SGCondition *
487 readNotCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
488 {
489   int nChildren = node->nChildren();
490   for (int i = 0; i < nChildren; i++) {
491     const SGPropertyNode * child = node->getChild(i);
492     SGCondition * condition = readCondition(prop_root, child);
493     if (condition != 0)
494       return new SGNotCondition(condition);
495   }
496   SG_LOG(SG_COCKPIT, SG_ALERT, "empty 'not' condition");
497   return 0;
498 }
499
500 static SGCondition *
501 readAndConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
502 {
503   SGAndCondition * andCondition = new SGAndCondition;
504   int nChildren = node->nChildren();
505   for (int i = 0; i < nChildren; i++) {
506     const SGPropertyNode * child = node->getChild(i);
507     SGCondition * condition = readCondition(prop_root, child);
508     if (condition != 0)
509       andCondition->addCondition(condition);
510   }
511   return andCondition;
512 }
513
514 static SGCondition *
515 readOrConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
516 {
517   SGOrCondition * orCondition = new SGOrCondition;
518   int nChildren = node->nChildren();
519   for (int i = 0; i < nChildren; i++) {
520     const SGPropertyNode * child = node->getChild(i);
521     SGCondition * condition = readCondition(prop_root, child);
522     if (condition != 0)
523       orCondition->addCondition(condition);
524   }
525   return orCondition;
526 }
527
528 static SGCondition *
529 readComparison( SGPropertyNode *prop_root,
530                 const SGPropertyNode *node,
531                 SGComparisonCondition::Type type,
532                 bool reverse)
533 {
534   SGComparisonCondition * condition = new SGComparisonCondition(type, reverse);
535   if (node->nChildren() < 2 || node->nChildren() > 3 ) {
536     throw sg_exception("condition: comparison without two or three children");
537   }
538   
539   const SGPropertyNode* left = node->getChild(0), 
540     *right = node->getChild(1);
541
542   {
543     string leftName(left->getName());
544     if (leftName == "property") {
545       condition->setLeftProperty(prop_root, left->getStringValue());
546     } else if (leftName == "value") {
547       condition->setLeftValue(left);
548     } else if (leftName == "expression") {
549       SGExpressiond* exp = SGReadDoubleExpression(prop_root, left->getChild(0));
550       condition->setLeftDExpression(exp);
551     } else {
552       throw sg_exception("Unknown condition comparison left child:" + leftName);
553     }
554   }
555     
556   {
557     string rightName(right->getName());
558     if (rightName == "property") {
559       condition->setRightProperty(prop_root, right->getStringValue());
560     } else if (rightName == "value") {
561       condition->setRightValue(right);
562     } else if (rightName == "expression") {
563       SGExpressiond* exp = SGReadDoubleExpression(prop_root, right->getChild(0));
564       condition->setRightDExpression(exp);
565     } else {
566       throw sg_exception("Unknown condition comparison right child:" + rightName);
567     }
568   }
569   
570   if( node->nChildren() == 3 ) {
571     const SGPropertyNode *n = node->getChild(2);
572     string name(n->getName());
573     if (name == "precision-property") {
574       condition->setPrecisionProperty(prop_root, n->getStringValue());
575     } else if (name == "precision-value") {
576       condition->setPrecisionValue(n);
577     } else if (name == "precision-expression") {
578       SGExpressiond* exp = SGReadDoubleExpression(prop_root, n->getChild(0));
579       condition->setPrecisionDExpression(exp);
580     } else {
581       throw sg_exception("Unknown condition comparison precision child:" + name );
582     }
583   }
584   
585   return condition;
586 }
587
588 static SGCondition *
589 readCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
590 {
591   const string &name = node->getName();
592   if (name == "property")
593     return readPropertyCondition(prop_root, node);
594   else if (name == "not")
595     return readNotCondition(prop_root, node);
596   else if (name == "and")
597     return readAndConditions(prop_root, node);
598   else if (name == "or")
599     return readOrConditions(prop_root, node);
600   else if (name == "less-than")
601     return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
602                           false);
603   else if (name == "less-than-equals")
604     return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
605                           true);
606   else if (name == "greater-than")
607     return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
608                           false);
609   else if (name == "greater-than-equals")
610     return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
611                           true);
612   else if (name == "equals")
613     return readComparison(prop_root, node, SGComparisonCondition::EQUALS,
614                           false);
615   else if (name == "not-equals")
616     return readComparison(prop_root, node, SGComparisonCondition::EQUALS, true);
617   else if (name == "false") 
618     return new SGConstantCondition(false);
619   else if (name == "true")
620     return new SGConstantCondition(true);
621   else
622     return 0;
623 }
624
625
626 ////////////////////////////////////////////////////////////////////////
627 // Implementation of SGConditional.
628 ////////////////////////////////////////////////////////////////////////
629
630 SGConditional::SGConditional ()
631   : _condition (0)
632 {
633 }
634
635 SGConditional::~SGConditional ()
636 {
637 }
638
639 void
640 SGConditional::setCondition (SGCondition * condition)
641 {
642   _condition = condition;
643 }
644
645 bool
646 SGConditional::test () const
647 {
648   return ((_condition == 0) || _condition->test());
649 }
650
651
652 // The top-level is always an implicit 'and' group
653 SGCondition *
654 sgReadCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
655 {
656   return readAndConditions(prop_root, node);
657 }
658
659
660 // end of condition.cxx