ATLAS Offline Software
Loading...
Searching...
No Matches
TConvertingBranchElement Class Reference

A variant of TBranchElement that can call converters when reading objects in split mode. More...

#include <TConvertingBranchElement.h>

Inheritance diagram for TConvertingBranchElement:
Collaboration diagram for TConvertingBranchElement:

Public Member Functions

 TConvertingBranchElement ()
 Constructor.
virtual ~TConvertingBranchElement ()
 Destructor.
virtual Int_t GetEntry (Long64_t entry, Int_t getall)
 Read all branches into the previously-declared object.
virtual void Streamer (TBuffer &R__b)
 Read or write this object.
virtual void SetAddress (void *add)
 Set the address of the object to use for I/O.
virtual void ResetAddress ()
 Reset branch addresses and maybe delete the object.

Static Public Member Functions

static void Initialize ()
 Set up to allow for conversions in split mode.
static void SetDoDel (bool flag)
 Set the deletion flag.

Protected Member Functions

virtual void InitInfo ()
 Initialize the TStreamerInfo pointer.
virtual void InitializeOffsets ()
 Initialize data member offsets.
void ReadLeavesCollectionConverting (TBuffer &b)
 Read leaves into I/O buffers for this branch.
void ReadLeavesMemberBranchCountConverting (TBuffer &b)

Private Member Functions

void BuildConvertedElisions ()
 Add dummy nodes if needed to recover the correct tree structure.
void CheckForConversion ()
 Check to see if we need to worry about conversions for this branch.
void ConvResetType ()
 Recursively reset the type field of containers in conversions.
Int_t ReadSubBranches (Long64_t entry, Int_t getall, bool dont_reset)
 @branch Read in the subbranches of this branch.
TConvertingBranchElementoperator= (const TConvertingBranchElement &)
 If true, try to delete the.
 TConvertingBranchElement (const TConvertingBranchElement &)

Static Private Member Functions

static void * new_TConvertingBranchElement (void *p)
 new() method for this object.

Private Attributes

TVirtualConverterfConv
TClass * fConvClass
 Conversion for this branch.
char * fConvObject
 Class for conversion.
TObjArray * fConvOrigBranches
 Pointer to tmp obj used for conversion.
Int_t fConvOrigType
 Saved branch list. If we change.
bool fConvContainerFlag
 Saved branch type. The original.
bool fConvDontReset
 True if we're doing a container.

Static Private Attributes

static constexpr unsigned int kIsDummy = BIT(20)
 Flag used to mark dummy nodes created by BuildConvertedElisions.
static std::atomic< bool > fgDoDel = false
 Flag that the next read should.

Detailed Description

A variant of TBranchElement that can call converters when reading objects in split mode.

Definition at line 64 of file TConvertingBranchElement.h.

Constructor & Destructor Documentation

◆ TConvertingBranchElement() [1/2]

TConvertingBranchElement::TConvertingBranchElement ( )

Constructor.

Definition at line 287 of file TConvertingBranchElement.cxx.

288: fConv(nullptr)
289, fConvClass(nullptr)
290, fConvObject(nullptr)
291, fConvOrigBranches(nullptr)
292, fConvOrigType(-1)
293, fConvContainerFlag(false)
294, fConvDontReset(false)
295{
296}
Int_t fConvOrigType
Saved branch list. If we change.
bool fConvDontReset
True if we're doing a container.
bool fConvContainerFlag
Saved branch type. The original.
TClass * fConvClass
Conversion for this branch.
char * fConvObject
Class for conversion.
TObjArray * fConvOrigBranches
Pointer to tmp obj used for conversion.

◆ ~TConvertingBranchElement()

TConvertingBranchElement::~TConvertingBranchElement ( )
virtual

Destructor.

Constructor.

Get rid of any temporary objects which we made.

Definition at line 304 of file TConvertingBranchElement.cxx.

305{
306 // If we made a temporary object instance for conversions, delete it.
307 if (fConv && fConvObject)
308 fConv->DeletePersObj (fConvObject);
309
310 // If we contain dummy branches, delete them here.
311 // In that case, we should also delete the saved original branch list.
312 if (fConvOrigBranches) {
313 Int_t nbranches = fBranches.GetEntriesFast();
314 for (Int_t i = 0; i < nbranches; i++) {
315 if (fBranches[i]->TestBit (kIsDummy))
316 delete fBranches[i];
317 }
318 fBranches = *fConvOrigBranches;
319 delete fConvOrigBranches;
320 }
321
322 // If we're a dummy ourselves, we should delete the branch list.
323 if (TestBit (kIsDummy))
324 fBranches.Clear();
325
326 // Try to delete the object, if requested.
327 if (fgDoDel)
329}
virtual void ResetAddress()
Reset branch addresses and maybe delete the object.
static std::atomic< bool > fgDoDel
Flag that the next read should.
static constexpr unsigned int kIsDummy
Flag used to mark dummy nodes created by BuildConvertedElisions.

◆ TConvertingBranchElement() [2/2]

TConvertingBranchElement::TConvertingBranchElement ( const TConvertingBranchElement & )
private

Member Function Documentation

◆ BuildConvertedElisions()

void TConvertingBranchElement::BuildConvertedElisions ( )
private

Add dummy nodes if needed to recover the correct tree structure.

Given a TBranchElement tree structure, Root will elide some of the intermediate tree nodes. For example, given:

a a.b a.b.c a.b.c.d1 a.b.c.d2

Root will elide the ‘c’ node — so one has node ‘a’, with child ‘a.b’, with children ‘a.b.c.d1’ and ‘a.b.c.d2’.

This greatly complicates the process of running conversions, if ‘c’ has a conversion. So, what we do is if we determine that a conversion is needed, we modify the tree to reinsert the elided nodes. These nodes will have the kIsDummy flag set. Further, if we do that, we remember the original branch list from the parent node (‘a.b’ in the above example), so that if the structure is written, we can write the original, elided structure.

