DD4hep  1.30.0
Detector Description Toolkit for High Energy Physics
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 <algorithm>
27 #include <stdexcept>
28 #include <mutex>
29 #include <map>
30 
31 #if defined(DD4HEP_PARSER_HEADER)
32 
33 #define DD4HEP_NEED_EVALUATOR
34 // This is the case, if the parsers are externalized
35 // and the dd4hep namespace is renamed!
36 #include DD4HEP_PARSER_HEADER
37 
38 #endif
39 
40 namespace dd4hep {
41  const dd4hep::tools::Evaluator& evaluator();
42  const dd4hep::tools::Evaluator& g4Evaluator();
43 }
44 namespace {
45  static const dd4hep::tools::Evaluator* s__eval(&dd4hep::g4Evaluator());
46 }
47 
48 
49 namespace {
50  std::mutex s_mutex;
51 
52  typedef const dd4hep::BasicGrammar& (*grammar_create_t)();
53  typedef std::pair<grammar_create_t, dd4hep::BasicGrammar::specialization_t> grammar_args_t;
54 
55  // This static object needs to be in function to trick out static constructors populating this registry....
56  static std::map<dd4hep::BasicGrammar::key_type, dd4hep::BasicGrammar*>& active_registry() {
57  static std::map<dd4hep::BasicGrammar::key_type, dd4hep::BasicGrammar*> s_registry;
58  return s_registry;
59  }
60  static std::map<dd4hep::BasicGrammar::key_type, grammar_args_t>& prenote_registry() {
61  static std::map<dd4hep::BasicGrammar::key_type, grammar_args_t> s_registry;
62  return s_registry;
63  }
64 }
65 
67 namespace dd4hep {
68 
70  namespace detail {
72  std::string grammar_pre_parse_map(const std::string& in);
74  std::string grammar_pre_parse_obj(const std::string& in);
76  std::string grammar_pre_parse_cont(const std::string& in);
78  std::pair<int,double> grammar_evaluate_item(std::string val);
79  }
80 
82  void setGrammarEvaluator(const std::string& type) {
83  if ( type == "TGeo" )
84  s__eval = &evaluator();
85  else if ( type == "Geant4" || type == "G4" )
86  s__eval = &g4Evaluator();
87  else if ( type == "CGS" )
88  s__eval = &g4Evaluator();
89  else
90  except("Grammar","++ Undefined evaluator type: "+type);
91  }
92 }
93 
96  return this->bind == cp.bind &&
97  this->copy == cp.copy && this->str == cp.str &&
98  this->fromString == cp.fromString && this->eval == cp.eval;
99 }
100 
102 dd4hep::BasicGrammar::BasicGrammar(const std::string& typ)
103  : name(typ), hash_value(dd4hep::detail::hash64(typ))
104 {
105  auto j = prenote_registry().find(hash_value);
106  if ( j != prenote_registry().end() ) {
107  specialization = j->second.second;
108  }
109  if ( !active_registry().emplace(hash_value,this).second ) {
110  }
111 }
112 
113 
116 }
117 #include <iostream>
119 void dd4hep::BasicGrammar::pre_note(const std::type_info& info,
120  const BasicGrammar& (*fcn)(),
121  specialization_t specs) {
122  key_type hash = dd4hep::detail::hash64(typeName(info));
123 #ifdef DD4HEP_DEBUG_PROPERTIES
124  std::cout << "pre_note(1) " << typeName(info)
125  << " " << (void*)specs.str
126  << " " << (void*)specs.fromString
127  << std::endl;
128 #endif
129  if ( !prenote_registry().emplace(hash, std::make_pair(fcn,specs)).second ) {
130  auto j = prenote_registry().find(hash);
131  const auto& entry = (*j).second;
132 #ifdef DD4HEP_DEBUG_PROPERTIES
133  const auto& gramm = entry.first();
134  std::cout << "pre_note(2) " << typeName(info)
135  << " " << (void*)gramm.specialization.fromString
136  << " " << (void*)entry.second.fromString
137  << std::endl;
138 #endif
139  if ( !(entry.first == fcn && entry.second == specs) ) {
140  // Error: Already existing grammar.
141  dd4hep::except("BasicGrammar","FAILED to add existent registry: %s [%016llX]",
142  typeName(info).c_str(), hash);
143  }
144  }
146  auto i = active_registry().find(hash);
147  if ( i != active_registry().end() ) {
148  i->second->specialization = specs;
149  }
150 }
151 
154  auto i = active_registry().find(hash);
155  if ( i != active_registry().end() ) {
156 #ifdef DD4HEP_DEBUG_PROPERTIES
157  const auto& entry = (*i).second;
158  const auto& gramm = *entry;
159  std::cout << "get(1) " << hash
160  << " grammar: " << (void*)&gramm
161  << " " << (void*)gramm.specialization.fromString
162  << " " << (void*)entry->specialization.fromString
163  << std::endl;
164 #endif
165  return *(i->second);
166  }
167  auto j = prenote_registry().find(hash);
168  if ( j != prenote_registry().end() ) {
169 #ifdef DD4HEP_DEBUG_PROPERTIES
170  const auto& entry = (*j).second;
171  const auto& gramm = entry.first();
172  std::cout << "get(2) " << hash
173  << " " << (void*)gramm.specialization.fromString
174  << " " << (void*)entry.second.fromString
175  << std::endl;
176 #endif
177  return (j->second.first)();
178  }
179  dd4hep::except("BasicGrammar","FAILED to look up non existent registry: %016llX",hash);
180  throw "Error"; // Not reachable anyhow. Simply to please the compiler!
181 }
182 
184 const dd4hep::BasicGrammar& dd4hep::BasicGrammar::get(const std::type_info& info) {
185  key_type hash = dd4hep::detail::hash64(typeName(info));
186  auto i = active_registry().find(hash);
187  if ( i != active_registry().end() )
188  return *(i->second);
189  auto j = prenote_registry().find(hash);
190  if ( j != prenote_registry().end() )
191  return (j->second.first)();
192  dd4hep::except("BasicGrammar","FAILED to look up non existent registry: %016llX [%s]",
193  hash, typeName(info).c_str());
194  throw "Error"; // Not reachable anyhow. Simply to please the compiler!
195 }
196 
199  std::lock_guard<std::mutex> lock(s_mutex);
200  if ( !inited ) {
201  TClass* cl = gROOT->GetClass(type());
202  if ( cl ) {
203  root_class = cl;
204  inited = true;
205  return;
206  }
207  root_data_type = TDataType::GetType(type());
208  if ( root_data_type == kOther_t ) {
209  except("BasicGrammar",
210  "+++ ERROR +++ Cannot initialize gammar object: %s. "
211  "No TClass and no data type information present!",name.c_str());
212  }
213  inited = true;
214  }
215 }
216 
219  this->initialize();
220  return root_data_type;
221 }
222 
225  this->initialize();
226  return root_class;
227 }
228 
230 void dd4hep::BasicGrammar::invalidConversion(const std::string& value, const std::type_info& to) {
231  std::string to_name = typeName(to);
232  throw unrelated_value_error(to,
233  "Data conversion of " + value + " to type '" +
234  to_name + "' is not defined.");
235 }
236 
238 void dd4hep::BasicGrammar::invalidConversion(const std::type_info& from, const std::type_info& to) {
239  std::string to_name = typeName(to);
240  std::string from_name = typeName(from);
241  throw unrelated_type_error(from, to,
242  "Data conversion from '" + from_name +
243  "' to '" + to_name + "' is not implemented.");
244 }
245 
247 void dd4hep::BasicGrammar::setCast(const Cast* cast) const {
248  BasicGrammar* g = const_cast<BasicGrammar*>(this);
249  g->specialization.cast = cast;
250 }
251 
253 const dd4hep::Cast& dd4hep::BasicGrammar::cast() const {
254  if ( specialization.cast )
255  return *specialization.cast;
256  except("Grammar","Cannot serialize object with incomplete grammar: %s",type_name().c_str());
257  return *specialization.cast;
258 }
259 
261 std::string dd4hep::BasicGrammar::str(const void* ptr) const {
262  if ( specialization.str )
263  return specialization.str(*this, ptr);
264  except("Grammar", "Cannot serialize object with incomplete grammar: %s", type_name().c_str());
265  return "";
266 }
267 
269 bool dd4hep::BasicGrammar::fromString(void* ptr, const std::string& value) const {
270  if ( specialization.fromString )
271  return specialization.fromString(*this, ptr, value);
272  except("Grammar", "Cannot deserialize object with incomplete grammar: %s [%s] %p fromString: %s",
273  type_name().c_str(), this->name.c_str(), (void*)this, (void*)specialization.fromString);
274  return false;
275 }
276 
278 int dd4hep::BasicGrammar::evaluate(void* ptr, const std::string& value) const {
279  if ( specialization.eval )
280  return specialization.eval(*this, ptr, value);
281  except("Grammar", "Cannot evaluate object with incomplete grammar: %s", type_name().c_str());
282  return 0;
283 }
284 
286 std::pair<int,double> dd4hep::detail::grammar_evaluate_item(std::string val) {
287  size_t idx = val.find("(int)");
288  if (idx != std::string::npos)
289  val.erase(idx, 5);
290  while (val[0] == ' ')
291  val.erase(0, 1);
292  auto result = s__eval->evaluate(val.c_str());
293  return result;
294 }
295 
297 std::string dd4hep::detail::grammar_pre_parse_map(const std::string& in) {
298  bool ignore_blanks = true;
299  bool str_open = false;
300  bool obj_open = false;
301  bool start = false;
302  std::string res = "";
303  res.reserve(1024);
304  // std::cout << "Pre-parsed (in):" << in << std::endl;
305  for(const char* c = in.c_str(); *c; ++c) {
306  switch(*c) {
307  case '\'':
308  res += *c;
309  if ( start ) { start = false; }
310  if ( str_open ) { str_open = false; }
311  break;
312  case ':':
313  if ( str_open ) { res += '\''; }
314  res += *c;
315  res += ' ';
316  res += '\'';
317  str_open = true;
318  ignore_blanks = true;
319  break;
320  case ',':
321  if ( !obj_open && str_open ) { res += '\''; str_open = false; }
322  res += ",";
323  start = true;
324  ignore_blanks = true;
325  break;
326  case '(':
327  res += *c ;
328  obj_open = true;
329  break;
330  case ')':
331  res += *c ;
332  obj_open = false;
333  break;
334  case '[':
335  case '{':
336  res += *c ;
337  start = true;
338  ignore_blanks = true;
339  break;
340  case ']':
341  case '}':
342  if ( str_open ) {
343  res += '\'';
344  str_open = false;
345  }
346  res += *c ;
347  break;
348  case ' ':
349  if ( !ignore_blanks ) res += *c;
350  break;
351  default:
352  if ( start ) {
353  if ( !obj_open ) res += '\'';
354  start = false;
355  str_open = true;
356  }
357  ignore_blanks = false;
358  res += *c;
359  break;
360  }
361  }
362  // std::cout << "Pre-parsed (out):" << res << std::endl;
363  return res;
364 }
365 
367 std::string dd4hep::detail::grammar_pre_parse_cont(const std::string& in) {
368  bool ignore_blanks = true;
369  bool str_open = false;
370  bool start = false;
371  std::string res = "";
372  res.reserve(1024);
373  // std::cout << "Pre-parsed (in):" << in << std::endl;
374  for(const char* c = in.c_str(); *c; ++c) {
375  switch(*c) {
376  case '\'':
377  res += *c;
378  if ( start ) { start = false; }
379  if ( str_open ) { str_open = false; }
380  break;
381  case ':':
382  if ( str_open ) { res += '\''; }
383  res += *c;
384  res += ' ';
385  res += '\'';
386  str_open = true;
387  ignore_blanks = true;
388  break;
389  case ',':
390  if ( str_open ) { res += '\''; str_open = false; }
391  res += ",";
392  start = true;
393  ignore_blanks = true;
394  break;
395  case '(':
396  case '[':
397  case '{':
398  res += *c ;
399  start = true;
400  ignore_blanks = true;
401  break;
402  case ')':
403  case ']':
404  case '}':
405  if ( str_open ) { res += '\''; str_open = false; }
406  res += *c ;
407  break;
408  case ' ':
409  if ( !ignore_blanks ) res += *c;
410  break;
411  default:
412  if ( start ) {
413  res += '\'';
414  start = false;
415  str_open = true;
416  }
417  ignore_blanks = false;
418  res += *c;
419  break;
420  }
421  }
422  // std::cout << "Pre-parsed (out):" << res << std::endl;
423  return res;
424 }
425 
427 std::string dd4hep::detail::grammar_pre_parse_obj(const std::string& in) {
428  std::string res = "";
429  res.reserve(1024);
430  for(const char* c = in.c_str(); *c; ++c) {
431  switch(*c) {
432  case '\'':
433  return "Bad object representation";
434  case ',':
435  res += "','";
436  break;
437  case '(':
438  case '[':
439  res += "['";
440  break;
441  case ')':
442  case ']':
443  res += "']";
444  break;
445  default:
446  res += *c;
447  break;
448  }
449  }
450  //cout << "Pre-parsed:" << res << endl;
451  return res;
452 }
453 
456  static GrammarRegistry s_reg;
457  return s_reg;
458 }
459 
dd4hep::BasicGrammar::pre_note
static void pre_note(const std::type_info &info, const BasicGrammar &(*fcn)(), specialization_t specs)
Instance factory.
Definition: Grammar.cpp:119
dd4hep::BasicGrammar::name
const std::string name
Instance type name.
Definition: Grammar.h:61
dd4hep::BasicGrammar::key_type
unsigned long long int key_type
Definition: Grammar.h:59
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:278
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:367
dd4hep::setGrammarEvaluator
void setGrammarEvaluator(const std::string &type)
Set grammar evaluator.
Definition: Grammar.cpp:82
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:95
dd4hep::BasicGrammar::hash_value
const key_type hash_value
Instance hash code.
Definition: Grammar.h:63
dd4hep::BasicGrammar::initialized_clazz
TClass * initialized_clazz() const
Access the ROOT class for complex objects.
Definition: Grammar.cpp:224
dd4hep::BasicGrammar::BasicGrammar
BasicGrammar(const std::string &typ)
Default constructor.
Definition: Grammar.cpp:102
dd4hep::BasicGrammar::specialization_t::copy
void(* copy)(void *to, const void *from)=0
Opaque copy constructor.
Definition: Grammar.h:78
dd4hep::BasicGrammar::str
virtual std::string str(const void *ptr) const
Serialize an opaque value to a string.
Definition: Grammar.cpp:261
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:269
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:297
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:82
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:286
dd4hep::BasicGrammar
Base class describing string evaluation to C++ objects using boost::spirit.
Definition: Grammar.h:56
dd4hep::GrammarRegistry
Grammar registry interface.
Definition: Grammar.h:235
dd4hep::detail::eval
Definition: RootDictionary.h:84
dd4hep::BasicGrammar::specialization_t::cast
const Cast * cast
Ponter to ABI Cast structure.
Definition: Grammar.h:74
dd4hep::BasicGrammar::get
static const BasicGrammar & get(const std::type_info &info)
Access grammar by type info.
Definition: Grammar.cpp:184
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:84
dd4hep::BasicGrammar::specialization_t::bind
void(* bind)(void *pointer)=0
Bind opaque address to object.
Definition: Grammar.h:76
dd4hep::BasicGrammar::setCast
virtual void setCast(const Cast *cast) const
Set cast structure.
Definition: Grammar.cpp:247
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:80
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:218
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:253
dd4hep::BasicGrammar::initialize
void initialize() const
Second step initialization after the virtual table is fixed.
Definition: Grammar.cpp:198
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:72
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:427
dd4hep::BasicGrammar::invalidConversion
static void invalidConversion(const std::type_info &from, const std::type_info &to)
Error callback on invalid conversion.
Definition: Grammar.cpp:238
dd4hep::BasicGrammar::~BasicGrammar
virtual ~BasicGrammar()
Default destructor.
Definition: Grammar.cpp:115
Printout.h
Exceptions.h
Grammar.h
dd4hep::GrammarRegistry::instance
static const GrammarRegistry & instance()
Registry instance singleton.
Definition: Grammar.cpp:455