DD4hep  1.32.0
Detector Description Toolkit for High Energy Physics
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Grammar.cpp
Go to the documentation of this file.
1 //==========================================================================
2 // AIDA Detector description implementation
3 //--------------------------------------------------------------------------
4 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
5 // All rights reserved.
6 //
7 // For the licensing terms see $DD4hepINSTALL/LICENSE.
8 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
9 //
10 // Author : M.Frank
11 //
12 //==========================================================================
13 
14 // Framework include files
15 #include <DD4hep/Printout.h>
16 #include <DD4hep/Primitives.h>
17 #include <DD4hep/Exceptions.h>
18 #include <DD4hep/Grammar.h>
19 #include <Evaluator/Evaluator.h>
20 
21 // ROOT include files
22 #include <TDataType.h>
23 #include <TROOT.h>
24 
25 // C/C++ include files
26 #include <mutex>
27 #include <map>
28 #include <string>
29 
30 #if defined(DD4HEP_PARSER_HEADER)
31 
32 #define DD4HEP_NEED_EVALUATOR
33 // This is the case, if the parsers are externalized
34 // and the dd4hep namespace is renamed!
35 #include DD4HEP_PARSER_HEADER
36 
37 #endif
38 
39 namespace dd4hep {
40  const dd4hep::tools::Evaluator& evaluator();
41  const dd4hep::tools::Evaluator& g4Evaluator();
42 }
43 namespace {
44  static const dd4hep::tools::Evaluator* s__eval(&dd4hep::g4Evaluator());
45 }
46 
47 
48 namespace {
49  std::mutex s_mutex;
50 
51  typedef const dd4hep::BasicGrammar& (*grammar_create_t)();
52  typedef std::pair<grammar_create_t, dd4hep::BasicGrammar::specialization_t> grammar_args_t;
53 
54  // This static object needs to be in function to trick out static constructors populating this registry....
55  static std::map<dd4hep::BasicGrammar::key_type, dd4hep::BasicGrammar*>& active_registry() {
56  static std::map<dd4hep::BasicGrammar::key_type, dd4hep::BasicGrammar*> s_registry;
57  return s_registry;
58  }
59  static std::map<dd4hep::BasicGrammar::key_type, grammar_args_t>& prenote_registry() {
60  static std::map<dd4hep::BasicGrammar::key_type, grammar_args_t> s_registry;
61  return s_registry;
62  }
63 }
64 
66 namespace dd4hep {
67 
69  namespace detail {
71  std::string grammar_pre_parse_map(const std::string& in);
73  std::string grammar_pre_parse_obj(const std::string& in);
75  std::string grammar_pre_parse_cont(const std::string& in);
77  std::pair<int,double> grammar_evaluate_item(std::string val);
78  }
79 
81  void setGrammarEvaluator(const std::string& type) {
82  if ( type == "TGeo" )
83  s__eval = &evaluator();
84  else if ( type == "Geant4" || type == "G4" )
85  s__eval = &g4Evaluator();
86  else if ( type == "CGS" )
87  s__eval = &g4Evaluator();
88  else
89  except("Grammar","++ Undefined evaluator type: "+type);
90  }
91 }
92 
95  return this->bind == cp.bind &&
96  this->copy == cp.copy && this->str == cp.str &&
97  this->fromString == cp.fromString && this->eval == cp.eval;
98 }
99 
101 dd4hep::BasicGrammar::BasicGrammar(const std::string& typ)
102  : name(typ), hash_value(dd4hep::detail::hash64(typ))
103 {
104  auto j = prenote_registry().find(hash_value);
105  if ( j != prenote_registry().end() ) {
106  specialization = j->second.second;
107  }
108  if ( !active_registry().emplace(hash_value,this).second ) {
109  }
110 }
111 
112 
115 }
116 #include <iostream>
118 void dd4hep::BasicGrammar::pre_note(const std::type_info& info,
119  const BasicGrammar& (*fcn)(),
120  specialization_t specs) {
121  key_type hash = dd4hep::detail::hash64(typeName(info));
122 #ifdef DD4HEP_DEBUG_PROPERTIES
123  std::cout << "pre_note(1) " << typeName(info)
124  << " " << (void*)specs.str
125  << " " << (void*)specs.fromString
126  << std::endl;
127 #endif
128  if ( !prenote_registry().emplace(hash, std::make_pair(fcn,specs)).second ) {
129  auto j = prenote_registry().find(hash);
130  const auto& entry = (*j).second;
131 #ifdef DD4HEP_DEBUG_PROPERTIES
132  const auto& gramm = entry.first();
133  std::cout << "pre_note(2) " << typeName(info)
134  << " " << (void*)gramm.specialization.fromString
135  << " " << (void*)entry.second.fromString
136  << std::endl;
137 #endif
138  if ( !(entry.first == fcn && entry.second == specs) ) {
139  // Error: Already existing grammar.
140  dd4hep::except("BasicGrammar","FAILED to add existent registry: %s [%016llX]",
141  typeName(info).c_str(), hash);
142  }
143  }
145  auto i = active_registry().find(hash);
146  if ( i != active_registry().end() ) {
147  i->second->specialization = specs;
148  }
149 }
150 
153  auto i = active_registry().find(hash);
154  if ( i != active_registry().end() ) {
155 #ifdef DD4HEP_DEBUG_PROPERTIES
156  const auto& entry = (*i).second;
157  const auto& gramm = *entry;
158  std::cout << "get(1) " << hash
159  << " grammar: " << (void*)&gramm
160  << " " << (void*)gramm.specialization.fromString
161  << " " << (void*)entry->specialization.fromString
162  << std::endl;
163 #endif
164  return *(i->second);
165  }
166  auto j = prenote_registry().find(hash);
167  if ( j != prenote_registry().end() ) {
168 #ifdef DD4HEP_DEBUG_PROPERTIES
169  const auto& entry = (*j).second;
170  const auto& gramm = entry.first();
171  std::cout << "get(2) " << hash
172  << " " << (void*)gramm.specialization.fromString
173  << " " << (void*)entry.second.fromString
174  << std::endl;
175 #endif
176  return (j->second.first)();
177  }
178  dd4hep::except("BasicGrammar","FAILED to look up non existent registry: %016llX",hash);
179  throw "Error"; // Not reachable anyhow. Simply to please the compiler!
180 }
181 
183 const dd4hep::BasicGrammar& dd4hep::BasicGrammar::get(const std::type_info& info) {
184  key_type hash = dd4hep::detail::hash64(typeName(info));
185  auto i = active_registry().find(hash);
186  if ( i != active_registry().end() )
187  return *(i->second);
188  auto j = prenote_registry().find(hash);
189  if ( j != prenote_registry().end() )
190  return (j->second.first)();
191  dd4hep::except("BasicGrammar","FAILED to look up non existent registry: %016llX [%s]",
192  hash, typeName(info).c_str());
193  throw "Error"; // Not reachable anyhow. Simply to please the compiler!
194 }
195 
198  std::lock_guard<std::mutex> lock(s_mutex);
199  if ( !inited ) {
200  TClass* cl = gROOT->GetClass(type());
201  if ( cl ) {
202  root_class = cl;
203  inited = true;
204  return;
205  }
206  root_data_type = TDataType::GetType(type());
207  if ( root_data_type == kOther_t ) {
208  except("BasicGrammar",
209  "+++ ERROR +++ Cannot initialize gammar object: %s. "
210  "No TClass and no data type information present!",name.c_str());
211  }
212  inited = true;
213  }
214 }
215 
218  this->initialize();
219  return root_data_type;
220 }
221 
224  this->initialize();
225  return root_class;
226 }
227 
229 void dd4hep::BasicGrammar::invalidConversion(const std::string& value, const std::type_info& to) {
230  std::string to_name = typeName(to);
231  throw unrelated_value_error(to,
232  "Data conversion of " + value + " to type '" +
233  to_name + "' is not defined.");
234 }
235 
237 void dd4hep::BasicGrammar::invalidConversion(const std::type_info& from, const std::type_info& to) {
238  std::string to_name = typeName(to);
239  std::string from_name = typeName(from);
240  throw unrelated_type_error(from, to,
241  "Data conversion from '" + from_name +
242  "' to '" + to_name + "' is not implemented.");
243 }
244 
246 void dd4hep::BasicGrammar::setCast(const Cast* cast) const {
247  BasicGrammar* g = const_cast<BasicGrammar*>(this);
248  g->specialization.cast = cast;
249 }
250 
252 const dd4hep::Cast& dd4hep::BasicGrammar::cast() const {
253  if ( specialization.cast )
254  return *specialization.cast;
255  except("Grammar","Cannot serialize object with incomplete grammar: %s",type_name().c_str());
256  return *specialization.cast;
257 }
258 
260 std::string dd4hep::BasicGrammar::str(const void* ptr) const {
261  if ( specialization.str )
262  return specialization.str(*this, ptr);
263  except("Grammar", "Cannot serialize object with incomplete grammar: %s", type_name().c_str());
264  return "";
265 }
266 
268 bool dd4hep::BasicGrammar::fromString(void* ptr, const std::string& value) const {
269  if ( specialization.fromString )
270  return specialization.fromString(*this, ptr, value);
271  except("Grammar", "Cannot deserialize object with incomplete grammar: %s [%s] %p fromString: %s",
272  type_name().c_str(), this->name.c_str(), (void*)this, (void*)specialization.fromString);
273  return false;
274 }
275 
277 int dd4hep::BasicGrammar::evaluate(void* ptr, const std::string& value) const {
278  if ( specialization.eval )
279  return specialization.eval(*this, ptr, value);
280  except("Grammar", "Cannot evaluate object with incomplete grammar: %s", type_name().c_str());
281  return 0;
282 }
283 
285 std::pair<int,double> dd4hep::detail::grammar_evaluate_item(std::string val) {
286  size_t idx = val.find("(int)");
287  if (idx != std::string::npos)
288  val.erase(idx, 5);
289  while (val[0] == ' ')
290  val.erase(0, 1);
291  auto result = s__eval->evaluate(val.c_str());
292  return result;
293 }
294 
296 std::string dd4hep::detail::grammar_pre_parse_map(const std::string& in) {
297  bool ignore_blanks = true;
298  bool str_open = false;
299  bool obj_open = false;
300  bool start = false;
301  std::string res = "";
302  res.reserve(1024);
303  // std::cout << "Pre-parsed (in):" << in << std::endl;
304  for(const char* c = in.c_str(); *c; ++c) {
305  switch(*c) {
306  case '\'':
307  res += *c;
308  if ( start ) { start = false; }
309  if ( str_open ) { str_open = false; }
310  break;
311  case ':':
312  if ( str_open ) { res += '\''; }
313  res += *c;
314  res += ' ';
315  res += '\'';
316  str_open = true;
317  ignore_blanks = true;
318  break;
319  case ',':
320  if ( !obj_open && str_open ) { res += '\''; str_open = false; }
321  res += ",";
322  start = true;
323  ignore_blanks = true;
324  break;
325  case '(':
326  res += *c ;
327  obj_open = true;
328  break;
329  case ')':
330  res += *c ;
331  obj_open = false;
332  break;
333  case '[':
334  case '{':
335  res += *c ;
336  start = true;
337  ignore_blanks = true;
338  break;
339  case ']':
340  case '}':
341  if ( str_open ) {
342  res += '\'';
343  str_open = false;
344  }
345  res += *c ;
346  break;
347  case ' ':
348  if ( !ignore_blanks ) res += *c;
349  break;
350  default:
351  if ( start ) {
352  if ( !obj_open ) res += '\'';
353  start = false;
354  str_open = true;
355  }
356  ignore_blanks = false;
357  res += *c;
358  break;
359  }
360  }
361  // std::cout << "Pre-parsed (out):" << res << std::endl;
362  return res;
363 }
364 
366 std::string dd4hep::detail::grammar_pre_parse_cont(const std::string& in) {
367  bool ignore_blanks = true;
368  bool str_open = false;
369  bool start = false;
370  std::string res = "";
371  res.reserve(1024);
372  // std::cout << "Pre-parsed (in):" << in << std::endl;
373  for(const char* c = in.c_str(); *c; ++c) {
374  switch(*c) {
375  case '\'':
376  res += *c;
377  if ( start ) { start = false; }
378  if ( str_open ) { str_open = false; }
379  break;
380  case ':':
381  if ( str_open ) { res += '\''; }
382  res += *c;
383  res += ' ';
384  res += '\'';
385  str_open = true;
386  ignore_blanks = true;
387  break;
388  case ',':
389  if ( str_open ) { res += '\''; str_open = false; }
390  res += ",";
391  start = true;
392  ignore_blanks = true;
393  break;
394  case '(':
395  case '[':
396  case '{':
397  res += *c ;
398  start = true;
399  ignore_blanks = true;
400  break;
401  case ')':
402  case ']':
403  case '}':
404  if ( str_open ) { res += '\''; str_open = false; }
405  res += *c ;
406  break;
407  case ' ':
408  if ( !ignore_blanks ) res += *c;
409  break;
410  default:
411  if ( start ) {
412  res += '\'';
413  start = false;
414  str_open = true;
415  }
416  ignore_blanks = false;
417  res += *c;
418  break;
419  }
420  }
421  // std::cout << "Pre-parsed (out):" << res << std::endl;
422  return res;
423 }
424 
426 std::string dd4hep::detail::grammar_pre_parse_obj(const std::string& in) {
427  std::string res = "";
428  res.reserve(1024);
429  for(const char* c = in.c_str(); *c; ++c) {
430  switch(*c) {
431  case '\'':
432  return "Bad object representation";
433  case ',':
434  res += "','";
435  break;
436  case '(':
437  case '[':
438  res += "['";
439  break;
440  case ')':
441  case ']':
442  res += "']";
443  break;
444  default:
445  res += *c;
446  break;
447  }
448  }
449  //cout << "Pre-parsed:" << res << endl;
450  return res;
451 }
452 
455  static GrammarRegistry s_reg;
456  return s_reg;
457 }
458 
dd4hep::BasicGrammar::pre_note
static void pre_note(const std::type_info &info, const BasicGrammar &(*fcn)(), specialization_t specs)
Instance factory.
Definition: Grammar.cpp:118
dd4hep::BasicGrammar::name
const std::string name
Instance type name.
Definition: Grammar.h:60
dd4hep::BasicGrammar::key_type
unsigned long long int key_type
Definition: Grammar.h:58
dd4hep::BasicGrammar::evaluate
virtual int evaluate(void *ptr, const std::string &value) const
Evaluate string value if possible before calling boost::spirit.
Definition: Grammar.cpp:277
dd4hep::detail::grammar_pre_parse_cont
std::string grammar_pre_parse_cont(const std::string &in)
Helper function to parse data type.
Definition: Grammar.cpp:366
dd4hep::setGrammarEvaluator
void setGrammarEvaluator(const std::string &type)
Set grammar evaluator.
Definition: Grammar.cpp:81
dd4hep::info
std::size_t info(const std::string &src, const std::string &msg)
Definition: RootDictionary.h:65
dd4hep::BasicGrammar::specialization_t::operator==
bool operator==(const specialization_t &copy) const
Equality operator.
Definition: Grammar.cpp:94
dd4hep::BasicGrammar::hash_value
const key_type hash_value
Instance hash code.
Definition: Grammar.h:62
dd4hep::BasicGrammar::initialized_clazz
TClass * initialized_clazz() const
Access the ROOT class for complex objects.
Definition: Grammar.cpp:223
dd4hep::BasicGrammar::BasicGrammar
BasicGrammar(const std::string &typ)
Default constructor.
Definition: Grammar.cpp:101
dd4hep::BasicGrammar::specialization_t::copy
void(* copy)(void *to, const void *from)=0
Opaque copy constructor.
Definition: Grammar.h:77
dd4hep::BasicGrammar::str
virtual std::string str(const void *ptr) const
Serialize an opaque value to a string.
Definition: Grammar.cpp:260
dd4hep::g4Evaluator
const dd4hep::tools::Evaluator & g4Evaluator()
Access to G4 evaluator. Note: Uses Geant4 units!
Definition: ExpressionEvaluator.cpp:68
dd4hep::BasicGrammar::fromString
virtual bool fromString(void *ptr, const std::string &value) const
Set value from serialized string. On successful data conversion TRUE is returned.
Definition: Grammar.cpp:268
dd4hep::detail::grammar_pre_parse_map
std::string grammar_pre_parse_map(const std::string &in)
Helper function to parse data type.
Definition: Grammar.cpp:296
dd4hep::BasicGrammar::specialization_t::fromString
bool(* fromString)(const BasicGrammar &gr, void *ptr, const std::string &value)=0
PropertyGrammar overload: Retrieve value from string.
Definition: Grammar.h:81
dd4hep::evaluator
const dd4hep::tools::Evaluator & evaluator()
Definition: ExpressionEvaluator.cpp:62
dd4hep::detail::grammar_evaluate_item
std::pair< int, double > grammar_evaluate_item(std::string val)
Helper to parse single item.
Definition: Grammar.cpp:285
dd4hep::BasicGrammar
Base class describing string evaluation to C++ objects using boost::spirit.
Definition: Grammar.h:55
dd4hep::GrammarRegistry
Grammar registry interface.
Definition: Grammar.h:234
dd4hep::detail::eval
Definition: RootDictionary.h:84
dd4hep::BasicGrammar::specialization_t::cast
const Cast * cast
Ponter to ABI Cast structure.
Definition: Grammar.h:73
dd4hep::BasicGrammar::get
static const BasicGrammar & get(const std::type_info &info)
Access grammar by type info.
Definition: Grammar.cpp:183
dd4hep::BasicGrammar::specialization_t::eval
int(* eval)(const BasicGrammar &gr, void *ptr, const std::string &val)=0
Evaluate string value if possible before calling boost::spirit.
Definition: Grammar.h:83
dd4hep::BasicGrammar::specialization_t::bind
void(* bind)(void *pointer)=0
Bind opaque address to object.
Definition: Grammar.h:75
dd4hep::BasicGrammar::setCast
virtual void setCast(const Cast *cast) const
Set cast structure.
Definition: Grammar.cpp:246
dd4hep::BasicGrammar::specialization_t::str
std::string(* str)(const BasicGrammar &gr, const void *ptr)=0
PropertyGrammar overload: Serialize a property to a string.
Definition: Grammar.h:79
dd4hep::BasicGrammar::specialization
struct dd4hep::BasicGrammar::specialization_t specialization
dd4hep::BasicGrammar::initialized_data_type
int initialized_data_type() const
Access ROOT data type for fundamentals.
Definition: Grammar.cpp:217
Primitives.h
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
dd4hep::BasicGrammar::cast
virtual const Cast & cast() const
Access ABI object cast.
Definition: Grammar.cpp:252
dd4hep::BasicGrammar::initialize
void initialize() const
Second step initialization after the virtual table is fixed.
Definition: Grammar.cpp:197
dd4hep::sim::hash
unsigned int hash(unsigned int initialSeed, unsigned int eventNumber, unsigned int runNumber)
calculate hash from initialSeed, eventID and runID
Definition: Geant4EventSeed.h:201
dd4hep::BasicGrammar::specialization_t
Structure to be filled if automatic object parsing from string is supposed to be supported.
Definition: Grammar.h:71
dd4hep::detail::grammar_pre_parse_obj
std::string grammar_pre_parse_obj(const std::string &in)
Helper function to parse data type.
Definition: Grammar.cpp:426
dd4hep::BasicGrammar::invalidConversion
static void invalidConversion(const std::type_info &from, const std::type_info &to)
Error callback on invalid conversion.
Definition: Grammar.cpp:237
dd4hep::BasicGrammar::~BasicGrammar
virtual ~BasicGrammar()
Default destructor.
Definition: Grammar.cpp:114
Printout.h
Exceptions.h
Grammar.h
dd4hep::GrammarRegistry::instance
static const GrammarRegistry & instance()
Registry instance singleton.
Definition: Grammar.cpp:454