Definition at line 380 of file TConvertingBranchElement.cxx.

381{
382 // Can't do anything if we can't find the @c TStreamerInfo.
383 if (!fInfo) return;
384
385 // The class of this branch's element.
386 TClass* topclass = nullptr;
387 if (fID < 0)
388 topclass = gROOT->GetClass (GetClassName());
389 else {
390 std::string s = BasenameOfBranch (GetName());
391 int offset = 0;
392 TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
393 if (elt)
394 topclass = elt->GetClass();
395 }
396 if (!topclass) return;
397
398 // Here's the plan.
399 // We start by adding all branches to the @c branches list.
400 // Then we walk through the members of this class (using the
401 // @c TStreamerInfo).
402 // If this member is contained in the branch list, then we
403 // remove it from @c branches and add it to @c noconv_branches
404 // (it wasn't elided).
405 // If it's not in the branch list, then it was elided.
406 // We look then to see if the corresponding class (or anything
407 // it contains) requires a conversion. If so, then we build
408 // a dummy node for it, and add the dummy to @c conv_dummies.
409 // We then look through @c branches, find any that actually
410 // belong to the new dummy node, remove them from @c branches,
411 // and add them to the dummy.
412 // If no conversion is needed, then we don't need to do anything
413 // at this point.
414 //
415 // When we're done scanning all the members of the class, we take
416 // anything remaining in @c branches and move to @c noconv_branches
417 // (these correspond to branches with elided nodes, but with
418 // no conversions required.) Then, if we made any dummy nodes,
419 // then we replace our branch list with the concatenation of the
420 // dummy list and the @c noconv_branches list (saving the original
421 // branch list so that we can restore it later, if needed).
422 std::vector<TBranch*> conv_dummies;
423 std::vector<TBranch*> noconv_branches;
424 std::vector<TBranch*> branches;
425
426 // To start with, add all our child branches to @c branches.
427 Int_t nbranches = fBranches.GetEntriesFast();
428 branches.reserve (nbranches);
429 for (Int_t i=0; i < nbranches; i++) {
430 TBranch* b = dynamic_cast<TBranchElement*> (fBranches[i]);
431 if (b)
432 branches.push_back (b);
433 }
434
435 // Get the @c TStreamerInfo for this class.
436 // If this class is a container, then we actually want
437 // to get the @c TStreamerInfo for the contained class.
438 TStreamerInfo* info = GetStreamerInfoFromFile (topclass, this);
439 if (!info && fType == 4) {
440 TVirtualCollectionProxy* proxy = topclass->GetCollectionProxy();
441 if (!proxy) return;
442 topclass = proxy->GetValueClass();
443 if (!topclass) return;
444 info = GetStreamerInfoFromFile (topclass, this);
445 }
446 else if (fType == 3) {
447 topclass = gROOT->GetClass (fClonesName);
448 if (!topclass) return;
449 info = GetStreamerInfoFromFile (topclass, this);
450 }
451 if (!info) return;
452
453 // Now walk through all elements in the @c TStreamerInfo.
454 TObjArray* elems = info->GetElements();
455 size_t ndata = elems->GetEntriesFast();
456 for (size_t ielt = 0; ielt < ndata; ++ielt) {
457 // The element.
458 TStreamerElement* elt =
459 reinterpret_cast<TStreamerElement*> (elems->At(ielt));
460
461 // See if there's a branch corresponding to this element.
462 // If so, add it to the noconv list.
463 bool found = false;
464 for (unsigned i=0; i < branches.size(); i++) {
465 TBranchElement* b = dynamic_cast<TBranchElement*>(branches[i]);
466
467 // Test branch @b to see if corresponds to the SI element @ elt.
468 if (b && gROOT->GetClass (b->GetClassName()) == topclass) {
469 if (dynamic_cast<TStreamerBase*> (elt) != 0 && b->GetType() == 1) {
470 // For a base class, the test above is sufficient.
471 found = true;
472 }
473 else {
474 // Test the name.
475 std::string s = BasenameOfBranch (b->GetName());
476 if (s == elt->GetName())
477 found = true;
478 }
479
480 if (found) {
481 // We found a branch matching the element.
482 // Move the branch from @c branches to @c noconv_branches,
483 // and exit the loop over branches.
484 noconv_branches.push_back (b);
485 branches.erase (branches.begin()+i);
486 break;
487 }
488 }
489 }
490
491 if (!found) {
492 // We didn't find a branch corresponding to this element.
493 // Maybe this is an elided class.
494 // If this is a class type, then see if it or anything
495 // it contains has a conversion. If so, then build a dummy
496 // node for it.
497 TClass* cl = elt->GetClass();
498 if (cl && DoesClassNeedConv (cl, this)) {
499 // It needs a conversion. Make a dummy node.
500 TClass* clparent = gROOT->GetClass (info->GetName());
502 dum->SetBit (kIsDummy);
503 TString name;
504 if (fID < 0)
505 name = elt->GetName();
506 else {
507 name = GetName();
508 if (fType == 1) {
509 Ssiz_t i = name.Length()-1;
510 while (i >= 0 && name[i] != '.')
511 --i;
512 name.Remove (i+1);
513 }
514 else
515 name += ".";
516 name += elt->GetName();
517 }
518 dum->SetName (name);
519 dum->SetTitle (name);
520 TString namedot = name + ".";
521 dum->SetParentClass (clparent);
522 dum->SetClassName (info->GetName());
523 dum->fCheckSum = info->GetCheckSum();
524 dum->fClassVersion = topclass->GetClassVersion();
525 dum->fID = ielt;
526 dum->fTree = this->fTree;
527 dum->fDirectory = this->fDirectory;
528 dum->fBranchClass = topclass;
529 if (dynamic_cast<TStreamerBase*> (elt) != nullptr) {
530 dum->fType = 1;
531 Ssiz_t i = namedot.Length()-2;
532 while (i >= 0 && namedot[i] != '.')
533 --i;
534 namedot.Remove (i+1);
535 }
536 else
537 dum->fType = 2;
538
539 // Add the dummy node to @c conv_dummies.
540 conv_dummies.push_back (dum);
541
542 // Find all branches that are a part of this class and
543 // move them from @c branches to the dummy node
544 for (unsigned i=0; i < branches.size(); ) {
545 TString bname = branches[i]->GetName();
546 if (bname.Index (namedot) == 0 &&
547 (dum->fType == 2 ||
548 BaseHasField (dynamic_cast<TStreamerBase*>(elt),
549 bname,
550 namedot,
551 this)))
552 {
553 dum->GetListOfBranches()->Add (branches[i]);
555 dynamic_cast<TConvertingBranchElement*> (branches[i]))
556 {
557 be->fParentClass = cl;
558 }
559 branches.erase (branches.begin()+i);
560 }
561 else {
562 ++i;
563 }
564 }
565 }
566 }
567 // End of loop over elements.
568 }
569
570 // Any remaining branches go to @c noconv_branches.
571 for (unsigned int i=0; i < branches.size(); i++)
572 noconv_branches.push_back (branches[i]);
573
574 if (conv_dummies.size() > 0) {
575 // We made some dummies.
576 // Replace our branch list with the concatenation
577 // of the dummy list (@c conv_dummies) and the branches
578 // that don't need special processing (@c noconv_branches --- because
579 // they either did not have an elision or they didn't require
580 // a conversion).
581 fConvOrigBranches = new TObjArray;
582 *fConvOrigBranches = fBranches;
583 fBranches.Clear();
584 for (unsigned int i=0; i < conv_dummies.size(); i++)
585 fBranches.Add (conv_dummies[i]);
586 for (unsigned int i=0; i < noconv_branches.size(); i++)
587 fBranches.Add (noconv_branches[i]);
588 }
589}
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]

