The Gaudi Framework  master (69a68366)
Loading...
Searching...
No Matches
RootNTupleCnv.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2026 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11//------------------------------------------------------------------------------
12//
13// Implementation of class : RootNTupleCnv
14//
15// Author : Markus Frank
16//
17//------------------------------------------------------------------------------
18
19#define ALLOW_ALL_TYPES
20// Include files
21#include <RootCnv/RootAddress.h>
24#include <RootCnv/RootRefs.h>
25
30#include <GaudiKernel/NTuple.h>
31#include <GaudiKernel/SmartIF.h>
34
35// ROOT include files
36#include <TBranch.h>
37#include <TROOT.h>
38#include <TTree.h>
39
40#include <limits>
41#include <memory>
42
43#define S_OK StatusCode::SUCCESS
44#define S_FAIL StatusCode::FAILURE
45
46using namespace Gaudi;
47using namespace std;
48
49// Helper to read values from stream - default uses operator>>
50template <class TYP>
51static inline istream& readValue( istream& is, TYP& val ) {
52 return is >> val;
53}
54// For pointer types, just read and discard a long (pointers have meaningless 0 values in the descriptor)
55template <class TYP>
56static inline istream& readValue( istream& is, TYP*& ) {
57 long dummy;
58 return is >> dummy;
59}
60// Specializations for float/double to work around libc++ vs libstdc++ difference.
61//
62// libc++ (macOS/clang) sets failbit when parsing floating point values near the
63// minimum representable value (e.g., FLT_MIN ~1.17549e-38), even though the value
64// is parsed correctly. libstdc++ (Linux/gcc) does not set failbit in this case.
65// This is due to ambiguity in the C++ standard about when failbit should be set
66// for underflow conditions (see LWG Issue 3689).
67//
68// Reproducer:
69// echo '#include <iostream>
70// #include <sstream>
71// int main() {
72// std::istringstream is("1.17549e-38");
73// float f;
74// is >> f;
75// std::cout << "good=" << is.good() << " fail=" << is.fail() << " val=" << f << std::endl;
76// }' | c++ -x c++ - -o /tmp/test && /tmp/test
77//
78// libstdc++ (Linux): good=0 fail=0 val=1.17549e-38
79// libc++ (macOS): good=0 fail=1 val=1.17549e-38
80//
81// The workaround clears failbit if a value was successfully read (i.e., not bad/eof).
82template <>
83inline istream& readValue<float>( istream& is, float& val ) {
84 is >> val;
85 if ( is.fail() && !is.bad() && !is.eof() ) is.clear( is.rdstate() & ~std::ios::failbit );
86 return is;
87}
88template <>
89inline istream& readValue<double>( istream& is, double& val ) {
90 is >> val;
91 if ( is.fail() && !is.bad() && !is.eof() ) is.clear( is.rdstate() & ~std::ios::failbit );
92 return is;
93}
94
95template <class TYP>
96static StatusCode createItem( TTree* tree, INTuple* tuple, istream& is, const string& name, bool add,
97 const TYP& null ) {
98 string idxName;
99 long len, ndim, dim[4], hasIdx, idxLow, idxLen;
100 long dim1 = 1, dim2 = 1;
101 INTupleItem* it = nullptr;
102 char c;
103 is >> len >> c >> ndim >> c >> hasIdx >> c;
104 if ( hasIdx ) { getline( is, idxName, ';' ) >> idxLow >> c >> idxLen >> c; }
105 for ( int i = 0; i < ndim; i++ ) is >> dim[i] >> c;
106
107 TYP low = null, high = null;
108 readValue( is, low ) >> c;
109 readValue( is, high ) >> c;
110 is >> c;
111 switch ( ndim ) {
112 case 0:
113 it = NTuple::_Item<TYP>::create( tuple, name, typeid( TYP ), low, high, null );
114 break;
115 case 1:
116 dim1 = ( hasIdx ) ? idxLen : dim[0];
117 it = NTuple::_Array<TYP>::create( tuple, name, typeid( TYP ), idxName, dim1, low, high, null );
118 break;
119 case 2:
120 dim1 = ( hasIdx ) ? idxLen : dim[0];
121 dim2 = ( hasIdx ) ? dim[0] : dim[1];
122 it = NTuple::_Matrix<TYP>::create( tuple, name, typeid( TYP ), idxName, dim1, dim2, low, high, null );
123 break;
124 default:
125 return S_FAIL;
126 }
127 if ( add ) {
128 TBranch* b = tree->GetBranch( it->name().c_str() );
129 if ( b ) {
130 b->SetAddress( const_cast<void*>( it->buffer() ) );
131 } else {
132 // return StatusCode::SUCCESS;
133 return tuple->add( it );
134 }
135 }
136 return tuple->add( it );
137}
138
139template <class T>
140static inline void putRange( ostream& os, NTuple::_Data<T>* it ) {
141 const NTuple::Range<T>& x = it->range();
142 os << x.lower() << ';' << x.upper() << ';';
143}
144
145static inline string _tr( string s ) {
146 string local = std::move( s );
147 auto p = std::begin( local );
148 if ( local.compare( 0, 7, "<local>" ) == 0 ) p += 7;
149 std::replace_if(
150 p, std::end( local ), []( const char& c ) { return !isalnum( c ); }, '_' );
151 return local;
152}
153
154// Converter overrides: Update the references of an updated transient object.
156 StatusCode status = S_FAIL;
157 RootDataConnection* con = nullptr;
158 IRegistry* pRegistry = pAddr->registry();
159 RootAddress* rpA = dynamic_cast<RootAddress*>( pAddr );
160 string path = fileName( pRegistry );
161 string cntName = containerName( pRegistry );
162 string* par = const_cast<string*>( pAddr->par() );
163 status = m_dbMgr->connectDatabase( path, IDataConnection::READ, &con );
164 if ( status.isSuccess() ) {
165 string par_val, par_guid;
166 TBranch* b = con->getBranch( "##Descriptors", "GaudiStatisticsDescription" );
167 if ( b ) {
169 std::unique_ptr<RootNTupleDescriptor> dsc( ptr = new RootNTupleDescriptor() );
170 b->SetAddress( &ptr );
171 for ( Long64_t i = 0, nent = b->GetEntries(); i < nent; ++i ) {
172 int nb = b->GetEntry( i );
173 if ( nb > 1 ) {
174 if ( ptr->container == cntName ) {
175 par_val = ptr->description;
176 break;
177 }
178 }
179 }
180 }
181 par[2] = _tr( cntName );
182 TTree* tree = con->getSection( par[2] );
183 if ( nullptr == tree ) { return makeError( "Failed to access N-Tuple tree:" + cntName ); }
184 if ( !par_val.empty() ) {
185 auto ntupleSvc = dataProvider().as<INTupleSvc>();
186 if ( ntupleSvc ) {
187 char c;
188 CLID clid;
189 int siz, typ;
190 string title;
191 NTuple::Tuple* nt = nullptr;
192 istringstream is( par_val );
193 getline( is, title, ';' ) >> clid >> c >> siz >> c;
194 status = ntupleSvc->create( clid, title, nt );
195 for ( int j = 0; j < siz && status.isSuccess(); j++ ) {
196 is >> c;
197 getline( is, title, ';' ) >> typ >> c;
198 switch ( typ ) {
200 status = createItem( tree, nt, is, title, true, (unsigned char)0 );
201 break;
203 status = createItem( tree, nt, is, title, true, (unsigned short)0 );
204 break;
206 status = createItem( tree, nt, is, title, true, 0u );
207 break;
209 status = createItem( tree, nt, is, title, true, 0ul );
210 break;
212 status = createItem( tree, nt, is, title, true, char( 0 ) );
213 break;
215 status = createItem( tree, nt, is, title, true, short( 0 ) );
216 break;
218 status = createItem( tree, nt, is, title, true, 0 );
219 break;
221 status = createItem( tree, nt, is, title, true, 0l );
222 break;
224 status = createItem( tree, nt, is, title, true, false );
225 break;
227 status = createItem( tree, nt, is, title, true, 0.f );
228 break;
230 status = createItem( tree, nt, is, title, true, 0. );
231 break;
232 /*
233 case DataTypeInfo::NTCHAR:
234 case DataTypeInfo::LONG_NTCHAR:
235 status =
236 createItem(tree, nt, is, title, true, (char*)0);
237 break;
238 case DataTypeInfo::STRING:
239 case DataTypeInfo::LONG_STRING:
240 status =
241 createItem(tree, nt, is, title, true, string(""));
242 break;
243 */
245 status = createItem( tree, nt, is, title, false, static_cast<IOpaqueAddress*>( nullptr ) );
246 break;
248 status = createItem( tree, nt, is, title, true, static_cast<void*>( nullptr ) );
249 break;
251 default:
252 status = S_FAIL;
253 break;
254 }
255 if ( !status.isSuccess() ) {
256 log() << MSG::FATAL << "Error connecting (Unknown) column:" << j << endmsg << par_val << endmsg;
257 return makeError( "createObj[NTuple]> Cannot determine column!" );
258 }
259 }
260 if ( status.isSuccess() && rpA ) {
261 unsigned long* ipar = const_cast<unsigned long*>( rpA->ipar() );
262 log() << MSG::DEBUG << "Created N-tuple with description:" << par_val << endl;
263 ipar[0] = reinterpret_cast<uintptr_t>( con );
264 ipar[1] = ~0x0UL;
265 rpA->section = tree;
266 refpObject = nt;
267 } else {
268 refpObject = nullptr;
269 if ( nt ) nt->release();
270 }
271 }
272 }
273 }
274 return status;
275}
276
277// Update the transient object: NTuples end here when reading records
279 INTuple* tupl = dynamic_cast<INTuple*>( pObj );
280 RootAddress* rpA = dynamic_cast<RootAddress*>( pAddr );
281 if ( !tupl || !rpA ) return makeError( "updateObj> Invalid Tuple reference." );
282 RootDataConnection* con = reinterpret_cast<RootDataConnection*>( rpA->ipar()[0] );
283 if ( !con ) return makeError( "updateObj> Failed to access data source!" );
284 TTree* tree = rpA->section;
285 if ( !tree ) return makeError( "Failed to access data tree:" + pAddr->par()[1] );
286 con->resetAge();
287 if ( con->tool()->refs() ) return i__updateObjRoot( rpA, tupl, tree, con );
288#ifdef __POOL_COMPATIBILITY
289 // POOL compatibility mode:
290 return i__updateObjPool( rpA, tupl, tree, con );
291#else
292 return makeError( "Failed to access reference branch for data tree:" + rpA->par()[1] );
293#endif
294}
295
296// Update the transient object: NTuples end here when reading records
298 typedef INTuple::ItemContainer Cont;
299 const string* par = rpA->par();
300 unsigned long* ipar = const_cast<unsigned long*>( rpA->ipar() );
301 ++ipar[1];
302 if ( Long64_t( ipar[1] ) <= tree->GetEntries() ) {
303 GenericAddress* pA = nullptr;
304 Cont& it = tupl->items();
305 size_t k, n = it.size();
306 vector<RootRef*> paddr( n );
307 vector<RootRef> addr( n );
308 for ( k = 0; k < n; ++k ) {
309 Cont::value_type j = it[k];
310 switch ( j->type() ) {
312 paddr[k] = &addr[k];
313 tree->SetBranchAddress( j->name().c_str(), &paddr[k] );
314 break;
315 default:
316 break;
317 }
318 }
319
320 ULong64_t last = tree->GetEntries();
321 ISelectStatement* sel = tupl->selector();
322 if ( sel ) {
323 string criteria = ( sel && ( sel->type() & ISelectStatement::STRING ) ) ? sel->criteria() : string( "" );
324 if ( !( criteria.length() == 0 || criteria == "*" ) ) {
325 if ( rpA->select == nullptr ) {
326 log() << MSG::DEBUG << "Selection criteria: " << criteria << " " << ipar[1] << endmsg;
327 rpA->select = new TTreeFormula( tree->GetName(), criteria.c_str(), tree );
328 }
329 rpA->select->SetTree( tree );
330 for ( ; ipar[1] < last; ++ipar[1] ) { // loop on all selected entries
331 tree->LoadTree( ipar[1] );
332 rpA->select->GetNdata();
333 if ( fabs( rpA->select->EvalInstance( 0 ) ) > std::numeric_limits<double>::epsilon() ) { break; }
334 log() << MSG::DEBUG << par[0] << "/" << par[1] << " SKIP Entry: " << ipar[1] << endmsg;
335 }
336 }
337 }
338 if ( ipar[1] < last ) {
339 unsigned long entry = ipar[1];
340 if ( tree->GetEntry( entry ) > 1 ) {
341 RootRef* r = nullptr;
342 string* spar = nullptr;
343 for ( k = 0; k < n; ++k ) {
344 Cont::value_type j = it[k];
345 switch ( j->type() ) {
347 r = paddr[k];
348 pA = ( *(GenericAddress**)j->buffer() );
349 if ( pA ) { // Fill only if item is connected!
350 spar = const_cast<string*>( pA->par() );
351 ipar = const_cast<unsigned long*>( pA->ipar() );
352 log() << MSG::DEBUG;
353 pair<const RootRef*, const RootDataConnection::ContainerSection*> ls =
354 con->getMergeSection( tree->GetName(), entry );
355 if ( ls.first ) {
356 if ( ls.first->dbase >= 0 ) {
357 // Now patch the references and links 'en block' to be efficient
358 // First the leafs from the TES
359
360 r->dbase += ls.first->dbase;
361 r->container += ls.first->container;
362 r->link += ls.first->link;
363
364 if ( log().isActive() ) {
365 log() << "Refs: LS [" << entry << "] -> " << ls.first->dbase << "," << ls.first->container << ","
366 << ls.first->link << "," << ls.first->entry << " DB:" << con->getDb( r->dbase ) << endmsg;
367 }
368 }
369 }
370 spar[0] = con->getDb( r->dbase );
371 spar[1] = con->getCont( r->container );
372 spar[2] = con->getLink( r->link );
373 ipar[0] = 0;
374 ipar[1] = r->entry;
375 pA->setClID( r->clid );
376 pA->setSvcType( r->svc );
377 break;
378 }
379 break;
380 default:
381 break;
382 }
383 }
384 return StatusCode::SUCCESS;
385 }
386 log() << MSG::ERROR << "Failed to read data from NTuple tree." << endmsg;
387 return StatusCode::FAILURE;
388 }
389 log() << MSG::INFO << "End of input Ntuple." << endmsg;
390 return StatusCode::FAILURE;
391 }
392 return StatusCode::FAILURE;
393}
394
397 IRegistry* pRegistry = pObj->registry();
398 if ( pRegistry ) {
399 pAddr = pRegistry->address();
400 if ( pAddr ) return S_OK;
401
402 RootDataConnection* con = nullptr;
403 string path = fileName( pRegistry );
404 string cntName = containerName( pRegistry );
405 string secName = cntName;
406 const INTuple* nt = dynamic_cast<const INTuple*>( pObj );
407 StatusCode status = m_dbMgr->connectDatabase( path, IDataConnection::UPDATE, &con );
408 if ( !status.isSuccess() ) { return makeError( "Failed to access Tuple file:" + path ); }
409 TTree* tree = con->getSection( _tr( secName ), true );
410 if ( nullptr != nt ) {
411 const INTuple::ItemContainer& items = nt->items();
412 ostringstream os;
413 size_t item_no;
414 string desc;
415 os << nt->title() << ';' << pObj->clID() << ';' << items.size() << ';';
416 map<string, TBranch*> branches;
417 TBranch* b = nullptr;
418 for ( item_no = 0; item_no < items.size(); ++item_no ) {
419 INTupleItem* it = items[item_no];
420 if ( it->hasIndex() ) {
421 INTupleItem* itm = it->indexItem();
422 const string& n = itm->name();
423 switch ( itm->type() ) {
425 desc = n + "/b";
426 b = tree->Branch( n.c_str(), const_cast<void*>( itm->buffer() ), desc.c_str() );
427 break;
429 desc = n + "/s";
430 b = tree->Branch( n.c_str(), const_cast<void*>( itm->buffer() ), desc.c_str() );
431 break;
433 desc = n + "/i";
434 b = tree->Branch( n.c_str(), const_cast<void*>( itm->buffer() ), desc.c_str() );
435 break;
437 desc = n + "/l";
438 b = tree->Branch( n.c_str(), const_cast<void*>( itm->buffer() ), desc.c_str() );
439 break;
441 desc = n + "/B";
442 b = tree->Branch( n.c_str(), const_cast<void*>( itm->buffer() ), desc.c_str() );
443 break;
445 desc = n + "/S";
446 b = tree->Branch( n.c_str(), const_cast<void*>( itm->buffer() ), desc.c_str() );
447 break;
449 desc = n + "/I";
450 b = tree->Branch( n.c_str(), const_cast<void*>( itm->buffer() ), desc.c_str() );
451 break;
453 desc = n + "/L";
454 b = tree->Branch( n.c_str(), const_cast<void*>( itm->buffer() ), desc.c_str() );
455 break;
456 default:
457 return makeError( "Column " + it->index() + " is not a valid index column!" );
458 }
459 branches[n] = b;
460 }
461 }
462 for ( item_no = 0; item_no < items.size(); ++item_no ) {
463 INTupleItem* it = items[item_no];
464 const string& n = it->name();
465 os << '{' << n << ';' << it->type() << ';' << it->length() << ';' << it->ndim() << ';' << it->hasIndex() << ';';
466 if ( it->hasIndex() ) {
467 os << it->index() << ';';
468 INTupleItem* itm = it->indexItem();
469 switch ( itm->type() ) {
471 putRange( os, dynamic_cast<NTuple::_Data<unsigned char>*>( itm ) );
472 break;
474 putRange( os, dynamic_cast<NTuple::_Data<unsigned short>*>( itm ) );
475 break;
477 putRange( os, dynamic_cast<NTuple::_Data<unsigned int>*>( itm ) );
478 break;
480 putRange( os, dynamic_cast<NTuple::_Data<unsigned long>*>( itm ) );
481 break;
483 putRange( os, dynamic_cast<NTuple::_Data<char>*>( itm ) );
484 break;
486 putRange( os, dynamic_cast<NTuple::_Data<short>*>( itm ) );
487 break;
489 putRange( os, dynamic_cast<NTuple::_Data<int>*>( itm ) );
490 break;
492 putRange( os, dynamic_cast<NTuple::_Data<long>*>( itm ) );
493 break;
494 default:
495 return makeError( "NTuple:" + pRegistry->name() + " Column " + it->index() +
496 " is not a valid index column!" );
497 }
498 }
499 for ( long k = 0; k < it->ndim(); k++ ) { os << it->dim( k ) << ';'; }
500 desc = n;
501 TClass* cl = nullptr;
502 switch ( it->type() ) {
504 desc = "/C";
505 os << 0 << ';' << 0 << ';';
506 break;
508 desc = "/C";
509 os << 0 << ';' << 0 << ';';
510 break;
512 if ( it->length() == 1 ) {
513 desc = System::typeinfoName( typeid( RootRef ) );
514 os << 0 << ';' << 0 << ';';
515 cl = TClass::GetClass( desc.c_str(), kTRUE );
516 }
517 break;
519 if ( it->length() == 1 ) {
520 os << 0 << ';' << 0 << ';';
521 cl = TClass::GetClass( it->typeID(), kTRUE );
522 }
523 break;
525 desc = "/b";
526 putRange( os, dynamic_cast<NTuple::_Data<unsigned char>*>( it ) );
527 break;
529 desc = "/s";
530 putRange( os, dynamic_cast<NTuple::_Data<unsigned short>*>( it ) );
531 break;
533 desc = "/i";
534 putRange( os, dynamic_cast<NTuple::_Data<unsigned int>*>( it ) );
535 break;
537 desc = "/l";
538 putRange( os, dynamic_cast<NTuple::_Data<unsigned long>*>( it ) );
539 break;
541 desc = "/B";
542 putRange( os, dynamic_cast<NTuple::_Data<char>*>( it ) );
543 break;
545 desc = "/S";
546 putRange( os, dynamic_cast<NTuple::_Data<short>*>( it ) );
547 break;
549 desc = "/I";
550 putRange( os, dynamic_cast<NTuple::_Data<int>*>( it ) );
551 break;
553 desc = "/L";
554 putRange( os, dynamic_cast<NTuple::_Data<long>*>( it ) );
555 break;
557 desc = "/b";
558 putRange( os, dynamic_cast<NTuple::_Data<bool>*>( it ) );
559 break;
561 desc = "/F";
562 putRange( os, dynamic_cast<NTuple::_Data<float>*>( it ) );
563 break;
565 desc = "/D";
566 putRange( os, dynamic_cast<NTuple::_Data<double>*>( it ) );
567 break;
569 default:
570 return makeError( "Create item[FAIL]: " + it->name() );
571 }
572 os << '}';
573 if ( branches.find( n ) == branches.end() ) {
574 string tmp;
575 char text[32];
576 switch ( it->ndim() ) {
577 case 0:
578 desc = n + desc;
579 break;
580 case 2:
581 snprintf( text, sizeof( text ), "[%ld]", it->dim( 0 ) );
582 tmp = text;
583 [[fallthrough]];
584 case 1:
585 if ( it->hasIndex() ) {
586 INTupleItem* itm = it->indexItem();
587 desc = n + tmp + "[" + itm->name() + "]" + desc;
588 } else {
589 snprintf( text, sizeof( text ), "[%ld]", it->dim( 0 ) );
590 desc = n + tmp + text + desc;
591 }
592 }
593 log() << MSG::DEBUG << "Create branch:" << n << " Desc:" << desc << " of type:" << it->type() << endmsg;
594 switch ( it->type() ) {
596 branches[n] = tree->Branch( n.c_str(), cl->GetName(), const_cast<void*>( it->buffer() ) );
597 break;
599 branches[n] = tree->Branch( n.c_str(), cl->GetName(), const_cast<void*>( it->buffer() ) );
600 break;
601 default:
602 branches[n] = tree->Branch( n.c_str(), const_cast<void*>( it->buffer() ), desc.c_str() );
603 break;
604 }
605 }
606 }
607
608 log() << MSG::DEBUG << "Save description:" << path << " -> " << cntName << endmsg << os.str() << endmsg;
609 status = saveDescription( path, cntName, os.str(), "", pObj->clID() );
610 if ( status.isSuccess() ) {
611 status = m_dbMgr->commitOutput( path, true );
612 if ( status.isSuccess() ) {
613 string spar[] = { path, cntName };
614 unsigned long ipar[] = { (unsigned long)con, ~0x0u };
615 status = m_dbMgr->createAddress( repSvcType(), pObj->clID(), spar, ipar, pAddr );
616 if ( status.isSuccess() ) {
617 RootAddress* rpA = dynamic_cast<RootAddress*>( pAddr );
618 if ( rpA ) {
619 ( (unsigned long*)rpA->ipar() )[0] = (unsigned long)con;
620 rpA->section = tree;
621 } else {
622 log() << MSG::ERROR << "cannot dynamic cast to RootAddress" << endmsg;
623 }
624
625 } else {
626 pAddr->release();
627 pAddr = nullptr;
628 }
629 }
630 }
631 return status;
632 }
633 }
634 return S_FAIL;
635}
636
637// Resolve the references of the converted object.
639 typedef INTuple::ItemContainer Cont;
640 INTuple* tupl = dynamic_cast<INTuple*>( pObj );
641 IRegistry* pReg = pObj->registry();
642 RootAddress* rpA = dynamic_cast<RootAddress*>( pAddr );
643 if ( tupl && pReg && rpA ) {
644 string cntName = containerName( pReg );
645 unsigned long* ipar = const_cast<unsigned long*>( pAddr->ipar() );
646 RootDataConnection* con = reinterpret_cast<RootDataConnection*>( rpA->ipar()[0] );
647 if ( con ) {
648 TTree* tree = rpA->section;
649 if ( tree ) {
650 Cont& it = tupl->items();
651 size_t k, n = it.size();
652 vector<RootRef*> paddr( n );
653 vector<RootRef> addr( n );
654 for ( k = 0; k < n; ++k ) {
655 IOpaqueAddress* pA = nullptr;
656 Cont::value_type j = it[k];
657 switch ( j->type() ) {
659 pA = ( *(IOpaqueAddress**)j->buffer() );
660 paddr[k] = &addr[k];
661 addr[k].reset();
662 if ( pA ) {
663 con->makeRef( *pA->registry(), addr[k] );
664 addr[k].entry = pA->ipar()[1];
665 }
666 tree->SetBranchAddress( j->name().c_str(), &paddr[k] );
667 break;
668 default:
669 break;
670 }
671 }
672 int nb = tree->Fill();
673 if ( nb > 1 ) ++ipar[1];
674 for ( k = 0; k < n; ++k ) it[k]->reset();
676 }
677 return makeError( "fillRepRefs> Failed to access data tree:" + cntName );
678 }
679 return makeError( "fillRepRefs> Failed to access data source!" );
680 }
681 return makeError( "fillRepRefs> Invalid Tuple reference." );
682}
683
684#ifdef __POOL_COMPATIBILITY
685# include <RootCnv/PoolClasses.h>
686
687// Compatibility code to access ETCs, which were written using POOL
688
689namespace {
690 // Blob I/O helper class
691 class IOBuffer : public StreamBuffer {
692 public:
693 UCharDbArray d;
694 IOBuffer() = default;
695 virtual ~IOBuffer() {
696 m_pointer = 0;
697 m_length = 0;
698 m_buffer = nullptr;
699 }
700 void start() {
701 m_pointer = 0;
702 m_buffer = (char*)d.m_buffer;
703 m_length = d.m_size;
704 }
705 };
706} // namespace
707
708// Helper to read
709template <class T>
710static inline int load( int blob, IOBuffer& s, void* buff ) {
711 if ( blob ) {
712 int len;
713 s >> len;
714 s.swapFromBuffer( buff, len * sizeof( T ) );
715 }
716 return 0;
717}
718
719// Helper to read specialized for strings
720template <>
721inline int load<string>( int blob, IOBuffer& s, void* ptr ) {
722 if ( blob ) {
723 string* str = (string*)ptr;
724 s >> ( *str );
725 }
726 return 0;
727}
728
729// Update the transient object: NTuples end here when reading records
730StatusCode RootNTupleCnv::i__updateObjPool( RootAddress* rpA, INTuple* tupl, TTree* tree, RootDataConnection* con ) {
731 typedef INTuple::ItemContainer Cont;
732 const string* par = rpA->par();
733 unsigned long* ipar = const_cast<unsigned long*>( rpA->ipar() );
734 ++ipar[1];
735 if ( Long64_t( ipar[1] ) <= tree->GetEntries() ) {
736 Cont& it = tupl->items();
737 size_t k, n = it.size();
738 vector<PoolDbTokenWrap*> paddr( n );
739 vector<PoolDbTokenWrap> addr( n );
740 vector<int> blob_items( n, 0 );
741 for ( k = 0; k < n; ++k ) {
742 Cont::value_type j = it[k];
743 switch ( j->type() ) {
745 paddr[k] = &addr[k];
746 tree->SetBranchAddress( j->name().c_str(), &paddr[k] );
747 break;
748 default:
749 if ( nullptr == tree->GetBranch( j->name().c_str() ) ) blob_items[k] = 1;
750 break;
751 }
752 }
753 ULong64_t last = (ULong64_t)tree->GetEntries();
754 ISelectStatement* sel = tupl->selector();
755 if ( sel ) {
756 string criteria = ( sel && ( sel->type() & ISelectStatement::STRING ) ) ? sel->criteria() : string( "" );
757 if ( !( criteria.length() == 0 || criteria == "*" ) ) {
758 if ( rpA->select == nullptr ) {
759 log() << MSG::DEBUG << "Selection criteria: " << criteria << " " << ipar[1] << endmsg;
760 rpA->select = new TTreeFormula( tree->GetName(), criteria.c_str(), tree );
761 }
762 rpA->select->SetTree( tree );
763 // loop on all selected entries
764 for ( ; ipar[1] < last; ++ipar[1] ) {
765 tree->LoadTree( ipar[1] );
766 rpA->select->GetNdata();
767 if ( fabs( rpA->select->EvalInstance( 0 ) ) > std::numeric_limits<double>::epsilon() ) { break; }
768 log() << MSG::DEBUG << par[0] << "/" << par[1] << " SKIP Entry: " << ipar[1] << endmsg;
769 }
770 }
771 }
772 if ( ipar[1] < last ) {
773 IOBuffer blob;
774 UCharDbArray* pblob = &blob.d;
775 tree->GetBranch( "BlobData" )->SetAddress( &pblob );
776 if ( tree->GetEntry( ipar[1] ) > 1 ) {
777 int sc = 0;
778 blob.start();
779 for ( k = 0; k < n; ++k ) {
780 Cont::value_type j = it[k];
781 char* buf = (char*)j->buffer();
782 switch ( j->type() ) {
784 RootRef r = con->tool()->poolRef( addr[k].token.m_oid.first );
785 GenericAddress* pA = *reinterpret_cast<GenericAddress**>( buf );
786 if ( pA ) { // Fill only if item is connected!
787 string* spar = const_cast<string*>( pA->par() );
788 ipar = (unsigned long*)pA->ipar();
789 spar[0] = con->getDb( r.dbase );
790 spar[1] = con->getCont( r.container );
791 spar[2] = con->getLink( r.link );
792 ipar[0] = 0;
793 ipar[1] = addr[k].token.m_oid.second;
797 }
798 pA->setClID( r.clid );
799 pA->setSvcType( r.svc );
800 break;
801 }
802 sc = 11;
803 break;
804 }
806 sc = load<unsigned char>( blob_items[k], blob, buf );
807 break;
809 sc = load<unsigned short>( blob_items[k], blob, buf );
810 break;
812 sc = load<unsigned int>( blob_items[k], blob, buf );
813 break;
815 sc = load<unsigned long>( blob_items[k], blob, buf );
816 break;
818 sc = load<char>( blob_items[k], blob, buf );
819 break;
821 sc = load<short>( blob_items[k], blob, buf );
822 break;
824 sc = load<int>( blob_items[k], blob, buf );
825 break;
827 sc = load<long>( blob_items[k], blob, buf );
828 break;
830 sc = load<bool>( blob_items[k], blob, buf );
831 break;
833 sc = load<float>( blob_items[k], blob, buf );
834 break;
836 sc = load<double>( blob_items[k], blob, buf );
837 break;
839 sc = load<string>( blob_items[k], blob, buf );
840 break;
842 sc = load<char*>( blob_items[k], blob, buf );
843 break;
845 sc = 0;
846 break;
848 break;
849 default:
850 break;
851 }
852 if ( sc ) {
853 log() << MSG::DEBUG;
854 switch ( sc ) {
855 case 10:
856 log() << "CANNOT Set Ntuple token: dynamic_cast<GenericAddress*> is NULL";
857 break;
858 case 11:
859 log() << "CANNOT Set Ntuple token: invalid address buffer";
860 break;
861 }
862 log() << endmsg;
863 }
864 }
865 return StatusCode::SUCCESS;
866 }
867 log() << MSG::ERROR << "Failed to read data from NTuple tree." << endmsg;
868 return StatusCode::FAILURE;
869 }
870 log() << MSG::INFO << "End of input Ntuple." << endmsg;
871 return StatusCode::FAILURE;
872 }
873 return StatusCode::FAILURE;
874}
875#endif
const long POOL_ROOTKEY_StorageType
Definition ClassID.h:77
unsigned int CLID
Class ID definition.
Definition ClassID.h:16
const long POOL_ROOT_StorageType
Definition ClassID.h:76
const long POOL_ROOTTREE_StorageType
Definition ClassID.h:78
const long ROOT_StorageType
Definition ClassID.h:60
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define S_OK
#define S_FAIL
istream & readValue< double >(istream &is, double &val)
istream & readValue< float >(istream &is, float &val)
SmartIF< IDataProviderSvc > & dataProvider() const override
Get Data provider service.
Definition Converter.cpp:77
A DataObject is the base class of any identifiable object on any data store.
Definition DataObject.h:37
IRegistry * registry() const
Get pointer to Registry.
Definition DataObject.h:79
virtual const CLID & clID() const
Retrieve reference to class definition structure.
virtual unsigned long release()
release reference to object
void resetAge()
Reset age.
Description:
Definition RootAddress.h:45
TTreeFormula * select
Pointer to ROOT select statement (filled for N-tuples only)
Definition RootAddress.h:48
TTree * section
Pointer to ROOT TTree (filled for N-tuples only)
Definition RootAddress.h:50
RootCnvSvc * m_dbMgr
Conversion service needed for proper operation to forward requests.
long repSvcType() const override
Retrieve the class type of the data store the converter uses.
virtual RootRef poolRef(size_t) const
Internal overload to facilitate the access to POOL files.
Concrete implementation of the IDataConnection interface to access ROOT files.
const std::string & getLink(int which) const
Access link name from saved index.
Tool * tool() const
Access tool.
TTree * getSection(std::string_view sect, bool create=false)
Access TTree section from section name. The section is created if required.
TBranch * getBranch(std::string_view section, std::string_view branch_name)
Access data branch by name: Get existing branch in read only mode.
void makeRef(const IRegistry &pA, RootRef &ref)
Create reference object from registry entry.
const std::string & getDb(int which) const
Access database/file name from saved index.
std::pair< const RootRef *, const ContainerSection * > getMergeSection(std::string_view container, int entry) const
Access link section for single container and entry.
const std::string & getCont(int which) const
Access container name from saved index.
StatusCode fillRepRefs(IOpaqueAddress *pAdd, DataObject *pObj) override
Resolve the references of the converted object.
StatusCode i__updateObjRoot(RootAddress *rpA, INTuple *tupl, TTree *tree, RootDataConnection *con)
Update the transient object: NTuples end here when reading records.
StatusCode createRep(DataObject *pObj, IOpaqueAddress *&refpAdd) override
Converter overrides: Convert the transient object to the requested representation.
StatusCode createObj(IOpaqueAddress *pAddress, DataObject *&refpObject) override
Converter overrides: Update the references of an updated transient object.
StatusCode updateObj(IOpaqueAddress *pAddress, DataObject *pObject) override
Update the transient object: NTuples end here when reading records.
StatusCode saveDescription(const std::string &path, const std::string &ident, const std::string &desc, const std::string &opt, const CLID &clid)
Save statistics object description.
virtual const std::string fileName(IRegistry *pReg) const
Retrieve the name of the file a given object is placed into.
StatusCode makeError(const std::string &msg, bool throw_exception=false) const
Helper method to issue error messages.
MsgStream & log() const
Helper to use mesage logger.
Definition RootStatCnv.h:47
virtual const std::string containerName(IRegistry *pDir) const
Retrieve the name of the container a given object is placed into.
Generic Transient Address.
void setClID(const CLID &clid)
Access : Set class ID of the link.
const std::string * par() const override
Retrieve string parameters.
const unsigned long * ipar() const override
Retrieve integer parameters.
void setSvcType(long typ)
Access : set the storage type of the class id.
NTuple interface class definition.
Definition INTuple.h:86
std::vector< INTupleItem * > ItemContainer
Definition INTuple.h:93
virtual ISelectStatement * selector()=0
Access selector.
virtual ItemContainer & items()=0
Access item container.
virtual const std::string & title() const =0
Object title.
NTuple interface class definition.
Definition INTuple.h:32
virtual long ndim() const =0
Dimension.
virtual const void * buffer() const =0
Access data buffer (CONST)
virtual long dim(long i) const =0
Access individual dimensions.
virtual const std::string & index() const =0
Access the index _Item.
virtual const std::type_info & typeID() const =0
Compiler type ID.
virtual long type() const =0
Type information of the item.
virtual long length() const =0
Access the buffer length.
virtual INTupleItem * indexItem()=0
Pointer to index column (if present, 0 else)
virtual const std::string & name() const =0
Access _Item name.
virtual bool hasIndex() const =0
Is the tuple have an index item?
Opaque address interface definition.
virtual unsigned long release()=0
release reference to object
virtual const unsigned long * ipar() const =0
Access to generic link parameters.
virtual const std::string * par() const =0
Retrieve String parameters.
virtual IRegistry * registry() const =0
Update branch name.
The IRegistry represents the entry door to the environment any data object residing in a transient da...
Definition IRegistry.h:29
virtual const name_type & name() const =0
Name of the directory (or key)
virtual IOpaqueAddress * address() const =0
Retrieve opaque storage address.
A select statement can either contain.
static _Array * create(INTuple *tup, const std::string &name, const std::type_info &info, const std::string &index, long len, TYP min, TYP max, TYP def)
Create instance.
Abstract class describing basic data in an Ntuple.
Definition NTuple.h:122
virtual const ItemRange & range() const =0
Access the range if specified.
static _Item * create(INTuple *tup, const std::string &name, const std::type_info &info, TYP min, TYP max, TYP def)
Create instance.
static _Matrix * create(INTuple *tup, const std::string &name, const std::type_info &info, const std::string &index, long ncol, long nrow, TYP min, TYP max, TYP def)
Create instance.
Class defining a range.
Definition NTuple.h:58
TYP lower() const
Lower boundary of range.
Definition NTuple.h:78
TYP upper() const
Upper boundary of range.
Definition NTuple.h:80
Abstract base class which allows the user to interact with the actual N tuple implementation.
Definition NTuple.h:380
SmartIF< IFace > as() const
return a new SmartIF instance to another interface
Definition SmartIF.h:110
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
bool isSuccess() const
Definition StatusCode.h:314
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
The stream buffer is a small object collecting object data.
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1
@ FATAL
Definition IMessageSvc.h:22
@ DEBUG
Definition IMessageSvc.h:22
@ ERROR
Definition IMessageSvc.h:22
@ INFO
Definition IMessageSvc.h:22
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition System.cpp:260
STL namespace.
std::string description
Description string.
Definition RootRefs.h:88
std::string container
Identifier of description.
Definition RootRefs.h:92
Persistent reference object.
Definition extractEvt.C:44
int dbase
Data members to define object location in the persistent world.
Definition RootRefs.h:41
Shadow class to mimik POOL blobs.
Definition PoolClasses.h:56
unsigned char * m_buffer
Buffer with object content.
Definition PoolClasses.h:61
int m_size
Size of buffer.
Definition PoolClasses.h:59