ATLAS Offline Software
TDVCollectionProxy.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // System include(s):
6 #include <cassert>
7 
8 // ROOT include(s):
9 #include <TError.h>
10 #include <TClassEdit.h>
11 #include <TClass.h>
12 #include <TBaseClass.h>
13 #include <TCollectionProxyInfo.h>
14 #include <TSystem.h>
15 #include <TList.h>
16 
17 // EDM include(s):
21 #include "RootUtils/Type.h"
22 
23 // Local include(s):
25 
26 #include <iostream>
27 using namespace std;
28 const bool mn = getenv("MN_DEBUG");
29 
30 namespace xAOD {
31 
40  int safeGetBaseOffset( TClass* cls, TClass* base ) {
41 
42  return cls->GetBaseClassOffset( base );
43  }
44 
49  TClass* classFromDVClass( TClass* dvclass ) {
50 
51  // Split up the class name into template arguments.
52  std::vector< std::string > args;
53  int tailloc;
54  {
55  // Protect against data race inside TClassEdit.
56  // https://github.com/root-project/root/issues/10353
57  // Should be fixed in root 6.26.02.
58  R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
59  TClassEdit::GetSplit( dvclass->GetName(), args, tailloc );
60  }
61  assert( args.size() > 1 );
62 
63  // This should be the element type name.
64  std::string elname = args[ 1 ];
65  assert( elname.size() > 0 );
66 
67  // Look up the element class.
68  TClass* elclass = TClass::GetClass( elname.c_str() );
69  if (!elclass) {
70  ::Error( "xAOD::TDVCollectionProxy", "Cannot find class %s",
71  elname.c_str() );
72  }
73 
74  return elclass;
75  }
76 
87  TClass* findDVBase( TClass* dvclass ) {
88 
89  TIter next( dvclass->GetListOfBases() );
90  while( TBaseClass* bcl = dynamic_cast< TBaseClass* >( next() ) ) {
91  TClass* cc = bcl->GetClassPointer();
92  if( strncmp( cc->GetName(), "DataVector", 10 ) == 0 ) {
93  TClass* bdv = findDVBase( cc );
94  if( bdv ) return bdv;
95  if( strncmp( cc->GetName(), "DataVector<", 11 ) == 0 )
96  return cc;
97  }
98  }
99 
100  return nullptr;
101  }
102 
112  std::string findDVElement( TClass* cl ) {
113 
114  // Make sure that the minimal set of dictionaries are loaded:
115  TClass* dummyCl =
116  TClass::GetClass( "DataVector<xAOD::TDVCollectionProxyDummy>" );
117  if( ! dummyCl ) {
118  Error( "xAOD::findDVElement",
119  "Couldn't load the dictionary for "
120  "DataVector<xAOD::TDVCollectionProxyDummy>" );
121  return "";
122  }
123 
124  // Is this a DV class?
125  std::string elt;
126  const char* name = cl->GetName();
127  if( strncmp( name, "DataVector<", 11 ) == 0 ) {
128 
129  elt = std::string( name + 11, strlen( name ) - 11 - 1 );
130 
131  // Usually the full DataVector name includes two template
132  // arguments. But we only need the first one, before the first comma.
133  const std::string::size_type comma = elt.find( ',' );
134  if( comma != std::string::npos ) {
135  elt.resize (comma);
136  }
137 
138  return elt;
139  }
140 
141  // Scan base classes too.
142  TIter next( cl->GetListOfBases() );
143  while( TBaseClass* bcl = dynamic_cast< TBaseClass* >( next() ) ) {
144  TClass* cc = bcl->GetClassPointer();
145  elt = findDVElement( cc );
146  if( ! elt.empty() ) {
147  break;
148  }
149  }
150 
151  return elt;
152  }
153 
156 
157  public:
161  typedef std::vector< char* > Cont_t;
162 
173  struct TEnvBuff {
174 
176  size_t fIndex;
177 
182 
184  void* fEltPtr;
185 
188  int fOffset;
189 
190  }; // struct TEnvBuff
191 
193  using Env_t = ROOT::TCollectionProxyInfo::Environ<TEnvBuff>;
194 
198  static Cont_t* cont( void* env ) {
199 
200  Env_t& e = *reinterpret_cast< Env_t* >( env );
201  TEnvBuff& buff = e.fIterator;
202  return buff.fCont;
203  }
204 
211  static void* first( void* env ) {
212  Env_t& e = *reinterpret_cast< Env_t* >( env );
213  Cont_t& c = *cont( env );
214  TEnvBuff& buff = e.fIterator;
215  buff.fIndex = 0;
216  e.fSize = c.size();
217  if( 0 == e.fSize ) {
218  return nullptr;
219  }
220  char* start = c[ 0 ];
221  buff.fEltPtr = start + buff.fOffset;
222  return buff.fEltPtr;
223  }
224 
233  static void* next( void* env ) {
234 
235  Env_t& e = *reinterpret_cast< Env_t* >( env );
236  Cont_t& c = *cont( env );
237  TEnvBuff& buff = e.fIterator;
238  buff.fIndex += e.fIdx;
239  e.fIdx = 0;
240  if( buff.fIndex >= e.fSize ) {
241  return nullptr;
242  }
243  char* ptr = c[ buff.fIndex ];
244  buff.fEltPtr = ptr + buff.fOffset;
245  return buff.fEltPtr;
246  }
247 
251  static void* size( void* env ) {
252 
253  Env_t* e = reinterpret_cast< Env_t* >( env );
254  e->fSize = cont( env )->size();
255  return &( e->fSize );
256  }
257 
261  static void* clear( void* env ) {
262 
263  cont( env )->clear();
264  return nullptr;
265  }
266 
268  static void* create_env() {
269 
270  return new Env_t;
271  }
272 
273  //*************************************************************************
274  // These methods are not needed for the xAOD usage,
275  // and are not implemented.
276 
278  // template <typname T> // T will be equal to final class
279  static void resize( void* /*obj*/, size_t /*size*/ ) {
280  ::Fatal( "xAOD::TDVCollectionProxy", "resize function not specified!" );
281  }
282 
284  static void* construct( void* /*from*/, size_t /*size*/ ) {
285  ::Fatal( "xAOD::TDVCollectionProxy", "construct not implemented" );
286  return nullptr;
287  }
288 
290  static void destruct( void* /*obj*/, size_t /*size*/ ) {
291  ::Fatal( "xAOD::TDVCollectionProxy", "destruct not implemented" );
292  }
293 
295  static void* feed( void* /*from*/, void* to, size_t size )
296  {
297  DataVector<char> *dv = reinterpret_cast<DataVector<char>*>(to);
298  // find out vector element typeinfo and get RootUtils::Type for it
299  const std::type_info &elem_typeinfo = dv->dvlinfo_v().elt_tinfo();
300  auto ru_type = RootUtils::Type( SG::normalizedTypeinfoName(elem_typeinfo) );
301  // copy vector elements into DataVector
302  if(mn) cout << "PROX: feed, typename=" << ru_type.getTypeName() << " typesize=" << ru_type.getSize() <<endl;
303 
304  //char *src = reinterpret_cast<char*>( from );
305  for(size_t i=0; i<size; i++) {
306  void *obj = ru_type.create();
307  // ru_type.assign(obj, src); //MN: this may crash, so for now we do not copy data (bad only for CaloCluster
308  dv->dvlinfo_v().push(dv,obj);
309  //src += ru_type.getSize();
310  }
311  return nullptr;
312  }
313 
315  static void* collect( void* /*from*/, void* /*to*/ ) {
316  ::Fatal( "xAOD::TDVCollectionProxy", "collect not implemented" );
317  return nullptr;
318  }
319  }; // class TDVCollectionFuncs
320 
328  TDVCollectionProxy::TDVCollectionProxy( const char* conttype )
329  : TGenCollectionProxy( typeid( DataVector< TDVCollectionProxyDummy > ),
330  sizeof( char* ) ),
331  fName( conttype ), fInitialized( kFALSE ),
332  fContoff( 0 ), fOffset( 0 ), fEltBase( nullptr ), fEltType( nullptr ) {
333 
334  // Set up the element size. No offset, since this isn't a map.
335  fValDiff = sizeof( void* );
336  fValOffset = 0;
337 
338  // Set up the worker functions.
339  fSize.call = TDVCollectionFuncs::size;
340  fNext.call = TDVCollectionFuncs::next;
341  fFirst.call = TDVCollectionFuncs::first;
342  fClear.call = TDVCollectionFuncs::clear;
343  fCollect = TDVCollectionFuncs::collect;
344  fCreateEnv.call = TDVCollectionFuncs::create_env;
345  fResize = TDVCollectionFuncs::resize;
346  fConstruct = TDVCollectionFuncs::construct;
347  fDestruct = TDVCollectionFuncs::destruct;
348  fFeed = TDVCollectionFuncs::feed;
349 
350  // Make sure that TGenCollectionProxy knows that it's not
351  // fully set up yet:
352  if( fValue ) {
353  delete fValue.exchange( nullptr );
354  }
355  if( fVal ) {
356  delete fVal;
357  fVal = nullptr;
358  }
359 
360  // This container pretends to hold objects, not pointers:
361  fPointers = kFALSE;
362 
363  // Remember that we are not initialized yet:
364  fProperties = 0;
365  }
366 
371  : TGenCollectionProxy( rhs ),
372  fName( rhs.fName ),
373  fInitialized( rhs.fInitialized ),
374  fContoff( rhs.fContoff ),
375  fOffset( rhs.fOffset ),
376  fEltBase( rhs.fEltBase ),
377  fEltType( rhs.fEltType ) {
378 
379  // If we're not initialised yet, make sure that the base class is
380  // on the same page...
381  if( ! fInitialized ) {
382  if( fValue ) {
383  delete fValue.exchange( nullptr );
384  }
385  if( fVal ) {
386  delete fVal;
387  fVal = nullptr;
388  }
389  }
390  }
391 
396 
397  // Do the base class stuff.
398  // This will create an environment buffer if needed.
399  ::TGenCollectionProxy::PushProxy( objstart );
400 
401  // Save the calculated element offset in the environment buffer.
403  reinterpret_cast< TDVCollectionFuncs::Env_t* >( fEnv )->fIterator;
404 
405  // Get the offset needed for the pointer operations:
406  buff.fOffset = fOffset;
407 
408  // Save the address of the underlying vector of the DataVector.
409  // First, adjust the address to the base DataVector.
410  char* dvstart = reinterpret_cast< char* >( objstart ) + fContoff;
411  // Cast to DV.
412  // This gets a ubsan warning about casting between types.
413  // However, this is deliberate, so suppress ubsan warnings
414  // for this function.
416  reinterpret_cast< DataVector< char >* >( dvstart );
417  // Find the underlying vector.
418  const std::vector< char* >& vec = dv->stdcont();
419  // And store its address.
420  std::vector<char*>* vptr ATLAS_THREAD_SAFE =
421  const_cast< std::vector< char* >* >( &vec );
422  buff.fCont = vptr;
423 
424  return;
425  }
426 
428  TVirtualCollectionProxy* TDVCollectionProxy::Generate() const {
429 
430  return new TDVCollectionProxy( *this );
431  }
432 
440 
441  fResize = func;
442  return;
443  }
444 
445  TGenCollectionProxy* TDVCollectionProxy::InitializeEx( Bool_t silent ) {
446 
447  // Check if we're initialised already:
448  if( fInitialized ) return this;
449 
450  // Check for the class's dictionary, and for its element type:
451  TClass* cl = TClass::GetClass( fName );
452  if( ! cl ) {
453  ::Fatal( "xAOD::TDVCollectionProxy::InitializeEx",
454  "Couldn't find dictionary for class %s",
455  fName.Data() );
456  return nullptr;
457  }
458 
459  // Check if it is a DataVector:
460  const std::string eltname = findDVElement( cl );
461  if( eltname.empty() ) {
462  ::Fatal( "xAOD::TDVCollectionProxy::InitializeEx",
463  "Class \"%s\" doesn't seem to be a DataVector",
464  cl->GetName() );
465  return nullptr;
466  }
467 
468  // Find the container and element offsets.
469  FindOffsets( eltname.c_str(), fName );
470 
471  // Set up the element size. No offset, since this isn't a map.
472  fValDiff = sizeof( void* );
473  fValOffset = 0;
474 
475  // Do the base class initialization.
476  CheckFunctions();
477  TGenCollectionProxy::InitializeEx( silent );
478  // xAODRootAccess/THolder relies on the setting below
479  // to be able to skip some inheritance tests.
480  fSTL_type = TClassEdit::kList;
481 
482  // Need to override what that set up for fValue and fVal.
483  if( fValue ) {
484  delete fValue.exchange( nullptr );
485  }
486  if( fVal ) delete fVal;
487  fValue = new TGenCollectionProxy::Value( eltname.c_str(), false );
488  fVal = new TGenCollectionProxy::Value( *fValue );
489  fClass = cl;
490 
491  // This container pretends to hold objects, not pointers:
492  fPointers = kFALSE;
493 
494  // Remember that the initialisation succeeded:
495  fInitialized = kTRUE;
496  return this;
497  }
498 
522  void TDVCollectionProxy::FindOffsets( const char* elttype,
523  const char* conttype ) {
524 
525  // Start by assuming no offsets.
526  fContoff = 0;
527  fOffset = 0;
528 
529  // Find its TClass.
530  TClass* dvclass = TClass::GetClass( conttype );
531  if( ! dvclass ) {
532  ::Fatal( "xAOD::TDVCollectionProxy::FindOffsets",
533  "Cannot find class %s", conttype );
534  return;
535  }
536 
537  // Find the TClass for the base DataVector class.
538  TClass* dvbase = findDVBase( dvclass );
539  if( ! dvbase ) {
540  TClass* elclass = classFromDVClass( dvclass );
541  if( ! elclass ) {
542  ::Fatal( "xAOD::TDVCollectionProxy::FindOffsets",
543  "Couldn't find element type of %s",
544  dvclass->GetName() );
545  return;
546  }
547  fEltBase = elclass;
548  fEltType = fEltBase;
549 
550  // No inheritance --- offsets are zero.
551  return;
552  }
553 
554  // Find the container offset.
555  fContoff = safeGetBaseOffset( dvclass, dvbase );
556 
557  // Now, find the base and derived element classes.
558  std::string elttype2 = elttype;
559  if( elttype2[ elttype2.size() - 1 ] == '*' ) {
560  elttype2.erase( elttype2.size() - 1 );
561  }
562  fEltType = TClass::GetClass( elttype2.c_str() );
563  fEltBase = classFromDVClass( dvbase );
564 
565  if( ( ! fEltType ) || ( ! fEltBase ) ) {
566  ::Fatal( "xAOD::TDVCollectionProxy::FindOffsets",
567  "Couldn't find dictionaries for DV element "
568  "type(s) for %s", conttype );
569  return;
570  }
571 
572  // Get the offset needed for the pointer operations:
574 
575  return;
576  }
577 
578 } // namespace xAOD
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
base
std::string base
Definition: hcg.cxx:78
get_hdefs.buff
buff
Definition: get_hdefs.py:61
xAOD::TDVCollectionFuncs::feed
static void * feed(void *, void *to, size_t size)
Definition: TDVCollectionProxy.cxx:295
xAOD::TDVCollectionFuncs::destruct
static void destruct(void *, size_t)
Not implemented for xAOD.
Definition: TDVCollectionProxy.cxx:290
PlotCalibFromCool.dv
dv
Definition: PlotCalibFromCool.py:762
xAOD::TDVCollectionFuncs::cont
static Cont_t * cont(void *env)
Fetch the container from a proxy environment.
Definition: TDVCollectionProxy.cxx:198
xAOD::TDVCollectionFuncs::first
static void * first(void *env)
Return the first element of the container.
Definition: TDVCollectionProxy.cxx:211
rootconvert.fName
string fName
Definition: rootconvert.py:5
xAOD::TDVCollectionProxy::PushProxy
virtual void PushProxy(void *objstart)
Start working with a new collection.
SG::normalizedTypeinfoName
std::string normalizedTypeinfoName(const std::type_info &info)
Convert a type_info to a normalized string representation (matching the names used in the root dictio...
Definition: normalizedTypeinfoName.cxx:120
xAOD::TDVCollectionProxy::TDVCollectionProxy
TDVCollectionProxy(const char *conttype)
Constructor.
Definition: TDVCollectionProxy.cxx:328
xAOD::TDVCollectionFuncs::Env_t
ROOT::TCollectionProxyInfo::Environ< TEnvBuff > Env_t
The Root proxy environment structure.
Definition: TDVCollectionProxy.cxx:193
mergePhysValFiles.start
start
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:14
xAOD::char
char
Definition: TrigDecision_v1.cxx:38
xAOD::TDVCollectionFuncs::TEnvBuff
Proxy environment buffer.
Definition: TDVCollectionProxy.cxx:173
CaloClusterListBadChannel.cls
cls
Definition: CaloClusterListBadChannel.py:8
xAOD::NO_SANITIZE_UNDEFINED
void TDVCollectionProxy::PushProxy NO_SANITIZE_UNDEFINED(void *objstart)
Start working with a new collection.
Definition: TDVCollectionProxy.cxx:395
xAOD
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
Definition: ICaloAffectedTool.h:24
vec
std::vector< size_t > vec
Definition: CombinationsGeneratorTest.cxx:12
dbg::ptr
void * ptr(T *p)
Definition: SGImplSvc.cxx:74
xAOD::TDVCollectionProxy
A Root collection proxy for DataVector containers.
Definition: TDVCollectionProxy.h:46
xAOD::TDVCollectionFuncs
Helper functions for accessing the container data via the proxy.
Definition: TDVCollectionProxy.cxx:155
xAOD::TDVCollectionFuncs::TEnvBuff::fOffset
int fOffset
Offset between the pointer held by the DV and the start of the object.
Definition: TDVCollectionProxy.cxx:188
xAOD::TDVCollectionFuncs::Cont_t
std::vector< char * > Cont_t
The container type.
Definition: TDVCollectionProxy.cxx:161
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
CxxUtils::vec
typename vecDetail::vec_typedef< T, N >::type vec
Define a nice alias for the vectorized type.
Definition: vec.h:207
TDVCollectionProxy.h
Type
RootType Type
Definition: TrigTSerializer.h:30
xAOD::TDVCollectionProxy::fInitialized
Bool_t fInitialized
Flag for knowing whether the class was initialised already.
Definition: TDVCollectionProxy.h:82
xAOD::TDVCollectionFuncs::create_env
static void * create_env()
Return a new environment structure.
Definition: TDVCollectionProxy.cxx:268
xAOD::TDVCollectionProxy::FindOffsets
void FindOffsets(const char *elttype, const char *conttype)
Initialize the cached pointer offsets.
Definition: TDVCollectionProxy.cxx:522
Type.h
Wrapper for ROOT types.
fillPileUpNoiseLumi.next
next
Definition: fillPileUpNoiseLumi.py:52
lumiFormat.i
int i
Definition: lumiFormat.py:85
xAOD::TDVCollectionProxy::fName
TString fName
Name of the container that this class proxies.
Definition: TDVCollectionProxy.h:80
xAOD::TDVCollectionFuncs::next
static void * next(void *env)
Return a following element of the container.
Definition: TDVCollectionProxy.cxx:233
xAOD::TDVCollectionProxy::SetResize
void SetResize(Sizing_t func)
Set the resize(...) function used by the proxy.
Definition: TDVCollectionProxy.cxx:439
xAOD::TDVCollectionFuncs::resize
static void resize(void *, size_t)
Not implemented for xAOD.
Definition: TDVCollectionProxy.cxx:279
xAOD::findDVElement
std::string findDVElement(TClass *cl)
Find the element type of a DataVector class.
Definition: TDVCollectionProxy.cxx:112
xAOD::TDVCollectionProxy::InitializeEx
virtual TGenCollectionProxy * InitializeEx(Bool_t silent)
Function initialising the proxy just in time.
Definition: TDVCollectionProxy.cxx:445
xAOD::TDVCollectionFuncs::TEnvBuff::fCont
Cont_t * fCont
Pointer to the container.
Definition: TDVCollectionProxy.cxx:181
DataVector
Derived DataVector<T>.
Definition: DataVector.h:794
xAOD::TDVCollectionFuncs::collect
static void * collect(void *, void *)
Not implemented for xAOD.
Definition: TDVCollectionProxy.cxx:315
xAOD::TDVCollectionProxy::fContoff
ptrdiff_t fContoff
The offset of the underlying DataVector in the declared type.
Definition: TDVCollectionProxy.h:85
xAOD::TDVCollectionProxy::fOffset
ptrdiff_t fOffset
Offset between the DV base pointer and the full DV pointer.
Definition: TDVCollectionProxy.h:87
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:228
mn
const bool mn
Definition: TDVCollectionProxy.cxx:28
xAOD::TDVCollectionFuncs::TEnvBuff::fEltPtr
void * fEltPtr
The last element pointer to have been returned.
Definition: TDVCollectionProxy.cxx:184
xAOD::TDVCollectionFuncs::TEnvBuff::fIndex
size_t fIndex
The index of the last element retrieved.
Definition: TDVCollectionProxy.cxx:176
xAOD::TDVCollectionProxy::fEltBase
TClass * fEltBase
The element type to which the DV representation points.
Definition: TDVCollectionProxy.h:90
CxxUtils::to
CONT to(RANGE &&r)
Definition: ranges.h:39
DataVector.h
An STL vector of pointers that by default owns its pointed-to elements.
xAOD::TDVCollectionProxy::fEltType
TClass * fEltType
The declared element type of the DV.
Definition: TDVCollectionProxy.h:92
SCT_ConditionsAlgorithms::CoveritySafe::getenv
std::string getenv(const std::string &variableName)
get an environment variable
Definition: SCT_ConditionsUtilities.cxx:17
python.trfDecorators.silent
def silent(func)
Redirect stdout/err to /dev/null Useful wrapper to get rid of ROOT verbosity...
Definition: trfDecorators.py:24
xAOD::TDVCollectionFuncs::clear
static void * clear(void *env)
Erase the container.
Definition: TDVCollectionProxy.cxx:261
xAOD::TDVCollectionProxyDummy
Dummy class to use as the DataVector template argument for the class we give to the Root proxy.
Definition: TDVCollectionProxy.h:24
L1Topo::Error
Error
The different types of error that can be flagged in the L1TopoRDO.
Definition: Error.h:16
no_sanitize_undefined.h
Helper to disable undefined behavior sanitizer for a function.
xAOD::safeGetBaseOffset
int safeGetBaseOffset(TClass *cls, TClass *base)
Find base class offset using Reflex.
Definition: TDVCollectionProxy.cxx:40
ATLAS_THREAD_SAFE
#define ATLAS_THREAD_SAFE
Definition: checker_macros.h:211
xAOD::findDVBase
TClass * findDVBase(TClass *dvclass)
Find the unique base DataVector class.
Definition: TDVCollectionProxy.cxx:87
xAOD::TDVCollectionFuncs::size
static void * size(void *env)
Return the size of the container.
Definition: TDVCollectionProxy.cxx:251
python.DataFormatRates.env
env
Definition: DataFormatRates.py:32
checker_macros.h
Define macros for attributes used to control the static checker.
python.PyAthena.obj
obj
Definition: PyAthena.py:132
xAOD::TDVCollectionFuncs::construct
static void * construct(void *, size_t)
Not implemented for xAOD.
Definition: TDVCollectionProxy.cxx:284
xAOD::classFromDVClass
TClass * classFromDVClass(TClass *dvclass)
Find the contained class in a DataVector.
Definition: TDVCollectionProxy.cxx:49
xAOD::TDVCollectionProxy::Sizing_t
TGenCollectionProxy::Sizing_t Sizing_t
Make the definition of Sizing_t public.
Definition: TDVCollectionProxy.h:50
python.compressB64.c
def c
Definition: compressB64.py:93
dq_make_web_display.cl
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition: dq_make_web_display.py:26
python.CaloScaleNoiseConfig.args
args
Definition: CaloScaleNoiseConfig.py:80
python.handimod.cc
int cc
Definition: handimod.py:523
xAOD::TDVCollectionProxy::Generate
virtual TVirtualCollectionProxy * Generate() const
Clone this object.
Definition: TDVCollectionProxy.cxx:428