μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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
41namespace 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();
218
219
220 template < typename R >
222 {
223 if ( mFuncPtr )
224 {
225 return ( *mFuncPtr ) ( aNode );
226 }
227 else
229 exception::NoActionSpecified lExc;
230 log ( lExc , "No action specified!" );
231 throw lExc;
232 }
233 }
234
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 std::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 std::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 std::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 std::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 ( std::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 ( std::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
\rst Wraps a Python iterator so that it can also be used as a C++ input iterator
Definition: pytypes.h:1102
xml_attribute next_attribute() const
Definition: pugixml.cpp:5160
xml_attribute first_attribute() const
Definition: pugixml.cpp:5619
virtual ~BaseFunctionObject()
Destructor.
Definition: XmlParser.hxx:51
BaseFunctionObject()
Default constructor.
Definition: XmlParser.hxx:45
Class for wrapping bound functions and function objects as an object.
Definition: XmlParser.hpp:93
R operator()(const pugi::xml_node &aNode)
Functor which converts an XML node to an object of template type R.
Definition: XmlParser.hxx:66
FunctionObject(T &aT)
Constructor.
Definition: XmlParser.hxx:59
~Parser()
Destructor.
Definition: XmlParser.hxx:248
void addRule(const Rule< R > &aRule, T aCallbackHandler)
Method to add the rules to the parser.
Definition: XmlParser.hxx:255
Parser()
Default constructor.
Definition: XmlParser.hxx:239
R operator()(const pugi::xml_node &aNode)
Functor which converts an XML node to an object of template type R.
Definition: XmlParser.hxx:330
std::unordered_map< std::string, uint64_t > mHashes
Map of the tags to the one-hot encoded hash.
Definition: XmlParser.hpp:241
Rule for matching XML attributes.
Definition: XmlParser.hpp:145
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
Rule< R > & forbid(const std::string &aStr)
Add an forbidden attribute to the rule.
Definition: XmlParser.hxx:125
Rule< R > & optional(const std::string &aStr)
Add an optional attribute to the rule.
Definition: XmlParser.hxx:140
std::set< std::string > mRequired
The required attributes for this rule.
Definition: XmlParser.hpp:194
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
uint32_t mRuleId
The ID of the rule.
Definition: XmlParser.hpp:201
std::string description() const
A function to return a string description of the rule.
Definition: XmlParser.hxx:148
virtual ~Rule()
Destructor.
Definition: XmlParser.hxx:99
std::set< std::string > mForbidden
The forbidden attributes for this rule.
Definition: XmlParser.hpp:196
uint64_t mForbiddenHash
The hash for forbidden attributes.
Definition: XmlParser.hpp:205
uint64_t mRequiredHash
The hash for required attributes.
Definition: XmlParser.hpp:203
Rule()
Default constructor.
Definition: XmlParser.hxx:89
Rule< R > & require(const std::string &aStr)
Add a required attribute to the rule.
Definition: XmlParser.hxx:110
std::set< std::string > mOptional
The optional attributes for this rule.
Definition: XmlParser.hpp:198
_Quote< T > Quote(const T &aT)
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
void log(FatalLevel &aFatal, const T0 &aArg0)
Function to add a log entry at Fatal level.
Definition: log.hxx:18
WarningLevel Warning
Definition: LogLevels.cpp:79