ATLAS Offline Software
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):
6 #include "AsgTools/TProperty.h"
7 
8 #include <cassert>
9 
10 namespace 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]))
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 
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 
568 template< >
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 
589 Property* createProperty( const bool& rval ) {
590  return new TProperty< bool >( const_cast< bool& >( rval ), Property::BOOL );
591 }
592 
593 Property* createProperty( const int& rval ) {
594  return new TProperty< int >( const_cast< int& >( rval ), Property::INT );
595 }
596 
597 Property* createProperty( const float& rval ) {
598  return new TProperty< float >( const_cast< float& >( rval ),
599  Property::FLOAT );
600 }
601 
602 Property* createProperty( const double& rval ) {
603  return new TProperty< double >( const_cast< double& >( rval ),
605 }
606 
607 Property* createProperty( const std::string& rval ) {
608  return new TProperty< std::string >( const_cast< std::string& >( rval ),
610 }
611 
612 Property* 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 
618 Property* 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 
624 Property* 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 //
Property::StringVector
std::vector< std::string > StringVector
Convenience type declaration for a string vector.
Definition: Property.h:46
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
TProperty.h
Property::BOOL
@ BOOL
Definition: Property.h:29
Token::m_type
int m_type
Token type.
Definition: Token.h:121
sendEI_SPB.ch
ch
Definition: sendEI_SPB.py:35
asg::detail::packStringVector
StatusCode packStringVector(const std::vector< std::string > &value, std::string &result)
Definition: TProperty.cxx:289
get_generator_info.result
result
Definition: get_generator_info.py:21
Property::getCastString
virtual StatusCode getCastString(std::string &result) const
get the property as a string I can pas to setString
Definition: Property.cxx:81
Property::STRING
@ STRING
Definition: Property.h:33
index
Definition: index.py:1
asg::detail::packStringSingle
StatusCode packStringSingle(const std::string &value, std::string &result)
Definition: TProperty.cxx:305
Property::FloatVector
std::vector< float > FloatVector
Convenience type declaration for a float vector.
Definition: Property.h:44
mergePhysValFiles.start
start
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:14
Property::INTVECTOR
@ INTVECTOR
Definition: Property.h:34
asg
Definition: DataHandleTestTool.h:28
Property::STRINGVECTOR
@ STRINGVECTOR
Definition: Property.h:36
ANA_MSG_ERROR
#define ANA_MSG_ERROR(xmsg)
Macro printing error messages.
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:294
athena.value
value
Definition: athena.py:122
detail
Definition: extract_histogram_tag.cxx:14
ANA_CHECK
#define ANA_CHECK(EXP)
check whether the given expression was successful
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:324
atn_test_sgProducerConsumerDataPool_jobOptions.end
end
Definition: atn_test_sgProducerConsumerDataPool_jobOptions.py:25
beamspotman.tokens
tokens
Definition: beamspotman.py:1284
asg::detail::unpackStringMap
StatusCode unpackStringMap(const std::string &value, std::map< std::string, std::string > &result)
Definition: TProperty.cxx:489
python.utils.SPACE
string SPACE
Definition: Reconstruction/RecExample/RecExOnline/python/utils.py:21
Property
Support class for PropertyMgr.
Definition: Property.h:23
python.iconfTool.models.loaders.level
level
Definition: loaders.py:20
Token
This class provides a token that identifies in a unique way objects on the persistent storage.
Definition: Token.h:21
Property::DOUBLE
@ DOUBLE
Definition: Property.h:32
asg::detail::unpackStringVector
StatusCode unpackStringVector(const std::string &value, std::vector< std::string > &result)
Definition: TProperty.cxx:381
m_type
TokenType m_type
the type
Definition: TProperty.cxx:44
asg::detail::packStringMap
StatusCode packStringMap(const std::map< std::string, std::string > &value, std::string &result)
Definition: TProperty.cxx:273
m_subtokens
std::vector< Token > m_subtokens
the sub-tokens (if this is a sub group)
Definition: TProperty.cxx:53
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
m_cooked
std::string m_cooked
the cooked input string
Definition: TProperty.cxx:50
TProperty
Templated wrapper around user properties.
Definition: TProperty.h:28
PlotPulseshapeFromCool.input
input
Definition: PlotPulseshapeFromCool.py:106
m_raw
std::string_view m_raw
the raw input string
Definition: TProperty.cxx:47
Property::INT
@ INT
Definition: Property.h:30
Property::IntVector
std::vector< int > IntVector
Convenience type declaration for an integer vector.
Definition: Property.h:42
Property::FLOAT
@ FLOAT
Definition: Property.h:31
TProperty::setFrom
virtual int setFrom(const Property &rhs)
Set value using that from another property.
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
Property::FLOATVECTOR
@ FLOATVECTOR
Definition: Property.h:35
asg::detail::unpackStringSingle
StatusCode unpackStringSingle(const std::string &value, std::string &result)
Definition: TProperty.cxx:339
DeMoScan.index
string index
Definition: DeMoScan.py:362
IOVDbNamespace::quote
std::string quote(const std::string &sentence)
Enclose a string in ".
Definition: IOVDbStringFunctions.cxx:85
createProperty
Property * createProperty(const bool &rval)
Create a boolean propert.
Definition: TProperty.cxx:589