ATLAS Offline Software
Loading...
Searching...
No Matches
TDVCollectionProxy.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 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#include <ESTLType.h>
17
18// EDM include(s):
22#include "RootUtils/Type.h"
23
24// Local include(s):
26
27#include <iostream>
28using namespace std;
29const bool mn = getenv("MN_DEBUG");
30
31namespace xAOD {
32
41 int safeGetBaseOffset( TClass* cls, TClass* base ) {
42
43 return cls->GetBaseClassOffset( base );
44 }
45
50 TClass* classFromDVClass( TClass* dvclass ) {
51
52 // Split up the class name into template arguments.
53 std::vector< std::string > args;
54 int tailloc;
55 {
56 // Protect against data race inside TClassEdit.
57 // https://github.com/root-project/root/issues/10353
58 // Should be fixed in root 6.26.02.
59 R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
60 TClassEdit::GetSplit( dvclass->GetName(), args, tailloc );
61 }
62 assert( args.size() > 1 );
63
64 // This should be the element type name.
65 std::string elname = args[ 1 ];
66 assert( elname.size() > 0 );
67
68 // Look up the element class.
69 TClass* elclass = TClass::GetClass( elname.c_str() );
70 if (!elclass) {
71 ::Error( "xAOD::TDVCollectionProxy", "Cannot find class %s",
72 elname.c_str() );
73 }
74
75 return elclass;
76 }
77
88 TClass* findDVBase( TClass* dvclass ) {
89
90 TIter next( dvclass->GetListOfBases() );
91 while( TBaseClass* bcl = dynamic_cast< TBaseClass* >( next() ) ) {
92 TClass* cc = bcl->GetClassPointer();
93 if( strncmp( cc->GetName(), "DataVector", 10 ) == 0 ) {
94 TClass* bdv = findDVBase( cc );
95 if( bdv ) return bdv;
96 if( strncmp( cc->GetName(), "DataVector<", 11 ) == 0 )
97 return cc;
98 }
99 }
100
101 return nullptr;
102 }
103
113 std::string findDVElement( TClass* cl ) {
114
115 // Make sure that the minimal set of dictionaries are loaded:
116 TClass* dummyCl =
117 TClass::GetClass( "DataVector<xAOD::TDVCollectionProxyDummy>" );
118 if( ! dummyCl ) {
119 Error( "xAOD::findDVElement",
120 "Couldn't load the dictionary for "
121 "DataVector<xAOD::TDVCollectionProxyDummy>" );
122 return "";
123 }
124
125 // Is this a DV class?
126 std::string elt;
127 const char* name = cl->GetName();
128 if( strncmp( name, "DataVector<", 11 ) == 0 ) {
129
130 elt = std::string( name + 11, strlen( name ) - 11 - 1 );
131
132 // Usually the full DataVector name includes two template
133 // arguments. But we only need the first one, before the first comma.
134 const std::string::size_type comma = elt.find( ',' );
135 if( comma != std::string::npos ) {
136 elt.resize (comma);
137 }
138
139 return elt;
140 }
141
142 // Scan base classes too.
143 TIter next( cl->GetListOfBases() );
144 while( TBaseClass* bcl = dynamic_cast< TBaseClass* >( next() ) ) {
145 TClass* cc = bcl->GetClassPointer();
146 elt = findDVElement( cc );
147 if( ! elt.empty() ) {
148 break;
149 }
150 }
151
152 return elt;
153 }
154
157
158 public:
162 typedef std::vector< char* > Cont_t;
163
174 struct TEnvBuff {
175
177 size_t fIndex;
178
183
185 void* fEltPtr;
186
190
191 }; // struct TEnvBuff
192
194 using Env_t = ROOT::TCollectionProxyInfo::Environ<TEnvBuff>;
195
199 static Cont_t* cont( void* env ) {
200
201 Env_t& e = *reinterpret_cast< Env_t* >( env );
202 TEnvBuff& buff = e.fIterator;
203 return buff.fCont;
204 }
205
212 static void* first( void* env ) {
213 Env_t& e = *reinterpret_cast< Env_t* >( env );
214 Cont_t& c = *cont( env );
215 TEnvBuff& buff = e.fIterator;
216 buff.fIndex = 0;
217 e.fSize = c.size();
218 if( 0 == e.fSize ) {
219 return nullptr;
220 }
221 char* start = c[ 0 ];
222 buff.fEltPtr = start + buff.fOffset;
223 return buff.fEltPtr;
224 }
225
234 static void* next( void* env ) {
235
236 Env_t& e = *reinterpret_cast< Env_t* >( env );
237 Cont_t& c = *cont( env );
238 TEnvBuff& buff = e.fIterator;
239 buff.fIndex += e.fIdx;
240 e.fIdx = 0;
241 if( buff.fIndex >= e.fSize ) {
242 return nullptr;
243 }
244 char* ptr = c[ buff.fIndex ];
245 buff.fEltPtr = ptr + buff.fOffset;
246 return buff.fEltPtr;
247 }
248
252 static void* size( void* env ) {
253
254 Env_t* e = reinterpret_cast< Env_t* >( env );
255 e->fSize = cont( env )->size();
256 return &( e->fSize );
257 }
258
262 static void* clear( void* env ) {
263
264 cont( env )->clear();
265 return nullptr;
266 }
267
269 static void* create_env() {
270
271 return new Env_t;
272 }
273
274 //*************************************************************************
275 // These methods are not needed for the xAOD usage,
276 // and are not implemented.
277
279 // template <typname T> // T will be equal to final class
280 static void resize( void* /*obj*/, size_t /*size*/ ) {
281 ::Fatal( "xAOD::TDVCollectionProxy", "resize function not specified!" );
282 }
283
285 static void* construct( void* /*from*/, size_t /*size*/ ) {
286 ::Fatal( "xAOD::TDVCollectionProxy", "construct not implemented" );
287 return nullptr;
288 }
289
291 static void destruct( void* /*obj*/, size_t /*size*/ ) {
292 ::Fatal( "xAOD::TDVCollectionProxy", "destruct not implemented" );
293 }
294
296 static void* feed( void* /*from*/, void* to, size_t size )
297 {
298 DataVector<char> *dv = reinterpret_cast<DataVector<char>*>(to);
299 // find out vector element typeinfo and get RootUtils::Type for it
300 const std::type_info &elem_typeinfo = dv->dvlinfo_v().elt_tinfo();
301 auto ru_type = RootUtils::Type( SG::normalizedTypeinfoName(elem_typeinfo) );
302 // copy vector elements into DataVector
303 if(mn) cout << "PROX: feed, typename=" << ru_type.getTypeName() << " typesize=" << ru_type.getSize() <<endl;
304
305 //char *src = reinterpret_cast<char*>( from );
306 for(size_t i=0; i<size; i++) {
307 void *obj = ru_type.create();
308 // ru_type.assign(obj, src); //MN: this may crash, so for now we do not copy data (bad only for CaloCluster
309 dv->dvlinfo_v().push(dv,obj);
310 //src += ru_type.getSize();
311 }
312 return nullptr;
313 }
314
316 static void* collect( void* /*from*/, void* /*to*/ ) {
317 ::Fatal( "xAOD::TDVCollectionProxy", "collect not implemented" );
318 return nullptr;
319 }
320 }; // class TDVCollectionFuncs
321
330 : TGenCollectionProxy( typeid( DataVector< TDVCollectionProxyDummy > ),
331 sizeof( char* ) ),
332 fName( conttype ), fInitialized( kFALSE ),
333 fContoff( 0 ), fOffset( 0 ), fEltBase( nullptr ), fEltType( nullptr ) {
334
335 // Set up the element size. No offset, since this isn't a map.
336 fValDiff = sizeof( void* );
337 fValOffset = 0;
338
339 // Set up the worker functions.
340 fSize.call = TDVCollectionFuncs::size;
341 fNext.call = TDVCollectionFuncs::next;
342 fFirst.call = TDVCollectionFuncs::first;
343 fClear.call = TDVCollectionFuncs::clear;
345 fCreateEnv.call = TDVCollectionFuncs::create_env;
350
351 // Make sure that TGenCollectionProxy knows that it's not
352 // fully set up yet:
353 if( fValue ) {
354 delete fValue.exchange( nullptr );
355 }
356 if( fVal ) {
357 delete fVal;
358 fVal = nullptr;
359 }
360
361 // This container pretends to hold objects, not pointers:
362 fPointers = kFALSE;
363
364 // Remember that we are not initialized yet:
365 fProperties = 0;
366 }
367
372 : TGenCollectionProxy( rhs ),
373 fName( rhs.fName ),
375 fContoff( rhs.fContoff ),
376 fOffset( rhs.fOffset ),
377 fEltBase( rhs.fEltBase ),
378 fEltType( rhs.fEltType ) {
379
380 // If we're not initialised yet, make sure that the base class is
381 // on the same page...
382 if( ! fInitialized ) {
383 if( fValue ) {
384 delete fValue.exchange( nullptr );
385 }
386 if( fVal ) {
387 delete fVal;
388 fVal = nullptr;
389 }
390 }
391 }
392
397
398 // Do the base class stuff.
399 // This will create an environment buffer if needed.
400 ::TGenCollectionProxy::PushProxy( objstart );
401
402 // Save the calculated element offset in the environment buffer.
404 reinterpret_cast< TDVCollectionFuncs::Env_t* >( fEnv )->fIterator;
405
406 // Get the offset needed for the pointer operations:
407 buff.fOffset = fOffset;
408
409 // Save the address of the underlying vector of the DataVector.
410 // First, adjust the address to the base DataVector.
411 char* dvstart = reinterpret_cast< char* >( objstart ) + fContoff;
412 // Cast to DV.
413 // This gets a ubsan warning about casting between types.
414 // However, this is deliberate, so suppress ubsan warnings
415 // for this function.
417 reinterpret_cast< DataVector< char >* >( dvstart );
418 // Find the underlying vector.
419 const std::vector< char* >& vec = dv->stdcont();
420 // And store its address.
421 std::vector<char*>* vptr ATLAS_THREAD_SAFE =
422 const_cast< std::vector< char* >* >( &vec );
423 buff.fCont = vptr;
424
425 return;
426 }
427
429 TVirtualCollectionProxy* TDVCollectionProxy::Generate() const {
430
431 return new TDVCollectionProxy( *this );
432 }
433
441
442 fResize = func;
443 return;
444 }
445
446 TGenCollectionProxy* TDVCollectionProxy::InitializeEx( Bool_t silent ) {
447
448 // Check if we're initialised already:
449 if( fInitialized ) return this;
450
451 // Check for the class's dictionary, and for its element type:
452 TClass* cl = TClass::GetClass( fName );
453 if( ! cl ) {
454 ::Fatal( "xAOD::TDVCollectionProxy::InitializeEx",
455 "Couldn't find dictionary for class %s",
456 fName.Data() );
457 return nullptr;
458 }
459
460 // Check if it is a DataVector:
461 const std::string eltname = findDVElement( cl );
462 if( eltname.empty() ) {
463 ::Fatal( "xAOD::TDVCollectionProxy::InitializeEx",
464 "Class \"%s\" doesn't seem to be a DataVector",
465 cl->GetName() );
466 return nullptr;
467 }
468 /*
469 * CID 20575: (#1 of 1): String converted to C pointer then back to string
470 * (UNNECESSARY_STRING_COPY)
471 * string_to_ptr_and_back: In eltname.c_str(), a C++ string is converted to
472 * a C-style pointer, then passed to a function that uses this pointer to construct
473 * one or more strings.
474 */
475 // Find the container and element offsets.
476 //coverity[UNNECESSARY_STRING_COPY]
477 FindOffsets( eltname.c_str(), fName );
478
479 // Set up the element size. No offset, since this isn't a map.
480 fValDiff = sizeof( void* );
481 fValOffset = 0;
482
483 // Do the base class initialization.
484 CheckFunctions();
485 TGenCollectionProxy::InitializeEx( silent );
486 // xAODRootAccess/THolder relies on the setting below
487 // to be able to skip some inheritance tests.
488 fSTL_type = ROOT::kSTLlist;
489
490 // Need to override what that set up for fValue and fVal.
491 if( fValue ) {
492 delete fValue.exchange( nullptr );
493 }
494 if( fVal ) delete fVal;
495 fValue = new TGenCollectionProxy::Value( eltname.c_str(), false );
496 fVal = new TGenCollectionProxy::Value( *fValue );
497 fClass = cl;
498
499 // This container pretends to hold objects, not pointers:
500 fPointers = kFALSE;
501
502 // Remember that the initialisation succeeded:
503 fInitialized = kTRUE;
504 return this;
505 }
506
530 void TDVCollectionProxy::FindOffsets( const char* elttype,
531 const char* conttype ) {
532
533 // Start by assuming no offsets.
534 fContoff = 0;
535 fOffset = 0;
536
537 // Find its TClass.
538 TClass* dvclass = TClass::GetClass( conttype );
539 if( ! dvclass ) {
540 ::Fatal( "xAOD::TDVCollectionProxy::FindOffsets",
541 "Cannot find class %s", conttype );
542 return;
543 }
544
545 // Find the TClass for the base DataVector class.
546 TClass* dvbase = findDVBase( dvclass );
547 if( ! dvbase ) {
548 TClass* elclass = classFromDVClass( dvclass );
549 if( ! elclass ) {
550 ::Fatal( "xAOD::TDVCollectionProxy::FindOffsets",
551 "Couldn't find element type of %s",
552 dvclass->GetName() );
553 return;
554 }
555 fEltBase = elclass;
557
558 // No inheritance --- offsets are zero.
559 return;
560 }
561
562 // Find the container offset.
563 fContoff = safeGetBaseOffset( dvclass, dvbase );
564
565 // Now, find the base and derived element classes.
566 std::string elttype2 = elttype;
567 if( elttype2[ elttype2.size() - 1 ] == '*' ) {
568 elttype2.erase( elttype2.size() - 1 );
569 }
570 fEltType = TClass::GetClass( elttype2.c_str() );
571 fEltBase = classFromDVClass( dvbase );
572
573 if( ( ! fEltType ) || ( ! fEltBase ) ) {
574 ::Fatal( "xAOD::TDVCollectionProxy::FindOffsets",
575 "Couldn't find dictionaries for DV element "
576 "type(s) for %s", conttype );
577 return;
578 }
579
580 // Get the offset needed for the pointer operations:
582
583 return;
584 }
585
586} // 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 void * feed(void *, void *to, size_t size)
static void * next(void *env)
Return a following element of the container.
static void * create_env()
Return a new environment structure.
std::vector< char * > Cont_t
The container type.
static void * clear(void *env)
Erase the container.
ROOT::TCollectionProxyInfo::Environ< TEnvBuff > Env_t
The Root proxy environment structure.
static void * first(void *env)
Return the first element of the container.
static void resize(void *, size_t)
Not implemented for xAOD.
static void * collect(void *, void *)
Not implemented for xAOD.
static void * size(void *env)
Return the size of the container.
static void destruct(void *, size_t)
Not implemented for xAOD.
static Cont_t * cont(void *env)
Fetch the container from a proxy environment.
static void * construct(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.
virtual TGenCollectionProxy * InitializeEx(Bool_t silent)
Function initialising the proxy just in time.
void FindOffsets(const char *elttype, const char *conttype)
Initialize the cached pointer offsets.
TClass * fEltBase
The element type to which the DV representation points.
Bool_t fInitialized
Flag for knowing whether the class was initialised already.
TClass * fEltType
The declared element type of the DV.
void SetResize(Sizing_t func)
Set the resize(...) function used by the proxy.
virtual TVirtualCollectionProxy * Generate() const
Clone this object.
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.
TGenCollectionProxy::Sizing_t Sizing_t
Make the definition of Sizing_t public.
TDVCollectionProxy(const char *conttype)
Constructor.
std::string base
Definition hcg.cxx:83
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...
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
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.
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
Proxy environment buffer.
void * fEltPtr
The last element pointer to have been returned.
size_t fIndex
The index of the last element retrieved.
Cont_t * fCont
Pointer to the container.
int fOffset
Offset between the pointer held by the DV and the start of the object.