μHAL (v2.7.9)
Part of the IPbus software repository
XmlParser.hxx
Go to the documentation of this file.
1 /*
2 ---------------------------------------------------------------------------
3 
4  This file is part of uHAL.
5 
6  uHAL is a hardware access library and programming framework
7  originally developed for upgrades of the Level-1 trigger of the CMS
8  experiment at CERN.
9 
10  uHAL is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  uHAL is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with uHAL. If not, see <http://www.gnu.org/licenses/>.
22 
23 
24  Andrew Rose, Imperial College, London
25  email: awr01 <AT> imperial.ac.uk
26 
27  Marc Magrans de Abril, CERN
28  email: marc.magrans.de.abril <AT> cern.ch
29 
30 ---------------------------------------------------------------------------
31 */
32 
39 #include <sstream>
40 
41 namespace uhal
42 {
43 
44  template < typename R >
46  {
47  }
48 
49 
50  template < typename R >
52  {
53  }
54 
55 
56 
57 
58  template < typename R , typename T >
60  mT ( aT )
61  {
62  }
63 
64 
65  template < typename R , typename T >
67  {
68  return ( mT ) ( aNode );
69  }
70 
71 
72  template < typename R , typename T >
74  mT ( aT )
75  {
76  }
77 
78 
79  template < typename R , typename T >
81  {
82  return ( *mT ) ( aNode );
83  }
84 
85 
86 
87 
88  template < typename R >
90  mRuleId ( 0 ),
91  mRequiredHash ( 0x0000000000000000 ),
92  mForbiddenHash ( 0x0000000000000000 ),
93  mFuncPtr ( NULL )
94  {
95  }
96 
97 
98  template < typename R >
100  {
101  if ( mFuncPtr )
102  {
103  delete mFuncPtr;
104  mFuncPtr = NULL;
105  }
106  }
107 
108 
109  template < typename R >
110  Rule<R>& Rule<R>::require ( const std::string& aStr )
111  {
112  if ( mForbidden.find ( aStr ) != mForbidden.end() )
113  {
114  exception::ContradictoryParserRule lExc;
115  log ( lExc , "Contradictory rule for attribute ", Quote ( aStr ) );
116  throw lExc;
117  }
118 
119  mRequired.insert ( aStr );
120  return *this;
121  }
122 
123 
124  template < typename R >
125  Rule<R>& Rule<R>::forbid ( const std::string& aStr )
126  {
127  if ( mRequired.find ( aStr ) != mRequired.end() )
128  {
129  exception::ContradictoryParserRule lExc;
130  log ( lExc , "Contradictory rule for attribute ", Quote ( aStr ) );
131  throw lExc;
132  }
133 
134  mForbidden.insert ( aStr );
135  return *this;
136  }
137 
138 
139  template < typename R >
140  Rule<R>& Rule<R>::optional ( const std::string& aStr )
141  {
142  mOptional.insert ( aStr );
143  return *this;
144  }
145 
146 
147  template < typename R >
148  std::string Rule<R>::description() const
149  {
150  std::set<std::string>::const_iterator lIt;
151  std::stringstream lStr;
152  lStr << "Rule " << mRuleId ;
153  lIt = mRequired.begin();
154 
155  if ( lIt != mRequired.end() )
156  {
157  lStr << " {Require : ";
158 
159  while ( true )
160  {
161  lStr << *lIt ;
162 
163  if ( ( ++lIt ) == mRequired.end() )
164  {
165  break;
166  }
167 
168  lStr<< ", ";
169  }
170 
171  lStr << "}";
172  }
173 
174  lIt = mForbidden.begin();
175 
176  if ( lIt != mForbidden.end() )
177  {
178  lStr << " {Forbid : ";
179 
180  while ( true )
181  {
182  lStr << *lIt ;
183 
184  if ( ( ++lIt ) == mForbidden.end() )
185  {
186  break;
187  }
188 
189  lStr<< ", ";
190  }
191 
192  lStr << "}";
193  }
194 
195  lIt = mOptional.begin();
196 
197  if ( lIt != mOptional.end() )
198  {
199  lStr << " {Optional : ";
200 
201  while ( true )
202  {
203  lStr << *lIt ;
204 
205  if ( ( ++lIt ) == mOptional.end() )
206  {
207  break;
208  }
209 
210  lStr<< ", ";
211  }
212 
213  lStr << "}";
214  }
215 
216  return lStr.str();
217  }
218 
219 
220  template < typename R >
222  {
223  if ( mFuncPtr )
224  {
225  return ( *mFuncPtr ) ( aNode );
226  }
227  else
228  {
229  exception::NoActionSpecified lExc;
230  log ( lExc , "No action specified!" );
231  throw lExc;
232  }
233  }
234 
235 
236 
237 
238  template < typename R >
240  mNextHash ( 0x0000000000000001 ),
241  mRuleCounter ( 0 )
242  {
243  mHashes.clear();
244  }
245 
246 
247  template < typename R >
249  {
250  }
251 
252 
253  template < typename R >
254  template < typename T >
255  void Parser<R>::addRule ( const Rule<R> & aRule , T aCallbackHandler )
256  {
257  mRules.push_back ( aRule );
258  Rule<R>& lRule ( mRules.back() );
259 
260  for ( std::set<std::string>::iterator lIt = lRule.mRequired.begin() ; lIt != lRule.mRequired.end() ; ++lIt )
261  {
262  boost::unordered_map< std::string , uint64_t >::iterator lIt2 ( mHashes.find ( *lIt ) );
263 
264  if ( lIt2 == mHashes.end() )
265  {
266  if ( mNextHash == 0x0000000000000000 )
267  {
268  exception::TooManyAttributes lExc;
269  log ( lExc , "Too many attributes" );
270  throw lExc;
271  }
272 
273  lRule.mRequiredHash |= mNextHash;
274  mHashes.insert ( std::make_pair ( *lIt , mNextHash ) );
275  mNextHash <<= 1;
276  }
277  else
278  {
279  lRule.mRequiredHash |= lIt2->second;
280  }
281  }
282 
283  for ( std::set<std::string>::iterator lIt = lRule.mForbidden.begin() ; lIt != lRule.mForbidden.end() ; ++lIt )
284  {
285  boost::unordered_map< std::string , uint64_t >::iterator lIt2 ( mHashes.find ( *lIt ) );
286 
287  if ( lIt2 == mHashes.end() )
288  {
289  if ( mNextHash == 0x0000000000000000 )
290  {
291  exception::TooManyAttributes lExc;
292  log ( lExc , "Too many attributes" );
293  throw lExc;
294  }
295 
296  lRule.mForbiddenHash |= mNextHash;
297  mHashes.insert ( std::make_pair ( *lIt , mNextHash ) );
298  mNextHash <<= 1;
299  }
300  else
301  {
302  lRule.mForbiddenHash |= lIt2->second;
303  }
304  }
305 
306  for ( std::set<std::string>::iterator lIt = lRule.mOptional.begin() ; lIt != lRule.mOptional.end() ; ++lIt )
307  {
308  boost::unordered_map< std::string , uint64_t >::iterator lIt2 ( mHashes.find ( *lIt ) );
309 
310  if ( lIt2 == mHashes.end() )
311  {
312  if ( mNextHash == 0x0000000000000000 )
313  {
314  exception::TooManyAttributes lExc;
315  log ( lExc , "Too many attributes" );
316  throw lExc;
317  }
318 
319  mHashes.insert ( std::make_pair ( *lIt , mNextHash ) );
320  mNextHash <<= 1;
321  }
322  }
323 
324  lRule.mRuleId = ++mRuleCounter;
325  lRule.mFuncPtr = new FunctionObject<R,T> ( aCallbackHandler );
326  }
327 
328 
329  template < typename R >
331  {
332  uint64_t lHash ( 0x0000000000000000 );
333 
334  for ( pugi::xml_attribute lAttr = aNode.first_attribute(); lAttr; lAttr = lAttr.next_attribute() )
335  {
336  boost::unordered_map< std::string , uint64_t >::iterator lIt2 ( mHashes.find ( lAttr.name() ) );
337 
338  if ( lIt2 == mHashes.end() )
339  {
340  exception::UnknownAttribute lExc;
341  log ( lExc , "Parser failed because of unknown attribute ", Quote ( lAttr.name() ) );
342  throw lExc;
343  }
344 
345  lHash |= lIt2->second;
346  }
347 
348  std::deque< Rule<R>* > lPassed;
349  std::deque< Rule<R>* > lFailedRequired;
350  std::deque< Rule<R>* > lFailedForbidden;
351  int i ( 0 );
352 
353  for ( typename std::deque< Rule<R> >::iterator lIt = mRules.begin() ; lIt != mRules.end() ; ++lIt, ++i )
354  {
355  if ( lIt->mForbiddenHash & lHash )
356  {
357  lFailedForbidden.push_back ( & ( *lIt ) );
358  }
359  else if ( lIt->mRequiredHash & ~lHash )
360  {
361  lFailedRequired.push_back ( & ( *lIt ) );
362  continue;
363  }
364  else
365  {
366  lPassed.push_back ( & ( *lIt ) );
367  }
368  }
369 
370  if ( lPassed.size() == 1 )
371  {
372  return ( *lPassed.front() ) ( aNode );
373  }
374 
375  if ( lPassed.size() > 1 )
376  {
377  log ( Warning() , "Ambiguity! " , Integer ( lPassed.size() ) ," rules passed. Attempting to find the rule with the most stringent requirements." );
378  Rule<R>* lMostStringent ( NULL );
379  uint32_t lCounter ( 0 );
380 
381  for ( typename std::deque< Rule<R>* >::iterator lIt = lPassed.begin(); lIt != lPassed.end(); ++lIt )
382  {
383  if ( lCounter < ( **lIt ).mRequired.size() )
384  {
385  lMostStringent = ( *lIt );
386  lCounter = ( **lIt ).mRequired.size();
387  }
388  else if ( lCounter == ( **lIt ).mRequired.size() )
389  {
390  lMostStringent = NULL;
391  }
392  }
393 
394  if ( !lMostStringent )
395  {
396  exception::AmbiguousParserRules lExc;
397  log ( lExc , "Ambiguity remains! Multiple rules passed " , Integer ( lCounter ) , " requirements." );
398  throw lExc;
399  }
400 
401  log ( Warning() , "In ambiguous case, selected " , lMostStringent->description() );
402  return ( *lMostStringent ) ( aNode );
403  }
404 
405  std::stringstream lStr;
406 
407  for ( pugi::xml_attribute lAttr = aNode.first_attribute(); lAttr; lAttr = lAttr.next_attribute() )
408  {
409  lStr << lAttr.name() << "=\"" << lAttr.value() << "\", ";
410  }
411 
412  std::string lString ( lStr.str() );
413  lString.resize ( lString.size() - 2 );
414  exception::NoRulesPassed lExc;
415  log ( lExc , "Node with attributes : " , lString , " failed all parser rules because : " );
416 
417  for ( typename std::deque< Rule<R>* >::iterator lIt = lFailedRequired.begin() ; lIt != lFailedRequired.end(); ++lIt )
418  {
419  std::stringstream lStr;
420  uint64_t lTemp ( ( **lIt ).mRequiredHash & ~lHash );
421 
422  for ( boost::unordered_map< std::string , uint64_t >::iterator lIt2 = mHashes.begin() ; lIt2 != mHashes.end() ; ++lIt2 )
423  {
424  if ( ( lIt2->second ) & lTemp )
425  {
426  lStr << "\"" << lIt2->first << "\", ";
427  }
428  }
429 
430  std::string lString ( lStr.str() );
431  lString.resize ( lString.size() - 2 );
432  log ( lExc , "Rule " , Integer ( ( **lIt ).mRuleId ) , " requires attributes : " , lString );
433  }
434 
435  for ( typename std::deque< Rule<R>* >::iterator lIt = lFailedForbidden.begin() ; lIt != lFailedForbidden.end(); ++lIt )
436  {
437  std::stringstream lStr;
438  uint64_t lTemp ( ( **lIt ).mForbiddenHash & lHash );
439 
440  for ( boost::unordered_map< std::string , uint64_t >::iterator lIt2 = mHashes.begin() ; lIt2 != mHashes.end() ; ++lIt2 )
441  {
442  if ( ( lIt2->second ) & lTemp )
443  {
444  lStr << "\"" << lIt2->first << "\", ";
445  }
446  }
447 
448  std::string lString ( lStr.str() );
449  lString.resize ( lString.size() - 2 );
450  log ( lExc , "Rule " , Integer ( ( **lIt ).mRuleId ) , " forbids attributes : " , lString );
451  }
452 
453  throw lExc;
454  }
455 
456 }
457 
pugi::xml_attribute
Definition: pugixml.hpp:349
uhal::Rule::operator()
R operator()(const pugi::xml_node &aNode)
Functor which converts an XML node to an object of template type R (Calls the function pointer,...
Definition: XmlParser.hxx:221
uhal::FunctionObject::FunctionObject
FunctionObject(T &aT)
Constructor.
Definition: XmlParser.hxx:59
uhal::Rule::mOptional
std::set< std::string > mOptional
The optional attributes for this rule.
Definition: XmlParser.hpp:198
uhal::Rule::mForbidden
std::set< std::string > mForbidden
The forbidden attributes for this rule.
Definition: XmlParser.hpp:196
uhal::FunctionObject
Class for wrapping bound functions and function objects as an object.
Definition: XmlParser.hpp:93
uhal::Parser::~Parser
~Parser()
Destructor.
Definition: XmlParser.hxx:248
uhal::Parser::Parser
Parser()
Default constructor.
Definition: XmlParser.hxx:239
uhal::Parser::mHashes
boost::unordered_map< std::string, uint64_t > mHashes
Map of the tags to the one-hot encoded hash.
Definition: XmlParser.hpp:241
uhal::Rule::mRuleId
uint32_t mRuleId
The ID of the rule.
Definition: XmlParser.hpp:201
uhal
Definition: HttpResponseGrammar.hpp:49
uhal::Rule::mFuncPtr
BaseFunctionObject< R > * mFuncPtr
An object wrapping the function pointer for the function to be called when the rule conditions are me...
Definition: XmlParser.hpp:208
uhal::Rule::description
std::string description() const
A function to return a string description of the rule.
Definition: XmlParser.hxx:148
pugi::xml_node::first_attribute
xml_attribute first_attribute() const
Definition: pugixml.cpp:5619
uhal::Rule::optional
Rule< R > & optional(const std::string &aStr)
Add an optional attribute to the rule.
Definition: XmlParser.hxx:140
uhal::log
void log(FatalLevel &aFatal, const T0 &aArg0)
Function to add a log entry at Fatal level.
Definition: log.hxx:20
uhal::Rule::forbid
Rule< R > & forbid(const std::string &aStr)
Add an forbidden attribute to the rule.
Definition: XmlParser.hxx:125
uhal::Integer
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
Definition: log_inserters.integer.hxx:43
uhal::Rule::mRequired
std::set< std::string > mRequired
The required attributes for this rule.
Definition: XmlParser.hpp:194
pugi::xml_node
Definition: pugixml.hpp:455
uhal::Rule
Rule for matching XML attributes.
Definition: XmlParser.hpp:145
uhal::Warning
WarningLevel Warning
Definition: LogLevels.cpp:79
uhal::Rule::mRequiredHash
uint64_t mRequiredHash
The hash for required attributes.
Definition: XmlParser.hpp:203
uhal::Rule::Rule
Rule()
Default constructor.
Definition: XmlParser.hxx:89
pugi::xml_attribute::next_attribute
xml_attribute next_attribute() const
Definition: pugixml.cpp:5160
uhal::BaseFunctionObject::BaseFunctionObject
BaseFunctionObject()
Default constructor.
Definition: XmlParser.hxx:45
uhal::Quote
_Quote< T > Quote(const T &aT)
Definition: log_inserters.quote.hxx:49
uhal::Rule::require
Rule< R > & require(const std::string &aStr)
Add a required attribute to the rule.
Definition: XmlParser.hxx:110
uhal::Parser::operator()
R operator()(const pugi::xml_node &aNode)
Functor which converts an XML node to an object of template type R.
Definition: XmlParser.hxx:330
uhal::Rule::~Rule
virtual ~Rule()
Destructor.
Definition: XmlParser.hxx:99
uhal::FunctionObject::mT
T mT
The function object or bound function which will be called when the object is evaluated (bracket oper...
Definition: XmlParser.hpp:112
uhal::Rule::mForbiddenHash
uint64_t mForbiddenHash
The hash for forbidden attributes.
Definition: XmlParser.hpp:205
uhal::BaseFunctionObject::~BaseFunctionObject
virtual ~BaseFunctionObject()
Destructor.
Definition: XmlParser.hxx:51
uhal::Parser::addRule
void addRule(const Rule< R > &aRule, T aCallbackHandler)
Method to add the rules to the parser.
Definition: XmlParser.hxx:255
uhal::FunctionObject::operator()
R operator()(const pugi::xml_node &aNode)
Functor which converts an XML node to an object of template type R.
Definition: XmlParser.hxx:66