μHAL (v2.6.5)
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  template < typename R >
51  {
52  }
53 
54 
55  template < typename R , typename T >
57  mT ( aT )
58  {
59  }
60 
61  template < typename R , typename T >
62  R FunctionObject<R,T>::operator() ( const pugi::xml_node& aNode )
63  {
64  return ( mT ) ( aNode );
65  }
66 
67  template < typename R , typename T >
69  mT ( aT )
70  {
71  }
72 
73  template < typename R , typename T >
74  R FunctionObject<R,T*>::operator() ( const pugi::xml_node& aNode )
75  {
76  return ( *mT ) ( aNode );
77  }
78 
79 
80  template < typename R >
82  mRuleId ( 0 ),
83  mRequiredHash ( 0x0000000000000000 ),
84  mForbiddenHash ( 0x0000000000000000 ),
85  mFuncPtr ( NULL )
86  {
87  }
88 
89  template < typename R >
91  {
92  if ( mFuncPtr )
93  {
94  delete mFuncPtr;
95  mFuncPtr = NULL;
96  }
97  }
98 
99  template < typename R >
100  Rule<R>& Rule<R>::require ( const std::string& aStr )
101  {
102  if ( mForbidden.find ( aStr ) != mForbidden.end() )
103  {
104  exception::ContradictoryParserRule lExc;
105  log ( lExc , "Contradictory rule for attribute ", Quote ( aStr ) );
106  throw lExc;
107  }
108 
109  mRequired.insert ( aStr );
110  return *this;
111  }
112 
113  template < typename R >
114  Rule<R>& Rule<R>::forbid ( const std::string& aStr )
115  {
116  if ( mRequired.find ( aStr ) != mRequired.end() )
117  {
118  exception::ContradictoryParserRule lExc;
119  log ( lExc , "Contradictory rule for attribute ", Quote ( aStr ) );
120  throw lExc;
121  }
122 
123  mForbidden.insert ( aStr );
124  return *this;
125  }
126 
127  template < typename R >
128  Rule<R>& Rule<R>::optional ( const std::string& aStr )
129  {
130  mOptional.insert ( aStr );
131  return *this;
132  }
133 
134  template < typename R >
135  std::string Rule<R>::description() const
136  {
137  std::set<std::string>::const_iterator lIt;
138  std::stringstream lStr;
139  lStr << "Rule " << mRuleId ;
140  lIt = mRequired.begin();
141 
142  if ( lIt != mRequired.end() )
143  {
144  lStr << " {Require : ";
145 
146  while ( true )
147  {
148  lStr << *lIt ;
149 
150  if ( ( ++lIt ) == mRequired.end() )
151  {
152  break;
153  }
154 
155  lStr<< ", ";
156  }
157 
158  lStr << "}";
159  }
160 
161  lIt = mForbidden.begin();
162 
163  if ( lIt != mForbidden.end() )
164  {
165  lStr << " {Forbid : ";
166 
167  while ( true )
168  {
169  lStr << *lIt ;
170 
171  if ( ( ++lIt ) == mForbidden.end() )
172  {
173  break;
174  }
175 
176  lStr<< ", ";
177  }
178 
179  lStr << "}";
180  }
181 
182  lIt = mOptional.begin();
183 
184  if ( lIt != mOptional.end() )
185  {
186  lStr << " {Optional : ";
187 
188  while ( true )
189  {
190  lStr << *lIt ;
191 
192  if ( ( ++lIt ) == mOptional.end() )
193  {
194  break;
195  }
196 
197  lStr<< ", ";
198  }
199 
200  lStr << "}";
201  }
202 
203  return lStr.str();
204  }
205 
206  template < typename R >
207  R Rule<R>::operator() ( const pugi::xml_node& aNode )
208  {
209  if ( mFuncPtr )
210  {
211  return ( *mFuncPtr ) ( aNode );
212  }
213  else
214  {
215  exception::NoActionSpecified lExc;
216  log ( lExc , "No action specified!" );
217  throw lExc;
218  }
219  }
220 
221 
222  template < typename R >
224  mNextHash ( 0x0000000000000001 ),
225  mRuleCounter ( 0 )
226  {
227  mHashes.clear();
228  }
229 
230  template < typename R >
232  {
233  }
234 
235 
236 
237  template < typename R >
238  template < typename T >
239  void Parser<R>::addRule ( const Rule<R> & aRule , T aCallbackHandler )
240  {
241  mRules.push_back ( aRule );
242  Rule<R>& lRule ( mRules.back() );
243 
244  for ( std::set<std::string>::iterator lIt = lRule.mRequired.begin() ; lIt != lRule.mRequired.end() ; ++lIt )
245  {
246  boost::unordered_map< std::string , uint64_t >::iterator lIt2 ( mHashes.find ( *lIt ) );
247 
248  if ( lIt2 == mHashes.end() )
249  {
250  if ( mNextHash == 0x0000000000000000 )
251  {
252  exception::TooManyAttributes lExc;
253  log ( lExc , "Too many attributes" );
254  throw lExc;
255  }
256 
257  lRule.mRequiredHash |= mNextHash;
258  mHashes.insert ( std::make_pair ( *lIt , mNextHash ) );
259  mNextHash <<= 1;
260  }
261  else
262  {
263  lRule.mRequiredHash |= lIt2->second;
264  }
265  }
266 
267  for ( std::set<std::string>::iterator lIt = lRule.mForbidden.begin() ; lIt != lRule.mForbidden.end() ; ++lIt )
268  {
269  boost::unordered_map< std::string , uint64_t >::iterator lIt2 ( mHashes.find ( *lIt ) );
270 
271  if ( lIt2 == mHashes.end() )
272  {
273  if ( mNextHash == 0x0000000000000000 )
274  {
275  exception::TooManyAttributes lExc;
276  log ( lExc , "Too many attributes" );
277  throw lExc;
278  }
279 
280  lRule.mForbiddenHash |= mNextHash;
281  mHashes.insert ( std::make_pair ( *lIt , mNextHash ) );
282  mNextHash <<= 1;
283  }
284  else
285  {
286  lRule.mForbiddenHash |= lIt2->second;
287  }
288  }
289 
290  for ( std::set<std::string>::iterator lIt = lRule.mOptional.begin() ; lIt != lRule.mOptional.end() ; ++lIt )
291  {
292  boost::unordered_map< std::string , uint64_t >::iterator lIt2 ( mHashes.find ( *lIt ) );
293 
294  if ( lIt2 == mHashes.end() )
295  {
296  if ( mNextHash == 0x0000000000000000 )
297  {
298  exception::TooManyAttributes lExc;
299  log ( lExc , "Too many attributes" );
300  throw lExc;
301  }
302 
303  mHashes.insert ( std::make_pair ( *lIt , mNextHash ) );
304  mNextHash <<= 1;
305  }
306  }
307 
308  lRule.mRuleId = ++mRuleCounter;
309  lRule.mFuncPtr = new FunctionObject<R,T> ( aCallbackHandler );
310  }
311 
312 
313  template < typename R >
314  R Parser<R>::operator() ( const pugi::xml_node& aNode )
315  {
316  uint64_t lHash ( 0x0000000000000000 );
317 
318  for ( pugi::xml_attribute lAttr = aNode.first_attribute(); lAttr; lAttr = lAttr.next_attribute() )
319  {
320  boost::unordered_map< std::string , uint64_t >::iterator lIt2 ( mHashes.find ( lAttr.name() ) );
321 
322  if ( lIt2 == mHashes.end() )
323  {
324  exception::UnknownAttribute lExc;
325  log ( lExc , "Parser failed because of unknown attribute ", Quote ( lAttr.name() ) );
326  throw lExc;
327  }
328 
329  lHash |= lIt2->second;
330  }
331 
332  std::deque< Rule<R>* > lPassed;
333  std::deque< Rule<R>* > lFailedRequired;
334  std::deque< Rule<R>* > lFailedForbidden;
335  int i ( 0 );
336 
337  for ( typename std::deque< Rule<R> >::iterator lIt = mRules.begin() ; lIt != mRules.end() ; ++lIt, ++i )
338  {
339  if ( lIt->mForbiddenHash & lHash )
340  {
341  lFailedForbidden.push_back ( & ( *lIt ) );
342  }
343  else if ( lIt->mRequiredHash & ~lHash )
344  {
345  lFailedRequired.push_back ( & ( *lIt ) );
346  continue;
347  }
348  else
349  {
350  lPassed.push_back ( & ( *lIt ) );
351  }
352  }
353 
354  if ( lPassed.size() == 1 )
355  {
356  return ( *lPassed.front() ) ( aNode );
357  }
358 
359  if ( lPassed.size() > 1 )
360  {
361  log ( Warning() , "Ambiguity! " , Integer ( lPassed.size() ) ," rules passed. Attempting to find the rule with the most stringent requirements." );
362  Rule<R>* lMostStringent ( NULL );
363  uint32_t lCounter ( 0 );
364 
365  for ( typename std::deque< Rule<R>* >::iterator lIt = lPassed.begin(); lIt != lPassed.end(); ++lIt )
366  {
367  if ( lCounter < ( **lIt ).mRequired.size() )
368  {
369  lMostStringent = ( *lIt );
370  lCounter = ( **lIt ).mRequired.size();
371  }
372  else if ( lCounter == ( **lIt ).mRequired.size() )
373  {
374  lMostStringent = NULL;
375  }
376  }
377 
378  if ( !lMostStringent )
379  {
380  exception::AmbiguousParserRules lExc;
381  log ( lExc , "Ambiguity remains! Multiple rules passed " , Integer ( lCounter ) , " requirements." );
382  throw lExc;
383  }
384 
385  log ( Warning() , "In ambiguous case, selected " , lMostStringent->description() );
386  return ( *lMostStringent ) ( aNode );
387  }
388 
389  std::stringstream lStr;
390 
391  for ( pugi::xml_attribute lAttr = aNode.first_attribute(); lAttr; lAttr = lAttr.next_attribute() )
392  {
393  lStr << lAttr.name() << "=\"" << lAttr.value() << "\", ";
394  }
395 
396  std::string lString ( lStr.str() );
397  lString.resize ( lString.size() - 2 );
398  exception::NoRulesPassed lExc;
399  log ( lExc , "Node with attributes : " , lString , " failed all parser rules because : " );
400 
401  for ( typename std::deque< Rule<R>* >::iterator lIt = lFailedRequired.begin() ; lIt != lFailedRequired.end(); ++lIt )
402  {
403  std::stringstream lStr;
404  uint64_t lTemp ( ( **lIt ).mRequiredHash & ~lHash );
405 
406  for ( boost::unordered_map< std::string , uint64_t >::iterator lIt2 = mHashes.begin() ; lIt2 != mHashes.end() ; ++lIt2 )
407  {
408  if ( ( lIt2->second ) & lTemp )
409  {
410  lStr << "\"" << lIt2->first << "\", ";
411  }
412  }
413 
414  std::string lString ( lStr.str() );
415  lString.resize ( lString.size() - 2 );
416  log ( lExc , "Rule " , Integer ( ( **lIt ).mRuleId ) , " requires attributes : " , lString );
417  }
418 
419  for ( typename std::deque< Rule<R>* >::iterator lIt = lFailedForbidden.begin() ; lIt != lFailedForbidden.end(); ++lIt )
420  {
421  std::stringstream lStr;
422  uint64_t lTemp ( ( **lIt ).mForbiddenHash & lHash );
423 
424  for ( boost::unordered_map< std::string , uint64_t >::iterator lIt2 = mHashes.begin() ; lIt2 != mHashes.end() ; ++lIt2 )
425  {
426  if ( ( lIt2->second ) & lTemp )
427  {
428  lStr << "\"" << lIt2->first << "\", ";
429  }
430  }
431 
432  std::string lString ( lStr.str() );
433  lString.resize ( lString.size() - 2 );
434  log ( lExc , "Rule " , Integer ( ( **lIt ).mRuleId ) , " forbids attributes : " , lString );
435  }
436 
437  throw lExc;
438  }
439 
440 }
441 
std::set< std::string > mOptional
The optional attributes for this rule.
Definition: XmlParser.hpp:204
Rule< R > & optional(const std::string &aStr)
Add an optional attribute to the rule.
Definition: XmlParser.hxx:128
std::string description() const
A function to return a string description of the rule.
Definition: XmlParser.hxx:135
Class for wrapping bound functions and function objects as an object.
Definition: XmlParser.hpp:92
WarningLevel Warning
Definition: LogLevels.cpp:79
BaseFunctionObject< R > * mFuncPtr
An object wrapping the function pointer for the function to be called when the rule conditions are me...
Definition: XmlParser.hpp:214
T mT
The function object or bound function which will be called when the object is evaluated (bracket oper...
Definition: XmlParser.hpp:112
uint32_t mRuleId
The ID of the rule.
Definition: XmlParser.hpp:207
virtual ~Rule()
Destructor.
Definition: XmlParser.hxx:90
R operator()(const pugi::xml_node &aNode)
Functor which converts an XML node to an object of template type R.
Definition: XmlParser.hxx:62
_Quote< T > Quote(const T &aT)
Rule< R > & require(const std::string &aStr)
Add a required attribute to the rule.
Definition: XmlParser.hxx:100
Parser()
Default constructor.
Definition: XmlParser.hxx:223
FunctionObject(T &aT)
Constructor.
Definition: XmlParser.hxx:56
Rule for matching XML attributes.
Definition: XmlParser.hpp:146
std::set< std::string > mRequired
The required attributes for this rule.
Definition: XmlParser.hpp:200
virtual ~BaseFunctionObject()
Destructor.
Definition: XmlParser.hxx:50
Rule()
Default constructor.
Definition: XmlParser.hxx:81
BaseFunctionObject()
Default constructor.
Definition: XmlParser.hxx:45
Rule< R > & forbid(const std::string &aStr)
Add an forbidden attribute to the rule.
Definition: XmlParser.hxx:114
std::set< std::string > mForbidden
The forbidden attributes for this rule.
Definition: XmlParser.hpp:202
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:207
Forward declaration of the Parser so we can declare it friend.
Definition: XmlParser.hpp:71
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...