◆ CheckForConversion()

void TConvertingBranchElement::CheckForConversion ( )
private

Check to see if we need to worry about conversions for this branch.

Set up member variables if so.

Definition at line 596 of file TConvertingBranchElement.cxx.

597{
598 // Need @c TStreamerInfo in order to do anything.
599 if (!fInfo) return;
600
601 // Restore any elided tree nodes if there's a conversion.
603
604 // See if this element is a class.
605 const char* classname = 0;
606 int checksum = 0;
607
608 if (fID < 0) {
609 // Special case for top-level branch.
610 classname = GetClassName();
611 checksum = fCheckSum;
612 }
613 else {
614 // Otherwise, we need to look at the streamerinfo element.
615 std::string s = BasenameOfBranch (GetName());
616 int offset = 0;
617 TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
618 if (elt) {
619 TClass* cl = elt->GetClass();
620 if (cl) {
621 classname = cl->GetName();
622 TStreamerInfo* info = GetStreamerInfoFromFile (cl, this);
623 if (info)
624 checksum = info->GetCheckSum();
625 }
626 }
627 }
628
629 if (classname) {
630 // Ok, this branch represents a class.
631 // See if there's a conversion for it.
632 TVirtualConverter* conv =
633 TConverterRegistry::Instance()->GetConverter (classname, checksum);
634
635 // If there's not a conversion and this class is a container,
636 // then we need to see if something in the container needs a conversion.
637 if (!conv && (fType == 4 || fType == 3)) {
638 // Find the contained class.
639 TClass* contclass = gROOT->GetClass (fClonesName.Data());
640 if (contclass) {
641 TStreamerInfo* info = GetStreamerInfoFromFile (contclass, this);
642 if (info) {
643 // Found the contained class with its @c TStreamerInfo.
644 // See if the contained class has a conversion.
645 conv =
646 TConverterRegistry::Instance()->GetConverter (fClonesName.Data(),
647 info->GetCheckSum());
648
649 // If the contained class, or anything it contains, has a conversion,
650 // then we need to deal with conversions when reading this container.
651 if (conv || DoesClassNeedConv (contclass, this)) {
652 fConvContainerFlag = true;
654 }
655 }
656 }
657 }
658
659 if (conv) {
660 TClass* convclass = conv->GetPersClass();
661 if (convclass) {
662 // We have a conversion! Remember the converter and persistent
663 // class, and create the temporary persistent class instance.
664 fConv = conv;
665 fConvClass = convclass;
666 fConvObject = (char*)conv->NewPersObj();
667 }
668 }
669 }
670
671 // Now see if the class containing this element has a conversion.
672 if (fID > -1) {
673 TVirtualConverter* conv =
675 fCheckSum);
676 if (conv) {
677 TClass* convclass = conv->GetPersClass();
678 if (convclass) {
679 // The class containing this class has a conversion.
680 // Change the @c TStreamerInfo to correspond to the
681 // appropriate persistent class; also change the parent class
682 // pointer.
683 Bool_t optim = TStreamerInfo::CanOptimize();
684 TStreamerInfo::Optimize(kFALSE);
685 TStreamerInfo* info =
686 dynamic_cast<TStreamerInfo*> (convclass->GetStreamerInfo (0));
687 if (info)
688 fInfo = info;
689 TStreamerInfo::Optimize(optim);
690 fParentClass = convclass;
691 }
692 }
693 }
694}
static TConverterRegistry * Instance()
Return a pointer to the global registry instance.
TVirtualConverter * GetConverter(const char *name, int checksum) const
Look up a converter in the registry by name and checksum.
void ConvResetType()
Recursively reset the type field of containers in conversions.
void BuildConvertedElisions()
Add dummy nodes if needed to recover the correct tree structure.

◆ ConvResetType()

void TConvertingBranchElement::ConvResetType ( )
private

Recursively reset the type field of containers in conversions.

Recursively reset the type field of container elts in conversions.

Walk recursively through all children of this node. Any of them that have a fType corresponding to a member field within a container (31 or 41) are reset to 2 (normal member).

Definition at line 738 of file TConvertingBranchElement.cxx.

