ATLAS Offline Software
Loading...
Searching...
No Matches
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>
27using namespace std;
28const bool mn = getenv("MN_DEBUG");
29
30namespace 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
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
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;
344 fCreateEnv.call = TDVCollectionFuncs::create_env;
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 ),
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;
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
std::vector< size_t > vec
An STL vector of pointers that by default owns its pointed-to elements.
const bool mn
Wrapper for ROOT types.
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
Derived DataVector<T>.
Definition DataVector.h:795
Wrapper for ROOT types.
Definition Type.h:40
Helper functions for accessing the container data via the proxy.
static Cont_t * cont(void *env)
Fetch the container from a proxy environment.
static void * collect(void *, void *)
Not implemented for xAOD.
static void * first(void *env)
Return the first element of the container.
static void * construct(void *, size_t)
Not implemented for xAOD.
static void * size(void *env)
Return the size of the container.
static void * clear(void *env)
Erase the container.
ROOT::TCollectionProxyInfo::Environ< TEnvBuff > Env_t
The Root proxy environment structure.
static void * next(void *env)
Return a following element of the container.
std::vector< char * > Cont_t
The container type.
static void resize(void *, size_t)
Not implemented for xAOD.
static void * feed(void *, void *to, size_t size)
static void * create_env()
Return a new environment structure.
static void destruct(void *, size_t)
Not implemented for xAOD.
Dummy class to use as the DataVector template argument for the class we give to the Root proxy.
TClass * fEltBase
The element type to which the DV representation points.
void FindOffsets(const char *elttype, const char *conttype)
Initialize the cached pointer offsets.
virtual TVirtualCollectionProxy * Generate() const
Clone this object.
Bool_t fInitialized
Flag for knowing whether the class was initialised already.
virtual TGenCollectionProxy * InitializeEx(Bool_t silent)
Function initialising the proxy just in time.
TClass * fEltType
The declared element type of the DV.
void SetResize(Sizing_t func)
Set the resize(...) function used by the proxy.
TString fName
Name of the container that this class proxies.
virtual void PushProxy(void *objstart)
Start working with a new collection.
ptrdiff_t fContoff
The offset of the underlying DataVector in the declared type.
ptrdiff_t fOffset
Offset between the DV base pointer and the full DV pointer.
TDVCollectionProxy(const char *conttype)
Constructor.
TGenCollectionProxy::Sizing_t Sizing_t
Make the definition of Sizing_t public.
std::string base
Definition hcg.cxx:81
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...
STL namespace.
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
int safeGetBaseOffset(TClass *cls, TClass *base)
Find base class offset using Reflex.
std::string findDVElement(TClass *cl)
Find the element type of a DataVector class.
TClass * classFromDVClass(TClass *dvclass)
Find the contained class in a DataVector.
TClass * findDVBase(TClass *dvclass)
Find the unique base DataVector class.
Helper to disable undefined behavior sanitizer for a function.
#define NO_SANITIZE_UNDEFINED
size_t fIndex
The index of the last element retrieved.
int fOffset
Offset between the pointer held by the DV and the start of the object.
void * fEltPtr
The last element pointer to have been returned.
Cont_t * fCont
Pointer to the container.