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