739{
740 Int_t nbranches = fBranches.GetEntriesFast();
741 for (Int_t i=0; i < nbranches; i++) {
743 dynamic_cast<TConvertingBranchElement*> (fBranches[i]);
744 if (b) {
745 if (b->fType == 41 || b->fType == 31) {
746 b->fConvOrigType = b->fType;
747 b->fType = 2;
748 }
749 b->ConvResetType();
750 }
751 }
752}

◆ GetEntry()

Int_t TConvertingBranchElement::GetEntry ( Long64_t entry,
Int_t getall )
virtual

Read all branches into the previously-declared object.

Parameters
entryThe ntuple row to read.
getallIf true, force reading all branches, even those previously deactivated.

If entry = 0, then use current entry number + 1. If entry < 0, then reset entry number to 0.

Returns the number of bytes read from the input buffer. If entry does not exist, then returns 0. If an I/O error occurs, then returns -1.

Parameters
entryThe ntuple row to read.
getallIf true, force reading all branches, even those previously deactivated.

If entry = 0, then use current entry number + 1. If entry < 0, then reset entry number to 0.

Returns the number of bytes read from the input buffer. If entry does not exist, then returns 0. If an I/O error occurs, then returns -1.

Some notes about conversions. If this branch has a conversion, then rather than reading directly into the target address, we instead read into a temporary object of the persistent type (fConvObject), and then call the converter to copy from the persistent to the transient object. We override SetAddress so that this will get set correctly for children of converted classes.

Note that the need to call the converter from the branch node corresponding to the class with the conversion is why we have problems with elided tree nodes — and the reason for BuildConvertedElisions.

Containers are more complicated. Suppose we have something like:

struct A { int a1; int a2; }; struct B { int b1; A b2; }; struct C { std::vector c1; };

and we're working on the vector.

The way Root handles this is that we have three branches: c1.b1, c1.b1.a1, c1.b1.a2 holding the container data. In addition, the container branch c1 will hold the count of the number of elements in the container. What Root does is:

  • First read the element count from branch c1. This will be stored in the c1 TBranchElement. Its children point to it to get the number of elements.
  • We then loop over the branches.
  • We read all elements at once for each branch, via TBranchInfo::ReadBufferSTL. We get the number of elements by looking in the parent container branch. Note that for the children of the container, the address set via SetAddress is not the address of the object itself, but rather the address of a collection proxy. The proxy is then associated with the actual container being read.

Now, when we try to do this with conversions, we run into the problem that we need the complete object in order to run the conversion. One way of doing this would be to buffer the complete collection of persistent objects, then loop over them calling the converter. I wanted to avoid having to do that for large collections, so what's done here is somewhat more complicated. The idea is to change the order of the loop over the branches and the loop over the elements, so that we make one complete object at a time. In a little more detail:

  • We change the type of the children of the containers from 31/41 (member field of container) to 2 (normal member).
  • When reading the collection branch, we read the number of elements, then loop over each element. For each element, we loop over each branch, calling GetEntry. But first, we call SetAddress to pass in the address of the temporary persistent object (if a conversion is being done for the object directly contained by the container) or the address of the object in the container (if the conversion is further down).
  • A complication is that normally when GetEntry is called for a member in a container, it (via ReadLeaves) resets the TBuffer to point at the first element in the collection. Because of how we've rearranged the loops, we want this to happen only on the first time. To accomplish this, a ‘dont_reset’ flag is introduced, to tell GetEntry not to call ReadLeaves. It would be most natural to do this by adding a parameter to GetEntry. However, at this point, we do not want to change the GetEntry interface. So, instead of passing this as an argument, it's passed in a member variable, fConvDontReset.

All of this is handled by the following methods: GetEntry ReadLeaves ReadSubBranches

Definition at line 843 of file TConvertingBranchElement.cxx.

844{
845 // The first part of this just copies the base class @c GetEntry.
846 // Differences from the base class implementation will be pointed out below.
847
848 // Remember which entry we are reading.
849 fReadEntry = entry;
850
851 // If our tree has a branch ref, make it remember the entry and
852 // this branch. This allows a TRef::GetObject() call done during
853 // the following I/O operation, for example in a custom streamer,
854 // to search for the referenced object in the proper element of the
855 // proper branch.
856 TBranchRef* bref = fTree->GetBranchRef();
857 if (bref) {
858 bref->SetParent(this, fBranchID);
859 bref->SetRequestedEntry(entry);
860 }
861
862 Int_t nbytes = 0;
863
864 SetupAddresses();
865
866 Int_t nbranches = fBranches.GetEntriesFast();
867 if (nbranches) {
868 // -- Branch has daughters.
869 // One must always read the branch counter.
870 // In the case when one reads consecutively twice the same entry,
871 // the user may have cleared the TClonesArray between the GetEntry calls.
872 if ((fType == 3) || (fType == 4)) {
873 Int_t nb = TBranch::GetEntry(entry, getall);
874 if (nb < 0) {
875 return nb;
876 }
877 nbytes += nb;
878 }
879
880 // Here's a difference from the @c TBranchElement base class.
881 // First, we need to pick up the current state of the
882 // @c fConvDontReset flag (and clear it in the process).
883 // Instead of looping over branches here, we factor out
884 // that part into @c ReadSubBranches.
885 bool dont_reset = fConvDontReset;
886 fConvDontReset = false;
887 switch(fSTLtype) {
888 case TClassEdit::kSet:
889 case TClassEdit::kMultiSet:
890 case TClassEdit::kMap:
891 case TClassEdit::kMultiMap:
892 break;
893 default:
894 // Read non-container composite and list/vector.
895 // Associative containers will get entirely read
896 // within the @c GetEntry call above (when it calls @c ReadLeaves).
897 nbytes += ReadSubBranches (entry, getall, dont_reset);
898 break;
899 }
900 }
901 else {
902 // -- Terminal branch.
903 // Difference from base implementation: pick up the dont_reset flag here.
904 bool dont_reset = fConvDontReset;
905 fConvDontReset = false;
906
907 if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) {
908 Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
909 if (nb < 0) {
910 return nb;
911 }
912 nbytes += nb;
913 }
914 Int_t nb = 0;
915
916 // The base implementation just calls @c TBranch::GetEntry here.
917 // But we need to pay attention to the dont_reset flag.
918 // If it's set, we can't call @c TBranch::GetEntry (because
919 // that would reset the buffer pointer back to the
920 // beginning of the container). Instead, we pick up the
921 // buffer pointer and call @c ReadLeaves `by hand'.
922 if (dont_reset) {
923 TBasket* basket = (TBasket*)GetBasket(GetReadBasket());
924 TBuffer* buffer = basket->GetBufferRef();
925 Int_t bufbegin = buffer->Length();
926
927 // Suppress false positive seen with gcc.
928#if __GNUC__ >= 11 && __GNUC__ <= 14
929# pragma GCC diagnostic push
930# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
931#endif
932 (this->*fReadLeaves) (*buffer);
933#if __GNUC__ >= 11 && __GNUC__ <= 14
934# pragma GCC diagnostic pop
935#endif
936
937 nb = buffer->Length() - bufbegin;
938 }
939 else
940 nb = TBranch::GetEntry (entry, getall);
941
942 // Rest is the same as the base implementation.
943 if (nb < 0) {
944 return nb;
945 }
946 nbytes += nb;
947 }
948
949 if (fTree->Debug() > 0) {
950 if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
951 Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
952 }
953 }
954 return nbytes;
955}
Int_t ReadSubBranches(Long64_t entry, Int_t getall, bool dont_reset)
@branch Read in the subbranches of this branch.
@ Info
Definition ZDCMsg.h:20

