Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

Arith.cxx

Go to the documentation of this file.
00001 // $Header: /nfs/slac/g/glast/ground/cvs/xmlUtil/src/Arith.cxx,v 1.4 2002/07/23 20:39:09 jrb Exp $
00002 
00003 #include <string>
00004 #include "xmlUtil/Arith.h"
00005 #include "xml/Dom.h"
00006 #include <dom/DOM_Document.hpp>
00007 
00008 namespace xmlUtil {
00009 
00010   inline DOM_Element firstEltChild(DOM_Element& elt) {
00011     DOM_Node curNode = elt.getFirstChild();
00012     if (curNode == DOM_Node()) return DOM_Element();
00013     while (curNode.getNodeType() != DOM_Node::ELEMENT_NODE) {
00014       curNode = curNode.getNextSibling();
00015       if (curNode == DOM_Node()) return DOM_Element();
00016     }
00017     return DOM_Element(static_cast<DOM_Element &>(curNode));
00018   }
00019   
00020   inline  DOM_Element nextEltSibling(DOM_Element& elt) {
00021     DOM_Node curNode = elt.getNextSibling();
00022     if (curNode == DOM_Node()) return DOM_Element();
00023     while (curNode.getNodeType() != DOM_Node::ELEMENT_NODE) {
00024       curNode = curNode.getNextSibling();
00025       if (curNode == DOM_Node()) return DOM_Element();
00026     }
00027     return DOM_Element(static_cast<DOM_Element &>(curNode));
00028   }
00029 
00030   // Define statics here.
00031   // Rather than continually creating and destroying DOMStrings
00032   // needed for comparison, initialize them once and for all in 
00033   // init()
00034   Arith::ptrDOMString * Arith::typeNames;
00035   Arith::ptrDOMString Arith::valString;   // a DOMString containing "value"
00036   Arith::ptrDOMString Arith::refToString;
00037   Arith::ptrDOMString Arith::constString;
00038   Arith::ptrDOMString Arith::referString;
00039   Arith::ptrDOMString Arith::addString;
00040   Arith::ptrDOMString Arith::minusString;
00041   Arith::ptrDOMString Arith::uminusString;
00042   Arith::ptrDOMString Arith::mulString;
00043   Arith::ptrDOMString Arith::quoString;
00044   Arith::ptrDOMString Arith::maxString;
00045   Arith::ptrDOMString Arith::notesString;
00046   Arith::ptrDOMString Arith::lengthString;
00047   Arith::ptrDOMString Arith::cmString;
00048   Arith::ptrDOMString Arith::mString;
00049   
00050   Arith::Arith(const DOM_Element elt) {
00051     int i = 0;
00052     bool notFound = true;
00053     DOMString tagName = elt.getTagName();
00054     m_elt = elt;
00055     m_evaluated = false;
00056     m_tag = -1;
00057     if (typeNames == 0) init();
00058 
00059     while ((notFound) && (i < ETAG_n)) {
00060       DOMString *p = typeNames[i];
00061       DOMString tmp = DOMString(*p);
00062       if (tagName.equals(tmp) ) {
00063         m_tag = i;
00064         notFound = false;
00065       }
00066       i++;
00067     }
00068   }
00069 
00070   double Arith::evaluate() {
00071     if (!m_evaluated) { // evaluate
00072       DOM_Element curElt;
00073       switch(m_tag) {
00074       case ETAG_const: {
00075         DOMString val = m_elt.getAttribute(*valString);
00076         if (!(val.equals(DOMString()) ) ) { //got something 
00077           // Had better convert properly to a double
00078           m_number = atof(xml::Dom::transToChar(val));
00079           m_number *= getUnitsScale(m_elt);
00080         }
00081         else  { // must have a single operator child or refer child
00082           // either of which can be evaluated, optionally preceded
00083           // by a <notes> child, which we ignore
00084           curElt = firstEltChild(m_elt);
00085           if (curElt.getTagName().equals(*notesString)) { // move on
00086             DOM_Node next = curElt.getNextSibling();
00087             curElt = static_cast <DOM_Element &>(next);
00088           }
00089           m_number = Arith(curElt).evaluate();
00090         }
00091         break;
00092       }
00093       case ETAG_refer: {
00094         // Find the element pointed to and evaluate it
00095         DOMString ref = m_elt.getAttribute(*refToString);
00096         curElt = (m_elt.getOwnerDocument()).getElementById(ref);
00097         if (curElt.getTagName().equals("prim")) {
00098           m_number = 
00099             atof(xml::Dom::transToChar(curElt.getAttribute(*valString)));
00100           m_number *= getUnitsScale(curElt);
00101         }
00102         else {
00103           m_number = Arith(curElt).evaluate();
00104         }
00105         break;
00106       }
00107       case ETAG_uminus: {
00108         // Have a single child
00109         curElt = firstEltChild(m_elt);
00110         m_number = -(Arith(curElt).evaluate());
00111         break;
00112       }
00113       // Do the work elsewhere for the remaining operators
00114       case ETAG_add: {
00115         m_number = add();
00116         break;
00117       }
00118       
00119       case ETAG_mul: {
00120         m_number = mul();
00121         break;
00122       }
00123       
00124       case ETAG_minus: {
00125         m_number = minus();
00126         break;
00127       }
00128       case ETAG_quo: {
00129         m_number = quo();
00130         break;
00131       }
00132       
00133       case ETAG_max: {
00134         m_number = myMax();
00135         break;
00136       }
00137       default: {
00138         return 0;
00139       }
00140       }
00141       m_evaluated = true;
00142     }
00143     return m_number;
00144   }
00145 
00146   double Arith::add() {
00147     double  ans = 0.0;
00148     DOM_Element elt = firstEltChild(m_elt);
00149     ans += Arith(elt).evaluate();
00150     elt = nextEltSibling(elt);
00151     while (elt != DOM_Element()) {
00152       ans += Arith(elt).evaluate();
00153       elt = nextEltSibling(elt);
00154     }
00155     return ans;
00156   }
00157 
00158   double Arith::mul() {
00159     double  ans = 1.0;
00160     DOM_Element elt = firstEltChild(m_elt);
00161     ans *= Arith(elt).evaluate();
00162     elt = nextEltSibling(elt);
00163     while (elt != DOM_Element()) {
00164       ans *= Arith(elt).evaluate();
00165       elt = nextEltSibling(elt);
00166     }
00167     return ans;
00168   }
00169 
00170   double Arith::myMax() {
00171     DOM_Element elt = firstEltChild(m_elt);
00172     double  ans = Arith(elt).evaluate();
00173     elt = nextEltSibling(elt);
00174     while (elt != DOM_Element()) {
00175       double newAns = Arith(elt).evaluate();
00176       if (newAns > ans) ans = newAns;
00177       elt = nextEltSibling(elt);
00178     }
00179     return ans;
00180   }
00181   double Arith::minus() {
00182     double  ans;
00183     DOM_Element elt = firstEltChild(m_elt);
00184     ans = Arith(elt).evaluate();
00185     elt = nextEltSibling(elt);
00186     ans -= Arith(elt).evaluate();
00187     return ans;
00188   }
00189 
00190   double Arith::quo() {
00191     double  ans;
00192     double  divisor;
00193     DOM_Element elt = firstEltChild(m_elt);
00194     ans = Arith(elt).evaluate();
00195     elt = nextEltSibling(elt);
00196     divisor = Arith(elt).evaluate();  // check for 0?
00197     ans /= divisor;
00198     return ans;
00199   }
00200 
00201   // Store value back in DOM (evaluating first if necessary)
00202   void Arith::saveValue() {
00203     // Only makes sense for a const
00204     if (m_tag != ETAG_const) return;
00205 
00206     if (!m_evaluated) evaluate();
00207 
00208     // Check if we're supposed to be an int.  If so, coerce
00209     // m_number to be nearby int in case of round-off error 
00210     if (DOMString("int").equals(m_elt.getAttribute("type"))) {
00211       // If we're not already a perfect int, attempt to fix
00212       // so that we round the right way.
00213       // Otherwise, leave well enough alone
00214       long int intValue = m_number;
00215       double   intified = intValue;
00216       if (intified != m_number) {
00217         double fixup = 0.5;
00218         if (m_number < 0.0) fixup = -fixup;
00219         long int  intValue = (m_number + fixup);  
00220         m_number = intValue;
00221       }
00222     }
00223     // Answer will always be returned in mm for length-type
00224     // constants, so, just in case, this attribute should be
00225     // set to "mm".  If we're not a length-type constant,
00226     // setting this attribute is harmless.
00227 
00228     xml::Dom::addAttribute(m_elt, *valString, m_number);
00229     xml::Dom::addAttribute(m_elt, std::string("unitLength"), 
00230                            std::string("mm"));
00231   }
00232 
00233   double Arith::getUnitsScale(const DOM_Element& elt) {
00234     if (!(elt.getAttribute("uType")).equals(*lengthString) ) {
00235       return 1.0;
00236     }
00237 
00238     DOMString unitLength = elt.getAttribute("unitLength");
00239     if (unitLength.equals(*cmString)) return 10.0;
00240     else if (unitLength.equals(*mString)) return 1000.0;
00241     else return 1.0;
00242   }
00243 
00244   void Arith::init() {
00245     constString = new DOMString("const");
00246     referString = new DOMString("refer");
00247     addString = new DOMString("add");
00248     minusString = new DOMString("minus");
00249     mulString = new DOMString("mul");
00250     quoString = new DOMString("quo");
00251     uminusString = new DOMString("uminus");
00252     maxString = new DOMString("max");
00253     notesString = new DOMString("notes");
00254     lengthString = new DOMString("length");
00255     cmString = new DOMString("cm");
00256     mString = new DOMString("m");
00257 
00258     valString = new DOMString("value");
00259     refToString = new DOMString("refTo");
00260 
00261 
00262     typeNames = new ptrDOMString[ETAG_n];
00263     typeNames[ETAG_const] = constString;
00264     typeNames[ETAG_refer] = referString;
00265     typeNames[ETAG_add] = addString;
00266     typeNames[ETAG_minus] = minusString;
00267     typeNames[ETAG_mul] = mulString;
00268     typeNames[ETAG_quo] = quoString;
00269     typeNames[ETAG_uminus] = uminusString;
00270     typeNames[ETAG_max] = maxString;
00271   }
00272 }

Generated on Wed Oct 16 14:02:47 2002 by doxygen1.2.13.1 written by Dimitri van Heesch, © 1997-2001