DD4hep  1.37.0
Detector Description Toolkit for High Energy Physics
Primitives.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/Primitives.h>
16 #include <DD4hep/Exceptions.h>
17 #include <DD4hep/Printout.h>
18 
19 // C/C++ include files
20 #include <cstddef>
21 #include <cstring>
22 
23 #if defined(__linux) || defined(__APPLE__) || defined(__powerpc64__)
24 #include <cxxabi.h>
25 #ifndef __APPLE__
26 typedef abi::__class_type_info class_t;
27 using abi::__dynamic_cast;
28 #endif
29 #endif
30 
32 namespace {
33 
34 #if 0
35 //-----------------------------------------------------------------------------
36 // MurmurHash2, 64-bit versions, by Austin Appleby
37 //
38 // The same caveats as 32-bit MurmurHash2 apply here - beware of alignment
39 // and endian-ness issues if used across multiple platforms.
40  inline uint64_t murmur_hash_64 ( const void * key, int len) {
41 #define seed 0xFEEDBABE
42  typedef unsigned long long int uint64;
43 
44 #if INTPTR_MAX == INT32_MAX
45  const unsigned int * data = (const unsigned int *)key;
46  const unsigned int m = 0x5bd1e995;
47  const int r = 24;
48 
49  unsigned int h1 = seed ^ len;
50  unsigned int h2 = 0;
51 
52  while(len >= 8)
53  {
54  unsigned int k1 = *data++;
55  k1 *= m; k1 ^= k1 >> r; k1 *= m;
56  h1 *= m; h1 ^= k1;
57  len -= 4;
58 
59  unsigned int k2 = *data++;
60  k2 *= m; k2 ^= k2 >> r; k2 *= m;
61  h2 *= m; h2 ^= k2;
62  len -= 4;
63  }
64 
65  if(len >= 4)
66  {
67  unsigned int k1 = *data++;
68  k1 *= m; k1 ^= k1 >> r; k1 *= m;
69  h1 *= m; h1 ^= k1;
70  len -= 4;
71  }
72 
73  switch(len)
74  {
75  case 3: h2 ^= ((unsigned char*)data)[2] << 16;
76  case 2: h2 ^= ((unsigned char*)data)[1] << 8;
77  case 1: h2 ^= ((unsigned char*)data)[0];
78  h2 *= m;
79  };
80 
81  h1 ^= h2 >> 18; h1 *= m;
82  h2 ^= h1 >> 22; h2 *= m;
83  h1 ^= h2 >> 17; h1 *= m;
84  h2 ^= h1 >> 19; h2 *= m;
85 
86  uint64 h = h1;
87 
88  h = (h << 32) | h2;
89 #elif INTPTR_MAX == INT64_MAX
90  const uint64* data = (const uint64*)key;
91  const uint64 m = 0xc6a4a7935bd1e995;
92  const int r = 47;
93 
94  uint64 h = seed ^ (len * m);
95 
96  const uint64 * end = data + (len/8);
97 
98  while(data != end)
99  {
100  uint64 k = *data++;
101 
102  k *= m;
103  k ^= k >> r;
104  k *= m;
105 
106  h ^= k;
107  h *= m;
108  }
109 
110  const unsigned char * data2 = (const unsigned char*)data;
111 
112  switch(len & 7)
113  {
114  case 7: h ^= uint64(data2[6]) << 48;
115  case 6: h ^= uint64(data2[5]) << 40;
116  case 5: h ^= uint64(data2[4]) << 32;
117  case 4: h ^= uint64(data2[3]) << 24;
118  case 3: h ^= uint64(data2[2]) << 16;
119  case 2: h ^= uint64(data2[1]) << 8;
120  case 1: h ^= uint64(data2[0]);
121  h *= m;
122  };
123 
124  h ^= h >> r;
125  h *= m;
126  h ^= h >> r;
127 
128 #else
129 #error "Environment not 32 or 64-bit."
130 #endif
131  return h;
132  }
133 #endif
134 
135  struct FNV1a_64 {
136  static const unsigned long long int hashinit = 14695981039346656037ull;
137  static constexpr unsigned long long int doByte(unsigned long long int hash,unsigned char val)
138  { return (hash ^ val) * 1099511628211ull; }
139  };
140 
141  static unsigned char crc8_table[] =
142  { 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
143  157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
144  35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
145  190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
146  70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
147  219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
148  101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
149  248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
150  140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
151  17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
152  175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
153  50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
154  202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
155  87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
156  233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
157  116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53
158  };
160  static unsigned char pearson_hash(const void *data, size_t len) {
161  const char *s = (const char*)data;
162  unsigned char c = 0;
163  while (--len) c = crc8_table[c ^ *s++];
164  return c;
165  }
166  static unsigned char pearson_hash(const char *data) {
167  const char *s = data;
168  unsigned char c = 0;
169  while (*s) c = crc8_table[c ^ *s++];
170  return c;
171  }
172 }
173 
175 std::string dd4hep::volumeID(VolumeID vid) {
176  char text[32];
177  unsigned long long id = (unsigned long long)vid;
178  ::snprintf(text,sizeof(text), "%016llx", id);
179  return text;
180 }
181 
183 unsigned long long int dd4hep::detail::hash64(const char* key) {
184  return update_hash64(FNV1a_64::hashinit, key);
185 }
186 
188 unsigned long long int dd4hep::detail::hash64(const std::string& key) {
189  return update_hash64(FNV1a_64::hashinit, key.c_str(), key.length());
190 }
191 
193 unsigned long long int dd4hep::detail::hash64(const void* key, std::size_t len) {
194  return update_hash64(FNV1a_64::hashinit, key, len);
195 }
196 
198 unsigned long long int dd4hep::detail::update_hash64(unsigned long long int hash, const std::string& key) {
199  return update_hash64(hash, key.c_str(), key.length());
200 }
201 
203 unsigned long long int dd4hep::detail::update_hash64(unsigned long long int hash, const char* key) {
204  const unsigned char* str = (const unsigned char*)key;
205  for ( ; *str; ++str) hash = FNV1a_64::doByte(hash, *str);
206  return hash;
207 }
208 
210 unsigned long long int dd4hep::detail::update_hash64(unsigned long long int hash, const void* key, std::size_t len) {
211  const unsigned char* str = (const unsigned char*)key;
212  for (std::size_t i = 0; i < len; ++i) hash = FNV1a_64::doByte(hash, str[i]);
213  return hash;
214 }
215 
217 unsigned short dd4hep::detail::hash16(const void* key, std::size_t len) {
218  unsigned short value = (unsigned short)hash32(key, len);
219  return value;
220 }
221 
223 unsigned char dd4hep::detail::hash8(const void* key, std::size_t len) {
224  return pearson_hash(key, len);
225 }
226 
228 unsigned char dd4hep::detail::hash8(const char* key) {
229  return pearson_hash(key);
230 }
231 
233 std::string dd4hep::detail::str_replace(const std::string& str,
234  const std::string& pattern,
235  const std::string& replacement) {
236  std::string res = str;
237  for(size_t id=res.find(pattern); id != std::string::npos; id = res.find(pattern) )
238  res.replace(id, pattern.length(), replacement);
239  return res;
240 }
241 
243 std::string dd4hep::detail::str_replace(const std::string& str,
244  char pattern,
245  const std::string& replacement) {
246  std::string res = str;
247  for(size_t id=res.find(pattern); id != std::string::npos; id = res.find(pattern) )
248  res.replace(id, 1, replacement);
249  return res;
250 }
251 
253 std::string dd4hep::detail::str_replace(const std::string& str,
254  char pattern,
255  char replacement) {
256  std::string res = str;
257  for(size_t id=res.find(pattern); id != std::string::npos; id = res.find(pattern) )
258  res.replace(id, 1, 1, replacement);
259  return res;
260 }
261 
263 std::string dd4hep::detail::str_lower(const std::string& str) {
264  std::string res = str.c_str();
265  std::transform(res.begin(), res.end(), res.begin(), ::tolower);
266  return res;
267 }
268 
270 std::string dd4hep::detail::str_upper(const std::string& str) {
271  std::string res = str.c_str();
272  std::transform(res.begin(), res.end(), res.begin(), ::toupper);
273  return res;
274 }
275 
276 long int dd4hep::detail::makeTime(int year, int month, int day,
277  int hour, int minutes, int seconds)
278 {
279  struct tm tm_init;
280  ::memset(&tm_init,0,sizeof(tm_init));
281  tm_init.tm_year = year > 1900 ? year-1900 : year;
282  tm_init.tm_mon = month;
283  tm_init.tm_mday = day;
284  tm_init.tm_hour = hour;
285  tm_init.tm_min = minutes;
286  tm_init.tm_sec = seconds;
287  tm_init.tm_isdst = -1;
288  long int ti = ::mktime(&tm_init);
289  if ( ti >= 0 ) return ti;
290  except("dd4hep","Invalid time data given for conversion to epoch: %d-%d-%d %02d:%02d:%02d",
291  year, month, day, hour, minutes, seconds);
292  return ti;
293 }
294 
296 long int dd4hep::detail::makeTime(const std::string& date, const char* fmt) {
297  struct tm tm;
298  char* c = ::strptime(date.c_str(),fmt,&tm);
299  if ( 0 == c ) {
300  except("dd4hep",
301  "Invalid time format given for update:%s should be: %s",
302  date.c_str(), fmt);
303  }
304  long ti = ::mktime(&tm);
305  if ( ti >= 0 ) return ti;
306  except("dd4hep",
307  "Invalid time string given for conversion to epoch: %s (fmt='%s')",
308  date.c_str(), fmt);
309  return ti;
310 }
311 
312 static const std::string __typeinfoName(const std::type_info& tinfo) {
313  const char* class_name = tinfo.name();
314  std::string result;
315 #ifdef WIN32
316  std::size_t off = 0;
317  if ( ::strncmp(class_name, "class ", 6) == 0 ) {
318  // The returned name is prefixed with "class "
319  off = 6;
320  }
321  if ( ::strncmp(class_name, "struct ", 7) == 0 ) {
322  // The returned name is prefixed with "struct "
323  off = 7;
324  }
325  if ( off != std::string::npos ) {
326  std::string tmp = class_name + off;
327  size_t loc = 0;
328  while( (loc = tmp.find("class ")) != std::string::npos ) {
329  tmp.erase(loc, 6);
330  }
331  loc = 0;
332  while( (loc = tmp.find("struct ")) != std::string::npos ) {
333  tmp.erase(loc, 7);
334  }
335  result = tmp;
336  }
337  else {
338  result = class_name;
339  }
340  // Change any " *" to "*"
341  while ( (off=result.find(" *")) != std::string::npos ) {
342  result.replace(off, 2, "*");
343  }
344  // Change any " &" to "&"
345  while ( (off=result.find(" &")) != std::string::npos ) {
346  result.replace(off, 2, "&");
347  }
348 #elif defined(sun)
349  result = class_name;
350 #elif !defined(__ICC)
351  if (::strlen(class_name) == 1) {
352  // See http://www.realitydiluted.com/mirrors/reality.sgi.com/dehnert_engr/cxx/abi.pdf
353  // for details
354  switch (class_name[0]) {
355  case 'v':
356  result = "void";
357  break;
358  case 'w':
359  result = "wchar_t";
360  break;
361  case 'b':
362  result = "bool";
363  break;
364  case 'c':
365  result = "char";
366  break;
367  case 'h':
368  result = "unsigned char";
369  break;
370  case 's':
371  result = "short";
372  break;
373  case 't':
374  result = "unsigned short";
375  break;
376  case 'i':
377  result = "int";
378  break;
379  case 'j':
380  result = "unsigned int";
381  break;
382  case 'l':
383  result = "long";
384  break;
385  case 'm':
386  result = "unsigned long";
387  break;
388  case 'x':
389  result = "long long";
390  break;
391  case 'y':
392  result = "unsigned long long";
393  break;
394  case 'n':
395  result = "__int128";
396  break;
397  case 'o':
398  result = "unsigned __int128";
399  break;
400  case 'f':
401  result = "float";
402  break;
403  case 'd':
404  result = "double";
405  break;
406  case 'e':
407  result = "long double";
408  break;
409  case 'g':
410  result = "__float128";
411  break;
412  case 'z':
413  result = "ellipsis";
414  break;
415  }
416  }
417  else {
418  char buff[16 * 1024];
419  std::size_t len = sizeof(buff);
420  int status = 0;
421  result = __cxxabiv1::__cxa_demangle(class_name, buff, &len, &status);
422  }
423 #else
424  result = class_name;
425  throw std::runtime_error("CXXABI is missing for ICC!");
426 #endif
427  return result;
428 }
429 
430 std::string dd4hep::typeName(const std::type_info& typ) {
431  return __typeinfoName(typ);
432 }
433 
434 void dd4hep::invalidHandleError(const std::type_info& type)
435 {
436  throw invalid_handle_exception("Attempt to access invalid object of type "+typeName(type)+" [Invalid Handle]");
437 }
438 
439 void dd4hep::invalidHandleAssignmentError(const std::type_info& from,
440  const std::type_info& to)
441 {
442  std::string msg = "Wrong assingment from ";
443  msg += typeName(from);
444  msg += " to ";
445  msg += typeName(to);
446  msg += " not possible!!";
447  throw invalid_handle_exception(msg);
448 }
449 
451 void dd4hep::notImplemented(const std::string& msg)
452 {
453  std::string m = "The requested feature " + msg + " is not implemented!";
454  throw std::runtime_error(m);
455 }
456 
457 void dd4hep::typeinfoCheck(const std::type_info& typ1, const std::type_info& typ2, const std::string& text)
458 {
459  if (typ1 != typ2) {
460  throw unrelated_type_error(typ1, typ2, text);
461  }
462 }
463 
464 namespace dd4hep {
465  namespace detail {
466  template<> const char* Primitive<bool>::default_format() { return "%d"; }
467  template<> const char* Primitive<char>::default_format() { return "%c"; }
468  template<> const char* Primitive<unsigned char>::default_format() { return "%02X"; }
469  template<> const char* Primitive<short>::default_format() { return "%d"; }
470  template<> const char* Primitive<unsigned short>::default_format() { return "%04X"; }
471  template<> const char* Primitive<int>::default_format() { return "%d"; }
472  template<> const char* Primitive<unsigned int>::default_format() { return "%08X"; }
473  template<> const char* Primitive<long>::default_format() { return "%ld"; }
474  template<> const char* Primitive<unsigned long>::default_format() { return "%016X"; }
475  template<> const char* Primitive<float>::default_format() { return "%f"; }
476  template<> const char* Primitive<double>::default_format() { return "%g"; }
477  template<> const char* Primitive<char*>::default_format() { return "%s"; }
478  template<> const char* Primitive<const char*>::default_format() { return "%s"; }
479  template<> const char* Primitive<std::string>::default_format() { return "%s"; }
480 
482  template <typename T> std::string Primitive<T>::toString(T value) {
483  char text[1024];
484  ::snprintf(text,sizeof(text),default_format(),value);
485  return text;
486  }
487 
489  template <> std::string Primitive<const char*>::toString(const char* value) {
490  if ( value ) {
491  return value;
492  }
493  throw std::runtime_error("Failed to convert (char*)NULL to std::string!");
494  }
496  template <> std::string Primitive<char*>::toString(char* value) {
497  if ( value ) {
498  return value;
499  }
500  throw std::runtime_error("Failed to convert (char*)NULL to std::string!");
501  }
503  template <> std::string Primitive<std::string>::toString(std::string value) {
504  return value;
505  }
506 
507  template std::string Primitive<bool>::toString(bool value);
508  template std::string Primitive<char>::toString(char value);
509  template std::string Primitive<unsigned char>::toString(unsigned char value);
510  template std::string Primitive<short>::toString(short value);
511  template std::string Primitive<unsigned short>::toString(unsigned short value);
512  template std::string Primitive<int>::toString(int value);
513  template std::string Primitive<unsigned int>::toString(unsigned int value);
514  template std::string Primitive<long>::toString(long value);
515  template std::string Primitive<unsigned long>::toString(unsigned long value);
516  template std::string Primitive<float>::toString(float value);
517  template std::string Primitive<double>::toString(double value);
518  }
519 }
520 
521 #ifdef __APPLE__
522 dd4hep::Cast::Cast(const std::type_info& t, cast_t c) : type(t), cast(c) {
524 }
525 #else
526 dd4hep::Cast::Cast(const std::type_info& t) : type(t) {
528  abi_class = dynamic_cast<const class_t*>(&type);
529  if (!abi_class) {
530  throw std::runtime_error("Class type " + typeName(type) + " is not an abi object type!");
531  }
532 }
533 #endif
534 
536 dd4hep::Cast::~Cast() {
537 }
538 
540 void* dd4hep::Cast::apply_dynCast(const Cast& to, const void* ptr) const
541 {
542  if (&to == this) {
543  return (void*) ptr;
544  }
545 #ifdef __APPLE__
546  // First try down cast
547  void *r = (*to.cast)(ptr);
548  if (r)
549  return r;
550  // Now try the up-cast
551  r = (*cast)(ptr);
552  if (r) return r;
553  throw unrelated_type_error(type, to.type, "Failed to apply abi dynamic cast operation!");
554 #else
555  void* r = (void*)ptr;
556  if ( to.abi_class ) {
557  bool cast_worked = type.__do_upcast((const class_t*)to.abi_class,&r);
558  if ( cast_worked ) return r;
559  r = (void*)ptr;
560  cast_worked = to.type.__do_upcast((const class_t*)abi_class,&r);
561  if ( cast_worked ) return r;
562 #if 0
563  const class_t* src_type = (const class_t*)to.abi_class;
564  if (src_type) {
565  // First try down cast
566  void *r = cast_wrap(ptr, src_type, (const class_t*) abi_class, -1);
567  if ( r ) return r;
568  // Now try the up-cast
569  r = cast_wrap(ptr, (const class_t*) abi_class, src_type, -1);
570  if (r) return r;
571  }
572 #endif
573  throw unrelated_type_error(type, to.type, "Failed to apply abi dynamic cast operation!");
574  }
575 #endif
576  throw unrelated_type_error(type, to.type, "Target type is not an abi class type!");
577 }
578 
580 void* dd4hep::Cast::apply_upCast(const Cast& to, const void* ptr) const
581 {
582  if (&to == this) {
583  return (void*) ptr;
584  }
585  return apply_dynCast(to, ptr);
586 }
587 
589 void* dd4hep::Cast::apply_downCast(const Cast& to, const void* ptr) const
590 {
591  if (&to == this) {
592  return (void*) ptr;
593  }
594 #ifdef __APPLE__
595  void *r = (*to.cast)(ptr);
596  if (r) return r;
597  throw unrelated_type_error(type, to.type, "Failed to apply abi dynamic cast operation!");
598 #else
599  if ( to.abi_class ) {
600  // Since we have to cast a 'to' pointer up to the real pointer
601  // no virtual inheritance can be supported!
602  void* r = (void*)ptr;
603  bool cast_worked = type.__do_upcast((const class_t*)to.abi_class,&r);
604  if ( cast_worked ) return r;
605 #if 0
606  void *r = cast_wrap(ptr, src_type, (const class_t*)abi_class, -1);
607  if (r) return r;
608 #endif
609  throw unrelated_type_error(type, to.type, "Failed to apply abi dynamic cast operation!");
610  }
611  throw unrelated_type_error(type, to.type, "Target type is not an abi class type!");
612 #endif
613 }
Primitives.h
VolumeID
dd4hep::DDSegmentation::VolumeID VolumeID
Definition: SegmentationDictionary.h:50
key
unsigned char key
Definition: AlignmentsCalculator.cpp:69
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
dd4hep::detail::tools::toString
std::string toString(const PlacedVolume::VolIDs &ids)
Convert VolumeID to string.
Definition: DetectorTools.cpp:385
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:191
Printout.h
Exceptions.h
dd4hep::DDSegmentation::Segmentation::type
virtual const std::string & type() const
Access the segmentation type.
Definition: Segmentation.h:103