◆ Initialize()

void TConvertingBranchElement::Initialize ( )
static

Set up to allow for conversions in split mode.

Definition at line 335 of file TConvertingBranchElement.cxx.

336{
337}

◆ InitializeOffsets()

void TConvertingBranchElement::InitializeOffsets ( )
protectedvirtual

Initialize data member offsets.

(Overridden internal method.)

Definition at line 1286 of file TConvertingBranchElement.cxx.

1287{
1288 // previously in InitializeOffsets, after:
1289 // if (fType == 1) {
1290 // pClass = branchElem->GetClassPointer();
1291 // } else {
1292 // pClass = subBranch->GetParentClass();
1293 // }
1294 //
1295 // i had:
1296 //
1297 // if (fConvClass) pClass = fConvClass;
1298 //
1299 // This is a hack so we don't need to modify the base class
1300 // InitializeOffsets.
1301 //
1302 TStreamerElement* branchElem = 0;
1303 TClass* cl_orig = 0;
1304 if (fConvClass && fID > -1) {
1305 TStreamerInfo* si = GetInfo();
1306 branchElem = si->GetElem(fID);
1307 if (branchElem) {
1308 if (branchElem && branchElem->IsBase()) {
1309 cl_orig = branchElem->GetClassPointer();
1310 branchElem->Update (cl_orig, fConvClass);
1311 }
1312 else
1313 branchElem = 0;
1314 }
1315 }
1316
1317 if (fConvClass) {
1318 Int_t nbranches = fBranches.GetEntriesFast();
1319 for (Int_t subBranchIdx = 0; subBranchIdx < nbranches; ++subBranchIdx) {
1321 dynamic_cast<TConvertingBranchElement*> (fBranches[subBranchIdx]);
1322 if (br) {
1323 br->fParentClass = fConvClass;
1324 }
1325 }
1326 }
1327
1328 TBranchElement::InitializeOffsets();
1329
1330 if (branchElem)
1331 branchElem->Update (fConvClass, cl_orig);
1332}

◆ InitInfo()

void TConvertingBranchElement::InitInfo ( )
protectedvirtual

Initialize the TStreamerInfo pointer.

(Overridden internal method.)

(Overridden internal method.)

This gets called by GetInfo if the fInfo pointer is null. It should initialize that pointer.

Here is where we check for a conversion.

Definition at line 706 of file TConvertingBranchElement.cxx.

707{
708 // Do the standard stuff.
709 TBranchElement::InitInfo();
710
711 // Check for a conversion.
712 if (fInfo) {
713 const_cast<TConvertingBranchElement*>(this)->CheckForConversion();
714
715 // Re-find the fID.
716 const_cast<TConvertingBranchElement*>(this)->fInit = kFALSE;
717 TBranchElement::InitInfo();
718 }
719
720 // Change ReadLeaves implementation if needed.
721 // The base class implementation works here except for the case
722 // of an STL associative container. We need to change the code
723 // for that to notice @c fConvDontReset and to use @c ReadSubBranches.
724 if (fType == 4)
726 else if (fType == 2 && (fConvOrigType == 41 || fConvOrigType == 31))
728}
void ReadLeavesMemberBranchCountConverting(TBuffer &b)
void ReadLeavesCollectionConverting(TBuffer &b)
Read leaves into I/O buffers for this branch.
void CheckForConversion()
Check to see if we need to worry about conversions for this branch.

◆ new_TConvertingBranchElement()

void * TConvertingBranchElement::new_TConvertingBranchElement ( void * p)
staticprivate

new() method for this object.

Parameters
pAddress for placement new, or nullptr.
Returns
Address of the new object.

This is installed as the New method in TBranchElement's TClass. Thus, when we read from a file a TBranchElement, we actually make an instance of this class.

Parameters
pAddress for placement new, or 0.
Returns
Address of the new object.

This is installed as the New method in TBranchElement's TClass. Thus, when we read from a file a TBranchElement, we actually make an instance of this class.

Definition at line 349 of file TConvertingBranchElement.cxx.

350{
351 if (p)
352 return new (p) TConvertingBranchElement;
353 return new TConvertingBranchElement;
354}

◆ operator=()

TConvertingBranchElement & TConvertingBranchElement::operator= ( const TConvertingBranchElement & )
private

If true, try to delete the.

