diff --git a/io/io/inc/TStreamerInfoActions.h b/io/io/inc/TStreamerInfoActions.h index 68b7ead967171d7f176e1b5d377a047cf354ee89..b0e8c5419ae211d76fdef5a798c2efdc2ee8c9d3 100644 --- a/io/io/inc/TStreamerInfoActions.h +++ b/io/io/inc/TStreamerInfoActions.h @@ -13,6 +13,7 @@ #define ROOT_TStreamerInfoActions #include <vector> +#include <ROOT/RMakeUnique.hxx> #include "TStreamerInfo.h" #include <assert.h> @@ -50,12 +51,17 @@ namespace TStreamerInfoActions { /// Base class of the Configurations for the member wise looping routines. class TLoopConfiguration { public: - TLoopConfiguration() {}; + TVirtualCollectionProxy *fProxy = nullptr; + public: + TLoopConfiguration() = default; + TLoopConfiguration(TVirtualCollectionProxy *proxy) : fProxy(proxy) {} + // virtual void PrintDebug(TBuffer &buffer, void *object) const; virtual ~TLoopConfiguration() {}; virtual void Print() const; virtual void *GetFirstAddress(void *start, const void *end) const = 0; - virtual TLoopConfiguration* Copy() = 0; // { return new TLoopConfiguration(*this); } + virtual TLoopConfiguration* Copy() const = 0; // { return new TLoopConfiguration(*this); } + virtual TVirtualCollectionProxy* GetCollectionProxy() const { return fProxy; } }; typedef TVirtualCollectionProxy::Next_t Next_t; @@ -127,10 +133,43 @@ namespace TStreamerInfoActions { ClassDef(TConfiguredAction,0); // A configured action }; + struct TIDNode; + using TIDs = std::vector<TIDNode>; + + // Hold information about unfolded/extracted StreamerElement for + // a sub-object + struct TNestedIDs { + TNestedIDs() = default; + TNestedIDs(TStreamerInfo *info, Int_t offset) : fInfo(info), fOffset(offset) {} + + TStreamerInfo *fInfo = nullptr; ///< Not owned. + TVirtualArray *fOnfileObject = nullptr; ///< Not owned. + Int_t fOffset; + TIDs fIDs; + }; + + // A 'node' in the list of StreamerElement ID, either + // the index of the element in the current streamerInfo + // or a set of unfolded/extracted StreamerElement for a sub-object. + struct TIDNode { + TIDNode() = default; + TIDNode(Int_t id) : fElemID(id), fElement(nullptr), fInfo(nullptr) {} + TIDNode(TStreamerInfo *info, Int_t offset) : fElemID(-1), fElement(nullptr), fInfo(nullptr) { + fNestedIDs = std::make_unique<TNestedIDs>(info, offset); + } + Int_t fElemID = -1; + TStreamerElement *fElement = nullptr; + TStreamerInfo *fInfo = nullptr; + std::unique_ptr<TNestedIDs> fNestedIDs; + }; + typedef std::vector<TConfiguredAction> ActionContainer_t; class TActionSequence : public TObject { TActionSequence() {}; public: + struct SequencePtr; + using SequenceGetter_t = SequencePtr(*)(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *originalClass); + TActionSequence(TVirtualStreamerInfo *info, UInt_t maxdata) : fStreamerInfo(info), fLoopConfig(0) { fActions.reserve(maxdata); }; ~TActionSequence() { delete fLoopConfig; @@ -155,8 +194,63 @@ namespace TStreamerInfoActions { static TActionSequence *CreateWriteMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy); TActionSequence *CreateSubSequence(const std::vector<Int_t> &element_ids, size_t offset); + TActionSequence *CreateSubSequence(const TIDs &element_ids, size_t offset, SequenceGetter_t create); + void AddToSubSequence(TActionSequence *sequence, const TIDs &element_ids, Int_t offset, SequenceGetter_t create); + void Print(Option_t * = "") const; + // Maybe owner unique_ptr + struct SequencePtr { + TStreamerInfoActions::TActionSequence *fSequence = nullptr; + Bool_t fOwner = kFALSE; + + SequencePtr() = default; + SequencePtr(TStreamerInfoActions::TActionSequence *sequence, Bool_t owner) : fSequence(sequence), fOwner(owner) {} + + ~SequencePtr() { + if (fOwner) delete fSequence; + } + + // Accessor to the pointee. + TStreamerInfoActions::TActionSequence &operator*() const { + return *fSequence; + } + + // Accessor to the pointee + TStreamerInfoActions::TActionSequence *operator->() const { + return fSequence; + } + + // Return true is the pointee is not nullptr. + operator bool() { + return fSequence != nullptr; + } + }; + + // SequenceGetter_t implementations + + static SequencePtr ReadMemberWiseActionsCollectionGetter(TStreamerInfo *info, TVirtualCollectionProxy * /* collectionProxy */, TClass * /* originalClass */) { + auto seq = info->GetReadMemberWiseActions(kTRUE); + return {seq, kFALSE}; + } + static SequencePtr ConversionReadMemberWiseActionsViaProxyGetter(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *originalClass) { + auto seq = collectionProxy->GetConversionReadMemberWiseActions(originalClass, info->GetClassVersion()); + return {seq, kFALSE}; + } + static SequencePtr ReadMemberWiseActionsViaProxyGetter(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass * /* originalClass */) { + auto seq = collectionProxy->GetReadMemberWiseActions(info->GetClassVersion()); + return {seq, kFALSE}; + } + static SequencePtr ReadMemberWiseActionsCollectionCreator(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass * /* originalClass */) { + auto seq = TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(info,*collectionProxy); + return {seq, kTRUE}; + } + // Creator5() = Creator1; + static SequencePtr ReadMemberWiseActionsGetter(TStreamerInfo *info, TVirtualCollectionProxy * /* collectionProxy */, TClass * /* originalClass */) { + auto seq = info->GetReadMemberWiseActions(kFALSE); + return {seq, kFALSE}; + } + ClassDef(TActionSequence,0); }; diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 31352719c795efed4bff2f4109a66621822d5646..7d45f5a5b468af8adeffdba102e9d07c3c537fa2 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -998,7 +998,7 @@ namespace TStreamerInfoActions public: Long_t fIncrement; // Either a value to increase the cursor by and public: - TVectorLoopConfig(Long_t increment, Bool_t /* read */) : fIncrement(increment) {}; + TVectorLoopConfig(TVirtualCollectionProxy *proxy, Long_t increment, Bool_t /* read */) : TLoopConfiguration(proxy), fIncrement(increment) {}; //virtual void PrintDebug(TBuffer &buffer, void *); virtual ~TVectorLoopConfig() {}; void Print() const @@ -1013,23 +1013,20 @@ namespace TStreamerInfoActions return start; } - virtual TLoopConfiguration* Copy() { return new TVectorLoopConfig(*this); } + virtual TLoopConfiguration* Copy() const { return new TVectorLoopConfig(*this); } }; class TAssocLoopConfig : public TLoopConfiguration { // Base class of the Configurations used in member wise streaming. - protected: - public: - TVirtualCollectionProxy *fProxy; public: - TAssocLoopConfig(TVirtualCollectionProxy *proxy, Bool_t /* read */) : fProxy(proxy) {}; + TAssocLoopConfig(TVirtualCollectionProxy *proxy, Bool_t /* read */) : TLoopConfiguration(proxy) {}; //virtual void PrintDebug(TBuffer &buffer, void *); virtual ~TAssocLoopConfig() {}; void Print() const { printf("TAssocLoopConfig: proxy=%s\n",fProxy->GetCollectionClass()->GetName()); } - virtual TLoopConfiguration* Copy() { return new TAssocLoopConfig(*this); } + virtual TLoopConfiguration* Copy() const { return new TAssocLoopConfig(*this); } void* GetFirstAddress(void *start, const void * /* end */) const { @@ -1063,12 +1060,11 @@ namespace TStreamerInfoActions } } public: - TVirtualCollectionProxy *fProxy; TVirtualCollectionProxy::Next_t fNext; TVirtualCollectionProxy::CopyIterator_t fCopyIterator; TVirtualCollectionProxy::DeleteIterator_t fDeleteIterator; - TGenericLoopConfig(TVirtualCollectionProxy *proxy, Bool_t read) : fProxy(proxy), fNext(0), fCopyIterator(0), fDeleteIterator(0) + TGenericLoopConfig(TVirtualCollectionProxy *proxy, Bool_t read) : TLoopConfiguration(proxy), fNext(0), fCopyIterator(0), fDeleteIterator(0) { Init(read); } @@ -1077,7 +1073,7 @@ namespace TStreamerInfoActions { printf("TGenericLoopConfig: proxy=%s\n",fProxy->GetCollectionClass()->GetName()); } - virtual TLoopConfiguration* Copy() { return new TGenericLoopConfig(*this); } + virtual TLoopConfiguration* Copy() const { return new TGenericLoopConfig(*this); } void* GetFirstAddress(void *start_collection, const void *end_collection) const { @@ -1440,6 +1436,71 @@ namespace TStreamerInfoActions } }; + class TConfigurationPushDataCache : public TConfiguration { + // Configuration object for the PushDataCache case. + public: + TVirtualArray *fOnfileObject; + + TConfigurationPushDataCache(TVirtualStreamerInfo *info, TVirtualArray *onfileObject, Int_t offset) : + TConfiguration(info, -1, nullptr, offset), fOnfileObject(onfileObject) + {} + + virtual void Print() const { + TStreamerInfo *info = (TStreamerInfo*)fInfo; + if (fOnfileObject) + printf("StreamerInfoAction, class:%s, PushDataCache offset=%d\n", + info->GetClass()->GetName(), fOffset); + else + printf("StreamerInfoAction, class:%s, PopDataCache offset=%d\n", + info->GetClass()->GetName(), fOffset); + } + virtual void PrintDebug(TBuffer &buffer, void *object) const { + if (gDebug > 1) { + TStreamerInfo *info = (TStreamerInfo*)fInfo; + printf("StreamerInfoAction, class:%s, %sDataCache, bufpos=%d, arr=%p, offset=%d, onfileObject=%p\n", + info->GetClass()->GetName(), fOnfileObject ? "Push" : "Pop", buffer.Length(), object, fOffset, fOnfileObject); + + } + } + }; + + Int_t PushDataCache(TBuffer &b, void *, const TConfiguration *conf) + { + TConfigurationPushDataCache *config = (TConfigurationPushDataCache*)conf; + auto onfileObject = config->fOnfileObject; + + // onfileObject->SetSize(1); + b.PushDataCache( onfileObject ); + + return 0; + } + + Int_t PushDataCacheGenericCollection(TBuffer &b, void *, const void *, const TLoopConfiguration *loopconfig, const TConfiguration *conf) + { + TConfigurationPushDataCache *config = (TConfigurationPushDataCache*)conf; + auto onfileObject = config->fOnfileObject; + + TVirtualCollectionProxy *proxy = ((TGenericLoopConfig*)loopconfig)->fProxy; + UInt_t n = proxy->Size(); + + onfileObject->SetSize(n); + b.PushDataCache( onfileObject ); + + return 0; + } + + Int_t PopDataCache(TBuffer &b, void *, const TConfiguration *) + { + b.PopDataCache(); + return 0; + } + + Int_t PopDataCacheGenericCollection(TBuffer &b, void *, const void *, const TLoopConfiguration *, const TConfiguration *) + { + b.PopDataCache(); + return 0; + } + class TConfigurationUseCache : public TConfiguration { // Configuration object for the UseCache case. public: @@ -1469,7 +1530,6 @@ namespace TStreamerInfoActions } }; - INLINE_TEMPLATE_ARGS Int_t UseCache(TBuffer &b, void *addr, const TConfiguration *conf) { TConfigurationUseCache *config = (TConfigurationUseCache*)conf; @@ -1506,7 +1566,7 @@ namespace TStreamerInfoActions UInt_t n = (((void**)end)-((void**)start)); info->ReadBufferSkip(b,&ptr,config->fCompInfo,conf->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0); } else { - TVectorLoopConfig cached_config( cached->fClass->Size(), /* read */ kTRUE ); + TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE ); void *cached_start = (*cached)[0]; void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement; config->fAction(b,cached_start,cached_end,&cached_config); @@ -1532,7 +1592,7 @@ namespace TStreamerInfoActions UInt_t n = (((char*)end)-((char*)start))/((TVectorLoopConfig*)loopconf)->fIncrement; info->ReadBufferSkip(b,&ptr,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0); } else { - TVectorLoopConfig cached_config( cached->fClass->Size(), /* read */ kTRUE ); + TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE ); void *cached_start = (*cached)[0]; void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement; config->fAction(b,cached_start,cached_end,&cached_config); @@ -1559,7 +1619,7 @@ namespace TStreamerInfoActions UInt_t n = proxy->Size(); info->ReadBufferSkip(b, *proxy,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0); } else { - TVectorLoopConfig cached_config( cached->fClass->Size(), /* read */ kTRUE ); + TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE ); void *cached_start = (*cached)[0]; void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement; config->fAction(b,cached_start,cached_end,&cached_config); @@ -3821,14 +3881,14 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector. Long_t increment = proxy.GetIncrement(); - sequence->fLoopConfig = new TVectorLoopConfig(increment, /* read */ kTRUE); + sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE); } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLunorderedset || proxy.GetCollectionType() == ROOT::kSTLmultiset || proxy.GetCollectionType() == ROOT::kSTLunorderedmultiset || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap || proxy.GetCollectionType() == ROOT::kSTLunorderedmap || proxy.GetCollectionType() == ROOT::kSTLunorderedmultimap) { Long_t increment = proxy.GetIncrement(); - sequence->fLoopConfig = new TVectorLoopConfig(increment, /* read */ kTRUE); + sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE); // sequence->fLoopConfig = new TAssocLoopConfig(proxy); } else { sequence->fLoopConfig = new TGenericLoopConfig(&proxy, /* read */ kTRUE); @@ -3938,7 +3998,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector. Long_t increment = proxy.GetIncrement(); - sequence->fLoopConfig = new TVectorLoopConfig(increment, /* read */ kFALSE); + sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kFALSE); /*} else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) { @@ -4111,6 +4171,83 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr return sequence; } +void TStreamerInfoActions::TActionSequence::AddToSubSequence(TStreamerInfoActions::TActionSequence *sequence, + const TStreamerInfoActions::TIDs &element_ids, + Int_t offset, + TStreamerInfoActions::TActionSequence::SequenceGetter_t create) +{ + for(UInt_t id = 0; id < element_ids.size(); ++id) { + if ( element_ids[id].fElemID < 0 ) { + if (element_ids[id].fNestedIDs) { + auto original = create(element_ids[id].fNestedIDs->fInfo, + sequence->fLoopConfig ? sequence->fLoopConfig->GetCollectionProxy() : nullptr, + nullptr); + if (element_ids[id].fNestedIDs->fOnfileObject) { + auto conf = new TConfigurationPushDataCache(element_ids[id].fNestedIDs->fInfo, element_ids[id].fNestedIDs->fOnfileObject, offset); + if ( sequence->fLoopConfig ) + sequence->AddAction( PushDataCacheGenericCollection, conf ); + else + sequence->AddAction( PushDataCache, conf ); + } + + original->AddToSubSequence(sequence, element_ids[id].fNestedIDs->fIDs, element_ids[id].fNestedIDs->fOffset, create); + + if (element_ids[id].fNestedIDs->fOnfileObject) + sequence->AddAction( PopDataCache, + new TConfigurationPushDataCache(element_ids[id].fNestedIDs->fInfo, nullptr, element_ids[id].fNestedIDs->fOffset) ); + } else { + TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end(); + for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin(); + iter != end; + ++iter) + { + TConfiguration *conf = iter->fConfiguration->Copy(); + if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache)) + conf->AddToOffset(offset); + sequence->AddAction( iter->fAction, conf ); + } + } + } else { + int localIndex = 0; + TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end(); + for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin(); + iter != end; + ++iter) { + // fprintf(stderr, "With element_ids[%d] For %s comparing act[%d/%zu] %d to %d for %p vs %p %s\n", + // id, + // iter->fConfiguration->fInfo->GetName(), + // localIndex, fActions.size(), + // iter->fConfiguration->fElemId, + // (UInt_t)element_ids[id].fElemID, iter->fConfiguration->fInfo, + // element_ids[id].fInfo, + // element_ids[id].fInfo ? element_ids[id].fInfo->GetName() : "nullptr" ); + ++localIndex; + if ( iter->fConfiguration->fElemId == (UInt_t)element_ids[id].fElemID ) { + TConfiguration *conf = iter->fConfiguration->Copy(); + if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache)) + conf->AddToOffset(offset); + sequence->AddAction( iter->fAction, conf ); + } + } + } + } +} + +TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateSubSequence(const TIDs &element_ids, size_t offset, + TStreamerInfoActions::TActionSequence::SequenceGetter_t create) +{ + // Create a sequence containing the subset of the action corresponding to the SteamerElement whose ids is contained in the vector. + // 'offset' is the location of this 'class' within the object (address) that will be passed to ReadBuffer when using this sequence. + + TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(fStreamerInfo,element_ids.size()); + + sequence->fLoopConfig = fLoopConfig ? fLoopConfig->Copy() : 0; + + AddToSubSequence(sequence, element_ids, offset, create); + + return sequence; +} + TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateSubSequence(const std::vector<Int_t> &element_ids, size_t offset) { // Create a sequence containing the subset of the action corresponding to the SteamerElement whose ids is contained in the vector. diff --git a/io/io/src/TStreamerInfoReadBuffer.cxx b/io/io/src/TStreamerInfoReadBuffer.cxx index 17a9a0eaa5b04f58a3da795c4535d62eed7b1124..68ce0948f406428b714e7e3797ddfb9c0bb27c09 100644 --- a/io/io/src/TStreamerInfoReadBuffer.cxx +++ b/io/io/src/TStreamerInfoReadBuffer.cxx @@ -543,6 +543,7 @@ Int_t TStreamerInfo::ReadBufferArtificial(TBuffer &b, const T &arr, TVirtualArray *objarr = ((TBufferFile&)b).PeekDataCache(); if (objarr) { obj.fClass = objarr->fClass; + for(Int_t k=0; k<narr; ++k) { obj.fObject = objarr->GetObjectAt(k); readfunc(arr[k]+eoffset, &obj); diff --git a/tree/tree/inc/TBranchElement.h b/tree/tree/inc/TBranchElement.h index 501029aa12d781ff5475dcec4e6cfc0ec6039e20..994e26c99e985f89cca8b7e21b7408a8b51cdc3f 100644 --- a/tree/tree/inc/TBranchElement.h +++ b/tree/tree/inc/TBranchElement.h @@ -38,7 +38,11 @@ class TVirtualCollectionIterators; class TVirtualCollectionPtrIterators; class TVirtualArray; -namespace TStreamerInfoActions { class TActionSequence; } +namespace TStreamerInfoActions { + class TActionSequence; + struct TIDNode; + using TIDs = std::vector<TIDNode>; +} class TBranchElement : public TBranch { @@ -90,8 +94,9 @@ protected: TStreamerInfo *fInfo; ///<! Pointer to StreamerInfo char *fObject; ///<! Pointer to object at *fAddress TVirtualArray *fOnfileObject; ///<! Place holder for the onfile representation of data members. - Bool_t fInit; ///<! Initialization flag for branch assignment - Bool_t fInitOffsets; ///<! Initialization flag to not endlessly recalculate offsets + Bool_t fInit : 1; ///<! Initialization flag for branch assignment + Bool_t fInInitInfo : 1;///<! True during the 2nd part of InitInfo (cut recursion). + Bool_t fInitOffsets: 1;///<! Initialization flag to not endlessly recalculate offsets TClassRef fTargetClass; ///<! Reference to the target in-memory class TClassRef fCurrentClass; ///<! Reference to current (transient) class definition TClassRef fParentClass; ///<! Reference to class definition in fParentName @@ -100,6 +105,7 @@ protected: Int_t *fBranchOffset; ///<! Sub-Branch offsets with respect to current transient class Int_t fBranchID; ///<! ID number assigned by a TRefTable. std::vector<Int_t> fIDs; ///<! List of the serial number of all the StreamerInfo to be used. + TStreamerInfoActions::TIDs fNewIDs; ///<! Nested List of the serial number of all the StreamerInfo to be used. TStreamerInfoActions::TActionSequence *fReadActionSequence; ///<! Set of actions to be executed to extract the data from the basket. TStreamerInfoActions::TActionSequence *fFillActionSequence; ///<! Set of actions to be executed to write the data to the basket. TVirtualCollectionIterators *fIterators; ///<! holds the iterators when the branch is of fType==4. @@ -119,9 +125,11 @@ protected: virtual void InitializeOffsets(); virtual void InitInfo(); Bool_t IsMissingCollection() const; + TStreamerInfo *FindOnfileInfo(TClass *valueClass, const TObjArray &branches) const; TClass *GetParentClass(); // Class referenced by fParentName TStreamerInfo *GetInfoImp() const; void ReleaseObject(); + void SetupInfo(); void SetBranchCount(TBranchElement* bre); void SetBranchCount2(TBranchElement* bre) { fBranchCount2 = bre; } Int_t Unroll(const char* name, TClass* cltop, TClass* cl, char* ptr, Int_t basketsize, Int_t splitlevel, Int_t btype); diff --git a/tree/tree/src/TBranchElement.cxx b/tree/tree/src/TBranchElement.cxx index e0a850c92319e4f94e7410360cb741205ef9d0f9..51a023b63c7e3d565c5cdb85756648e7e27ede38 100644 --- a/tree/tree/src/TBranchElement.cxx +++ b/tree/tree/src/TBranchElement.cxx @@ -148,6 +148,7 @@ TBranchElement::TBranchElement() , fObject(0) , fOnfileObject(0) , fInit(kFALSE) +, fInInitInfo(kFALSE) , fInitOffsets(kFALSE) , fTargetClass() , fCurrentClass() @@ -192,6 +193,7 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TStreamerInfo* si , fObject(0) , fOnfileObject(0) , fInit(kTRUE) +, fInInitInfo(kFALSE) , fInitOffsets(kFALSE) , fTargetClass(fClassName) , fCurrentClass() @@ -234,6 +236,7 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TStreamerInfo , fObject(0) , fOnfileObject(0) , fInit(kTRUE) +, fInInitInfo(kFALSE) , fInitOffsets(kFALSE) , fTargetClass( fClassName ) , fCurrentClass() @@ -646,6 +649,9 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TClonesArray* clo , fClassName("TClonesArray") , fParentName() , fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo()) +, fInit(kTRUE) +, fInInitInfo(kFALSE) +, fInitOffsets(kFALSE) , fTargetClass( fClassName ) , fCurrentClass() , fParentClass() @@ -670,6 +676,9 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TClonesArray* , fClassName("TClonesArray") , fParentName() , fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo()) +, fInit(kTRUE) +, fInInitInfo(kFALSE) +, fInitOffsets(kFALSE) , fTargetClass( fClassName ) , fCurrentClass() , fParentClass() @@ -789,6 +798,9 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TVirtualCollectio : TBranch() , fClassName(cont->GetCollectionClass()->GetName()) , fParentName() +, fInit(kTRUE) +, fInInitInfo(kFALSE) +, fInitOffsets(kFALSE) , fTargetClass( fClassName ) , fCurrentClass() , fParentClass() @@ -812,6 +824,9 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TVirtualColle : TBranch() , fClassName(cont->GetCollectionClass()->GetName()) , fParentName() +, fInit(kTRUE) +, fInInitInfo(kFALSE) +, fInitOffsets(kFALSE) , fTargetClass( fClassName ) , fCurrentClass() , fParentClass() @@ -1883,94 +1898,209 @@ char* TBranchElement::GetAddress() const return fAddress; } -//////////////////////////////////////////////////////////////////////////////// -/// Init the streamer info for the branch class, try to compensate for class -/// code unload/reload and schema evolution. -void TBranchElement::InitInfo() +// For a mother branch of type 3 or 4, find the 'correct' StreamerInfo for the +// content of the collection by find a sub-branch corresponding to a direct data member +// of the containee class (valueClass) +// Default to the current StreamerInfo if none are found. +TStreamerInfo *TBranchElement::FindOnfileInfo(TClass *valueClass, const TObjArray &branches) const { - if (!fInfo) { - // We did not already have streamer info, so now we must find it. - TClass* cl = fBranchClass.GetClass(); + TStreamerInfo *localInfo = nullptr; + + // Search for the correct version. + for(auto subbe : TRangeDynCast<TBranchElement>( branches )) { + if (!subbe->fInfo) + subbe->SetupInfo(); + if (valueClass == subbe->fInfo->GetClass()) { // Use GetInfo to provoke its creation. + localInfo = subbe->fInfo; + break; + } + } + if (!localInfo) { + // This is likely sub-optimal as we really should call GetFile but it is non-const. + auto file = fDirectory ? fDirectory->GetFile() : nullptr; + if (file && file->GetSeekInfo()) { + localInfo = (TStreamerInfo*)file->GetStreamerInfoCache()->FindObject(valueClass->GetName()); + if (localInfo) { + if (valueClass->IsVersioned()) { + localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion()); + } else { + localInfo = (TStreamerInfo*)valueClass->FindStreamerInfo(localInfo->GetCheckSum()); + if (localInfo) { + // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo). + localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion()); + } + } + } + } + } + if (!localInfo) + localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(); + return localInfo; +} - //------------------------------------------------------------------------ - // Check if we're dealing with the name change - ////////////////////////////////////////////////////////////////////////// +namespace { + static void GatherArtificialElements(std::vector<int> &fIDs, const TObjArray &branches, TStreamerInfoActions::TIDs &ids, TString prefix, TStreamerInfo *info, Int_t offset) { + size_t ndata = info->GetNelement(); + for (size_t i =0; i < ndata; ++i) { + TStreamerElement *nextel = info->GetElement(i); - TClass* targetClass = 0; - if( fTargetClass.GetClassName()[0] ) { - targetClass = fTargetClass; - if (!targetClass && GetCollectionProxy()) { - // We are in the case where the branch holds a custom collection - // proxy but the dictionary is not loaded, calling - // GetCollectionProxy had the side effect of creating the TClass - // corresponding to this emulated collection. - targetClass = fTargetClass; - } - if ( !targetClass ) { - Error( "InitInfo", "The target class dictionary is not present!" ); - return; - } - } else { - targetClass = cl; + if (nextel->GetType() == TStreamerInfo::kCacheDelete + || nextel->GetType() == TStreamerInfo::kCacheNew) { + continue; } - if (cl) { - //--------------------------------------------------------------------- - // Get the streamer info for given version - /////////////////////////////////////////////////////////////////////// - { - if ( (cl->Property() & kIsAbstract) && cl == targetClass) { - TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this); - if (parent && parent != this && !parent->GetClass()->IsLoaded() ) { - // Our parent's class is emulated and we represent an abstract class. - // and the target class has not been set explicilty. - TString target = cl->GetName(); - target += "@@emulated"; - fTargetClass.SetName(target); - - if (!fTargetClass) { - cl->GetStreamerInfoAbstractEmulated(fClassVersion); - } - targetClass = fTargetClass; - } + TString ename = prefix + nextel->GetName(); + + if (ename[0]=='*') + ename.Remove(0,1); + + if (nextel->IsA() == TStreamerArtificial::Class() + && branches.FindObject(ename) == nullptr) { + + fIDs.push_back(i); + ids.push_back(i); + ids.back().fElement = nextel; + ids.back().fInfo = info; + } + + if (nextel->CannotSplit()) + continue; + + TClass *elementClass = nextel->GetClassPointer(); + TBranchElement *be = (TBranchElement*)branches.FindObject(ename); + if (elementClass && (!be || be->GetType() == -2)) { + TStreamerInfo *nextinfo = nullptr; + + // nextinfo_version = .... + auto search = be ? be->GetListOfBranches() : &branches; + TVirtualArray *onfileObject = nullptr; + for(auto subbe : TRangeDynCast<TBranchElement>( *search )) { + + if (elementClass == subbe->GetInfo()->GetClass()) { // Use GetInfo to provoke its creation. + nextinfo = subbe->GetInfo(); + onfileObject = subbe->GetOnfileObject(); + break; } - if( targetClass != cl ) { - fInfo = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fClassVersion ); - } else { - fInfo = (TStreamerInfo*)cl->GetStreamerInfo(fClassVersion); + } + if (!nextinfo) { + nextinfo = (TStreamerInfo *)elementClass->GetStreamerInfo(); + if (elementClass->GetCollectionProxy() && elementClass->GetCollectionProxy()->GetValueClass()) { + nextinfo = (TStreamerInfo *)elementClass->GetCollectionProxy()->GetValueClass()->GetStreamerInfo(); // NOTE: need to find the right version } } + ids.emplace_back(nextinfo, offset + nextel->GetOffset()); + std::vector<int> subids; // ignored + ids.back().fNestedIDs->fOnfileObject = onfileObject; + GatherArtificialElements(subids, branches, ids.back().fNestedIDs->fIDs, ename + ".", nextinfo, offset + nextel->GetOffset()); + if (ids.back().fNestedIDs->fIDs.empty()) + ids.pop_back(); + } + } +}; +} // Anonymous namespace. - // FIXME: Check that the found streamer info checksum matches our branch class checksum here. - // Check to see if the class code was unloaded/reloaded - // since we were created. - R__LOCKGUARD(gInterpreterMutex); - if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) { - // Try to compensate for a class that got unloaded on us. - // Search through the streamer infos by checksum - // and take the first match. - - TStreamerInfo* info; - if( targetClass != cl ) - info = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fCheckSum ); - else { - info = (TStreamerInfo*)cl->FindStreamerInfo( fCheckSum ); - if (info) { - // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo). - info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion()); + +//////////////////////////////////////////////////////////////////////////////// +/// Set the value of fInfo. This is part one of InitInfo. +/// To be used as: +/// if (!fInfo) +/// SetupInfo(); +/// It would only be used within InitInfo (and its callees) + +void TBranchElement::SetupInfo() +{ + // We did not already have streamer info, so now we must find it. + TClass* cl = fBranchClass.GetClass(); + + //------------------------------------------------------------------------ + // Check if we're dealing with the name change + ////////////////////////////////////////////////////////////////////////// + + TClass* targetClass = 0; + if( fTargetClass.GetClassName()[0] ) { + targetClass = fTargetClass; + if (!targetClass && GetCollectionProxy()) { + // We are in the case where the branch holds a custom collection + // proxy but the dictionary is not loaded, calling + // GetCollectionProxy had the side effect of creating the TClass + // corresponding to this emulated collection. + targetClass = fTargetClass; + } + if ( !targetClass ) { + Error( "InitInfo", "The target class dictionary is not present!" ); + return; + } + } else { + targetClass = cl; + } + if (cl) { + //--------------------------------------------------------------------- + // Get the streamer info for given version + /////////////////////////////////////////////////////////////////////// + + { + if ( (cl->Property() & kIsAbstract) && cl == targetClass) { + TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this); + if (parent && parent != this && !parent->GetClass()->IsLoaded() ) { + // Our parent's class is emulated and we represent an abstract class. + // and the target class has not been set explicilty. + TString target = cl->GetName(); + target += "@@emulated"; + fTargetClass.SetName(target); + + if (!fTargetClass) { + cl->GetStreamerInfoAbstractEmulated(fClassVersion); } + targetClass = fTargetClass; } - if( info ) { - fInfo = info; - // We no longer reset the class version so that in case the user is passing us later - // the address of a class that require (another) Conversion we can find the proper - // StreamerInfo. - // fClassVersion = fInfo->GetClassVersion(); + } + if( targetClass != cl ) { + fInfo = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fClassVersion ); + } else { + fInfo = (TStreamerInfo*)cl->GetStreamerInfo(fClassVersion); + } + } + + // FIXME: Check that the found streamer info checksum matches our branch class checksum here. + // Check to see if the class code was unloaded/reloaded + // since we were created. + R__LOCKGUARD(gInterpreterMutex); + if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) { + // Try to compensate for a class that got unloaded on us. + // Search through the streamer infos by checksum + // and take the first match. + + TStreamerInfo* info; + if( targetClass != cl ) + info = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fCheckSum ); + else { + info = (TStreamerInfo*)cl->FindStreamerInfo( fCheckSum ); + if (info) { + // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo). + info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion()); } } + if( info ) { + fInfo = info; + // We no longer reset the class version so that in case the user is passing us later + // the address of a class that require (another) Conversion we can find the proper + // StreamerInfo. + // fClassVersion = fInfo->GetClassVersion(); + } } } +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Init the streamer info for the branch class, try to compensate for class +/// code unload/reload and schema evolution. + +void TBranchElement::InitInfo() +{ + if (!fInfo) + SetupInfo(); // // Fixup cached streamer info if necessary. @@ -1984,6 +2114,10 @@ void TBranchElement::InitInfo() Error("InitInfo","StreamerInfo is not compiled."); } + // return immediately if we are called recursively. + if (fInInitInfo) + return; + fInInitInfo = kTRUE; if (!fInit) { // We were read in from a file, figure out what our fID should be, // schema evolution must be considered. @@ -2005,6 +2139,7 @@ void TBranchElement::InitInfo() if (elt && offset!=TStreamerInfo::kMissing) { size_t ndata = fInfo->GetNelement(); fIDs.clear(); + fNewIDs.clear(); for (size_t i = 0; i < ndata; ++i) { if (fInfo->GetElement(i) == elt) { if (elt->TestBit (TStreamerElement::kCache) @@ -2017,10 +2152,18 @@ void TBranchElement::InitInfo() // ReadLeaves). // fID = i+1; fID = i; - if (elt->TestBit(TStreamerElement::kRepeat)) { - fIDs.push_back(fID+1); - } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) { - fIDs.push_back(fID+1); + if (fType != 2) { + if (elt->TestBit(TStreamerElement::kRepeat)) { + fIDs.push_back(fID+1); + fNewIDs.push_back(fID+1); + fNewIDs.back().fElement = fInfo->GetElement(i+1); + fNewIDs.back().fInfo = fInfo; + } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) { + fIDs.push_back(fID+1); + fNewIDs.push_back(fID+1); + fNewIDs.back().fElement = fInfo->GetElement(i+1); + fNewIDs.back().fInfo = fInfo; + } } } else { fID = i; @@ -2033,6 +2176,11 @@ void TBranchElement::InitInfo() } for (size_t i = fID+1+(fIDs.size()); i < ndata; ++i) { TStreamerElement *nextel = fInfo->GetElement(i); + + if (s != nextel->GetName()) { + // We moved on to the next set + break; + } // Add all (and only) the Artificial Elements that follows this StreamerInfo. // fprintf(stderr,"%s/%d[%zu] passing trhough %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName()); if (fType==31||fType==41) { @@ -2052,16 +2200,20 @@ void TBranchElement::InitInfo() } if (nextel->IsA() != TStreamerArtificial::Class() || nextel->GetType() == TStreamerInfo::kCacheDelete ) { - break; + continue; } // NOTE: We should verify that the rule's source are 'before' // or 'at' this branch. // fprintf(stderr,"%s/%d[%zu] pushd %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName()); fIDs.push_back(i); + fNewIDs.push_back(i); + fNewIDs.back().fElement = nextel; + fNewIDs.back().fInfo = fInfo; } } else if (elt && offset==TStreamerInfo::kMissing) { // Still re-assign fID properly. fIDs.clear(); + fNewIDs.clear(); size_t ndata = fInfo->GetNelement(); for (size_t i = 0; i < ndata; ++i) { if (fInfo->GetElement(i) == elt) { @@ -2072,6 +2224,7 @@ void TBranchElement::InitInfo() } else { // We have not even found the element .. this is strange :( // fIDs.clear(); + // fNewIDs.clear(); // fID = -3; // SetBit(kDoNotProcess); } @@ -2100,6 +2253,30 @@ void TBranchElement::InitInfo() lastbranch->SetBit(kOwnOnfileObj); } } + if (fType == 3 || fType == 4 || (fType == 0 && fID == -2)) { + // Need to add the rule targetting transient members. + TStreamerInfo *localInfo = fInfo; + if (fType == 3 || fType == 4) { + // Don't we have real version information? + // Not unless there is a subbranch with a non-split element of the class. + // Search for the correct version. + localInfo = FindOnfileInfo(fClonesClass, fBranches); + } + + TString prefix(GetName()); + if (prefix[prefix.Length()-1] != '.') { + if (fType == 3 || fType == 4) { + prefix += "."; + } else { + prefix = ""; + } + } + fIDs.clear(); + fNewIDs.clear(); + + GatherArtificialElements(fIDs, fBranches, fNewIDs, prefix, localInfo, 0); + + } fInit = kTRUE; // Get the action sequence we need to copy for reading. @@ -2112,6 +2289,7 @@ void TBranchElement::InitInfo() } SetReadLeavesPtr(); SetFillLeavesPtr(); + fInInitInfo = kFALSE; } } @@ -2320,6 +2498,45 @@ Int_t TBranchElement::GetEntry(Long64_t entry, Int_t getall) } break; } + if (!TestBit(kDecomposedObj) && fReadActionSequence && !fReadActionSequence->fActions.empty()) { + if (fType == 3) { + // Apply the unattached rules; by definition they do not need any + // input from a buffer. + TBufferFile b(TBufferFile::kRead, 1); + + auto ndata = GetNdata(); + + TClonesArray* clones = (TClonesArray*) fObject; + if (clones->IsZombie()) { + return -1; + } + R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata); + + char **arr = (char **)clones->GetObjectRef(); + char **end = arr + fNdata; + + b.ApplySequenceVecPtr(*fReadActionSequence,arr,end); + } else if (fType == 4) { + // Apply the unattached rules; by definition they do not need any + // input from a buffer. + TBufferFile b(TBufferFile::kRead, 1); + + auto ndata = GetNdata(); + + R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata); + TVirtualCollectionProxy *proxy = GetCollectionProxy(); + TVirtualCollectionProxy::TPushPop helper(proxy, fObject); + + TVirtualCollectionIterators *iter = fIterators; + b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd); + } else { + // Apply the unattached rules; by definition they do not need any + // input from a buffer. + TBufferFile b(TBufferFile::kRead, 1); + R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata); + b.ApplySequence(*fReadActionSequence, fObject); + } + } } else { // -- Terminal branch. if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) { @@ -3263,6 +3480,15 @@ void TBranchElement::InitializeOffsets() } } } + const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty(); + if (fReadActionSequence && isSplitNode) { + TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this)); + auto index = parent->fBranches.IndexOf(this); + if (index >= 0) { + fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] ); + } + } + fInitOffsets = kTRUE; } @@ -3327,6 +3553,19 @@ Bool_t TBranchElement::IsMissingCollection() const //////////////////////////////////////////////////////////////////////////////// /// Print branch parameters. +static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions::TIDs &ids) +{ + for(auto &cursor : ids) { + auto id = cursor.fElemID; + if (id >= 0) + info->GetElement(id)->ls(); + else if (cursor.fNestedIDs) { + Printf(" With subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset); + PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs); + } + } +} + void TBranchElement::Print(Option_t* option) const { Int_t nbranches = fBranches.GetEntriesFast(); @@ -3356,9 +3595,30 @@ void TBranchElement::Print(Option_t* option) const if (strncmp(option,"debugInfo",strlen("debugInfo"))==0) { Printf("Branch %s uses:",GetName()); if (fID>=0) { - GetInfoImp()->GetElement(fID)->ls(); + // GetInfoImp()->GetElement(fID)->ls(); + // for(UInt_t i=0; i< fIDs.size(); ++i) { + // GetInfoImp()->GetElement(fIDs[i])->ls(); + // } + TStreamerInfo *localInfo = GetInfoImp(); + if (fType == 3 || fType == 4) { + // Search for the correct version. + localInfo = FindOnfileInfo(fClonesClass, fBranches); + } + Printf(" With new ids:"); + if (fType != 3 && fType != 4) + localInfo->GetElement(fID)->ls(); + PrintElements(localInfo, fNewIDs); + Printf(" with read actions:"); + if (fReadActionSequence) fReadActionSequence->Print(option); + Printf(" with write actions:"); + if (fFillActionSequence) fFillActionSequence->Print(option); + } else if (!fIDs.empty() && GetInfoImp()) { + TVirtualStreamerInfo *info = GetInfoImp(); + if (fType == 3 || fType == 4) { + info = fClonesClass->GetStreamerInfo(); + } for(UInt_t i=0; i< fIDs.size(); ++i) { - GetInfoImp()->GetElement(fIDs[i])->ls(); + info->GetElement(fIDs[i])->ls(); } Printf(" with read actions:"); if (fReadActionSequence) fReadActionSequence->Print(option); @@ -5038,6 +5298,56 @@ void TBranchElement::SetOffset(Int_t offset) //////////////////////////////////////////////////////////////////////////////// /// Set the sequence of actions needed to read the data out of the buffer. +#if 0 +// Maybe owner unique_ptr +struct SequencePtr { + TStreamerInfoActions::TActionSequence *fSequence = nullptr; + Bool_t fOwner = kFALSE; + + ~SequencePtr() { + if (fOwner) delete fSequence; + } + + // Accessor to the pointee. + TStreamerInfoActions::TActionSequence &operator*() const { + return *fSequence; + } + + // Accessor to the pointee + TStreamerInfoActions::TActionSequence *operator->() const { + return fSequence; + } + + // Return true is the pointee is not nullptr. + Bool_t operator bool() { + return fSequence != nullptr; + } +}; + +SequencePtr ReadMemberWiseActionsCollectionGetter(TVirtualStreamerInfo *info, TVirtualCollection *collectionProxy, TClass *originalClass) { + auto seq = info->GetReadMemberWiseActions(kTRUE); + return {seq, kFALSE}; +} +SequencePtr ConversionReadMemberWiseActionsCollectionGetter(TVirtualStreamerInfo *info, TVirtualCollection *collectionProxy, TClass *originalClass) { + auto seq = collectionProxy->GetConversionReadMemberWiseActions(originalClass, info->GetClassVersion()); + return {seq, kFALSE}; +} +SequencePtr ReadMemberWiseActionsViaProxyGetter(TVirtualStreamerInfo *info, TVirtualCollection *collectionProxy, TClass *originalClass) { + auto seq = collectionProxy->GetReadMemberWiseActions(info->GetClassVersion()); + return {seq, kFALSE}; +} +SequencePtr ReadMemberWiseActionsCollectionCreator(TVirtualStreamerInfo *info, TVirtualCollection *collectionProxy, TClass *originalClass) { + auto seq = TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(info,*collectionProxy); + return {seq, kTRUE}; +} +// Creator5() = Creator1; +SequencePtr ReadMemberWiseActionsGetter(TVirtualStreamerInfo *info, TVirtualCollection *collectionProxy, TClass *originalClass) { + auto seq = info->GetReadMemberWiseActions(kFALSE); + return {seq, kFALSE}; +} +// Creator7() = Creator4 +#endif + void TBranchElement::SetReadActionSequence() { if (fInfo == 0) { @@ -5046,6 +5356,7 @@ void TBranchElement::SetReadActionSequence() } // Get the action sequence we need to copy for reading. +#if 0 TStreamerInfoActions::TActionSequence *original = 0; TStreamerInfoActions::TActionSequence *transient = 0; if (fType == 41) { @@ -5071,14 +5382,105 @@ void TBranchElement::SetReadActionSequence() } else if (0<=fType && fType<=2) { // Note: this still requires the ObjectWise sequence to not be optimized! original = fInfo->GetReadMemberWiseActions(kFALSE); + } else if ( (fType == 3 || fType == 4) && !fIDs.empty()) { + auto localInfo = (TStreamerInfo*)fClonesClass->GetStreamerInfo(); + // original = localInfo->GetReadMemberWiseActions(kTRUE); + original = TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(localInfo, *GetCollectionProxy()); } if (original) { - fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence. + // A 'split' node does not store data itself (it has not associated baskets) + const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || (fType == 0 && fID == -2)); + if (!isSplitNode) + fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence. if (fReadActionSequence) delete fReadActionSequence; fReadActionSequence = original->CreateSubSequence(fIDs,fOffset); - fIDs.erase(fIDs.begin()); + if (!isSplitNode) + fIDs.erase(fIDs.begin()); + else { + // fObject has the address of the sub-object but the streamer action have + // offset relative to the parent. + TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this)); + if (fInitOffsets) { + auto index = parent->fBranches.IndexOf(this); + if (index >= 0) { + fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] ); + fprintf(stderr, "Adjust %d\n", - parent->fBranchOffset[index] ); + } + } // else it will be done by InitOffsets + } } delete transient; +#else + TStreamerInfoActions::TActionSequence::SequenceGetter_t create = nullptr; + TClass *originalClass = nullptr; + TStreamerInfo *localInfo = fInfo; + if (fType == 41) { + if( fSplitLevel >= TTree::kSplitCollectionOfPointers && fBranchCount->fSTLtype == ROOT::kSTLvector) { + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionGetter; + } else { + TVirtualStreamerInfo *info = GetInfoImp(); + if (GetParentClass() == info->GetClass()) { + if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) { + originalClass = fBranchClass; + create = TStreamerInfoActions::TActionSequence::ConversionReadMemberWiseActionsViaProxyGetter; + } else { + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsViaProxyGetter; + } + } else if (GetCollectionProxy()) { + // Base class and embedded objects. + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionCreator; + } + } + } else if (fType == 31) { + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionGetter; + } else if (0<=fType && fType<=2) { + // Note: this still requires the ObjectWise sequence to not be optimized! + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsGetter; + } else if ( fType == 4 && !fNewIDs.empty()) { + localInfo = FindOnfileInfo(fClonesClass, fBranches); + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionCreator; + } else if ( fType == 3 && !fNewIDs.empty()) { + localInfo = FindOnfileInfo(fClonesClass, fBranches); + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionGetter; + } + + if (create) { + // A 'split' node does not store data itself (it has not associated baskets) + const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty(); + + if (!isSplitNode) { + fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence. + } + if (!isSplitNode) + fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence. + + if (fReadActionSequence) delete fReadActionSequence; + auto original = create(localInfo, GetCollectionProxy(), originalClass); + + TStreamerInfoActions::TIDs element_ids; + for(auto i : fIDs) { + element_ids.push_back(i); + } + fReadActionSequence = original->CreateSubSequence(fNewIDs, fOffset, create); + + if (!isSplitNode) + fNewIDs.erase(fNewIDs.begin()); + if (!isSplitNode) + fIDs.erase(fIDs.begin()); + else { + // fObject has the address of the sub-object but the streamer action have + // offset relative to the parent. + TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this)); + if (fInitOffsets) { + auto index = parent->fBranches.IndexOf(this); + if (index >= 0) { + fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] ); + } + } // else it will be done by InitOffsets + } + } +#endif + } //////////////////////////////////////////////////////////////////////////////// @@ -5171,10 +5573,20 @@ void TBranchElement::SetFillActionSequence() original = fInfo->GetWriteMemberWiseActions(kFALSE); } if (original) { - fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence. + // A 'split' node does not store data itself (it has not associated baskets) + const bool isSplitNode = (fType == 2 || (fType == 0 && fID == -2)); + if (!isSplitNode) + fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence. if (fFillActionSequence) delete fFillActionSequence; fFillActionSequence = original->CreateSubSequence(fIDs,fOffset); - fIDs.erase(fIDs.begin()); + if (!isSplitNode) + fIDs.erase(fIDs.begin()); + else { + // fObject has the address of the sub-object but the streamer action have + // offset relative to the parent. + TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this)); + fFillActionSequence->AddToOffset( -( ((char*)fObject) - ((char*)parent->fObject) ) ); + } } delete transient; @@ -5356,6 +5768,7 @@ void TBranchElement::Streamer(TBuffer& R__b) fLeaves.Add(leaf); fTree->GetListOfLeaves()->Add(leaf); } + // SetReadLeavesPtr(); } else {