ATLAS Offline Software
Loading...
Searching...
No Matches
TProperty.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Local include(s):
7
8#include <cassert>
9
10namespace asg
11{
12 namespace detail
13 {
14 namespace
15 {
17 enum class TokenType
18 {
19 STRING,
20
21 SPACE,
22
23 NUMBER,
24
25 COMMA,
26
27 LIST_OPEN,
28
29 LIST_CLOSE,
30
31 MAP_SEPARATOR,
32
33 MAP_OPEN,
34
35 MAP_CLOSE,
36
37 SUBGROUP
38 };
39
41 struct Token
42 {
44 TokenType m_type;
45
47 std::string_view m_raw;
48
50 std::string m_cooked;
51
53 std::vector<Token> m_subtokens;
54 };
55
56 StatusCode make_string_token (const std::string& input,
57 std::string::size_type& pos,
58 Token& token)
59 {
60 using namespace asg::msgProperty;
61
62 token.m_type = TokenType::STRING;
63
64 char quote = 0;
65 if (input[pos] != '\'' && input[pos] != '"')
66 {
67 ANA_MSG_ERROR ("didn't find quote at position " << pos << " of string: " << input);
68 return StatusCode::FAILURE;
69 }
70 quote = input[pos];
71 ++ pos;
72 for (; pos < input.size() && input[pos] != quote; ++ pos)
73 {
74 if (input[pos] == '\\')
75 {
76 ++ pos;
77 if (pos == input.size())
78 {
79 ANA_MSG_ERROR ("premature end of string: " << input);
80 return StatusCode::FAILURE;
81 }
82 if (input[pos] == '\'' || input[pos] == '"' ||
83 input[pos] == '\\' || input[pos] == ',')
84 {
85 token.m_cooked += input[pos];
86 } else
87 {
88 ANA_MSG_ERROR ("invalid character '" << input[pos] << "' at position " << pos << " of string: " << input);
89 return StatusCode::FAILURE;
90 }
91 } else
92 {
93 token.m_cooked += input[pos];
94 }
95 }
96
97 // end-of-string quote handling
98 if (pos == input.size())
99 {
100 ANA_MSG_ERROR ("premature end of string: " << input);
101 return StatusCode::FAILURE;
102 }
103 ++ pos;
104 return StatusCode::SUCCESS;
105 }
106
107 StatusCode make_number_token (const std::string& input,
108 std::string::size_type& pos,
109 Token& token)
110 {
111 token.m_type = TokenType::NUMBER;
112
113 for (; pos < input.size() &&
114 (isalnum (input[pos]) || input[pos] == '.' ||
115 input[pos] == '+' || input[pos] == '-'); ++ pos)
116 token.m_cooked = input[pos];
117 return StatusCode::SUCCESS;
118 }
119
120 StatusCode make_space_token (const std::string& input,
121 std::string::size_type& pos,
122 Token& token)
123 {
124 token.m_type = TokenType::SPACE;
125
126 for (; pos < input.size() && isspace (input[pos]); ++ pos)
127 token.m_cooked = input[pos];
128 return StatusCode::SUCCESS;
129 }
130
131 StatusCode make_char_token (const std::string& input,
132 std::string::size_type& pos,
133 Token& token)
134 {
135 using namespace asg::msgProperty;
136
137 if (input[pos] == '[')
138 token.m_type = TokenType::LIST_OPEN;
139 else if (input[pos] == ']')
140 token.m_type = TokenType::LIST_CLOSE;
141 else if (input[pos] == ',')
142 token.m_type = TokenType::COMMA;
143 else if (input[pos] == '{')
144 token.m_type = TokenType::MAP_OPEN;
145 else if (input[pos] == '}')
146 token.m_type = TokenType::MAP_CLOSE;
147 else if (input[pos] == ':')
148 token.m_type = TokenType::MAP_SEPARATOR;
149 else
150 {
151 ANA_MSG_ERROR ("unexpected token '" << input[pos] << "' at position" << pos << " of string: " << input);
152 return StatusCode::FAILURE;
153 }
154 ++ pos;
155 return StatusCode::SUCCESS;
156 }
157
158 StatusCode make_token_list (const std::string& input,
159 std::vector<Token>& tokens)
160 {
161 using namespace asg::msgProperty;
162
163 tokens.clear ();
164 for (std::string::size_type start = 0, pos = 0;
165 pos < input.size(); start = pos)
166 {
167 Token token;
168 if (input[pos] == '\'' || input[pos] == '"')
169 {
170 ANA_CHECK (make_string_token (input, pos, token));
171 } else if (isdigit (input[pos]) || (input[pos]=='-'))
172 {
173 ANA_CHECK (make_number_token (input, pos, token));
174 } else if (isspace (input[pos]))
175 {
176 ANA_CHECK (make_space_token (input, pos, token));
177 } else
178 {
179 ANA_CHECK (make_char_token (input, pos, token));
180 }
181 token.m_raw = std::string_view (input).substr (start, pos - start);
182 tokens.push_back (std::move (token));
183 }
184 return StatusCode::SUCCESS;
185 }
186
187
188
189 StatusCode make_token_tree (std::vector<Token>::iterator& iterator,
190 std::vector<Token>::iterator end,
191 std::vector<Token>& result,
192 bool isSubTree)
193 {
194 using namespace asg::msgProperty;
195
196 while (iterator != end)
197 {
198 switch (iterator->m_type)
199 {
200 case TokenType::SPACE:
201 ++ iterator;
202 // no-op
203 break;
204 case TokenType::STRING:
205 case TokenType::NUMBER:
206 case TokenType::COMMA:
207 case TokenType::MAP_SEPARATOR:
208 case TokenType::SUBGROUP:
209 result.emplace_back (std::move (*iterator));
210 ++ iterator;
211 break;
212 case TokenType::LIST_OPEN:
213 case TokenType::MAP_OPEN:
214 {
215 Token subtoken;
216 subtoken.m_type = TokenType::SUBGROUP;
217 subtoken.m_subtokens.emplace_back (std::move (*iterator));
218 ++ iterator;
219 if (make_token_tree (iterator, end, subtoken.m_subtokens, true).isFailure())
220 return StatusCode::FAILURE;
221 // cppcheck-suppress mismatchingContainerExpression
222 subtoken.m_raw = std::string_view (subtoken.m_subtokens.front().m_raw.data(), subtoken.m_subtokens.back().m_raw.end() - subtoken.m_subtokens.front().m_raw.begin());
223 result.emplace_back (std::move (subtoken));
224 }
225 break;
226 case TokenType::LIST_CLOSE:
227 case TokenType::MAP_CLOSE:
228 if (!isSubTree)
229 {
230 ANA_MSG_ERROR ("unexpected closing token: " << iterator->m_raw);
231 return StatusCode::FAILURE;
232 }
233 result.emplace_back (std::move (*iterator));
234 ++ iterator;
235 if ((result.back().m_type == TokenType::LIST_CLOSE &&
236 result.front().m_type != TokenType::LIST_OPEN) ||
237 (result.back().m_type == TokenType::MAP_CLOSE &&
238 result.front().m_type != TokenType::MAP_OPEN))
239 {
240 ANA_MSG_ERROR ("missmatched open and closing token: " << result.front().m_raw << " " << result.back().m_raw);
241 return StatusCode::FAILURE;
242 }
243 return StatusCode::SUCCESS;
244 }
245 }
246 if (isSubTree)
247 {
248 ANA_MSG_ERROR ("missing closing token for: " << result.front().m_raw);
249 return StatusCode::FAILURE;
250 }
251 return StatusCode::SUCCESS;
252 }
253
254
255
256 std::string quoteString (const std::string& raw)
257 {
258 std::string quoted;
259 for (char ch : raw)
260 {
261 if (ch == ',' || ch == '\\' || ch == '"')
262 quoted += '\\';
263 quoted += ch;
264 }
265 if (quoted.empty())
266 quoted = "\"\"";
267 return quoted;
268 }
269 }
270
271
272
273 StatusCode packStringMap (const std::map<std::string,std::string>& value,
274 std::string& result)
275 {
276 std::string myresult;
277 for (const auto& subvalue : value)
278 {
279 if (!myresult.empty())
280 myresult += ",";
281 myresult += quoteString (subvalue.first) + ":" + quoteString (subvalue.second);
282 }
283 result = "{" + std::move (myresult) + "}";
284 return StatusCode::SUCCESS;
285 }
286
287
288
289 StatusCode packStringVector (const std::vector<std::string>& value,
290 std::string& result)
291 {
292 std::string myresult;
293 for (const auto& subvalue : value)
294 {
295 if (!myresult.empty())
296 myresult += ",";
297 myresult += quoteString (subvalue);
298 }
299 result = "[" + std::move (myresult) + "]";
300 return StatusCode::SUCCESS;
301 }
302
303
304
305 StatusCode packStringSingle (const std::string& value,
306 std::string& result)
307 {
308 if (value.find ("\\") == std::string::npos)
309 {
310 if (value.find ("\'") == std::string::npos)
311 {
312 result = "\'" + value + "\'";
313 return StatusCode::SUCCESS;
314 }
315 if (value.find ("\"") == std::string::npos)
316 {
317 result = "\"" + value + "\"";
318 return StatusCode::SUCCESS;
319 }
320 }
321 char quote = '\'';
322 if (value.find ("\'") != std::string::npos &&
323 value.find ("\"") == std::string::npos)
324 quote = '\"';
325 result = quote;
326 for (char ch : value)
327 {
328 if (ch == quote || ch == '\\')
329 result += '\\';
330 result += ch;
331 }
332 result += quote;
333 return StatusCode::SUCCESS;
334 }
335
336
337
338
339 StatusCode unpackStringSingle (const std::string& value,
340 std::string& result)
341 {
342 using namespace asg::msgProperty;
343
344 // special case: we don't have a quote, use string verbatim
345 if (value.find ('\'') == std::string::npos &&
346 value.find ('"') == std::string::npos)
347 {
348 result = value;
349 return StatusCode::SUCCESS;
350 }
351
352 std::vector<Token> tokens;
353 ANA_CHECK (make_token_list (value, tokens));
354 assert (!tokens.empty());
355 if (tokens.front().m_type == TokenType::SPACE)
356 {
357 tokens.erase (tokens.begin());
358 assert (!tokens.empty());
359 }
360 if (tokens.back().m_type == TokenType::SPACE)
361 {
362 tokens.erase (tokens.begin() + (tokens.size() - 1));
363 assert (!tokens.empty());
364 }
365 if (tokens[0].m_type != TokenType::STRING)
366 {
367 ANA_MSG_ERROR ("string property didn't start with a quote: " << value);
368 return StatusCode::FAILURE;
369 }
370 if (tokens.size() > 1)
371 {
372 ANA_MSG_ERROR ("extra text beyond quoted string: " << value);
373 return StatusCode::FAILURE;
374 }
375 result.swap (tokens[0].m_cooked);
376 return StatusCode::SUCCESS;
377 }
378
379
380
381 StatusCode unpackStringVector (const std::string& value,
382 std::vector<std::string>& result)
383 {
384 using namespace asg::msgProperty;
385
386 std::vector<std::string> myresult;
387
388 std::vector<Token> tokens;
389 ANA_CHECK (make_token_list (value, tokens));
390
391 bool done = false;
392 unsigned level = 0;
393 std::string subresult;
394 for (auto& token : tokens)
395 {
396 if (token.m_type == TokenType::LIST_OPEN)
397 ++ level;
398 if (level > 1)
399 {
400 subresult += token.m_raw;
401 } else if (level == 0)
402 {
403 if (token.m_type != TokenType::SPACE)
404 {
405 if (done)
406 {
407 ANA_MSG_ERROR ("vector property does not end with ']': " << value);
408 return StatusCode::FAILURE;
409 } else
410 {
411 ANA_MSG_ERROR ("vector property does not begin with '[': " << value);
412 return StatusCode::FAILURE;
413 }
414 }
415 } else switch (token.m_type)
416 {
417 case TokenType::MAP_SEPARATOR:
418 case TokenType::MAP_OPEN:
419 case TokenType::MAP_CLOSE:
420 case TokenType::SUBGROUP:
421 // not handling this (for now). if it comes up I fix it,
422 // but for now this would be more of a distraction.
423 ANA_MSG_ERROR ("(currently) unsupported token in vector: " << token.m_raw);
424 return StatusCode::FAILURE;
425 case TokenType::SPACE:
426 break;
427 case TokenType::STRING:
428 case TokenType::NUMBER:
429 if (!subresult.empty())
430 {
431 ANA_MSG_ERROR ("invalid entry in vector: " << subresult << token.m_raw);
432 return StatusCode::FAILURE;
433 }
434 subresult = std::move (token.m_raw);
435 break;
436 case TokenType::COMMA:
437 if (subresult.empty())
438 {
439 ANA_MSG_ERROR ("comma not preceded by value: " << value);
440 return StatusCode::FAILURE;
441 }
442 myresult.push_back (std::move (subresult));
443 subresult.clear ();
444 break;
445 case TokenType::LIST_OPEN:
446 if (done)
447 {
448 ANA_MSG_ERROR ("vector property does not begin with '[': " << value);
449 return StatusCode::FAILURE;
450 }
451 break;
452 case TokenType::LIST_CLOSE:
453 if (!subresult.empty())
454 {
455 myresult.push_back (std::move (subresult));
456 subresult.clear ();
457 } else
458 {
459 if (!myresult.empty())
460 {
461 ANA_MSG_ERROR ("vector property has ',' before ']': " << value);
462 return StatusCode::FAILURE;
463 }
464 }
465 done = true;
466 break;
467 }
468 if (token.m_type == TokenType::LIST_CLOSE)
469 {
470 if (level == 0)
471 {
472 ANA_MSG_ERROR ("extra ']' in vector: " << value);
473 return StatusCode::FAILURE;
474 }
475 -- level;
476 }
477 }
478 if (!done)
479 {
480 ANA_MSG_ERROR ("did not find a vector in the string");
481 return StatusCode::FAILURE;
482 }
483 result.swap (myresult);
484 return StatusCode::SUCCESS;
485 }
486
487
488
489 StatusCode unpackStringMap (const std::string& value,
490 std::map<std::string,std::string>& result)
491 {
492 using namespace asg::msgProperty;
493
494 std::vector<Token> tokenTree;
495 {
496 std::vector<Token> tokenList;
497 ANA_CHECK (make_token_list (value, tokenList));
498 auto iterator = tokenList.begin();
499 ANA_CHECK (make_token_tree (iterator, tokenList.end(), tokenTree, false));
500 }
501
502 if (tokenTree.size() != 1 ||
503 tokenTree[0].m_type != TokenType::SUBGROUP ||
504 tokenTree[0].m_subtokens[0].m_type != TokenType::MAP_OPEN)
505 {
506 ANA_MSG_ERROR ("failed to recognize value as map: " << value);
507 return StatusCode::FAILURE;
508 }
509
510 // note that this loop avoids the first and last token,
511 // i.e. "{" and "}"
512 for (std::size_t index = 1;
513 index < tokenTree[0].m_subtokens.size()-1; ++ index)
514 {
515 Token& mytoken = tokenTree[0].m_subtokens[index];
516 switch (index % 4)
517 {
518 case 0:
519 if (mytoken.m_type != TokenType::COMMA)
520 {
521 ANA_MSG_ERROR ("unexpected token " << mytoken.m_raw);
522 return StatusCode::FAILURE;
523 }
524 break;
525 case 1:
526 if (mytoken.m_type == TokenType::COMMA ||
527 mytoken.m_type == TokenType::MAP_SEPARATOR)
528 {
529 ANA_MSG_ERROR ("unexpected token " << mytoken.m_raw);
530 return StatusCode::FAILURE;
531 }
532 break;
533 case 2:
534 if (mytoken.m_type != TokenType::MAP_SEPARATOR)
535 {
536 ANA_MSG_ERROR ("unexpected token " << mytoken.m_raw);
537 return StatusCode::FAILURE;
538 }
539 break;
540 case 3:
541 if (mytoken.m_type == TokenType::COMMA ||
542 mytoken.m_type == TokenType::MAP_SEPARATOR)
543 {
544 ANA_MSG_ERROR ("unexpected token " << mytoken.m_raw);
545 return StatusCode::FAILURE;
546 }
547 Token& keytoken = tokenTree[0].m_subtokens[index-2];
548 result.emplace (keytoken.m_raw, mytoken.m_raw);
549 break;
550 }
551 }
552 if (tokenTree[0].m_subtokens.size() > 2 &&
553 tokenTree[0].m_subtokens.size()%4 != 1)
554 {
555 ANA_MSG_ERROR ("unexpected token " << tokenTree[0].m_subtokens.back().m_raw);
556 return StatusCode::FAILURE;
557 }
558 return StatusCode::SUCCESS;
559 }
560 }
561}
562
564//
565// Implementation of function specialisations
566//
567
568template< >
570 // Check that we have a valid pointer:
571 if( ! this->pointer() ) {
572 return 1;
573 }
574
575 std::string asString;
576 if (rhs.getCastString (asString).isFailure())
577 return 1;
578 return this->setString (asString).isFailure();
579}
580
581//
583
585//
586// Implementation of the createProperty specialisations/overloads
587//
588
589Property* createProperty( const bool& rval ) {
590 return new TProperty< bool >( const_cast< bool& >( rval ), Property::BOOL );
591}
592
593Property* createProperty( const int& rval ) {
594 return new TProperty< int >( const_cast< int& >( rval ), Property::INT );
595}
596
597Property* createProperty( const float& rval ) {
598 return new TProperty< float >( const_cast< float& >( rval ),
600}
601
602Property* createProperty( const double& rval ) {
603 return new TProperty< double >( const_cast< double& >( rval ),
605}
606
607Property* createProperty( const std::string& rval ) {
608 return new TProperty< std::string >( const_cast< std::string& >( rval ),
610}
611
612Property* createProperty( const std::vector< int >& rval ) {
613 typedef Property::IntVector vecInt_t;
614 return new TProperty< vecInt_t >( const_cast< vecInt_t& >( rval ),
616}
617
618Property* createProperty( const std::vector< float >& rval ) {
619 typedef Property::FloatVector vecFloat_t;
620 return new TProperty< vecFloat_t >( const_cast< vecFloat_t& >( rval ),
622}
623
624Property* createProperty( const std::vector< std::string >& rval ) {
625 typedef Property::StringVector vecString_t;
626 return new TProperty< vecString_t >( const_cast< vecString_t& >( rval ),
628}
629
630//
#define ANA_MSG_ERROR(xmsg)
Macro printing error messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
Property * createProperty(const bool &rval)
Create a boolean propert.
Support class for PropertyMgr.
Definition Property.h:23
std::vector< std::string > StringVector
Convenience type declaration for a string vector.
Definition Property.h:46
std::vector< int > IntVector
Convenience type declaration for an integer vector.
Definition Property.h:42
@ FLOATVECTOR
Definition Property.h:35
@ INTVECTOR
Definition Property.h:34
@ STRINGVECTOR
Definition Property.h:36
Property()
Default constructor.
Definition Property.cxx:43
virtual StatusCode getCastString(std::string &result) const
get the property as a string I can pas to setString
Definition Property.cxx:81
std::vector< float > FloatVector
Convenience type declaration for a float vector.
Definition Property.h:44
Templated wrapper around user properties.
Definition TProperty.h:28
virtual StatusCode setString(const std::string &value)
set the property from a string
const T * pointer() const
Return the address of the property variable.
virtual int setFrom(const Property &rhs)
Set value using that from another property.
int m_type
Token type.
Definition Token.h:123
::StatusCode StatusCode
StatusCode definition for legacy code.
std::string quote(const std::string &sentence)
Enclose a string in ".
const std::string COMMA
const std::string SPACE
StatusCode packStringSingle(const std::string &value, std::string &result)
StatusCode unpackStringVector(const std::string &value, std::vector< std::string > &result)
StatusCode packStringMap(const std::map< std::string, std::string > &value, std::string &result)
StatusCode unpackStringMap(const std::string &value, std::map< std::string, std::string > &result)
StatusCode unpackStringSingle(const std::string &value, std::string &result)
StatusCode packStringVector(const std::vector< std::string > &value, std::string &result)
Definition index.py:1
JetConstituentVector::iterator iterator