◆ ReadLeavesCollectionConverting()

void TConvertingBranchElement::ReadLeavesCollectionConverting ( TBuffer & b)
protected

Read leaves into I/O buffers for this branch.

Parameters
bRoot I/O buffer.

Definition at line 962 of file TConvertingBranchElement.cxx.

963{
964 // -- Read leaves into i/o buffers for this branch.
965 // Case of a collection (fType == 4).
966
967 ValidateAddress();
968 if (fObject == 0)
969 {
970 // We have nowhere to copy the data (probably because the data member was
971 // 'dropped' from the current schema) so let's no copy it in a random place.
972 return;
973 }
974
975 // STL container master branch (has only the number of elements).
976 Int_t n;
977 b >> n;
978 if ((n < 0) || (n > fMaximum)) {
979 if (IsMissingCollection()) {
980 n = 0;
981 b.SetBufferOffset(b.Length()-sizeof(n));
982 } else {
983 Error("ReadLeaves", "Incorrect size read for the container in %s\n\tThe size read is %d while the maximum is %d\n\tThe size is reset to 0 for this entry (%lld)", GetName(), n, fMaximum, GetReadEntry());
984 n = 0;
985 }
986 }
987 fNdata = n;
988
989 R__PushCache onfileObject((static_cast<TBufferFile&>(b)),fOnfileObject,n);
990
991 if (!fObject) {
992 return;
993 }
994 // Note: Proxy-helper needs to "embrace" the entire
995 // streaming of this STL container if the container
996 // is a set/multiset/map/multimap (what we do not
997 // know here).
998 // For vector/list/deque Allocate == Resize
999 // and Commit == noop.
1000 // TODO: Exception safety a la TPushPop
1001 TVirtualCollectionProxy* proxy = GetCollectionProxy();
1002 TVirtualCollectionProxy::TPushPop helper(proxy, fObject);
1003 void* alternate = proxy->Allocate(fNdata, true);
1004 if(fSTLtype != TClassEdit::kVector && proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers ) {
1005 fPtrIterators->CreateIterators(alternate, proxy);
1006 } else {
1007 fIterators->CreateIterators(alternate, proxy);
1008 }
1009
1010 //Int_t nbranches = fBranches.GetEntriesFast();
1011 switch (fSTLtype) {
1012 case TClassEdit::kSet:
1013 case TClassEdit::kMultiSet:
1014 case TClassEdit::kMap:
1015 case TClassEdit::kMultiMap:
1016 {
1017 // Change for conversions:
1018 // Use @c ReadSubBranches and obey @c fConvDontReset.
1019 bool dont_reset = fConvDontReset;
1020 fConvDontReset = false;
1021 ReadSubBranches (GetReadEntry(), 1, dont_reset);
1022 }
1023 break;
1024 default:
1025 break;
1026 }
1027 //------------------------------------------------------------------------
1028 // We have split this stuff, so we need to create the the pointers
1029 //-----------------------------------------------------------------------
1030 if( proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers )
1031 {
1032 TClass *elClass = proxy->GetValueClass();
1033
1034 //--------------------------------------------------------------------
1035 // The allocation is done in this strange way because ReadLeaves
1036 // is being called many times by TTreeFormula!!!
1037 //--------------------------------------------------------------------
1038 Int_t i = 0;
1039 if( !fNdata || *(void**)proxy->At( 0 ) != 0 )
1040 i = fNdata;
1041
1042 for( ; i < fNdata; ++i )
1043 {
1044 void **el = (void**)proxy->At( i );
1045 // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
1046 *el = elClass->New();
1047 }
1048 }
1049
1050 proxy->Commit(alternate);
1051}
Error
The different types of error that can be flagged in the L1TopoRDO.
Definition Error.h:16
alternate(gen, dictionary, weight_dict, p_nom)

◆ ReadLeavesMemberBranchCountConverting()

void TConvertingBranchElement::ReadLeavesMemberBranchCountConverting ( TBuffer & b)
protected

Definition at line 1054 of file TConvertingBranchElement.cxx.

1055{
1056 // -- Read leaves into i/o buffers for this branch.
1057 // For split-class branch, base class branch, data member branch, or top-level branch.
1058 // which do have a branch count and are not a counter.
1059
1060 assert(fStreamerType != TVirtualStreamerInfo::kCounter);
1061
1062 ValidateAddress();
1063 if (fObject == 0)
1064 {
1065 // We have nowhere to copy the data (probably because the data member was
1066 // 'dropped' from the current schema) so let's no copy it in a random place.
1067 return;
1068 }
1069
1070 R__PushCache onfileObject((static_cast<TBufferFile&>(b)),fOnfileObject,1);
1071 // If not a TClonesArray or STL container master branch
1072 // or sub-branch and branch inherits from tobject,
1073 // then register with the buffer so that pointers are
1074 // handled properly.
1075 if (TestBit(kBranchObject)) {
1076 b.ResetMap();
1077 b.MapObject((TObject*) fObject);
1078 } else if (TestBit(kBranchAny)) {
1079 b.ResetMap();
1080 b.MapObject(fObject, fBranchClass);
1081 }
1082
1083 fNdata = (Int_t) fBranchCount->GetValue(0, 0);
1084 TStreamerInfo *info = GetInfo();
1085 if (!info) {
1086 return;
1087 }
1088 // Since info is not null, fReadActionSequence is not null either.
1089 //b.ReadSequence(*fReadActionSequence, fObject);
1090 // FIXME!
1091 // ReadSequence doesn't work here, since it gets structure offsets
1092 // from TConfiguration, and those haven't been adjusted to take
1093 // into account the use of the temporary conversion objects.
1094 // FIXME!
1095 std::abort();
1096 //doesn't work
1097 //info->ReadBuffer (b, (char**)&fObject, fID);
1098}

◆ ReadSubBranches()

Int_t TConvertingBranchElement::ReadSubBranches ( Long64_t entry,
Int_t getall,
bool dont_reset )
private

@branch Read in the subbranches of this branch.

Parameters
entryThe entry number to read.
getallIf true, read all branches, even if disabled.
dont_resetIf true, don't reset the TBuffer read pointer.
Returns
The number of bytes read.
Parameters
entryThe entry number to read.
getallIf true, read all branches, even if disabled.
dont_resetIf true, don't reset the TBuffer read pointer.
Returns
The number of bytes read.

This is used to factor out the handling of conversions in containers.

Definition at line 1110 of file TConvertingBranchElement.cxx.

1113{
1114 Int_t nbytes = 0;
1115 Int_t nbranches = fBranches.GetEntriesFast();
1116
1117 if (fConvContainerFlag) {
1118 if (fNdata > 0) {
1119 // We're reading a container that needs a conversion.
1120 // We're going to invert the loop order so that we read
1121 // a single object at a time,
1122 // Remember the number of entries in the container, but change
1123 // the number we advertise to 1.
1124 UInt_t save_ndata = fNdata;
1125 fNdata = 1;
1126
1127 // Get either the container proxy or the clones array, as appropriate.
1128 TVirtualCollectionProxy* proxy = 0;
1129 TClonesArray* clones = 0;
1130 if (fType == 4)
1131 proxy = GetCollectionProxy();
1132 else if (fType == 3)
1133 clones = (TClonesArray*)fObject;
1134 else
1135 abort();
1136
1137 // If we had a proxy, associate it with the container object.
1138 // This is safe for the case where proxy is null.
1139 TPushPopSafe helper (proxy,fObject);
1140
1141 // For each element, we may have to call @c SetAddress for each
1142 // branch. This is used to avoid doing this repeatedly
1143 // with the same address (as would happen if we're reading into
1144 // the temporary persistent object).
1145 std::vector<char*> last_addrs (nbranches, (char*)0);
1146
1147 // Loop over elements.
1148 for (UInt_t j = 0; j < save_ndata; j++) {
1149 // Find the address of the element we want to initialize.
1150 // How we do this depends on whether we have a @c TClonesArray
1151 // or a proxy.
1152 char* addr = 0;
1153 if (proxy)
1154 addr = (char*)(proxy->At(j));
1155 else {
1156 if (!clones) std::abort();
1157 addr = (char*)((*clones)[j]);
1158 }
1159
1160 // The address of the object we want to read.
1161 // If we have a conversion on the class contained directly
1162 // in the container, then this will be the temporary persistent
1163 // object. Otherwise, it will be the address we found in the
1164 // last line.
1165 char* obj = fConvObject ? fConvObject : addr;
1166
1167 // Loop over branches for a single object.
1168 for (Int_t i = 0; i < nbranches; ++i) {
1169 TBranch* branch = (TBranch*) fBranches[i];
1170
1171 // If this isn't the first element in the container,
1172 // then we'll need to set the dont_reset flag.
1173 if (j > 0) {
1175 dynamic_cast<TConvertingBranchElement*>(branch);
1176 if (be)
1177 be->fConvDontReset = true;
1178 }
1179
1180 // Find the address for this member,
1181 char* this_addr = obj + fBranchOffset[i];
1182
1183 // Call @c SetAddress if it's different from the last one we set.
1184 if (this_addr != last_addrs[i]) {
1185 last_addrs[i] = this_addr;
1186 branch->SetAddress (obj + fBranchOffset[i]);
1187 }
1188
1189 // Read the branch.
1190 Int_t nb = branch->GetEntry(entry, getall);
1191
1192 // Bookkeeping.
1193 if (nb < 0) {
1194 return nb;
1195 }
1196 nbytes += nb;
1197 }
1198
1199 // End of loop over branches.
1200 // We just read one complete object.
1201 // Call the converter, if needed.
1202 if (fConv)
1203 fConv->ConvertVoid (addr, obj);
1204 }
1205
1206 // End of loop over entries. Restore @c fNdata.
1207 fNdata = save_ndata;
1208 }
1209 }
1210 else {
1211 // Non-container case.
1212 // We're reading a single object.
1213 // Loop over branches.
1214 for (Int_t i = 0; i < nbranches; ++i) {
1215 TBranch* branch = (TBranch*) fBranches[i];
1216
1217 // If @c dont_reset is set, we need to propagate it to our children.
1218 if (dont_reset) {
1220 dynamic_cast<TConvertingBranchElement*>(branch);
1221 if (!be) return -1;
1222 be->fConvDontReset = true;
1223 }
1224
1225 // Read the branch.
1226 Int_t nb = branch->GetEntry(entry, getall);
1227
1228 // Bookkeeping.
1229 if (nb < 0) {
1230 return nb;
1231 }
1232 nbytes += nb;
1233 }
1234
1235 // Done reading the object. Call the converter if needed.
1236 if (fConv)
1237 fConv->ConvertVoid (fObject, fConvObject);
1238 }
1239 return nbytes;
1240}

◆ ResetAddress()

void TConvertingBranchElement::ResetAddress ( )
virtual

Reset branch addresses and maybe delete the object.

We have this here because the functionality of getting the object is disabled in standard root, for reasons which aren't entirely clear. We want to add the option to turn it on again, to prevent leaks.

Definition at line 1373 of file TConvertingBranchElement.cxx.

1374{
1375 char* object = fObject;
1376 char* address = fAddress;
1377 TBranchElement::ResetAddress();
1378
1379 if (fgDoDel) {
1380 fObject = object;
1381 fAddress = address;
1382
1383 // This is copied from the disabled code of TBranchElement::ReleaseObject.
1384 if (fID < 0) {
1385 // -- We are a top-level branch.
1386 if (fAddress && (*((char**) fAddress) != fObject)) {
1387 // The semantics of fAddress and fObject are violated.
1388 // Assume the user changed the pointer on us.
1389 if (TestBit(kDeleteObject)) {
1390 Warning("ReleaseObject", "branch: %s, You have overwritten the pointer to an object which I owned!", GetName());
1391 Warning("ReleaseObject", "This is a memory leak. Please use SetAddress() to change the pointer instead.");
1392 ResetBit(kDeleteObject);
1393 }
1394 }
1395 }
1396
1397 // Delete any object we may have allocated during a call to SetAddress.
1398 // (sss - added fAddress check to fix coverity warning)
1399 if (fAddress && fObject && TestBit(kDeleteObject)) {
1400 ResetBit(kDeleteObject);
1401 if (fType == 3) {
1402 // -- We are a TClonesArray master branch.
1403 TClonesArray::Class()->Destructor(fObject);
1404 fObject = 0;
1405 if ((fStreamerType == TVirtualStreamerInfo::kObjectp) ||
1406 (fStreamerType == TVirtualStreamerInfo::kObjectP)) {
1407 // -- We are a pointer to a TClonesArray.
1408 // We must zero the pointer in the object.
1409 *((char**) fAddress) = 0;
1410 }
1411 } else if (fType == 4) {
1412 // -- We are an STL container master branch.
1413 TVirtualCollectionProxy* proxy = GetCollectionProxy();
1414 if (!proxy) {
1415 Warning("ResetAddress", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
1416 fObject = 0;
1417 } else {
1418 proxy->Destructor(fObject);
1419 fObject = 0;
1420 }
1421 if (fStreamerType == TVirtualStreamerInfo::kSTLp) {
1422 // -- We are a pointer to an STL container.
1423 // We must zero the pointer in the object.
1424 *((char**) fAddress) = 0;
1425 }
1426 } else {
1427 // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
1428 TClass* cl = fBranchClass.GetClass();
1429 if (!cl) {
1430 Warning("ResetAddress", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
1431 fObject = 0;
1432 } else {
1433 cl->Destructor(fObject);
1434 fObject = 0;
1435 }
1436 }
1437 }
1438
1439 fObject = 0;
1440 fAddress = 0;
1441 }
1442}

◆ SetAddress()

void TConvertingBranchElement::SetAddress ( void * add)
virtual

Set the address of the object to use for I/O.

Parameters
addObject address.
addObject address.

Overridden from the base class: if we have a temporary persistent object for conversions, then we pass down the address of that object rather than what we were given.

Definition at line 1343 of file TConvertingBranchElement.cxx.

1344{
1345 TBranchElement::SetAddress (add);
1346 if (fConvObject) {
1347 Int_t nbranches = fBranches.GetEntriesFast();
1348 for (Int_t i = 0; i < nbranches; ++i) {
1349 TBranch* abranch = (TBranch*) fBranches[i];
1350 abranch->SetAddress(fConvObject + fBranchOffset[i]);
1351 }
1352 }
1353}
bool add(const std::string &hname, TKey *tobj)
Definition fastadd.cxx:55

◆ SetDoDel()

void TConvertingBranchElement::SetDoDel ( bool flag)
static

Set the deletion flag.

Parameters
flagIf true, try to delete the branch object on branch deletion.

Definition at line 1449 of file TConvertingBranchElement.cxx.

1450{
1451 fgDoDel = flag;
1452}
bool flag
Definition master.py:29

◆ Streamer()

void TConvertingBranchElement::Streamer ( TBuffer & R__b)
virtual

Read or write this object.

Parameters
R__bThe Root buffer.
R__bThe Root buffer.

We wrap around the base class streamer. If we made any alterations to the persistent data members, we undo those changes here before calling the base streamer. This way the conversion handling won't change the persistent representation of the object.

Definition at line 1253 of file TConvertingBranchElement.cxx.

1254{
1255 TObjArray brsave;
1256 Int_t type_save = 0;
1257
1258 if (!R__b.IsReading()) {
1259 if (fConvOrigType == -1)
1260 fConvOrigType = fType;
1261
1262 type_save = fType;
1263 fType = fConvOrigType;
1264 if (fConvOrigBranches) {
1265 brsave = fBranches;
1266 fBranches = *fConvOrigBranches;
1267 }
1268 }
1269
1270 TBranchElement::Streamer (R__b);
1271
1272 if (!R__b.IsReading()) {
1273 fType = type_save;
1274 if (fConvOrigBranches) {
1275 fBranches = brsave;
1276 }
1277 }
1278}

Member Data Documentation

◆ fConv

TVirtualConverter* TConvertingBranchElement::fConv
private

Definition at line 195 of file TConvertingBranchElement.h.

◆ fConvClass

TClass* TConvertingBranchElement::fConvClass
private

Conversion for this branch.

Definition at line 196 of file TConvertingBranchElement.h.

◆ fConvContainerFlag

bool TConvertingBranchElement::fConvContainerFlag
private

Saved branch type. The original.

Definition at line 208 of file TConvertingBranchElement.h.

◆ fConvDontReset

bool TConvertingBranchElement::fConvDontReset
private

True if we're doing a container.

Definition at line 210 of file TConvertingBranchElement.h.

◆ fConvObject

char* TConvertingBranchElement::fConvObject
private

Class for conversion.

Definition at line 197 of file TConvertingBranchElement.h.

◆ fConvOrigBranches

TObjArray* TConvertingBranchElement::fConvOrigBranches
private

Pointer to tmp obj used for conversion.

Definition at line 198 of file TConvertingBranchElement.h.

◆ fConvOrigType

Int_t TConvertingBranchElement::fConvOrigType
private

Saved branch list. If we change.

Definition at line 203 of file TConvertingBranchElement.h.

◆ fgDoDel

std::atomic< bool > TConvertingBranchElement::fgDoDel = false
staticprivate

Flag that the next read should.

Definition at line 213 of file TConvertingBranchElement.h.

◆ kIsDummy

unsigned int TConvertingBranchElement::kIsDummy = BIT(20)
staticconstexprprivate

Flag used to mark dummy nodes created by BuildConvertedElisions.

Definition at line 155 of file TConvertingBranchElement.h.


The documentation for this class was generated from the following files: