From b2d242e8ca77c45d14674d1030887592045fcd37 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 15 Nov 2024 14:30:04 -0600 Subject: [PATCH 01/46] meta: Add TClass::HasDirectStreamerInfoUse This enables the StreamerInfoActions to enable the shortcuts that are possible in that case. --- core/meta/inc/TClass.h | 1 + 1 file changed, 1 insertion(+) diff --git a/core/meta/inc/TClass.h b/core/meta/inc/TClass.h index ff250aae7ef5a..56365cd720a0d 100644 --- a/core/meta/inc/TClass.h +++ b/core/meta/inc/TClass.h @@ -406,6 +406,7 @@ friend class TStreamerInfo; void ForceReload (TClass* oldcl); Bool_t HasDataMemberInfo() const { return fIsSyntheticPair || fHasRootPcmInfo || HasInterpreterInfo(); } Bool_t HasDefaultConstructor(Bool_t testio = kFALSE) const; + Bool_t HasDirectStreamerInfoUse() const { return fStreamerImpl == &TClass::StreamerStreamerInfo; } Bool_t HasInterpreterInfoInMemory() const { return nullptr != fClassInfo; } Bool_t HasInterpreterInfo() const { return fCanLoadClassInfo || fClassInfo; } UInt_t GetCheckSum(ECheckSum code = kCurrentCheckSum) const; From 7f17b54e27b6abbf1cfe1b6ec2ebbd199ac20167 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Mon, 16 Sep 2024 15:21:41 -0500 Subject: [PATCH 02/46] io: Correct setting of element's fNewType for pointer to STL collection --- core/meta/src/TStreamerElement.cxx | 16 ++++++++++++---- io/io/src/TStreamerInfo.cxx | 6 ++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/core/meta/src/TStreamerElement.cxx b/core/meta/src/TStreamerElement.cxx index c63bdbff3c6cb..b326ac2280313 100644 --- a/core/meta/src/TStreamerElement.cxx +++ b/core/meta/src/TStreamerElement.cxx @@ -480,8 +480,10 @@ void TStreamerElement::ls(Option_t *) const void TStreamerElement::SetArrayDim(Int_t dim) { fArrayDim = dim; - if (dim) fType += TVirtualStreamerInfo::kOffsetL; - fNewType = fType; + if (dim) { + fType += TVirtualStreamerInfo::kOffsetL; + fNewType += TVirtualStreamerInfo::kOffsetL; + } } //////////////////////////////////////////////////////////////////////////////// @@ -1715,7 +1717,10 @@ TStreamerSTL::TStreamerSTL(const char *name, const char *title, Int_t offset, fCtype = proxy.GetType(); if (proxy.HasPointers()) fCtype += TVirtualStreamerInfo::kOffsetP; } - if (TStreamerSTL::IsaPointer()) fType = TVirtualStreamerInfo::kSTLp; + if (TStreamerSTL::IsaPointer()) { + fType = TVirtualStreamerInfo::kSTLp; + fNewType = fType; + } } //////////////////////////////////////////////////////////////////////////////// @@ -1794,7 +1799,10 @@ TStreamerSTL::TStreamerSTL(const char *name, const char *title, Int_t offset, } } - if (TStreamerSTL::IsaPointer()) fType = TVirtualStreamerInfo::kSTLp; + if (TStreamerSTL::IsaPointer()) { + fType = TVirtualStreamerInfo::kSTLp; + fNewType = fType; + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index 401793f98e50e..534ae10f2cc49 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -535,8 +535,10 @@ void TStreamerInfo::Build(Bool_t isTransient) element = new TStreamerSTLstring(dmName, dmTitle, offset, dmFull, dmIsPtr); } else if (dm->IsSTLContainer()) { TVirtualCollectionProxy *proxy = TClass::GetClass(dmType /* the underlying type */)->GetCollectionProxy(); - if (proxy) element = new TStreamerSTL(dmName, dmTitle, offset, dmFull, *proxy, dmIsPtr); - else element = new TStreamerSTL(dmName, dmTitle, offset, dmFull, dmFull, dmIsPtr); + if (proxy) + element = new TStreamerSTL(dmName, dmTitle, offset, dmFull, *proxy, dmIsPtr); + else + element = new TStreamerSTL(dmName, dmTitle, offset, dmFull, dmFull, dmIsPtr); bool hasCustomAlloc = proxy ? proxy->GetProperties() & TVirtualCollectionProxy::kCustomAlloc : kFALSE; if (((TStreamerSTL*)element)->GetSTLtype() != ROOT::kSTLvector || hasCustomAlloc) { auto printErrorMsg = [&](const char* category) From 97bcf467922f7b945da92935859f5743b4788dfa Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 13 Nov 2024 13:09:36 -0600 Subject: [PATCH 03/46] io: Correct the class used for ReadVersion for kStreamer case. The version recorded 'here' is the version of the TStreamerInfo class not the user class --- io/io/src/TStreamerInfoReadBuffer.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io/io/src/TStreamerInfoReadBuffer.cxx b/io/io/src/TStreamerInfoReadBuffer.cxx index 5b84e330f9b91..7113f84f74815 100644 --- a/io/io/src/TStreamerInfoReadBuffer.cxx +++ b/io/io/src/TStreamerInfoReadBuffer.cxx @@ -1381,7 +1381,7 @@ Int_t TStreamerInfo::ReadBuffer(TBuffer &b, const T &arr, // Backward compatibility. Some TStreamerElement's where without // Streamer but were not removed from element list UInt_t start,count; - Version_t v = b.ReadVersion(&start, &count, cle); + Version_t v = b.ReadVersion(&start, &count, this->IsA()); if (fOldVersion<3){ // case of old TStreamerInfo if (aElement->IsBase() && aElement->IsA()!=TStreamerBase::Class()) { b.SetBufferOffset(start); //it was no byte count From d07c11f26f12de3b28582014929ab7b66396fa74 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 19 Sep 2024 11:26:14 -0500 Subject: [PATCH 04/46] io: TStreamerSTL: set fNewClass/fClassObject for collection of enums Even without schema evolution, the representation of a collection of enums on file is a `vector` so `TStreamerElement::fType` and `TStreamerElement::fClassObject` should point to `vector` while `TStreamerElement::fNewType` and `TStreamerElement::fNewClass` should point to the current in memory representaition `actualCollectionType< actualEnum >` that will know/remember what is the actual enum in memory representation. --- core/meta/inc/TStreamerElement.h | 3 ++ core/meta/src/TStreamerElement.cxx | 54 +++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/core/meta/inc/TStreamerElement.h b/core/meta/inc/TStreamerElement.h index 16b41c3e7c51e..773f005655e1b 100644 --- a/core/meta/inc/TStreamerElement.h +++ b/core/meta/inc/TStreamerElement.h @@ -52,6 +52,8 @@ class TStreamerElement : public TNamed { Double_t fXmax; //!Maximum of data member if a range is specified [xmin,xmax,nbits] Double_t fFactor; //!Conversion factor if a range is specified fFactor = (1<ClassInfo_IsEnum(arglist.fElements[1].c_str())) { + fCtype = enumdesc ? enumdesc->GetUnderlyingType() : 3; + } } if (TStreamerSTL::IsaPointer()) { fType = TVirtualStreamerInfo::kSTLp; @@ -1781,8 +1789,11 @@ TStreamerSTL::TStreamerSTL(const char *name, const char *title, Int_t offset, if (isPointer) fCtype = TVirtualStreamerInfo::kObjectp; else fCtype = TVirtualStreamerInfo::kObject; } else { - if (gCling->ClassInfo_IsEnum(intype.c_str())) { - if (isPointer) fCtype += TVirtualStreamerInfo::kOffsetP; + auto enumdesc = TEnum::GetEnum(intype.c_str()); + if (enumdesc || gCling->ClassInfo_IsEnum(intype.c_str())) { + fCtype = enumdesc ? enumdesc->GetUnderlyingType() : 3; + if (isPointer) + fCtype += TVirtualStreamerInfo::kOffsetP; } else { if (intype != "string") { // This case can happens when 'this' is a TStreamerElement for @@ -1852,6 +1863,41 @@ Bool_t TStreamerSTL::IsBase() const if (strcmp(ts.Data(),GetTypeNameBasic())==0) return kTRUE; return kFALSE; } + +//////////////////////////////////////////////////////////////////////////////// +/// Returns a pointer to the TClass of this element. + +TClass *TStreamerSTL::GetClassPointer() const +{ + if (fClassObject!=(TClass*)(-1)) + return fClassObject; + + bool quiet = (fType == TVirtualStreamerInfo::kArtificial); + + TString className(ExtractClassName(fTypeName)); + TClass *cl = TClass::GetClass(className, kTRUE, quiet); + + auto proxy = cl->GetCollectionProxy(); + if (fNewClass && proxy->GetValueClass() == nullptr) { + // Collection of numerical type, let check if it is an enum. + TClassEdit::TSplitType arglist(fTypeName, TClassEdit::kDropStlDefault); + if ( arglist.fElements[1].size() >= 2 ) { + auto enumdesc = TEnum::GetEnum(arglist.fElements[1].c_str()); + if (enumdesc || gCling->ClassInfo_IsEnum(arglist.fElements[1].c_str())) { + if (fNewClass == nullptr) { + ((TStreamerElement*)this)->fNewClass = cl; + if (proxy->HasPointers()) + cl = TClass::GetClass("vector"); + else + cl = TClass::GetClass("vector"); + } + } + } + } + ((TStreamerElement*)this)->fClassObject = cl; + return fClassObject; +} + //////////////////////////////////////////////////////////////////////////////// /// Returns size of STL container in bytes. From d5c44822857885a95925483b1f2272211a9f5896 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 13 Nov 2024 13:08:08 -0600 Subject: [PATCH 05/46] io actions: Delete unused TActionSequence default ctor --- io/io/inc/TStreamerInfoActions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io/io/inc/TStreamerInfoActions.h b/io/io/inc/TStreamerInfoActions.h index ea1cc24dfdcda..dfbaeec9db216 100644 --- a/io/io/inc/TStreamerInfoActions.h +++ b/io/io/inc/TStreamerInfoActions.h @@ -175,7 +175,7 @@ namespace TStreamerInfoActions { typedef std::vector ActionContainer_t; class TActionSequence : public TObject { - TActionSequence() {}; + TActionSequence() = delete; public: enum class EStatusBits { kVectorPtrLooper = BIT(14) From e34e08fc1f82ca3393c78c312d4c83e059a9cc96 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 13 Sep 2024 07:19:42 -0500 Subject: [PATCH 06/46] io actions: Add support for writing collections, including simple conversions --- io/io/src/TStreamerInfoActions.cxx | 1280 ++++++++++++++++++++++++++-- 1 file changed, 1202 insertions(+), 78 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index cb01ef9ee14ac..8c82b45ba963d 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -256,6 +256,18 @@ namespace TStreamerInfoActions return 0; } + template + struct WriteConvertBasicType { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config) + { + // Simple conversion from a 'From' on disk to a 'To' in memory. + Onfile temp; + temp = (Onfile)(*(Memory*)( ((char*)addr) + config->fOffset )); + buf << temp; + return 0; + } + }; + INLINE_TEMPLATE_ARGS Int_t WriteTextTNamed(TBuffer &buf, void *addr, const TConfiguration *config) { void *x = (void *)(((char *)addr) + config->fOffset); @@ -339,6 +351,16 @@ namespace TStreamerInfoActions return 0; } + static INLINE_TEMPLATE_ARGS void WriteCompressed(TBuffer &buf, float *addr, const TStreamerElement *elem) + { + buf.WriteFloat16(addr, const_cast(elem)); + } + + static INLINE_TEMPLATE_ARGS void WriteCompressed(TBuffer &buf, double *addr, const TStreamerElement *elem) + { + buf.WriteDouble32(addr, const_cast(elem)); + } + /** Direct copy of code from TStreamerInfo::WriteBufferAux, * potentially can be used later for non-text streaming */ template @@ -962,14 +984,18 @@ namespace TStreamerInfoActions class TConfigSTL : public TConfiguration { // Configuration object for the kSTL case private: - void Init() { + void Init(bool read) { TVirtualCollectionProxy *proxy = fNewClass->GetCollectionProxy(); if (proxy) { - fCreateIterators = proxy->GetFunctionCreateIterators(); - fCreateWriteIterators = proxy->GetFunctionCreateIterators(kFALSE); + fCreateIterators = proxy->GetFunctionCreateIterators(read); fCopyIterator = proxy->GetFunctionCopyIterator(); fDeleteIterator = proxy->GetFunctionDeleteIterator(); fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators(); + if (proxy->HasPointers()) { + fNext = TVirtualCollectionPtrIterators::Next; + } else { + fNext = proxy->GetFunctionNext(read); + } } } @@ -981,26 +1007,27 @@ namespace TStreamerInfoActions Bool_t fIsSTLBase; // aElement->IsBase() && aElement->IsA()!=TStreamerBase::Class() TVirtualCollectionProxy::CreateIterators_t fCreateIterators; - TVirtualCollectionProxy::CreateIterators_t fCreateWriteIterators; TVirtualCollectionProxy::CopyIterator_t fCopyIterator; TVirtualCollectionProxy::DeleteIterator_t fDeleteIterator; TVirtualCollectionProxy::DeleteTwoIterators_t fDeleteTwoIterators; + TVirtualCollectionProxy::Next_t fNext; + - TConfigSTL(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, const char *type_name, Bool_t isbase) : + TConfigSTL(Bool_t read, TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, const char *type_name, Bool_t isbase) : TConfiguration(info,id,compinfo,offset,length), fOldClass(oldClass), fNewClass(oldClass), fStreamer(0), fTypeName(type_name), fIsSTLBase(isbase), - fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(); } + fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(read); } - TConfigSTL(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, TClass *newClass, const char *type_name, Bool_t isbase) : + TConfigSTL(Bool_t read, TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, TClass *newClass, const char *type_name, Bool_t isbase) : TConfiguration(info,id,compinfo,offset,length), fOldClass(oldClass), fNewClass(newClass), fStreamer(0), fTypeName(type_name), fIsSTLBase(isbase), - fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(); } + fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(read); } - TConfigSTL(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, TMemberStreamer* streamer, const char *type_name, Bool_t isbase) : + TConfigSTL(Bool_t read, TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, TMemberStreamer* streamer, const char *type_name, Bool_t isbase) : TConfiguration(info,id,compinfo,offset,length), fOldClass(oldClass), fNewClass(oldClass), fStreamer(streamer), fTypeName(type_name), fIsSTLBase(isbase), - fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(); } + fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(read); } - TConfigSTL(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, TClass *newClass, TMemberStreamer* streamer, const char *type_name, Bool_t isbase) : + TConfigSTL(Bool_t read, TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, TClass *newClass, TMemberStreamer* streamer, const char *type_name, Bool_t isbase) : TConfiguration(info,id,compinfo,offset,length), fOldClass(oldClass), fNewClass(newClass), fStreamer(streamer), fTypeName(type_name), fIsSTLBase(isbase), - fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(); } + fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(read); } TConfiguration *Copy() override { return new TConfigSTL(*this); } }; @@ -1010,7 +1037,7 @@ namespace TStreamerInfoActions public: Double_t fFactor; Double_t fXmin; - TConfSTLWithFactor(TConfigSTL *orig, Double_t factor, Double_t xmin) : TConfigSTL(*orig),fFactor(factor),fXmin(xmin) {}; + TConfSTLWithFactor(TConfigSTL *orig, Double_t factor, Double_t xmin) : TConfigSTL(*orig), fFactor(factor), fXmin(xmin) {}; TConfiguration *Copy() override { return new TConfSTLWithFactor(*this); } }; @@ -1394,6 +1421,114 @@ namespace TStreamerInfoActions (*config->fStreamer)(buf,addr,conf->fLength); } + // To Upgrade this to WriteSTLMemberWiseChangedClass (see ReadSTLMemberWiseChangedClass) + // we would need to a TVirtualCollectionProxy::GetConversionWriteMemberWiseActions + INLINE_TEMPLATE_ARGS void WriteSTLMemberWise(TBuffer &buf, void *addr, const TConfiguration *conf) + { + // Collection was saved member-wise + // newClass -> in memory representation + // oldClass -> onfile representation + + TConfigSTL *config = (TConfigSTL*)conf; + TClass *newClass = config->fNewClass; + TClass *onfileClass = config->fOldClass; + + // Until the writing of TVirtualCollectionProxy::GetConversionWriteMemberWiseActions + assert(newClass && onfileClass && newClass == onfileClass && + "Class level transformation while writing is not yet supported"); + + if (newClass && onfileClass) { + + buf.WriteVersion( onfileClass->GetCollectionProxy()->GetValueClass(), kFALSE ); + + TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy(); + TVirtualCollectionProxy *onfileProxy = onfileClass->GetCollectionProxy(); + + TVirtualCollectionProxy::TPushPop helper( newProxy, (char*)addr ); + Int_t nobjects = newProxy->Size(); + buf.WriteInt(nobjects); + if (nobjects) { + TActionSequence *actions = onfileProxy->GetWriteMemberWiseActions(); + char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + void *begin = &(startbuf[0]); + void *end = &(endbuf[0]); + config->fCreateIterators( addr, &begin, &end, newProxy); + // We can not get here with a split vector of pointer, so we can indeed assume + // that actions->fConfiguration != null. + buf.ApplySequence(*actions, begin, end); + if (begin != &(startbuf[0])) { + // assert(end != endbuf); + config->fDeleteTwoIterators(begin,end); + } + } + } + } + + // This routine could/should be merge with WriteSTLMemberWise, the only difference + // is the for loop over the objects. We are not using this version for the case + // where `conf->fLength is 1` as we know this information at StreamerInfo build time + // and thus we can avoid the 'waste' of CPU cycles involved in doing a loop of length 1 + INLINE_TEMPLATE_ARGS void WriteArraySTLMemberWise(TBuffer &buf, void *addr, const TConfiguration *conf) + { + // Collection was saved member-wise + // newClass -> in memory representation + // oldClass -> onfile representation + + TConfigSTL *config = (TConfigSTL*)conf; + TClass *newClass = config->fNewClass; + TClass *onfileClass = config->fOldClass; + + // Until the writing of TVirtualCollectionProxy::GetConversionWriteMemberWiseActions + assert(newClass && onfileClass && newClass == onfileClass && + "Class level transformation while writing is not yet supported"); + + if (newClass && onfileClass) { + + buf.WriteVersion( onfileClass->GetCollectionProxy()->GetValueClass(), kFALSE ); + + TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy(); + TVirtualCollectionProxy *onfileProxy = onfileClass->GetCollectionProxy(); + + int objectSize = newClass->Size(); + char *obj = (char*)addr; + char *endobj = obj + conf->fLength * objectSize; + + for (; obj < endobj; obj += objectSize) { + TVirtualCollectionProxy::TPushPop helper( newProxy, (char*)obj ); + Int_t nobjects = newProxy->Size(); + buf.WriteInt(nobjects); + if (nobjects) { + TActionSequence *actions = onfileProxy->GetWriteMemberWiseActions(); + char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + void *begin = &(startbuf[0]); + void *end = &(endbuf[0]); + config->fCreateIterators( addr, &begin, &end, newProxy); + // We can not get here with a split vector of pointer, so we can indeed assume + // that actions->fConfiguration != null. + buf.ApplySequence(*actions, begin, end); + if (begin != &(startbuf[0])) { + // assert(end != endbuf); + config->fDeleteTwoIterators(begin,end); + } + } + } + } + } + + INLINE_TEMPLATE_ARGS void WriteSTLObjectWiseFastArray(TBuffer &buf, void *addr, const TConfiguration *conf) + { + TConfigSTL *config = (TConfigSTL*)conf; + // Idea: This needs to be unrolled, it currently calls the TGenCollectionStreamer .... + buf.WriteFastArray(addr,config->fNewClass,conf->fLength,(TMemberStreamer*)0); + } + INLINE_TEMPLATE_ARGS void WriteSTLObjectWiseStreamer(TBuffer &buf, void *addr, const TConfiguration *conf) + { + TConfigSTL *config = (TConfigSTL*)conf; + (*config->fStreamer)(buf,addr,conf->fLength); + } + template INLINE_TEMPLATE_ARGS Int_t ReadSTL(TBuffer &buf, void *addr, const TConfiguration *conf) @@ -1410,6 +1545,34 @@ namespace TStreamerInfoActions return 0; } + template + INLINE_TEMPLATE_ARGS Int_t WriteSTL(TBuffer &buf, void *addr, const TConfiguration *conf) + { + TConfigSTL *config = (TConfigSTL*)conf; + UInt_t start; + TClass *onfileClass = config->fOldClass; + TStreamerElement *aElement = config->fCompInfo->fElem; + TVirtualCollectionProxy *proxy = onfileClass->GetCollectionProxy(); + TClass* vClass = proxy ? proxy->GetValueClass() : 0; + + // See test in TStreamerInfo::kSTL case in TStreamerInfoWriteBuffer.cxx + if (!buf.TestBit(TBuffer::kCannotHandleMemberWiseStreaming) + && proxy && vClass + && config->fInfo->GetStreamMemberWise() && onfileClass->CanSplit() + && !(strspn(aElement->GetTitle(),"||") == 2) + && !(vClass->HasCustomStreamerMember()) ) + { + start = buf.WriteVersionMemberWise(config->fInfo->IsA(), kTRUE); + memberwise(buf, ((char *)addr) + config->fOffset, config); + } else { + start = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + objectwise(buf, ((char *)addr) + config->fOffset, config); + } + buf.SetByteCount(start); + return 0; + } + template struct ConvertBasicType { static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config) @@ -1819,6 +1982,56 @@ namespace TStreamerInfoActions return 0; } + template + struct WriteConvertBasicType { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config) + { + const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement; + iter = (char*)iter + config->fOffset; + end = (char*)end + config->fOffset; + for(; iter != end; iter = (char*)iter + incr ) { + // Simple conversion from a 'From' on disk to a 'To' in memory. + Onfile temp = (Onfile)(*(Memory*)((char*) iter)); + buf << temp; + } + return 0; + } + }; + + template + struct WriteConvertBasicType, Memory> { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config) + { + const TStreamerElement *elem = config->fCompInfo->fElem; + const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement; + iter = (char*)iter + config->fOffset; + end = (char*)end + config->fOffset; + for(; iter != end; iter = (char*)iter + incr ) { + // Simple conversion from a 'From' on disk to a 'To' in memory. + Onfile temp = (Onfile)(*(Memory*)((char*) iter)); + WriteCompressed(buf, &temp, elem); + } + return 0; + } + }; + + template + struct WriteConvertBasicType, Memory> { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config) + { + const TStreamerElement *elem = config->fCompInfo->fElem; + const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement; + iter = (char*)iter + config->fOffset; + end = (char*)end + config->fOffset; + for(; iter != end; iter = (char*)iter + incr ) { + // Simple conversion from a 'From' on disk to a 'To' in memory. + Onfile temp = (Onfile)(*(Memory*)((char*) iter)); + WriteCompressed(buf, &temp, elem); + } + return 0; + } + }; + template static INLINE_TEMPLATE_ARGS Int_t ReadAction(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config) { @@ -1928,6 +2141,24 @@ namespace TStreamerInfoActions return 0; } + template + static INLINE_TEMPLATE_ARGS Int_t WriteCollectionBasicType(TBuffer &buf, void *addr, const TConfiguration *conf) + { + // Collection of numbers. Memberwise or not, it is all the same. + + TConfigSTL *config = (TConfigSTL*)conf; + UInt_t start = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + + std::vector *const vec = (std::vector*)(((char*)addr)+config->fOffset); + Int_t nvalues = vec->size(); + buf.WriteInt(nvalues); + + T *begin = &(*vec->begin()); + buf.WriteFastArray(begin, nvalues); + + buf.SetByteCount(start); + return 0; + } static INLINE_TEMPLATE_ARGS Int_t ReadCollectionFloat16(TBuffer &buf, void *addr, const TConfiguration *conf) { @@ -1955,6 +2186,24 @@ namespace TStreamerInfoActions return 0; } + static INLINE_TEMPLATE_ARGS Int_t WriteCollectionFloat16(TBuffer &buf, void *addr, const TConfiguration *conf) + { + // Collection of numbers. Memberwise or not, it is all the same. + + TConfigSTL *config = (TConfigSTL*)conf; + UInt_t start = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + + std::vector *const vec = (std::vector*)(((char*)addr)+config->fOffset); + Int_t nvalues = vec->size(); + buf.WriteInt(nvalues); + + float *begin = &(*vec->begin()); + buf.WriteFastArrayFloat16(begin, nvalues); + + buf.SetByteCount(start); + return 0; + } + static INLINE_TEMPLATE_ARGS Int_t ReadCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf) { // Collection of numbers. Memberwise or not, it is all the same. @@ -1981,6 +2230,24 @@ namespace TStreamerInfoActions return 0; } + static INLINE_TEMPLATE_ARGS Int_t WriteCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf) + { + // Collection of numbers. Memberwise or not, it is all the same. + + TConfigSTL *config = (TConfigSTL*)conf; + UInt_t start = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + + std::vector *const vec = (std::vector*)(((char*)addr)+config->fOffset); + Int_t nvalues = vec->size(); + buf.WriteInt(nvalues); + + double *begin = &(*vec->begin()); + buf.WriteFastArrayDouble32(begin, nvalues); + + buf.SetByteCount(start); + return 0; + } + template struct ConvertCollectionBasicType { static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf) @@ -2060,6 +2327,32 @@ namespace TStreamerInfoActions return 0; } + template + struct WriteConvertCollectionBasicType { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf) + { + // Collection of numbers. Memberwise or not, it is all the same. + + TConfigSTL *config = (TConfigSTL*)conf; + UInt_t start = buf.WriteVersion( config->fInfo->IsA(), kTRUE ); + + std::vector *const vec = (std::vector*)(((char*)addr)+config->fOffset); + Int_t nvalues = vec->size(); + buf.WriteInt(nvalues); + + // We have to call WriteFastArray for proper JSON writing + // So we need to convert before hand :( + Onfile *temp = new Onfile[nvalues]; + for(Int_t ind = 0; ind < nvalues; ++ind) { + temp[ind] = (Onfile)((*vec)[ind]); + } + buf.WriteFastArray(temp, nvalues); + delete [] temp; + + buf.SetByteCount(start, kTRUE); + return 0; + } + }; }; struct VectorPtrLooper { @@ -2159,6 +2452,52 @@ namespace TStreamerInfoActions return 0; } + template + struct WriteConvertBasicType { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config) + { + const Int_t offset = config->fOffset; + + for(; iter != end; iter = (char*)iter + sizeof(void*) ) { + From *from = (From*)( ((char*) (*(void**)iter) ) + offset ); + To to = (To)(*from); + buf << to; + } + return 0; + } + }; + + template + struct WriteConvertBasicType, From> { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config) + { + const Int_t offset = config->fOffset; + const TStreamerElement *elem = config->fCompInfo->fElem; + + for(; iter != end; iter = (char*)iter + sizeof(void*) ) { + From *from = (From*)( ((char*) (*(void**)iter) ) + offset ); + To to = (To)(*from); + WriteCompressed(buf, &to, elem); + } + return 0; + } + }; + template + struct WriteConvertBasicType, From> { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config) + { + const Int_t offset = config->fOffset; + const TStreamerElement *elem = config->fCompInfo->fElem; + + for(; iter != end; iter = (char*)iter + sizeof(void*) ) { + From *from = (From*)( ((char*) (*(void**)iter) ) + offset ); + To to = (To)(*from); + WriteCompressed(buf, &to, elem); + } + return 0; + } + }; + template static INLINE_TEMPLATE_ARGS Int_t ReadAction(TBuffer &buf, void *start, const void *end, const TConfiguration *config) { @@ -2193,6 +2532,7 @@ namespace TStreamerInfoActions }; struct AssociativeLooper { +protected: template static INLINE_TEMPLATE_ARGS void SimpleRead(TBuffer &buf, void *addr, Int_t nvalues) @@ -2210,6 +2550,38 @@ namespace TStreamerInfoActions buf.ReadFastArrayDouble32((double*)addr, nvalues); } + template + static INLINE_TEMPLATE_ARGS void SimpleWrite(TBuffer &buf, void *addr, const TStreamerElement *) + { + buf << *(T*)addr; + } + + static INLINE_TEMPLATE_ARGS void SimpleWriteFloat16(TBuffer &buf, void *addr, const TStreamerElement *elem) + { + buf.WriteFloat16((float*)addr, const_cast(elem)); + } + + static INLINE_TEMPLATE_ARGS void SimpleWriteDouble32(TBuffer &buf, void *addr, const TStreamerElement *elem) + { + buf.WriteDouble32((double*)addr, const_cast(elem)); + } + + template + static INLINE_TEMPLATE_ARGS void ArrayWrite(TBuffer &buf, void *addr, Int_t nvalues, const TStreamerElement *) + { + buf.WriteFastArray((T*)addr, nvalues); + } + + static INLINE_TEMPLATE_ARGS void ArrayWriteCompressed(TBuffer &buf, float *addr, Int_t nvalues, const TStreamerElement *elem) + { + buf.WriteFastArrayFloat16((float*)addr, nvalues, const_cast(elem)); + } + + static INLINE_TEMPLATE_ARGS void ArrayWriteCompressed(TBuffer &buf, double *addr, Int_t nvalues, const TStreamerElement *elem) + { + buf.WriteFastArrayDouble32((double*)addr, nvalues, const_cast(elem)); + } + template static INLINE_TEMPLATE_ARGS Int_t ReadNumericalCollection(TBuffer &buf, void *addr, const TConfiguration *conf) { @@ -2248,31 +2620,106 @@ namespace TStreamerInfoActions return 0; } - static INLINE_TEMPLATE_ARGS Int_t ReadCollectionFloat16(TBuffer &buf, void *addr, const TConfiguration *conf) + template + static INLINE_TEMPLATE_ARGS void LoopOverCollection(TBuffer &buf, void *iter, const void *end, Next_t next, Int_t /* nvalues */, const TStreamerElement *elem) { - return ReadNumericalCollection(buf,addr,conf); + void *addr; + while( (addr = next(iter, end)) ) + { + action(buf, addr, elem); + } } - static INLINE_TEMPLATE_ARGS Int_t ReadCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf) + template + static INLINE_TEMPLATE_ARGS void ConvertLoopOverCollection(TBuffer &buf, void *iter, const void *end, Next_t next, Int_t nvalues, const TStreamerElement *elem) { - return ReadNumericalCollection(buf,addr,conf); + Onfile *temp = new Onfile[nvalues]; + Int_t ind = 0; + void *addr; + while( (addr = next(iter, end)) ) + { + temp[ind] = (Onfile)*(Memory*)addr; + ++ind; + } + action(buf, temp, nvalues, elem); + delete [] temp; } - template - static INLINE_TEMPLATE_ARGS Int_t ReadCollectionBasicType(TBuffer &buf, void *addr, const TConfiguration *conf) + template + static INLINE_TEMPLATE_ARGS Int_t WriteNumericalCollection(TBuffer &buf, void *addr, const TConfiguration *conf) { - return ReadNumericalCollection >(buf,addr,conf); - } + // Collection of numbers. Memberwise or not, it is all the same. - template - struct ConvertRead { - static INLINE_TEMPLATE_ARGS void Action(TBuffer &buf, void *addr, Int_t nvalues) - { - From *temp = new From[nvalues]; - buf.ReadFastArray(temp, nvalues); - To *vec = (To*)addr; - for(Int_t ind = 0; ind < nvalues; ++ind) { - vec[ind] = (To)temp[ind]; + TConfigSTL *config = (TConfigSTL*)conf; + UInt_t start = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + + TClass *newClass = config->fNewClass; + TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy(); + void *collection = ((char*)addr)+config->fOffset; + TVirtualCollectionProxy::TPushPop helper( newProxy, collection); + + Int_t nvalues = newProxy->Size(); + buf.WriteInt(nvalues); + if (nvalues) { + char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + void *begin = &(startbuf[0]); + void *end = &(endbuf[0]); + config->fCreateIterators(collection, &begin, &end, newProxy); + + action(buf, begin, end, config->fNext, nvalues, config->fCompInfo->fElem); + + if (begin != &(startbuf[0])) { + // assert(end != endbuf); + config->fDeleteTwoIterators(begin, end); + } + } + buf.SetByteCount(start); + return 0; + } + +public: + static INLINE_TEMPLATE_ARGS Int_t ReadCollectionFloat16(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return ReadNumericalCollection(buf,addr,conf); + } + + static INLINE_TEMPLATE_ARGS Int_t WriteCollectionFloat16(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return WriteNumericalCollection >(buf,addr,conf); + } + + static INLINE_TEMPLATE_ARGS Int_t ReadCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return ReadNumericalCollection(buf,addr,conf); + } + + static INLINE_TEMPLATE_ARGS Int_t WriteCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return WriteNumericalCollection >(buf,addr,conf); + } + + template + static INLINE_TEMPLATE_ARGS Int_t ReadCollectionBasicType(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return ReadNumericalCollection >(buf,addr,conf); + } + + template + static INLINE_TEMPLATE_ARGS Int_t WriteCollectionBasicType(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return WriteNumericalCollection> >(buf,addr,conf); + } + + template + struct ConvertRead { + static INLINE_TEMPLATE_ARGS void Action(TBuffer &buf, void *addr, Int_t nvalues) + { + From *temp = new From[nvalues]; + buf.ReadFastArray(temp, nvalues); + To *vec = (To*)addr; + for(Int_t ind = 0; ind < nvalues; ++ind) { + vec[ind] = (To)temp[ind]; } delete [] temp; } @@ -2306,7 +2753,6 @@ namespace TStreamerInfoActions delete [] temp; } }; - template struct ConvertCollectionBasicType { static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf) @@ -2315,6 +2761,29 @@ namespace TStreamerInfoActions } }; + template + struct WriteConvertCollectionBasicType { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return WriteNumericalCollection> >(buf,addr,conf); + } + }; + template + struct WriteConvertCollectionBasicType> { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return WriteNumericalCollection >(buf,addr,conf); + } + }; + + template + struct WriteConvertCollectionBasicType> { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return WriteNumericalCollection >(buf,addr,conf); + } + }; + }; struct GenericLooper { @@ -2361,6 +2830,30 @@ namespace TStreamerInfoActions return 0; } + template + struct Write_WithoutFastArray_ConvertBasicType { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config) + { + TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf; + + Next_t next = loopconfig->fNext; + const Int_t offset = config->fOffset; + + char iterator[TVirtualCollectionProxy::fgIteratorArenaSize]; + void *iter = loopconfig->fCopyIterator(iterator,start); + void *addr; + while( (addr = next(iter,end)) ) { + From *x = (From*)( ((char*)addr) + offset ); + To t = (To)(*x); + buf << t; + } + if (iter != &iterator[0]) { + loopconfig->fDeleteIterator(iter); + } + return 0; + } + }; + template static INLINE_TEMPLATE_ARGS Int_t ReadAction(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config) { @@ -2401,11 +2894,33 @@ namespace TStreamerInfoActions if (iter != &iterator[0]) { loopconfig->fDeleteIterator(iter); } + } + // ConvertAction used for writing. + static void WriteConvertAction(void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config, To *items) + { + TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf; + + const Int_t offset = config->fOffset; + Next_t next = loopconfig->fNext; + + char iterator[TVirtualCollectionProxy::fgIteratorArenaSize]; + void *iter = loopconfig->fCopyIterator(&iterator,start); + void *addr; + + while( (addr = next(iter,end)) ) { + From *x = (From*)( ((char*)addr) + offset ); + *items = (To)*x; + ++items; + } + if (iter != &iterator[0]) { + loopconfig->fDeleteIterator(iter); + } } }; template struct Numeric { + // ConvertAction used for reading. static void ConvertAction(From *items, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration * /* config */) { // The difference with ConvertAction is that we can modify the start @@ -2422,6 +2937,23 @@ namespace TStreamerInfoActions ++items; } } + // ConvertAction used for writing. + static void WriteConvertAction(void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration * /* config */, To *items) + { + // The difference with ConvertAction is that we can modify the start + // iterator and skip the copy. We also never have an offset. + + TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf; + Next_t next = loopconfig->fNext; + + void *iter = start; + void *addr; + while( (addr = next(iter,end)) ) { + From *x = (From*)(addr); + *items = (To)*x; + ++items; + } + } }; template class Converter = Generic > @@ -2519,6 +3051,68 @@ namespace TStreamerInfoActions } }; + template class Converter = Generic > + struct WriteConvertBasicType { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config) + { + // Simple conversion from a 'From' on disk to a 'To' in memory. + + TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf; + TVirtualCollectionProxy *proxy = loopconfig->fProxy; + Int_t nvalues = proxy->Size(); + + Onfile *items = new Onfile[nvalues]; + Converter::WriteConvertAction(start, end, loopconfig, config, items); + buf.WriteFastArray(items, nvalues); + delete [] items; + return 0; + } + }; + + template class Converter > + struct WriteConvertBasicType, Memory, Converter > { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer & /* buf */, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config) + { + // Simple conversion from a 'From' on disk to a 'To' in memory. + + TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf; + TVirtualCollectionProxy *proxy = loopconfig->fProxy; + Int_t nvalues = proxy->Size(); + + TConfSTLNoFactor *conf = (TConfSTLNoFactor *)config; + + Onfile *items = new Onfile[nvalues]; + Converter::WriteConvertAction(start, end, loopconfig, config, items); + R__ASSERT(false && "Not yet implemented"); + (void)conf; + // buf.WriteFastArrayWithNbits(items, nvalues, conf->fNbits); + delete [] items; + return 0; + } + }; + + template class Converter > + struct WriteConvertBasicType, Memory, Converter > { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer & /* buf */, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config) + { + // Simple conversion from a 'From' on disk to a 'To' in memory. + + TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf; + TVirtualCollectionProxy *proxy = loopconfig->fProxy; + Int_t nvalues = proxy->Size(); + + TConfSTLNoFactor *conf = (TConfSTLNoFactor *)config; + + Onfile *items = new Onfile[nvalues]; + Converter::WriteConvertAction(start, end, loopconfig, config, items); + R__ASSERT(false && "Not yet implemented"); + (void)conf; + // buf.WriteFastArrayWithNbits(items, nvalues, conf->fNbits); + delete [] items; + return 0; + } + }; + static INLINE_TEMPLATE_ARGS Int_t ReadBase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config) { // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now @@ -2552,6 +3146,11 @@ namespace TStreamerInfoActions buf.ReadWithNbits((float*)addr,12); } + static INLINE_TEMPLATE_ARGS void SimpleWriteFloat16(TBuffer &buf, void *addr) + { + buf.WriteFloat16((float*)addr, nullptr); + } + static INLINE_TEMPLATE_ARGS void SimpleReadDouble32(TBuffer &buf, void *addr) { //we read a float and convert it to double @@ -2560,6 +3159,13 @@ namespace TStreamerInfoActions *(double*)addr = (Double_t)afloat; } + static INLINE_TEMPLATE_ARGS void SimpleWriteDouble32(TBuffer &buf, void *addr) + { + //we read a float and convert it to double + Float_t afloat = (Float_t)*(double*)addr; + buf << afloat; + } + template static INLINE_TEMPLATE_ARGS Int_t ReadNumericalCollection(TBuffer &buf, void *addr, const TConfiguration *conf) { @@ -2599,9 +3205,51 @@ namespace TStreamerInfoActions return 0; } + template + static INLINE_TEMPLATE_ARGS Int_t WriteNumericalCollection(TBuffer &buf, void *addr, const TConfiguration *conf) + { + // Collection of numbers. Memberwise or not, it is all the same. + + TConfigSTL *config = (TConfigSTL*)conf; + UInt_t start = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + + TClass *newClass = config->fNewClass; + TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy(); + void *collection = ((char*)addr)+config->fOffset; + TVirtualCollectionProxy::TPushPop helper( newProxy, collection ); + + Int_t nvalues = newProxy->Size(); + buf.WriteInt(nvalues); + if (nvalues) { + char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + void *begin = &(startbuf[0]); + void *end = &(endbuf[0]); + config->fCreateIterators(collection, &begin, &end, newProxy); + // We can not get here with a split vector of pointer, so we can indeed assume + // that actions->fConfiguration != null. + + TGenericLoopConfig loopconf(newProxy, /* read */ kTRUE); + ActionHolder::Action(buf,begin,end,&loopconf,config); + + if (begin != &(startbuf[0])) { + // assert(end != endbuf); + config->fDeleteTwoIterators(begin,end); + } + } + + buf.SetByteCount(start); + return 0; + } + static INLINE_TEMPLATE_ARGS Int_t ReadCollectionFloat16(TBuffer &buf, void *addr, const TConfiguration *conf) { - return ReadNumericalCollection,float,Numeric > >(buf,addr,conf); + return ReadNumericalCollection, float, Numeric > >(buf,addr,conf); + } + + static INLINE_TEMPLATE_ARGS Int_t WriteCollectionFloat16(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return WriteNumericalCollection, float, Numeric > >(buf,addr,conf); } static INLINE_TEMPLATE_ARGS Int_t ReadCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf) @@ -2611,6 +3259,13 @@ namespace TStreamerInfoActions // return ReadNumericalCollection,double,Numeric > >(buf,addr,conf); } + static INLINE_TEMPLATE_ARGS Int_t WriteCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf) + { + return WriteNumericalCollection >(buf,addr,conf); + // Could also use: + // return ReadNumericalCollection, double, Numeric > >(buf,addr,conf); + } + template static INLINE_TEMPLATE_ARGS Int_t ReadCollectionBasicType(TBuffer &buf, void *addr, const TConfiguration *conf) { @@ -2619,6 +3274,14 @@ namespace TStreamerInfoActions return ReadNumericalCollection >(buf,addr,conf); } + template + static INLINE_TEMPLATE_ARGS Int_t WriteCollectionBasicType(TBuffer &buf, void *addr, const TConfiguration *conf) + { + //TODO: Check whether we can implement this without loading the data in + // a temporary variable and whether this is noticeably faster. + return WriteNumericalCollection >(buf,addr,conf); + } + template struct ConvertCollectionBasicType { static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf) @@ -2628,6 +3291,14 @@ namespace TStreamerInfoActions } }; + template + struct WriteConvertCollectionBasicType { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf) + { + // return ReadNumericalCollection::Action >(buf,addr,conf); + return WriteNumericalCollection >(buf,addr,conf); + } + }; }; } @@ -2937,10 +3608,141 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt return TConfiguredAction(); } +template +static TConfiguredAction GetConvertCollectionWriteActionFrom(Int_t onfileType, TConfiguration *conf) +{ + switch (onfileType) { + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kBits: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + + // Supporting this requires adding TBuffer::WiteFastArrayWithNbits + // and the proper struct WriteConvertCollectionBasicType> here + case TStreamerInfo::kFloat16: + Error("GetConvertCollectionWriteActionFrom", "Write Conversion to Float16_t not yet supported"); + return TConfiguredAction(); + // return TConfiguredAction( Looper::template WriteConvertCollectionBasicType>::Action, conf ); break; + case TStreamerInfo::kDouble32: + Error("GetConvertCollectionWriteActionFrom", "Write Conversion to Double32_t not yet supported"); + return TConfiguredAction(); + // return TConfiguredAction( Looper::template WriteConvertCollectionBasicType>::Action, conf ); break; + default: + break; + } + Error("GetConvertCollectionWriteActionFrom", "UNEXPECTED: onfileType/oldtype == %d", onfileType); + R__ASSERT(0); // We should never be here + return TConfiguredAction(); +} + +// Used in to implement the kSTL case +// Not to be confused with GetCollectionWriteConvertAction +// nor with GetConvertCollectionWriteActionFrom (used to implement this function) +template +static TConfiguredAction GetConvertCollectionWriteAction(Int_t onfileType, Int_t memoryType, TConfiguration *conf) +{ + switch (memoryType) { + case TStreamerInfo::kBool: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kChar: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kShort: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kInt: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kLong: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kLong64: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kFloat: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kDouble: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kUChar: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kUShort: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kUInt: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kULong: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kULong64: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kFloat16: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kDouble32: + return GetConvertCollectionWriteActionFrom(onfileType, conf ); + break; + case TStreamerInfo::kBits: + Error("GetConvertCollectionWriteActionFrom","There is no support for kBits outside of a TObject."); + break; + default: + break; + } + Error("GetConvertCollectionWriteActionFrom", "UNEXPECTED: memoryType/newype == %d", memoryType); + R__ASSERT(0); // We should never be here + return TConfiguredAction(); +} + +// Used in GetCollectionWriteAction for the kConv cases within a collection +// Not to be confused with GetConvertCollectionWriteAction +// Note the read and write version could be merged (using yet another template parameter) +template +static TConfiguredAction GetCollectionWriteConvertAction(Int_t newtype, TConfiguration *conf) +{ + switch (newtype) { + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kFloat16: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kDouble32:return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kBits: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + default: + return TConfiguredAction( Looper::GenericRead, conf ); + break; + } + R__ASSERT(0); // We should never be here + return TConfiguredAction(); +} + template -static TConfiguredAction GetCollectionWriteAction(TVirtualStreamerInfo *info, TStreamerElement * /*element*/, Int_t type, UInt_t i, TStreamerInfo::TCompInfo_t *compinfo, Int_t offset) { +static TConfiguredAction GetCollectionWriteAction(TVirtualStreamerInfo *info, TStreamerElement *element, Int_t type, UInt_t i, TStreamerInfo::TCompInfo_t *compinfo, Int_t offset) { switch (type) { - // read basic types + // write basic types case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; @@ -2955,6 +3757,77 @@ static TConfiguredAction GetCollectionWriteAction(TVirtualStreamerInfo *info, TS case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteBasicType,new TConfiguration(info,i,compinfo,offset) ); break; // the simple type missing are kBits and kCounter. + + + // Conversions. + case TStreamerInfo::kConv + TStreamerInfo::kBool: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kChar: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kShort: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kInt: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kLong: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kLong64: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kFloat: + return GetCollectionWriteConvertAction( element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kDouble: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kUChar: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kUShort: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kUInt: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kULong: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kULong64: + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + break; +#ifdef NOT_YET + /* The conversion writing acceleration was not yet written for kBits */ + case TStreamerInfo::kConv + TStreamerInfo::kBits: + return GetCollectionWriteConvertAction(element->GetNewType(), new TBitsConfiguration(info,i,compinfo,offset) ); + break; +#endif + case TStreamerInfo::kConv + TStreamerInfo::kFloat16: { + if (element->GetFactor() != 0) { + return GetCollectionWriteConvertAction >(element->GetNewType(), new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); + } else { + Int_t nbits = (Int_t)element->GetXmin(); + if (!nbits) nbits = 12; + return GetCollectionWriteConvertAction >(element->GetNewType(), new TConfNoFactor(info,i,compinfo,offset,nbits) ); + } + break; + } + case TStreamerInfo::kConv + TStreamerInfo::kDouble32: { + if (element->GetFactor() != 0) { + return GetCollectionWriteConvertAction >(element->GetNewType(), new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); + } else { + Int_t nbits = (Int_t)element->GetXmin(); + if (!nbits) { + return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); + } else { + return GetCollectionWriteConvertAction >(element->GetNewType(), new TConfNoFactor(info,i,compinfo,offset,nbits) ); + } + } + break; + } default: return TConfiguredAction( Looper::GenericWrite, new TConfiguration(info,i,compinfo,0 /* 0 because we call the legacy code */) ); } @@ -2962,6 +3835,62 @@ static TConfiguredAction GetCollectionWriteAction(TVirtualStreamerInfo *info, TS return TConfiguredAction(); } +template +static TConfiguredAction GetNumericCollectionWriteAction(Int_t type, TConfigSTL *conf) +{ + // If we ever support std::vector fValues; //[...] we would get the info from the StreamerElement for fValues. + + switch (type) { + // Write basic types. + // Because of std::vector of bool is not backed up by an array of bool we have to converted it first. + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteCollectionBasicType,conf ); break; + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kBits: Error("GetNumericCollectionWriteAction","There is no support for kBits outside of a TObject."); break; + case TStreamerInfo::kFloat16: { + TConfigSTL *alternate = new TConfSTLNoFactor(conf,12); + delete conf; + return TConfiguredAction( Looper::WriteCollectionFloat16, alternate ); + // if (element->GetFactor() != 0) { + // return TConfiguredAction( Looper::template WriteAction >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); + // } else { + // Int_t nbits = (Int_t)element->GetXmin(); + // if (!nbits) nbits = 12; + // return TConfiguredAction( Looper::template WriteAction >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); + // } + break; + } + case TStreamerInfo::kDouble32: { + TConfigSTL *alternate = new TConfSTLNoFactor(conf,0); + delete conf; + return TConfiguredAction( Looper::WriteCollectionDouble32, alternate ); + // if (element->GetFactor() != 0) { + // return TConfiguredAction( Looper::template WriteAction >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); + // } else { + // Int_t nbits = (Int_t)element->GetXmin(); + // if (!nbits) { + // return TConfiguredAction( Looper::template WriteAction >, new TConfiguration(info,i,compinfo,offset) ); + // } else { + // return TConfiguredAction( Looper::template WriteAction >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); + // } + // } + break; + } + } + Fatal("GetNumericCollectionWriteAction","Is confused about %d",type); + R__ASSERT(0); // We should never be here + return TConfiguredAction(); +} //////////////////////////////////////////////////////////////////////////////// /// loop on the TStreamerElement list @@ -3233,6 +4162,31 @@ static void AddReadConvertAction(TStreamerInfoActions::TActionSequence *sequence } } +template +static void AddWriteConvertAction(TStreamerInfoActions::TActionSequence *sequence, Int_t newtype, TConfiguration *conf) +{ + // When writing 'newtype' is the origin of the information (i.e. the in memory representation) + // and the template parameter `To` is the representation on disk + switch (newtype) { + case TStreamerInfo::kBool: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kChar: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kShort: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kInt: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kLong: sequence->AddAction( WriteConvertBasicType::Action,conf ); break; + case TStreamerInfo::kLong64: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kFloat: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kFloat16: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kDouble: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kDouble32:sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kUChar: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kUShort: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kUInt: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kULong: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kULong64: sequence->AddAction( WriteConvertBasicType::Action,conf ); break; + case TStreamerInfo::kBits: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + } +} + //////////////////////////////////////////////////////////////////////////////// /// Add a read action for the given element. @@ -3295,60 +4249,60 @@ void TStreamerInfo::AddReadAction(TStreamerInfoActions::TActionSequence *readSeq if (fOldVersion<3){ // case of old TStreamerInfo if (newClass && newClass != oldClass) { if (element->GetStreamer()) { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); } } else { if (element->GetStreamer()) { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); } } } else { if (newClass && newClass != oldClass) { if (element->GetStreamer()) { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else if (oldClass) { if (oldClass->GetCollectionProxy() == 0 || oldClass->GetCollectionProxy()->GetValueClass() || oldClass->GetCollectionProxy()->HasPointers() ) { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); } else { switch (SelectLooper(*newClass->GetCollectionProxy())) { case kVectorLooper: - readSequence->AddAction(GetConvertCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase))); + readSequence->AddAction(GetConvertCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase))); break; case kAssociativeLooper: - readSequence->AddAction(GetConvertCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase))); + readSequence->AddAction(GetConvertCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase))); break; case kVectorPtrLooper: case kGenericLooper: default: // For now TBufferXML would force use to allocate the data buffer each time and copy into the real thing. - readSequence->AddAction(GetConvertCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase))); + readSequence->AddAction(GetConvertCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase))); break; } } } } else { if (element->GetStreamer()) { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else if (oldClass) { if (oldClass->GetCollectionProxy() == 0 || oldClass->GetCollectionProxy()->GetValueClass() || oldClass->GetCollectionProxy()->HasPointers() ) { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); } else { switch (SelectLooper(*oldClass->GetCollectionProxy())) { case kVectorLooper: - readSequence->AddAction(GetNumericCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase))); + readSequence->AddAction(GetNumericCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase))); break; case kAssociativeLooper: - readSequence->AddAction(GetNumericCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase))); + readSequence->AddAction(GetNumericCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase))); break; case kVectorPtrLooper: case kGenericLooper: default: // For now TBufferXML would force use to allocate the data buffer each time and copy into the real thing. - readSequence->AddAction(GetNumericCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase))); + readSequence->AddAction(GetNumericCollectionReadAction(oldClass->GetCollectionProxy()->GetType(), new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase))); break; } } @@ -3359,29 +4313,29 @@ void TStreamerInfo::AddReadAction(TStreamerInfoActions::TActionSequence *readSeq if (fOldVersion<3){ // case of old TStreamerInfo if (newClass && newClass != oldClass) { if (element->GetStreamer()) { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); } } else { if (element->GetStreamer()) { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); } } } else { if (newClass && newClass != oldClass) { if (element->GetStreamer()) { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); } } else { if (element->GetStreamer()) { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { - readSequence->AddAction(ReadSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); + readSequence->AddAction(ReadSTL, new TConfigSTL(/*read = */ true, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); } } } @@ -3577,6 +4531,157 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS case TStreamerInfo::kUInt: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; case TStreamerInfo::kULong: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; case TStreamerInfo::kULong64: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + + case TStreamerInfo::kConv + TStreamerInfo::kChar: + AddWriteConvertAction(writeSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kShort: + AddWriteConvertAction(writeSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kInt: + AddWriteConvertAction(writeSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kLong: + AddWriteConvertAction(writeSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kLong64: + AddWriteConvertAction(writeSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kUChar: + AddWriteConvertAction(writeSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kUShort: + AddWriteConvertAction(writeSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kUInt: + AddWriteConvertAction(writeSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kULong: + AddWriteConvertAction(writeSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + case TStreamerInfo::kConv + TStreamerInfo::kULong64: + AddWriteConvertAction(writeSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + + case kSTL: + { + TClass *newClass = element->GetNewClass(); + TClass *onfileClass = element->GetClassPointer(); + Bool_t isSTLbase = element->IsBase() && element->IsA()!=TStreamerBase::Class(); + + if (element->GetArrayLength() <= 1) { + if (newClass && newClass != onfileClass) { + if (element->GetStreamer()) { + writeSequence->AddAction(WriteSTL, + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, 1, onfileClass, + newClass, element->GetStreamer(), element->GetTypeName(), + isSTLbase)); + } else if (onfileClass) { + if (onfileClass->GetCollectionProxy() == 0 || onfileClass->GetCollectionProxy()->GetValueClass() || + onfileClass->GetCollectionProxy()->HasPointers()) { + writeSequence->AddAction( + WriteSTL, + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, 1, onfileClass, newClass, + element->GetTypeName(), isSTLbase)); + } else { + switch (SelectLooper(*newClass->GetCollectionProxy())) { + case kVectorLooper: + writeSequence->AddAction(GetConvertCollectionWriteAction( + onfileClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, 1, onfileClass, newClass, + element->GetTypeName(), isSTLbase))); + break; + case kAssociativeLooper: + writeSequence->AddAction(GetConvertCollectionWriteAction( + onfileClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, 1, onfileClass, newClass, + element->GetTypeName(), isSTLbase))); + break; + case kVectorPtrLooper: + case kGenericLooper: + default: + // For now TBufferXML would force use to allocate the data buffer each time and copy into the + // real thing. + writeSequence->AddAction(GetConvertCollectionWriteAction( + onfileClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, 1, onfileClass, newClass, + element->GetTypeName(), isSTLbase))); + break; + } + } + } + } else { + if (element->GetStreamer()) { + writeSequence->AddAction(WriteSTL, + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, 1, onfileClass, + element->GetStreamer(), element->GetTypeName(), + isSTLbase)); + } else if (onfileClass) { + if (onfileClass->GetCollectionProxy() == 0 || + onfileClass->GetCollectionProxy()->GetValueClass() || + onfileClass->GetCollectionProxy()->HasPointers()) { + writeSequence->AddAction(WriteSTL, + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, 1, onfileClass, + element->GetTypeName(), isSTLbase)); + } else { + switch (SelectLooper(*onfileClass->GetCollectionProxy())) { + case kVectorLooper: + writeSequence->AddAction(GetNumericCollectionWriteAction( + onfileClass->GetCollectionProxy()->GetType(), + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, 1, onfileClass, element->GetTypeName(), + isSTLbase))); + break; + case kAssociativeLooper: + writeSequence->AddAction(GetNumericCollectionWriteAction( + onfileClass->GetCollectionProxy()->GetType(), + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, 1, onfileClass, element->GetTypeName(), + isSTLbase))); + break; + case kVectorPtrLooper: + case kGenericLooper: + default: + // For now TBufferXML would force use to allocate the data buffer each time and copy into the + // real thing. + writeSequence->AddAction(GetNumericCollectionWriteAction( + onfileClass->GetCollectionProxy()->GetType(), + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, 1, onfileClass, element->GetTypeName(), + isSTLbase))); + break; + } + } + } + } + } else { + if (newClass && newClass != onfileClass) { + if (element->GetStreamer()) { + writeSequence->AddAction( + WriteSTL, + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, element->GetArrayLength(), onfileClass, + newClass, element->GetStreamer(), element->GetTypeName(), isSTLbase)); + } else { + writeSequence->AddAction( + WriteSTL, + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, element->GetArrayLength(), onfileClass, + newClass, element->GetTypeName(), isSTLbase)); + } + } else { + if (element->GetStreamer()) { + writeSequence->AddAction(WriteSTL, + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, + element->GetArrayLength(), onfileClass, + element->GetStreamer(), element->GetTypeName(), isSTLbase)); + } else { + writeSequence->AddAction(WriteSTL, + new TConfigSTL(/*read = */ false, this, i, compinfo, compinfo->fOffset, + element->GetArrayLength(), onfileClass, + element->GetTypeName(), isSTLbase)); + } + } + } + break; + } + + // case TStreamerInfo::kBits: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; /*case TStreamerInfo::kFloat16: { if (element->GetFactor() != 0) { @@ -3614,29 +4719,29 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS if (element->GetArrayLength() <= 1) { if (newClass && newClass != oldClass) { if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { - writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); + writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); } } else { if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { - writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); + writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); } } } else { if (newClass && newClass != oldClass) { if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { - writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); + writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); } } else { if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { - writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); + writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); } } } @@ -3791,36 +4896,36 @@ void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *wr if (newClass && newClass != oldClass) { if (element->GetStreamer()) { writeSequence->AddAction(WriteSTL, new - TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { writeSequence->AddAction(WriteSTL, new - TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); + TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); } } else { if (element->GetStreamer()) { writeSequence->AddAction(WriteSTL, new - TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { writeSequence->AddAction(WriteSTL, new - TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); + TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); } } } else { if (newClass && newClass != oldClass) { if (element->GetStreamer()) { writeSequence->AddAction(WriteSTL, new - TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { writeSequence->AddAction(WriteSTL, new - TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); + TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); } } else { if (element->GetStreamer()) { writeSequence->AddAction(WriteSTL, new - TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); } else { writeSequence->AddAction(WriteSTL, new - TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); + TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); } } } @@ -3840,7 +4945,7 @@ void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *wr // use generic write action when special handling is not provided if (generic) - writeSequence->AddAction(GenericWriteAction, new TGenericConfiguration(this, i, compinfo)); + writeSequence->AddAction(GenericWriteAction, new TGenericConfiguration(this, i, compinfo)); #if defined(CDJ_NO_COMPILE) if (element->TestBit(TStreamerElement::kCache)) { @@ -3875,7 +4980,8 @@ void TStreamerInfo::AddWriteMemberWiseVecPtrAction(TStreamerInfoActions::TAction writeSequence->Addaction( GetCollectionWriteAction(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); } #else - writeSequence->AddAction( VectorPtrLooper::GenericWrite, new TGenericConfiguration(this,i,compinfo) ); + writeSequence->AddAction( GetCollectionWriteAction(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); + // writeSequence->AddAction( VectorPtrLooper::GenericWrite, new TGenericConfiguration(this,i,compinfo) ); #endif } @@ -3967,7 +5073,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr case kAssociativeLooper: // } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset // || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) { -// sequence->AddAction( GenericAssocCollectionAction, new TConfigSTL(info,i,compinfo,offset,0,proxy.GetCollectionClass(),0,0) ); +// sequence->AddAction( GenericAssocCollectionAction, new TConfigSTL(true, info,i,compinfo,offset,0,proxy.GetCollectionClass(),0,0) ); case kVectorLooper: case kVectorPtrLooper: // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector. @@ -4080,7 +5186,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr // } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset // || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) { - // sequence->AddAction( GenericAssocCollectionAction, new TConfigSTL(info,i,compinfo,offset,0,proxy.GetCollectionClass(),0,0) ); + // sequence->AddAction( GenericAssocCollectionAction, new TConfigSTL(false, info,i,compinfo,offset,0,proxy.GetCollectionClass(),0,0) ); } else { // The usual collection case. if (element->TestBit(TStreamerElement::kCache)) { @@ -4132,12 +5238,13 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr case TVirtualStreamerInfo::kTObject: sequence->AddAction( GenericLooper, new TConfiguration(info,i,compinfo,offset) ); break; case TVirtualStreamerInfo::kTString: sequence->AddAction( GenericLooper, new TConfiguration(info,i,compinfo,offset) ); break; default: - sequence->AddAction( GenericCollectionWriteAction, new TConfigSTL(info,i,0 /* the offset will be used from TStreamerInfo */,0,proxy.GetCollectionClass(),0,0) ); + sequence->AddAction( GenericCollectionWriteAction, new TConfigSTL(false, info,i,0 /* the offset will be used from TStreamerInfo */,0,proxy.GetCollectionClass(),0,0) ); break; } } } #else +#if 0 if ( IsDefaultVector(proxy) /*|| (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap)*/ ) @@ -4148,8 +5255,25 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr // as it does not create/use a TStaging as expected ... but then again it might // not be the right things to expect ... // sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); - sequence->AddAction( GenericLooper::GenericWrite, new TConfigSTL(info,i,compinfo,0 /* the offset will be used from TStreamerInfo */,0,proxy.GetCollectionClass(),0,0) ); + sequence->AddAction( GenericLooper::GenericWrite, new TConfigSTL(false, info,i,compinfo,0 /* the offset will be used from TStreamerInfo */,0,proxy.GetCollectionClass(),0,0) ); } +#else + switch (SelectLooper(proxy)) { + case kAssociativeLooper: + sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + break; + case kVectorLooper: + sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + break; + case kVectorPtrLooper: + sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + break; + case kGenericLooper: + default: + sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + break; + } +#endif #endif } return sequence; From 81255e54389b6f64f0a721b30c58f081c6bd849a Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 20:41:42 -0600 Subject: [PATCH 07/46] io actions: Add TConfObject --- io/io/src/TStreamerInfoActions.cxx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 8c82b45ba963d..f110ab8a62874 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -188,6 +188,19 @@ namespace TStreamerInfoActions }; + struct TConfObject : public TConfiguration + { + TClassRef fOnfileClass; + TClassRef fInMemoryClass; + + TConfObject(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, + TClass *onfileClass, TClass *inMemoryClass) : + TConfiguration(info, id, compinfo, offset), + fOnfileClass(onfileClass), + fInMemoryClass(inMemoryClass ? inMemoryClass : onfileClass) {}; + TConfiguration *Copy() override { return new TConfObject(*this); } + }; + Int_t GenericReadAction(TBuffer &buf, void *addr, const TConfiguration *config) { char *obj = (char*)addr; From 6102003ec024e6a42fc4b4a0b4eaa1fa4047efab Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 20:45:34 -0600 Subject: [PATCH 08/46] io actions: Add binary read action for kStreamer. Combine the code with the one use for the text actions --- io/io/src/TStreamerInfoActions.cxx | 58 ++++++++++++++++-------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index f110ab8a62874..ab556f0880666 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -244,6 +244,27 @@ namespace TStreamerInfoActions } } + Int_t ReadStreamerCase(TBuffer &buf, void *addr, const TConfiguration *config) + { + UInt_t start, count; + /* Version_t v = */ buf.ReadVersion(&start, &count, config->fInfo->IsA()); + + ReadViaExtStreamer(buf, addr, config); + + buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName()); + return 0; + } + + Int_t WriteStreamerCase(TBuffer &buf, void *addr, const TConfiguration *config) + { + UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + + WriteViaExtStreamer(buf, addr, config); + + buf.SetByteCount(pos, kTRUE); + return 0; + } + template <> INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *addr, const TConfiguration *config) { @@ -305,16 +326,6 @@ namespace TStreamerInfoActions return 0; } - INLINE_TEMPLATE_ARGS Int_t WriteTextStreamer(TBuffer &buf, void *addr, const TConfiguration *config) - { - void *x = (void *)(((char *)addr) + config->fOffset); - TMemberStreamer *pstreamer = config->fCompInfo->fStreamer; - UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); - (*pstreamer)(buf, x, config->fCompInfo->fLength); - buf.SetByteCount(pos, kTRUE); - return 0; - } - INLINE_TEMPLATE_ARGS Int_t ReadTextObject(TBuffer &buf, void *addr, const TConfiguration *config) { void *x = (void *)(((char *)addr) + config->fOffset); @@ -337,18 +348,6 @@ namespace TStreamerInfoActions return 0; } - INLINE_TEMPLATE_ARGS Int_t ReadTextStreamer(TBuffer &buf, void *addr, const TConfiguration *config) - { - void *x = (void *)(((char *)addr) + config->fOffset); - TMemberStreamer *pstreamer = config->fCompInfo->fStreamer; - - UInt_t start, count; - /* Version_t v = */ buf.ReadVersion(&start, &count, config->fCompInfo->fClass); - (*pstreamer)(buf, x, config->fCompInfo->fLength); - buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName()); - return 0; - } - INLINE_TEMPLATE_ARGS Int_t ReadTextTObjectBase(TBuffer &buf, void *addr, const TConfiguration *config) { // action required to call custom code for TObject as base class @@ -4421,6 +4420,13 @@ void TStreamerInfo::AddReadAction(TStreamerInfoActions::TActionSequence *readSeq } break; } + case TStreamerInfo::kStreamer: + if (fOldVersion >= 3) + readSequence->AddAction( ReadStreamerCase, new TGenericConfiguration(this,i,compinfo, compinfo->fOffset) ); + else + // Use the slower path for legacy files + readSequence->AddAction( GenericReadAction, new TGenericConfiguration(this,i,compinfo) ); + break; default: readSequence->AddAction( GenericReadAction, new TGenericConfiguration(this,i,compinfo) ); break; @@ -4482,7 +4488,7 @@ void TStreamerInfo::AddReadTextAction(TStreamerInfoActions::TActionSequence *rea case TStreamerInfo::kBase: isBase = kTRUE; break; case TStreamerInfo::kStreamer: - readSequence->AddAction(ReadTextStreamer, new TGenericConfiguration(this, i, compinfo)); + readSequence->AddAction(ReadStreamerCase, new TGenericConfiguration(this, i, compinfo)); break; default: generic = kTRUE; break; @@ -4490,7 +4496,7 @@ void TStreamerInfo::AddReadTextAction(TStreamerInfoActions::TActionSequence *rea if (isBase) { if (compinfo->fStreamer) { - readSequence->AddAction(ReadTextStreamer, new TGenericConfiguration(this, i, compinfo)); + readSequence->AddAction(ReadStreamerCase, new TGenericConfiguration(this, i, compinfo)); } else { readSequence->AddAction(ReadTextBaseClass, new TGenericConfiguration(this, i, compinfo)); } @@ -4859,7 +4865,7 @@ void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *wr case TStreamerInfo::kBase: isBase = kTRUE; break; case TStreamerInfo::kStreamer: - writeSequence->AddAction(WriteTextStreamer, new TGenericConfiguration(this, i, compinfo)); + writeSequence->AddAction(WriteStreamerCase, new TGenericConfiguration(this, i, compinfo)); break; // case TStreamerInfo::kBits: writeSequence->AddAction( WriteBasicType, new @@ -4949,7 +4955,7 @@ void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *wr if (isBase) { if (compinfo->fStreamer) { - writeSequence->AddAction(WriteTextStreamer, new TGenericConfiguration(this, i, compinfo)); + writeSequence->AddAction(WriteStreamerCase, new TGenericConfiguration(this, i, compinfo)); } else { writeSequence->AddAction(WriteTextBaseClass, new TGenericConfiguration(this, i, compinfo)); } From 6c5d490796cfe21d8b4abfa21e728f6ca94ba760 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 20:46:48 -0600 Subject: [PATCH 09/46] io actions: Add binary read action for kStreamerLoop Combine the code with the one use for the text actions --- io/io/src/TStreamerInfoActions.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index ab556f0880666..6dced2609b199 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -4420,6 +4420,10 @@ void TStreamerInfo::AddReadAction(TStreamerInfoActions::TActionSequence *readSeq } break; } + case TStreamerInfo::kStreamLoop: + case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: + readSequence->AddAction( ReadStreamerLoop, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); + break; case TStreamerInfo::kStreamer: if (fOldVersion >= 3) readSequence->AddAction( ReadStreamerCase, new TGenericConfiguration(this,i,compinfo, compinfo->fOffset) ); From 39b1a43c8ad0f944135c086912ed2cd15375e76b Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 20:48:28 -0600 Subject: [PATCH 10/46] io actions: Add read actions for kBase --- io/io/src/TStreamerInfoActions.cxx | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 6dced2609b199..6f36719645c7c 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -265,6 +265,34 @@ namespace TStreamerInfoActions return 0; } + // Read a full object objectwise including reading the version and + // selecting any conversion. + Int_t ReadViaClassBuffer(TBuffer &buf, void *addr, const TConfiguration *config) + { + auto conf = (TConfObject*)config; + auto memoryClass = conf->fInMemoryClass; + auto onfileClass = conf->fOnfileClass; + + char * const where = (((char*)addr)+config->fOffset); + buf.ReadClassBuffer( memoryClass, where, onfileClass ); + return 0; + } + + // Write a full object objectwise including reading the version and + // selecting any conversion. + Int_t WriteViaClassBuffer(TBuffer &buf, void *addr, const TConfiguration *config) + { + auto conf = (TConfObject*)config; + [[maybe_unused]] auto memoryClass = conf->fInMemoryClass; + auto onfileClass = conf->fOnfileClass; + assert((memoryClass == nullptr || memoryClass == onfileClass) + && "Need to new TBufferFile::WriteClassBuffer overload to support this case"); + + char * const where = (((char*)addr)+config->fOffset); + buf.WriteClassBuffer( onfileClass, where); + return 0; + } + template <> INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *addr, const TConfiguration *config) { @@ -4424,6 +4452,26 @@ void TStreamerInfo::AddReadAction(TStreamerInfoActions::TActionSequence *readSeq case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: readSequence->AddAction( ReadStreamerLoop, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); break; + case TStreamerInfo::kBase: + if (compinfo->fStreamer) + readSequence->AddAction( ReadStreamerCase, new TGenericConfiguration(this,i,compinfo, compinfo->fOffset) ); + else { + auto base = dynamic_cast(element); + auto onfileBaseCl = base ? base->GetClassPointer() : nullptr; + auto memoryBaseCl = base && base->GetNewBaseClass() ? base->GetNewBaseClass() : onfileBaseCl; + + if(!base || !memoryBaseCl || + memoryBaseCl->GetStreamer() || + memoryBaseCl->GetStreamerFunc() || memoryBaseCl->GetConvStreamerFunc()) + { + // Unusual Case. + readSequence->AddAction( GenericReadAction, new TGenericConfiguration(this,i,compinfo) ); + } + else + readSequence->AddAction( ReadViaClassBuffer, + new TConfObject(this, i, compinfo, compinfo->fOffset, onfileBaseCl, memoryBaseCl) ); + } + break; case TStreamerInfo::kStreamer: if (fOldVersion >= 3) readSequence->AddAction( ReadStreamerCase, new TGenericConfiguration(this,i,compinfo, compinfo->fOffset) ); From 6d5f71e639ac18fd0860ea90fbcc9ec30f823dcd Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 20:48:35 -0600 Subject: [PATCH 11/46] io actions: Add read actions for kAny --- io/io/src/TStreamerInfoActions.cxx | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 6f36719645c7c..f4a0819db4167 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -244,6 +244,22 @@ namespace TStreamerInfoActions } } + inline Int_t ReadViaExtStreamer(TBuffer &buf, void *addr, const TConfiguration *config) + { + void *x = (void *)(((char *)addr) + config->fOffset); + TMemberStreamer *pstreamer = config->fCompInfo->fStreamer; + (*pstreamer)(buf, x, config->fCompInfo->fLength); + return 0; + } + + inline Int_t WriteViaExtStreamer(TBuffer &buf, void *addr, const TConfiguration *config) + { + void *x = (void *)(((char *)addr) + config->fOffset); + TMemberStreamer *pstreamer = config->fCompInfo->fStreamer; + (*pstreamer)(buf, x, config->fCompInfo->fLength); + return 0; + } + Int_t ReadStreamerCase(TBuffer &buf, void *addr, const TConfiguration *config) { UInt_t start, count; @@ -4479,6 +4495,20 @@ void TStreamerInfo::AddReadAction(TStreamerInfoActions::TActionSequence *readSeq // Use the slower path for legacy files readSequence->AddAction( GenericReadAction, new TGenericConfiguration(this,i,compinfo) ); break; + case TStreamerInfo::kAny: + if (compinfo->fStreamer) + readSequence->AddAction( ReadViaExtStreamer, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); + else { + if (compinfo->fNewClass && compinfo->fNewClass->HasDirectStreamerInfoUse()) + readSequence->AddAction( ReadViaClassBuffer, + new TConfObject(this, i, compinfo, compinfo->fOffset, compinfo->fClass, compinfo->fNewClass) ); + else if (compinfo->fClass && compinfo->fClass->HasDirectStreamerInfoUse()) + readSequence->AddAction( ReadViaClassBuffer, + new TConfObject(this, i, compinfo, compinfo->fOffset, compinfo->fClass, nullptr) ); + else // Use the slower path for unusual cases + readSequence->AddAction( GenericReadAction, new TGenericConfiguration(this, i, compinfo) ); + } + break; default: readSequence->AddAction( GenericReadAction, new TGenericConfiguration(this,i,compinfo) ); break; From 4ecfe5706573bcc2593c4b8821c360460aa789aa Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 14 Nov 2024 16:33:54 -0600 Subject: [PATCH 12/46] io actions: Add write case kObject, kTNamed, kTString --- io/io/src/TStreamerInfoActions.cxx | 43 ++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index f4a0819db4167..4c02eb46f54db 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -1015,6 +1015,16 @@ namespace TStreamerInfoActions return 0; } + inline Int_t WriteTString(TBuffer &buf, void *addr, const TConfiguration *config) + { + // Read in a TString object. + + // Idea: We could separate the TString Streamer in its two parts and + // avoid the if (buf.IsReading()) and try having it inlined. + ((TString*)(((char*)addr)+config->fOffset))->TString::Streamer(buf); + return 0; + } + INLINE_TEMPLATE_ARGS Int_t ReadTObject(TBuffer &buf, void *addr, const TConfiguration *config) { // Read in a TObject object part. @@ -1025,6 +1035,16 @@ namespace TStreamerInfoActions return 0; } + inline Int_t WriteTObject(TBuffer &buf, void *addr, const TConfiguration *config) + { + // Read in a TObject object part. + + // Idea: We could separate the TObject Streamer in its two parts and + // avoid the if (buf.IsReading()). + ((TObject*)(((char*)addr)+config->fOffset))->TObject::Streamer(buf); + return 0; + } + INLINE_TEMPLATE_ARGS Int_t ReadTNamed(TBuffer &buf, void *addr, const TConfiguration *config) { // Read in a TNamed object part. @@ -1037,6 +1057,18 @@ namespace TStreamerInfoActions return buf.ReadClassBuffer(TNamed_cl,(((char*)addr)+config->fOffset)); } + inline Int_t WriteTNamed(TBuffer &buf, void *addr, const TConfiguration *config) + { + // Read in a TNamed object part. + // Since the TNamed streamer is solely delegating back to the StreamerInfo we + // can skip the streamer. + + // Idea: We could extract the code from ReadClassBuffer and avoid one function + // code. + static const TClass *TNamed_cl = TNamed::Class(); + return buf.WriteClassBuffer(TNamed_cl,(((char*)addr)+config->fOffset)); + } + class TConfigSTL : public TConfiguration { // Configuration object for the kSTL case private: @@ -4782,6 +4814,12 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS break; } + case TStreamerInfo::kTNamed: writeSequence->AddAction( WriteTNamed, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; + // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the + // Streamer alltogether. + case TStreamerInfo::kTObject: writeSequence->AddAction( WriteTObject, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; + case TStreamerInfo::kTString: writeSequence->AddAction( WriteTString, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; + // case TStreamerInfo::kBits: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; /*case TStreamerInfo::kFloat16: { @@ -4807,11 +4845,6 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS } break; } */ - //case TStreamerInfo::kTNamed: writeSequence->AddAction( WriteTNamed, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; - // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the - // Streamer alltogether. - //case TStreamerInfo::kTObject: writeSequence->AddAction( WriteTObject, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; - //case TStreamerInfo::kTString: writeSequence->AddAction( WriteTString, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; /*case TStreamerInfo::kSTL: { TClass *newClass = element->GetNewClass(); TClass *oldClass = element->GetClassPointer(); From b6397605698b18d5bd18b14ca6146918a6ac38a3 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 14 Nov 2024 16:34:39 -0600 Subject: [PATCH 13/46] io actions: Remove implemented sketch/comment for kSTL --- io/io/src/TStreamerInfoActions.cxx | 36 ------------------------------ 1 file changed, 36 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 4c02eb46f54db..4be40f4129dba 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -4844,42 +4844,6 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS } } break; - } */ - /*case TStreamerInfo::kSTL: { - TClass *newClass = element->GetNewClass(); - TClass *oldClass = element->GetClassPointer(); - Bool_t isSTLbase = element->IsBase() && element->IsA()!=TStreamerBase::Class(); - - if (element->GetArrayLength() <= 1) { - if (newClass && newClass != oldClass) { - if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); - } else { - writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); - } - } else { - if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); - } else { - writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); - } - } - } else { - if (newClass && newClass != oldClass) { - if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); - } else { - writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); - } - } else { - if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); - } else { - writeSequence->AddAction(WriteSTL, new TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); - } - } - } - break; } */ default: writeSequence->AddAction( GenericWriteAction, new TGenericConfiguration(this,i,compinfo) ); From 6616f270b2f8159dd7af29570626b08a67ec6efa Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 14 Nov 2024 16:43:52 -0600 Subject: [PATCH 14/46] io actions: Add write action for kBase --- io/io/src/TStreamerInfoActions.cxx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 4be40f4129dba..5dc2f475273b3 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -4820,6 +4820,27 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS case TStreamerInfo::kTObject: writeSequence->AddAction( WriteTObject, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; case TStreamerInfo::kTString: writeSequence->AddAction( WriteTString, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; + case TStreamerInfo::kBase: + if (compinfo->fStreamer) + writeSequence->AddAction( WriteStreamerCase, new TGenericConfiguration(this,i,compinfo, compinfo->fOffset) ); + else { + auto base = dynamic_cast(element); + auto onfileBaseCl = base ? base->GetClassPointer() : nullptr; + auto memoryBaseCl = base && base->GetNewBaseClass() ? base->GetNewBaseClass() : onfileBaseCl; + + if(!base || !memoryBaseCl || + memoryBaseCl->GetStreamer() || + memoryBaseCl->GetStreamerFunc() || memoryBaseCl->GetConvStreamerFunc()) + { + // Unusual Case. + writeSequence->AddAction( GenericWriteAction, new TGenericConfiguration(this,i,compinfo) ); + } + else { + writeSequence->AddAction( WriteViaClassBuffer, + new TConfObject(this, i, compinfo, compinfo->fOffset, onfileBaseCl, memoryBaseCl) ); + } + } + break; // case TStreamerInfo::kBits: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; /*case TStreamerInfo::kFloat16: { From aa133fd7d86c173ad8bdbcd5dae5b725e2c78f7c Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 14 Nov 2024 16:44:03 -0600 Subject: [PATCH 15/46] io actions: Add write action for kStreamLoop --- io/io/src/TStreamerInfoActions.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 5dc2f475273b3..61fcb2ed53b1e 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -4820,6 +4820,10 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS case TStreamerInfo::kTObject: writeSequence->AddAction( WriteTObject, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; case TStreamerInfo::kTString: writeSequence->AddAction( WriteTString, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; + case TStreamerInfo::kStreamLoop: + case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: + writeSequence->AddAction( WriteStreamerLoop, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); + break; case TStreamerInfo::kBase: if (compinfo->fStreamer) writeSequence->AddAction( WriteStreamerCase, new TGenericConfiguration(this,i,compinfo, compinfo->fOffset) ); From 30c2fec7f99b22be2adcf235eb0a261344090426 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 14 Nov 2024 16:44:23 -0600 Subject: [PATCH 16/46] io actions: Add write action for kAny --- io/io/src/TStreamerInfoActions.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 61fcb2ed53b1e..ef8e1d940d213 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -4845,6 +4845,20 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS } } break; + case TStreamerInfo::kAny: + if (compinfo->fStreamer) + writeSequence->AddAction( WriteViaExtStreamer, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); + else { + if (compinfo->fNewClass && compinfo->fNewClass->fStreamerImpl == &TClass::StreamerStreamerInfo) + writeSequence->AddAction( WriteViaClassBuffer, + new TConfObject(this, i, compinfo, compinfo->fOffset, compinfo->fClass, compinfo->fNewClass) ); + else if (compinfo->fClass && compinfo->fClass->fStreamerImpl == &TClass::StreamerStreamerInfo) + writeSequence->AddAction( WriteViaClassBuffer, + new TConfObject(this, i, compinfo, compinfo->fOffset, compinfo->fClass, nullptr) ); + else // Use the slower path for unusual cases + writeSequence->AddAction( GenericWriteAction, new TGenericConfiguration(this, i, compinfo) ); + } + break; // case TStreamerInfo::kBits: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; /*case TStreamerInfo::kFloat16: { From 826dda3f550c6e02e3a97a2040b8b4a31c4678b3 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 14 Nov 2024 16:44:30 -0600 Subject: [PATCH 17/46] io actions: Add write action for kStreamer --- io/io/src/TStreamerInfoActions.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index ef8e1d940d213..7b721f41b7b3b 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -4845,6 +4845,13 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS } } break; + case TStreamerInfo::kStreamer: + if (fOldVersion >= 3) + writeSequence->AddAction( WriteStreamerCase, new TGenericConfiguration(this,i,compinfo, compinfo->fOffset) ); + else + // Use the slower path for legacy files + writeSequence->AddAction( GenericWriteAction, new TGenericConfiguration(this,i,compinfo) ); + break; case TStreamerInfo::kAny: if (compinfo->fStreamer) writeSequence->AddAction( WriteViaExtStreamer, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); From 0841eedf976758cba8b0762c6578856f94a8bad0 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 14 Nov 2024 17:29:05 -0600 Subject: [PATCH 18/46] io actions: Remove unused sketch/comment --- io/io/src/TStreamerInfoActions.cxx | 98 ------------------------------ 1 file changed, 98 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 7b721f41b7b3b..2b79bbb862ca2 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -4895,13 +4895,6 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS writeSequence->AddAction( GenericWriteAction, new TGenericConfiguration(this,i,compinfo) ); break; } -#if defined(CDJ_NO_COMPILE) - if (element->TestBit(TStreamerElement::kCache)) { - TConfiguredAction action( writeSequence->fActions.back() ); // Action is moved, we must pop it next. - writeSequence->fActions.pop_back(); - writeSequence->AddAction( UseCache, new TConfigurationUseCache(this,action,element->TestBit(TStreamerElement::kRepeat)) ); - } -#endif } //////////////////////////////////////////////////////////////////////////////// @@ -4993,88 +4986,6 @@ void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *wr writeSequence->AddAction(WriteStreamerCase, new TGenericConfiguration(this, i, compinfo)); break; - // case TStreamerInfo::kBits: writeSequence->AddAction( WriteBasicType, new - // TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; - /*case TStreamerInfo::kFloat16: { - if (element->GetFactor() != 0) { - writeSequence->AddAction( WriteBasicType_WithFactor, new - TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) ); - } else { - Int_t nbits = (Int_t)element->GetXmin(); - if (!nbits) nbits = 12; - writeSequence->AddAction( WriteBasicType_NoFactor, new - TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) ); - } - break; - } */ - /*case TStreamerInfo::kDouble32: { - if (element->GetFactor() != 0) { - writeSequence->AddAction( WriteBasicType_WithFactor, new - TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) ); - } else { - Int_t nbits = (Int_t)element->GetXmin(); - if (!nbits) { - writeSequence->AddAction( ConvertBasicType, new - TConfiguration(this,i,compinfo,compinfo->fOffset) ); - } else { - writeSequence->AddAction( WriteBasicType_NoFactor, new - TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) ); - } - } - break; - } */ - // case TStreamerInfo::kTNamed: writeSequence->AddAction( WriteTNamed, new - // TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; - // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the - // Streamer alltogether. - // case TStreamerInfo::kTObject: writeSequence->AddAction( WriteTObject, new - // TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; - // case TStreamerInfo::kTString: writeSequence->AddAction( WriteTString, new - // TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; - /*case TStreamerInfo::kSTL: { - TClass *newClass = element->GetNewClass(); - TClass *oldClass = element->GetClassPointer(); - Bool_t isSTLbase = element->IsBase() && element->IsA()!=TStreamerBase::Class(); - - if (element->GetArrayLength() <= 1) { - if (newClass && newClass != oldClass) { - if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new - TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); - } else { - writeSequence->AddAction(WriteSTL, new - TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); - } - } else { - if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new - TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); - } else { - writeSequence->AddAction(WriteSTL, new - TConfigSTL(false, this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); - } - } - } else { - if (newClass && newClass != oldClass) { - if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new - TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); - } else { - writeSequence->AddAction(WriteSTL, new - TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); - } - } else { - if (element->GetStreamer()) { - writeSequence->AddAction(WriteSTL, new - TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); - } else { - writeSequence->AddAction(WriteSTL, new - TConfigSTL(false, this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); - } - } - } - break; - } */ default: generic = kTRUE; break; } @@ -5090,15 +5001,6 @@ void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *wr // use generic write action when special handling is not provided if (generic) writeSequence->AddAction(GenericWriteAction, new TGenericConfiguration(this, i, compinfo)); - -#if defined(CDJ_NO_COMPILE) - if (element->TestBit(TStreamerElement::kCache)) { - TConfiguredAction action(writeSequence->fActions.back()); // Action is moved, we must pop it next. - writeSequence->fActions.pop_back(); - writeSequence->AddAction(UseCache, - new TConfigurationUseCache(this, action, element->TestBit(TStreamerElement::kRepeat))); - } -#endif } //////////////////////////////////////////////////////////////////////////////// From 6e11b3c9bb04d012737d173b5b83b107e7c9f950 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 14 Nov 2024 17:55:57 -0600 Subject: [PATCH 19/46] io actions: rename Looper's ReadAction to LoopOverCollection --- io/io/src/TStreamerInfoActions.cxx | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 2b79bbb862ca2..90855a1f61d9c 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -2121,7 +2121,7 @@ namespace TStreamerInfoActions }; template - static INLINE_TEMPLATE_ARGS Int_t ReadAction(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config) + static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config) { const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement; //Idea: can we factor out the addition of fOffset @@ -2587,7 +2587,7 @@ namespace TStreamerInfoActions }; template - static INLINE_TEMPLATE_ARGS Int_t ReadAction(TBuffer &buf, void *start, const void *end, const TConfiguration *config) + static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TConfiguration *config) { for(void *iter = start; iter != end; iter = (char*)iter + sizeof(void*) ) { action(buf, *(void**)iter, config); @@ -2943,7 +2943,7 @@ namespace TStreamerInfoActions }; template - static INLINE_TEMPLATE_ARGS Int_t ReadAction(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config) + static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config) { TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf; @@ -3448,11 +3448,11 @@ static TConfiguredAction GetNumericCollectionReadAction(Int_t type, TConfigSTL * delete conf; return TConfiguredAction( Looper::ReadCollectionFloat16, alternate ); // if (element->GetFactor() != 0) { - // return TConfiguredAction( Looper::template ReadAction >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); + // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); // } else { // Int_t nbits = (Int_t)element->GetXmin(); // if (!nbits) nbits = 12; - // return TConfiguredAction( Looper::template ReadAction >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); + // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); // } break; } @@ -3461,13 +3461,13 @@ static TConfiguredAction GetNumericCollectionReadAction(Int_t type, TConfigSTL * delete conf; return TConfiguredAction( Looper::ReadCollectionDouble32, alternate ); // if (element->GetFactor() != 0) { - // return TConfiguredAction( Looper::template ReadAction >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); + // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); // } else { // Int_t nbits = (Int_t)element->GetXmin(); // if (!nbits) { - // return TConfiguredAction( Looper::template ReadAction >, new TConfiguration(info,i,compinfo,offset) ); + // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfiguration(info,i,compinfo,offset) ); // } else { - // return TConfiguredAction( Looper::template ReadAction >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); + // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); // } // } break; @@ -3587,35 +3587,35 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kBits: return TConfiguredAction( Looper::template ReadAction > , new TBitsConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kBits: return TConfiguredAction( Looper::template LoopOverCollection > , new TBitsConfiguration(info,i,compinfo,offset) ); break; case TStreamerInfo::kFloat16: { if (element->GetFactor() != 0) { - return TConfiguredAction( Looper::template ReadAction >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); + return TConfiguredAction( Looper::template LoopOverCollection >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); } else { Int_t nbits = (Int_t)element->GetXmin(); if (!nbits) nbits = 12; - return TConfiguredAction( Looper::template ReadAction >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); + return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); } break; } case TStreamerInfo::kDouble32: { if (element->GetFactor() != 0) { - return TConfiguredAction( Looper::template ReadAction >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); + return TConfiguredAction( Looper::template LoopOverCollection >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); } else { Int_t nbits = (Int_t)element->GetXmin(); if (!nbits) { - return TConfiguredAction( Looper::template ReadAction::Action >, new TConfiguration(info,i,compinfo,offset) ); + return TConfiguredAction( Looper::template LoopOverCollection::Action >, new TConfiguration(info,i,compinfo,offset) ); } else { - return TConfiguredAction( Looper::template ReadAction >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); + return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); } } break; } - case TStreamerInfo::kTNamed: return TConfiguredAction( Looper::template ReadAction, new TConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kTNamed: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the // Streamer alltogether. - case TStreamerInfo::kTObject: return TConfiguredAction( Looper::template ReadAction, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kTString: return TConfiguredAction( Looper::template ReadAction, new TConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kTObject: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kTString: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; case TStreamerInfo::kArtificial: case TStreamerInfo::kCacheNew: case TStreamerInfo::kCacheDelete: From 141ff2c08e4fbc57d6176035726d7c3f4a6886bd Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 14 Nov 2024 17:56:36 -0600 Subject: [PATCH 20/46] io actions: Add looper write actions for kTObject, kTNamed and kTString --- io/io/src/TStreamerInfoActions.cxx | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 90855a1f61d9c..43b89a78d9241 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -3611,11 +3611,14 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt } break; } - case TStreamerInfo::kTNamed: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kTNamed: + return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info, i, compinfo, offset) ); // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the // Streamer alltogether. - case TStreamerInfo::kTObject: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kTString: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kTObject: + return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info, i, compinfo,offset) ); + case TStreamerInfo::kTString: + return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info, i, compinfo,offset) ); case TStreamerInfo::kArtificial: case TStreamerInfo::kCacheNew: case TStreamerInfo::kCacheDelete: @@ -3916,6 +3919,12 @@ static TConfiguredAction GetCollectionWriteAction(TVirtualStreamerInfo *info, TS } break; } + case TStreamerInfo::kTNamed: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; + // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the + // Streamer alltogether. + case TStreamerInfo::kTObject: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kTString: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; + default: return TConfiguredAction( Looper::GenericWrite, new TConfiguration(info,i,compinfo,0 /* 0 because we call the legacy code */) ); } @@ -3950,11 +3959,11 @@ static TConfiguredAction GetNumericCollectionWriteAction(Int_t type, TConfigSTL delete conf; return TConfiguredAction( Looper::WriteCollectionFloat16, alternate ); // if (element->GetFactor() != 0) { - // return TConfiguredAction( Looper::template WriteAction >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); + // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); // } else { // Int_t nbits = (Int_t)element->GetXmin(); // if (!nbits) nbits = 12; - // return TConfiguredAction( Looper::template WriteAction >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); + // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); // } break; } @@ -3963,13 +3972,13 @@ static TConfiguredAction GetNumericCollectionWriteAction(Int_t type, TConfigSTL delete conf; return TConfiguredAction( Looper::WriteCollectionDouble32, alternate ); // if (element->GetFactor() != 0) { - // return TConfiguredAction( Looper::template WriteAction >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); + // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); // } else { // Int_t nbits = (Int_t)element->GetXmin(); // if (!nbits) { - // return TConfiguredAction( Looper::template WriteAction >, new TConfiguration(info,i,compinfo,offset) ); + // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfiguration(info,i,compinfo,offset) ); // } else { - // return TConfiguredAction( Looper::template WriteAction >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); + // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); // } // } break; From 0bf98207df05ef044e699c01c1e1fed42dc06f37 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 15 Nov 2024 11:27:29 -0600 Subject: [PATCH 21/46] io actions: Remove unreachable break statement --- io/io/src/TStreamerInfoActions.cxx | 79 ++++++++++++------------------ 1 file changed, 30 insertions(+), 49 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 43b89a78d9241..7d1b37f8209f6 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -3574,20 +3574,20 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt { switch (type) { // Read basic types. - case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ReadBasicType,new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kBits: return TConfiguredAction( Looper::template LoopOverCollection > , new TBitsConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ReadBasicType,new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ReadBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kBits: return TConfiguredAction( Looper::template LoopOverCollection > , new TBitsConfiguration(info,i,compinfo,offset) ); case TStreamerInfo::kFloat16: { if (element->GetFactor() != 0) { return TConfiguredAction( Looper::template LoopOverCollection >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); @@ -3596,7 +3596,6 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt if (!nbits) nbits = 12; return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); } - break; } case TStreamerInfo::kDouble32: { if (element->GetFactor() != 0) { @@ -3609,7 +3608,6 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); } } - break; } case TStreamerInfo::kTNamed: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info, i, compinfo, offset) ); @@ -3622,52 +3620,38 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt case TStreamerInfo::kArtificial: case TStreamerInfo::kCacheNew: case TStreamerInfo::kCacheDelete: - case TStreamerInfo::kSTL: return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info,i,compinfo) ); break; - case TStreamerInfo::kBase: return TConfiguredAction( Looper::ReadBase, new TGenericConfiguration(info,i,compinfo) ); break; + case TStreamerInfo::kSTL: return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info, i, compinfo) ); + case TStreamerInfo::kBase: return TConfiguredAction( Looper::ReadBase, new TGenericConfiguration(info, i, compinfo) ); // Conversions. case TStreamerInfo::kConv + TStreamerInfo::kBool: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kChar: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kShort: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kInt: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kLong: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kLong64: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kFloat: return GetCollectionReadConvertAction( element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kDouble: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kUChar: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kUShort: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kUInt: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kULong: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kULong64: return GetCollectionReadConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kBits: return GetCollectionReadConvertAction(element->GetNewType(), new TBitsConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kFloat16: { if (element->GetFactor() != 0) { return GetCollectionReadConvertAction >(element->GetNewType(), new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); @@ -3676,7 +3660,6 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt if (!nbits) nbits = 12; return GetCollectionReadConvertAction >(element->GetNewType(), new TConfNoFactor(info,i,compinfo,offset,nbits) ); } - break; } case TStreamerInfo::kConv + TStreamerInfo::kDouble32: { if (element->GetFactor() != 0) { @@ -3689,11 +3672,9 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt return GetCollectionReadConvertAction >(element->GetNewType(), new TConfNoFactor(info,i,compinfo,offset,nbits) ); } } - break; } default: return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info,i,compinfo) ); - break; } R__ASSERT(0); // We should never be here return TConfiguredAction(); @@ -3703,20 +3684,20 @@ template static TConfiguredAction GetConvertCollectionWriteActionFrom(Int_t onfileType, TConfiguration *conf) { switch (onfileType) { - case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kBits: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kBits: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); // Supporting this requires adding TBuffer::WiteFastArrayWithNbits // and the proper struct WriteConvertCollectionBasicType> here From 938dc25bf56eacf5db50f56a50bfc0a765092b4c Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 15 Nov 2024 12:46:06 -0600 Subject: [PATCH 22/46] io actions: Add EMode to distinguish read and write instantiation. To use be for case where the read and write implementation differs only slightly --- io/io/src/TStreamerInfoActions.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 7d1b37f8209f6..cc522c804028b 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -44,6 +44,12 @@ using namespace TStreamerInfoActions; namespace TStreamerInfoActions { + enum class EMode + { + kRead, + kWrite + }; + bool IsDefaultVector(TVirtualCollectionProxy &proxy) { const auto props = proxy.GetProperties(); From b516e809f12bf6dc50c0fd0c7caaded1664d5761 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 15 Nov 2024 12:47:55 -0600 Subject: [PATCH 23/46] io actions: Add GenericLooper. To be used for function template that can be used for more than one actual looper (usually in conjunction with the LoopOverCollection template --- io/io/src/TStreamerInfoActions.cxx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index cc522c804028b..c28ffed91a172 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -1973,7 +1973,12 @@ namespace TStreamerInfoActions } } - struct VectorLooper { + template + struct CollectionLooper { + + }; + + struct VectorLooper : public CollectionLooper { template static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config) @@ -2450,6 +2455,8 @@ namespace TStreamerInfoActions }; struct VectorPtrLooper { + // Can not inherit/use CollectionLooper, because this looper's + // function do not take a `TLoopConfiguration`. template static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *iter, const void *end, const TConfiguration *config) @@ -2880,7 +2887,7 @@ namespace TStreamerInfoActions }; - struct GenericLooper { + struct GenericLooper : public CollectionLooper { template static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config) From 94e7d5f636be51d7d20bfd364991fe4230de168d Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 12:33:55 -0600 Subject: [PATCH 24/46] io actions: Add ScalarLooper Allow to share code with the collection loopers. --- io/io/src/TStreamerInfoActions.cxx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index c28ffed91a172..83ed087cb4444 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -1978,6 +1978,17 @@ namespace TStreamerInfoActions }; + // The Scalar 'looper' only process one element. + struct ScalarLooper : public CollectionLooper + { + template + static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void * /* end */, const TLoopConfiguration *, const TConfiguration *config) + { + iter_action(buf, start, config); + return 0; + } + }; + struct VectorLooper : public CollectionLooper { template From bba479fdfc225ec7737e0141928a2a01e351a9a0 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 15 Nov 2024 12:56:43 -0600 Subject: [PATCH 25/46] io actions: Add kStreamer to memberwise streaming --- io/io/src/TStreamerInfoActions.cxx | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 83ed087cb4444..980d4fdee5a96 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -1976,6 +1976,27 @@ namespace TStreamerInfoActions template struct CollectionLooper { + static inline Int_t ReadStreamerCase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config) + { + UInt_t pos, count; + /* Version_t v = */ buf.ReadVersion(&pos, &count, config->fInfo->IsA()); + + Looper::template LoopOverCollection< ReadViaExtStreamer >(buf, start, end, loopconfig, config); + + buf.CheckByteCount(pos, count, config->fCompInfo->fElem->GetFullName()); + return 0; + } + + static inline Int_t WriteStreamerCase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config) + { + UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + + Looper::template LoopOverCollection< WriteViaExtStreamer >(buf, start, end, loopconfig, config); + + buf.SetByteCount(pos, kTRUE); + return 0; + } + }; // The Scalar 'looper' only process one element. @@ -2627,6 +2648,27 @@ namespace TStreamerInfoActions return GenericRead(buf,start,end,config); } + static inline Int_t ReadStreamerCase(TBuffer &buf, void *start, const void *end, const TConfiguration *config) + { + UInt_t pos, count; + /* Version_t v = */ buf.ReadVersion(&pos, &count, config->fInfo->IsA()); + + LoopOverCollection< ReadViaExtStreamer >(buf, start, end, config); + + buf.CheckByteCount(pos, count, config->fCompInfo->fElem->GetFullName()); + return 0; + } + + static inline Int_t WriteStreamerCase(TBuffer &buf, void *start, const void *end, const TConfiguration *config) + { + UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + + LoopOverCollection< WriteViaExtStreamer >(buf, start, end, config); + + buf.SetByteCount(pos, kTRUE); + return 0; + } + static INLINE_TEMPLATE_ARGS Int_t GenericRead(TBuffer &buf, void *iter, const void *end, const TConfiguration *config) { Int_t n = ( ((void**)end) - ((void**)iter) ); @@ -3646,6 +3688,11 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt case TStreamerInfo::kCacheDelete: case TStreamerInfo::kSTL: return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info, i, compinfo) ); case TStreamerInfo::kBase: return TConfiguredAction( Looper::ReadBase, new TGenericConfiguration(info, i, compinfo) ); + case TStreamerInfo::kStreamer: + if (info->GetOldVersion() >= 3) + return TConfiguredAction( Looper::ReadStreamerCase, new TGenericConfiguration(info, i, compinfo) ); + else + return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info, i, compinfo) ); // Conversions. case TStreamerInfo::kConv + TStreamerInfo::kBool: From b625392e697acdfb3be51c1c5e6cab10a865717f Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 15 Nov 2024 14:33:26 -0600 Subject: [PATCH 26/46] io actions: Add kAny to memberwise streaming --- io/io/src/TStreamerInfoActions.cxx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 980d4fdee5a96..7f5b96d609014 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -3693,6 +3693,19 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt return TConfiguredAction( Looper::ReadStreamerCase, new TGenericConfiguration(info, i, compinfo) ); else return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info, i, compinfo) ); + case TStreamerInfo::kAny: + if (compinfo->fStreamer) + return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info, i, compinfo,offset) ); + else { + if (compinfo->fNewClass && compinfo->fNewClass->HasDirectStreamerInfoUse()) + return TConfiguredAction( Looper::template LoopOverCollection, + new TConfObject(info, i, compinfo, compinfo->fOffset, compinfo->fClass, compinfo->fNewClass) ); + else if (compinfo->fClass && compinfo->fClass->HasDirectStreamerInfoUse()) + return TConfiguredAction( Looper::template LoopOverCollection, + new TConfObject(info, i, compinfo, compinfo->fOffset, compinfo->fClass, nullptr) ); + else // Use the slower path for unusual cases + return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info, i, compinfo) ); + } // Conversions. case TStreamerInfo::kConv + TStreamerInfo::kBool: From cbfda966489f5a10104f2bb2a92489a9e7fbe4ff Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 12:40:26 -0600 Subject: [PATCH 27/46] io actions: Move StreamerLooper from global to Looper --- io/io/src/TStreamerInfoActions.cxx | 783 ++++++++++++++--------------- 1 file changed, 391 insertions(+), 392 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 7f5b96d609014..50727c2197c9f 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -583,394 +583,6 @@ namespace TStreamerInfoActions return 0; } - /** Direct copy of code from TStreamerInfo::WriteBufferAux, - * potentially can be used later for non-text streaming */ - template - INLINE_TEMPLATE_ARGS Int_t WriteStreamerLoop(TBuffer &buf, void *addr, const TConfiguration *config) - { - UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing - UInt_t ioffset = eoffset + config->fOffset; - - if (!kIsTextT && config->fCompInfo->fStreamer) { - // Get any private streamer which was set for the data member. - TMemberStreamer* pstreamer = config->fCompInfo->fStreamer; - // -- We have a private streamer. - UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); - // Loop over the entries in the clones array or the STL container. - //for (int k = 0; k < narr; ++k) { - // Get a pointer to the counter for the varying length array. - Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/); - - // And call the private streamer, passing it the buffer, the object, and the counter. - (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter); - //} for k - buf.SetByteCount(pos, kTRUE); - // We are done, next streamer element. - return 0; - } - - // Get the class of the data member. - TClass* cl = config->fCompInfo->fClass; - // Which are we, an array of objects or an array of pointers to objects? - Bool_t isPtrPtr = (strstr(config->fCompInfo->fElem->GetTypeName(), "**") != 0); - - // By default assume the file version is the newest. - Int_t fileVersion = kMaxInt; - - if (!kIsTextT) { - // At this point we do *not* have a private streamer. - // Get the version of the file we are writing to. - TFile* file = (TFile*) buf.GetParent(); - if (file) { - fileVersion = file->GetVersion(); - } - } - // Write the class version to the buffer. - UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); - if (fileVersion > 51508) { - // -- Newer versions allow polymorphic pointers to objects. - // Loop over the entries in the clones array or the STL container. - //for (int k = 0; k < narr; ++k) { - // Get the counter for the varying length array. - Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/)); - - //b << vlen; - if (vlen) { - // Get a pointer to the array of pointers. - char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/); - // Loop over each element of the array of pointers to varying-length arrays. - for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { - if (!pp[ndx]) { - // -- We do not have a pointer to a varying-length array. - // Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); - // ::ErrorHandler(kError, "::WriteStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName())); - printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()); - continue; - } - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - // Write the entire array of objects to the buffer. - // Note: Polymorphism is not allowed here. - buf.WriteFastArray(pp[ndx], cl, vlen, nullptr); - } else { - // -- We are a varying-length array of pointers to objects. - // Write the entire array of object pointers to the buffer. - // Note: The object pointers are allowed to be polymorphic. - buf.WriteFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr); - } // isPtrPtr - } // ndx - } else // vlen - if (kIsTextT) { - // special handling for the text-based streamers - for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) - buf.WriteFastArray((void *)nullptr, cl, -1, nullptr); - } - //} // k - } - else { - // -- Older versions do *not* allow polymorphic pointers to objects. - // Loop over the entries in the clones array or the STL container. - //for (int k = 0; k < narr; ++k) { - // Get the counter for the varying length array. - Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/)); - //b << vlen; - if (vlen) { - // Get a pointer to the array of pointers. - char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/); - // -- Older versions do *not* allow polymorphic pointers to objects. - // Loop over each element of the array of pointers to varying-length arrays. - for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { - if (!pp[ndx]) { - // -- We do not have a pointer to a varying-length array. - //Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); - // ::ErrorHandler(kError, "::WriteTextStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName())); - printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()); - continue; - } - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - // Loop over the elements of the varying length array. - for (Int_t v = 0; v < vlen; ++v) { - // Write the object to the buffer. - cl->Streamer(pp[ndx] + (v * cl->Size()), buf); - } // v - } - else { - // -- We are a varying-length array of pointers to objects. - // Loop over the elements of the varying length array. - for (Int_t v = 0; v < vlen; ++v) { - // Get a pointer to the object pointer. - char** r = (char**) pp[ndx]; - // Write the object to the buffer. - cl->Streamer(r[v], buf); - } // v - } // isPtrPtr - } // ndx - } // vlen - //} // k - } // fileVersion - // Backpatch the byte count into the buffer. - buf.SetByteCount(pos, kTRUE); - - return 0; - } - - - /** Direct copy of code from TStreamerInfo::WriteBufferAux, - * potentially can be used later for non-text streaming */ - template - INLINE_TEMPLATE_ARGS Int_t ReadStreamerLoop(TBuffer &buf, void *addr, const TConfiguration *config) - { - UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing - UInt_t ioffset = eoffset + config->fOffset; - - // Get the class of the data member. - TClass* cl = config->fCompInfo->fClass; - - // Check for a private streamer. - if (!kIsTextT && config->fCompInfo->fStreamer) { - // Get any private streamer which was set for the data member. - TMemberStreamer* pstreamer = config->fCompInfo->fStreamer; - // -- We have a private streamer. - // Read the class version and byte count from the buffer. - UInt_t start = 0; - UInt_t count = 0; - buf.ReadVersion(&start, &count, cl); - // Loop over the entries in the clones array or the STL container. - //for (Int_t k = 0; k < narr; ++k) { - - Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/); - // And call the private streamer, passing it the buffer, the object, and the counter. - (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter); - - // } // for k - buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName()); - // We are done, next streamer element. - return 0; - } - - // Which are we, an array of objects or an array of pointers to objects? - Bool_t isPtrPtr = (strstr(config->fCompInfo->fElem->GetTypeName(), "**") != 0); - - // By default assume the file version is the newest. - Int_t fileVersion = kMaxInt; - if (!kIsTextT) { - // At this point we do *not* have a private streamer. - // Get the version of the file we are reading from. - TFile* file = (TFile*) buf.GetParent(); - if (file) { - fileVersion = file->GetVersion(); - } - } - // Read the class version and byte count from the buffer. - UInt_t start = 0; - UInt_t count = 0; - buf.ReadVersion(&start, &count, cl); - if (fileVersion > 51508) { - // -- Newer versions allow polymorphic pointers. - // Loop over the entries in the clones array or the STL container. - // for (Int_t k = 0; k < narr; ++k) { - // Get the counter for the varying length array. - Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ + eoffset /*entry offset*/ + - config->fCompInfo->fMethod /*counter offset*/)); - // Int_t realLen; - // b >> realLen; - // if (realLen != vlen) { - // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen); - //} - // Get a pointer to the array of pointers. - char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/); - // Loop over each element of the array of pointers to varying-length arrays. - // if (!pp) { - // continue; - // } - - if (pp) // SL: place it here instead of continue, which is related to for(k) loop - for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { - // if (!pp[ndx]) { - // -- We do not have a pointer to a varying-length array. - // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(), - // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); - // continue; - //} - // Delete any memory at pp[ndx]. - if (!isPtrPtr) { - cl->DeleteArray(pp[ndx]); - pp[ndx] = 0; - } else { - // Using vlen is wrong here because it has already - // been overwritten with the value needed to read - // the current record. Fixing this will require - // doing a pass over the object at the beginning - // of the I/O and releasing all the buffer memory - // for varying length arrays before we overwrite - // the counter values. - // - // For now we will just leak memory, just as we - // have always done in the past. Fix this. - // - // char** r = (char**) pp[ndx]; - // if (r) { - // for (Int_t v = 0; v < vlen; ++v) { - // cl->Destructor(r[v]); - // r[v] = 0; - // } - //} - delete[] pp[ndx]; - pp[ndx] = 0; - } - if (!vlen) { - if (kIsTextT) { - // special handling for the text-based streamers - keep calling to shift array index - buf.ReadFastArray((void *)nullptr, cl, -1, nullptr); - } - continue; - } - // Note: We now have pp[ndx] is null. - // Allocate memory to read into. - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - // Note: Polymorphism is not allowed here. - // Allocate a new array of objects to read into. - pp[ndx] = (char *)cl->NewArray(vlen); - if (!pp[ndx]) { - Error("ReadBuffer", "Memory allocation failed!\n"); - continue; - } - } else { - // -- We are a varying-length array of pointers to objects. - // Note: The object pointers are allowed to be polymorphic. - // Allocate a new array of pointers to objects to read into. - pp[ndx] = (char *)new char *[vlen]; - if (!pp[ndx]) { - Error("ReadBuffer", "Memory allocation failed!\n"); - continue; - } - // And set each pointer to null. - memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx] - // = (char*) new char*[vlen]; - } - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - buf.ReadFastArray(pp[ndx], cl, vlen, nullptr); - } else { - // -- We are a varying-length array of object pointers. - buf.ReadFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr); - } // isPtrPtr - } // ndx - // } // k - } else { - // -- Older versions do *not* allow polymorphic pointers. - // Loop over the entries in the clones array or the STL container. - // for (Int_t k = 0; k < narr; ++k) { - // Get the counter for the varying length array. - Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ + eoffset /*entry offset*/ + - config->fCompInfo->fMethod /*counter offset*/)); - // Int_t realLen; - // b >> realLen; - // if (realLen != vlen) { - // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen); - //} - // Get a pointer to the array of pointers. - char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/); - // if (!pp) { - // continue; - //} - - if (pp) // SL: place it here instead of continue, which is related to for(k) loop - - // Loop over each element of the array of pointers to varying-length arrays. - for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { - // if (!pp[ndx]) { - // -- We do not have a pointer to a varying-length array. - // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(), - // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); - // continue; - //} - // Delete any memory at pp[ndx]. - if (!isPtrPtr) { - cl->DeleteArray(pp[ndx]); - pp[ndx] = 0; - } else { - // Using vlen is wrong here because it has already - // been overwritten with the value needed to read - // the current record. Fixing this will require - // doing a pass over the object at the beginning - // of the I/O and releasing all the buffer memory - // for varying length arrays before we overwrite - // the counter values. - // - // For now we will just leak memory, just as we - // have always done in the past. Fix this. - // - // char** r = (char**) pp[ndx]; - // if (r) { - // for (Int_t v = 0; v < vlen; ++v) { - // cl->Destructor(r[v]); - // r[v] = 0; - // } - //} - delete[] pp[ndx]; - pp[ndx] = 0; - } - if (!vlen) { - continue; - } - // Note: We now have pp[ndx] is null. - // Allocate memory to read into. - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - // Note: Polymorphism is not allowed here. - // Allocate a new array of objects to read into. - pp[ndx] = (char *)cl->NewArray(vlen); - if (!pp[ndx]) { - Error("ReadBuffer", "Memory allocation failed!\n"); - continue; - } - } else { - // -- We are a varying-length array of pointers to objects. - // Note: The object pointers are allowed to be polymorphic. - // Allocate a new array of pointers to objects to read into. - pp[ndx] = (char *)new char *[vlen]; - if (!pp[ndx]) { - Error("ReadBuffer", "Memory allocation failed!\n"); - continue; - } - // And set each pointer to null. - memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx] - // = (char*) new char*[vlen]; - } - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - // Loop over the elements of the varying length array. - for (Int_t v = 0; v < vlen; ++v) { - // Read the object from the buffer. - cl->Streamer(pp[ndx] + (v * cl->Size()), buf); - } // v - } else { - // -- We are a varying-length array of object pointers. - // Get a pointer to the object pointer array. - char **r = (char **)pp[ndx]; - // Loop over the elements of the varying length array. - for (Int_t v = 0; v < vlen; ++v) { - // Allocate an object to read into. - r[v] = (char *)cl->New(); - if (!r[v]) { - // Do not print a second error message here. - // Error("ReadBuffer", "Memory allocation failed!\n"); - continue; - } - // Read the object from the buffer. - cl->Streamer(r[v], buf); - } // v - } // isPtrPtr - } // ndx - // } // k - } // fileVersion - buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName()); - return 0; - } - class TConfWithFactor : public TConfiguration { // Configuration object for the Float16/Double32 where a factor has been specified. public: @@ -1997,6 +1609,393 @@ namespace TStreamerInfoActions return 0; } + /** Direct copy of code from TStreamerInfo::WriteBufferAux, + * potentially can be used later for non-text streaming */ + template + static INLINE_TEMPLATE_ARGS Int_t WriteStreamerLoop(TBuffer &buf, void *addr, const TConfiguration *config) + { + UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing + UInt_t ioffset = eoffset + config->fOffset; + + if (!kIsTextT && config->fCompInfo->fStreamer) { + // Get any private streamer which was set for the data member. + TMemberStreamer* pstreamer = config->fCompInfo->fStreamer; + // -- We have a private streamer. + UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + // Loop over the entries in the clones array or the STL container. + //for (int k = 0; k < narr; ++k) { + // Get a pointer to the counter for the varying length array. + Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/); + + // And call the private streamer, passing it the buffer, the object, and the counter. + (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter); + //} for k + buf.SetByteCount(pos, kTRUE); + // We are done, next streamer element. + return 0; + } + + // Get the class of the data member. + TClass* cl = config->fCompInfo->fClass; + // Which are we, an array of objects or an array of pointers to objects? + Bool_t isPtrPtr = (strstr(config->fCompInfo->fElem->GetTypeName(), "**") != 0); + + // By default assume the file version is the newest. + Int_t fileVersion = kMaxInt; + + if (!kIsTextT) { + // At this point we do *not* have a private streamer. + // Get the version of the file we are writing to. + TFile* file = (TFile*) buf.GetParent(); + if (file) { + fileVersion = file->GetVersion(); + } + } + // Write the class version to the buffer. + UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + if (fileVersion > 51508) { + // -- Newer versions allow polymorphic pointers to objects. + // Loop over the entries in the clones array or the STL container. + //for (int k = 0; k < narr; ++k) { + // Get the counter for the varying length array. + Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/)); + + //b << vlen; + if (vlen) { + // Get a pointer to the array of pointers. + char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/); + // Loop over each element of the array of pointers to varying-length arrays. + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { + if (!pp[ndx]) { + // -- We do not have a pointer to a varying-length array. + // Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); + // ::ErrorHandler(kError, "::WriteStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName())); + printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()); + continue; + } + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Write the entire array of objects to the buffer. + // Note: Polymorphism is not allowed here. + buf.WriteFastArray(pp[ndx], cl, vlen, nullptr); + } else { + // -- We are a varying-length array of pointers to objects. + // Write the entire array of object pointers to the buffer. + // Note: The object pointers are allowed to be polymorphic. + buf.WriteFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr); + } // isPtrPtr + } // ndx + } else // vlen + if (kIsTextT) { + // special handling for the text-based streamers + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) + buf.WriteFastArray((void *)nullptr, cl, -1, nullptr); + } + //} // k + } + else { + // -- Older versions do *not* allow polymorphic pointers to objects. + // Loop over the entries in the clones array or the STL container. + //for (int k = 0; k < narr; ++k) { + // Get the counter for the varying length array. + Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/)); + //b << vlen; + if (vlen) { + // Get a pointer to the array of pointers. + char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/); + // -- Older versions do *not* allow polymorphic pointers to objects. + // Loop over each element of the array of pointers to varying-length arrays. + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { + if (!pp[ndx]) { + // -- We do not have a pointer to a varying-length array. + //Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); + // ::ErrorHandler(kError, "::WriteTextStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName())); + printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()); + continue; + } + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Loop over the elements of the varying length array. + for (Int_t v = 0; v < vlen; ++v) { + // Write the object to the buffer. + cl->Streamer(pp[ndx] + (v * cl->Size()), buf); + } // v + } + else { + // -- We are a varying-length array of pointers to objects. + // Loop over the elements of the varying length array. + for (Int_t v = 0; v < vlen; ++v) { + // Get a pointer to the object pointer. + char** r = (char**) pp[ndx]; + // Write the object to the buffer. + cl->Streamer(r[v], buf); + } // v + } // isPtrPtr + } // ndx + } // vlen + //} // k + } // fileVersion + // Backpatch the byte count into the buffer. + buf.SetByteCount(pos, kTRUE); + + return 0; + } + + /** Direct copy of code from TStreamerInfo::WriteBufferAux, + * potentially can be used later for non-text streaming */ + template + static INLINE_TEMPLATE_ARGS Int_t ReadStreamerLoop(TBuffer &buf, void *addr, const TConfiguration *config) + { + UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing + UInt_t ioffset = eoffset + config->fOffset; + + // Get the class of the data member. + TClass* cl = config->fCompInfo->fClass; + + // Check for a private streamer. + if (!kIsTextT && config->fCompInfo->fStreamer) { + // Get any private streamer which was set for the data member. + TMemberStreamer* pstreamer = config->fCompInfo->fStreamer; + // -- We have a private streamer. + // Read the class version and byte count from the buffer. + UInt_t start = 0; + UInt_t count = 0; + buf.ReadVersion(&start, &count, cl); + // Loop over the entries in the clones array or the STL container. + //for (Int_t k = 0; k < narr; ++k) { + + Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/); + // And call the private streamer, passing it the buffer, the object, and the counter. + (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter); + + // } // for k + buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName()); + // We are done, next streamer element. + return 0; + } + + // Which are we, an array of objects or an array of pointers to objects? + Bool_t isPtrPtr = (strstr(config->fCompInfo->fElem->GetTypeName(), "**") != 0); + + // By default assume the file version is the newest. + Int_t fileVersion = kMaxInt; + if (!kIsTextT) { + // At this point we do *not* have a private streamer. + // Get the version of the file we are reading from. + TFile* file = (TFile*) buf.GetParent(); + if (file) { + fileVersion = file->GetVersion(); + } + } + // Read the class version and byte count from the buffer. + UInt_t start = 0; + UInt_t count = 0; + buf.ReadVersion(&start, &count, cl); + if (fileVersion > 51508) { + // -- Newer versions allow polymorphic pointers. + // Loop over the entries in the clones array or the STL container. + // for (Int_t k = 0; k < narr; ++k) { + // Get the counter for the varying length array. + Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ + eoffset /*entry offset*/ + + config->fCompInfo->fMethod /*counter offset*/)); + // Int_t realLen; + // b >> realLen; + // if (realLen != vlen) { + // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen); + //} + // Get a pointer to the array of pointers. + char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/); + // Loop over each element of the array of pointers to varying-length arrays. + // if (!pp) { + // continue; + // } + + if (pp) // SL: place it here instead of continue, which is related to for(k) loop + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { + // if (!pp[ndx]) { + // -- We do not have a pointer to a varying-length array. + // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(), + // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); + // continue; + //} + // Delete any memory at pp[ndx]. + if (!isPtrPtr) { + cl->DeleteArray(pp[ndx]); + pp[ndx] = 0; + } else { + // Using vlen is wrong here because it has already + // been overwritten with the value needed to read + // the current record. Fixing this will require + // doing a pass over the object at the beginning + // of the I/O and releasing all the buffer memory + // for varying length arrays before we overwrite + // the counter values. + // + // For now we will just leak memory, just as we + // have always done in the past. Fix this. + // + // char** r = (char**) pp[ndx]; + // if (r) { + // for (Int_t v = 0; v < vlen; ++v) { + // cl->Destructor(r[v]); + // r[v] = 0; + // } + //} + delete[] pp[ndx]; + pp[ndx] = 0; + } + if (!vlen) { + if (kIsTextT) { + // special handling for the text-based streamers - keep calling to shift array index + buf.ReadFastArray((void *)nullptr, cl, -1, nullptr); + } + continue; + } + // Note: We now have pp[ndx] is null. + // Allocate memory to read into. + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Note: Polymorphism is not allowed here. + // Allocate a new array of objects to read into. + pp[ndx] = (char *)cl->NewArray(vlen); + if (!pp[ndx]) { + Error("ReadBuffer", "Memory allocation failed!\n"); + continue; + } + } else { + // -- We are a varying-length array of pointers to objects. + // Note: The object pointers are allowed to be polymorphic. + // Allocate a new array of pointers to objects to read into. + pp[ndx] = (char *)new char *[vlen]; + if (!pp[ndx]) { + Error("ReadBuffer", "Memory allocation failed!\n"); + continue; + } + // And set each pointer to null. + memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx] + // = (char*) new char*[vlen]; + } + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + buf.ReadFastArray(pp[ndx], cl, vlen, nullptr); + } else { + // -- We are a varying-length array of object pointers. + buf.ReadFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr); + } // isPtrPtr + } // ndx + // } // k + } else { + // -- Older versions do *not* allow polymorphic pointers. + // Loop over the entries in the clones array or the STL container. + // for (Int_t k = 0; k < narr; ++k) { + // Get the counter for the varying length array. + Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ + eoffset /*entry offset*/ + + config->fCompInfo->fMethod /*counter offset*/)); + // Int_t realLen; + // b >> realLen; + // if (realLen != vlen) { + // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen); + //} + // Get a pointer to the array of pointers. + char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/); + // if (!pp) { + // continue; + //} + + if (pp) // SL: place it here instead of continue, which is related to for(k) loop + + // Loop over each element of the array of pointers to varying-length arrays. + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { + // if (!pp[ndx]) { + // -- We do not have a pointer to a varying-length array. + // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(), + // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); + // continue; + //} + // Delete any memory at pp[ndx]. + if (!isPtrPtr) { + cl->DeleteArray(pp[ndx]); + pp[ndx] = 0; + } else { + // Using vlen is wrong here because it has already + // been overwritten with the value needed to read + // the current record. Fixing this will require + // doing a pass over the object at the beginning + // of the I/O and releasing all the buffer memory + // for varying length arrays before we overwrite + // the counter values. + // + // For now we will just leak memory, just as we + // have always done in the past. Fix this. + // + // char** r = (char**) pp[ndx]; + // if (r) { + // for (Int_t v = 0; v < vlen; ++v) { + // cl->Destructor(r[v]); + // r[v] = 0; + // } + //} + delete[] pp[ndx]; + pp[ndx] = 0; + } + if (!vlen) { + continue; + } + // Note: We now have pp[ndx] is null. + // Allocate memory to read into. + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Note: Polymorphism is not allowed here. + // Allocate a new array of objects to read into. + pp[ndx] = (char *)cl->NewArray(vlen); + if (!pp[ndx]) { + Error("ReadBuffer", "Memory allocation failed!\n"); + continue; + } + } else { + // -- We are a varying-length array of pointers to objects. + // Note: The object pointers are allowed to be polymorphic. + // Allocate a new array of pointers to objects to read into. + pp[ndx] = (char *)new char *[vlen]; + if (!pp[ndx]) { + Error("ReadBuffer", "Memory allocation failed!\n"); + continue; + } + // And set each pointer to null. + memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx] + // = (char*) new char*[vlen]; + } + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Loop over the elements of the varying length array. + for (Int_t v = 0; v < vlen; ++v) { + // Read the object from the buffer. + cl->Streamer(pp[ndx] + (v * cl->Size()), buf); + } // v + } else { + // -- We are a varying-length array of object pointers. + // Get a pointer to the object pointer array. + char **r = (char **)pp[ndx]; + // Loop over the elements of the varying length array. + for (Int_t v = 0; v < vlen; ++v) { + // Allocate an object to read into. + r[v] = (char *)cl->New(); + if (!r[v]) { + // Do not print a second error message here. + // Error("ReadBuffer", "Memory allocation failed!\n"); + continue; + } + // Read the object from the buffer. + cl->Streamer(r[v], buf); + } // v + } // isPtrPtr + } // ndx + // } // k + } // fileVersion + buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName()); + return 0; + } + }; // The Scalar 'looper' only process one element. @@ -4572,7 +4571,7 @@ void TStreamerInfo::AddReadAction(TStreamerInfoActions::TActionSequence *readSeq } case TStreamerInfo::kStreamLoop: case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: - readSequence->AddAction( ReadStreamerLoop, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); + readSequence->AddAction( ScalarLooper::ReadStreamerLoop, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); break; case TStreamerInfo::kBase: if (compinfo->fStreamer) @@ -4670,7 +4669,7 @@ void TStreamerInfo::AddReadTextAction(TStreamerInfoActions::TActionSequence *rea case TStreamerInfo::kStreamLoop: case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: - readSequence->AddAction(ReadStreamerLoop, new TConfiguration(this, i, compinfo, compinfo->fOffset)); + readSequence->AddAction(ScalarLooper::ReadStreamerLoop, new TConfiguration(this, i, compinfo, compinfo->fOffset)); break; case TStreamerInfo::kBase: isBase = kTRUE; break; @@ -4896,7 +4895,7 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS case TStreamerInfo::kStreamLoop: case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: - writeSequence->AddAction( WriteStreamerLoop, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); + writeSequence->AddAction( ScalarLooper::WriteStreamerLoop, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); break; case TStreamerInfo::kBase: if (compinfo->fStreamer) @@ -5051,7 +5050,7 @@ void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *wr case TStreamerInfo::kStreamLoop: case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: - writeSequence->AddAction(WriteStreamerLoop, new TConfiguration(this, i, compinfo, compinfo->fOffset)); + writeSequence->AddAction(ScalarLooper::WriteStreamerLoop, new TConfiguration(this, i, compinfo, compinfo->fOffset)); break; case TStreamerInfo::kBase: isBase = kTRUE; break; From 421255b8792f75b406a85e4c208ff47a1defda3c Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 13:01:05 -0600 Subject: [PATCH 28/46] io actions: Correct class used for StreamerLoop version read --- io/io/src/TStreamerInfoActions.cxx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 50727c2197c9f..c429bdecde077 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -1760,9 +1760,7 @@ namespace TStreamerInfoActions // Read the class version and byte count from the buffer. UInt_t start = 0; UInt_t count = 0; - buf.ReadVersion(&start, &count, cl); - // Loop over the entries in the clones array or the STL container. - //for (Int_t k = 0; k < narr; ++k) { + buf.ReadVersion(&pos, &count, config->fInfo->IsA()); Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/); // And call the private streamer, passing it the buffer, the object, and the counter. @@ -1790,7 +1788,7 @@ namespace TStreamerInfoActions // Read the class version and byte count from the buffer. UInt_t start = 0; UInt_t count = 0; - buf.ReadVersion(&start, &count, cl); + buf.ReadVersion(&start, &count, config->fInfo->IsA()); if (fileVersion > 51508) { // -- Newer versions allow polymorphic pointers. // Loop over the entries in the clones array or the STL container. From 99df53eeececf2e03ba7095ec38ce502b8a882ea Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 15 Nov 2024 12:56:55 -0600 Subject: [PATCH 29/46] io actions: Add kStreamLoop to memberwise streaming This required the addition of a concept that can be used to reduce boiler plate duplication. We now have an example where a generic function (Read/WriteStreamerLoop) is used with action with different signature by leveraging template arguments packs and a using statement declaration within the *Looper helper structs --- io/io/src/TStreamerInfoActions.cxx | 839 ++++++++++++++++------------- 1 file changed, 455 insertions(+), 384 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index c429bdecde077..48b4efa268279 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -207,6 +207,17 @@ namespace TStreamerInfoActions TConfiguration *Copy() override { return new TConfObject(*this); } }; + struct TConfStreamerLoop : public TConfiguration { + bool fIsPtrPtr = false; // Which are we, an array of objects or an array of pointers to objects? + + TConfStreamerLoop(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, bool isPtrPtr) + : TConfiguration(info, id, compinfo, offset), fIsPtrPtr(isPtrPtr) + { + } + + TConfiguration *Copy() override { return new TConfStreamerLoop(*this); }; + }; + Int_t GenericReadAction(TBuffer &buf, void *addr, const TConfiguration *config) { char *obj = (char*)addr; @@ -1609,405 +1620,447 @@ namespace TStreamerInfoActions return 0; } - /** Direct copy of code from TStreamerInfo::WriteBufferAux, - * potentially can be used later for non-text streaming */ - template - static INLINE_TEMPLATE_ARGS Int_t WriteStreamerLoop(TBuffer &buf, void *addr, const TConfiguration *config) - { - UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing - UInt_t ioffset = eoffset + config->fOffset; - - if (!kIsTextT && config->fCompInfo->fStreamer) { - // Get any private streamer which was set for the data member. - TMemberStreamer* pstreamer = config->fCompInfo->fStreamer; - // -- We have a private streamer. - UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); - // Loop over the entries in the clones array or the STL container. - //for (int k = 0; k < narr; ++k) { - // Get a pointer to the counter for the varying length array. - Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/); - - // And call the private streamer, passing it the buffer, the object, and the counter. - (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter); - //} for k - buf.SetByteCount(pos, kTRUE); - // We are done, next streamer element. - return 0; - } + static inline Int_t StreamerLoopExternal(TBuffer &buf, void *addr, const TConfiguration *actionConfig) { + UInt_t ioffset = actionConfig->fOffset; + // Get any private streamer which was set for the data member. + TMemberStreamer* pstreamer = actionConfig->fCompInfo->fStreamer; + Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + actionConfig->fCompInfo->fMethod /*counter offset*/); + // And call the private streamer, passing it the buffer, the object, and the counter. + (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter); + return 0; + }; + template + static Int_t WriteStreamerLoopPoly(TBuffer &buf, void *addr, const TConfiguration *config) { // Get the class of the data member. TClass* cl = config->fCompInfo->fClass; - // Which are we, an array of objects or an array of pointers to objects? - Bool_t isPtrPtr = (strstr(config->fCompInfo->fElem->GetTypeName(), "**") != 0); + UInt_t ioffset = config->fOffset; + bool isPtrPtr = ((TConfStreamerLoop*)config)->fIsPtrPtr; - // By default assume the file version is the newest. - Int_t fileVersion = kMaxInt; + // Get the counter for the varying length array. + Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + config->fCompInfo->fMethod /*counter offset*/)); - if (!kIsTextT) { - // At this point we do *not* have a private streamer. - // Get the version of the file we are writing to. - TFile* file = (TFile*) buf.GetParent(); - if (file) { - fileVersion = file->GetVersion(); - } - } - // Write the class version to the buffer. - UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); - if (fileVersion > 51508) { - // -- Newer versions allow polymorphic pointers to objects. - // Loop over the entries in the clones array or the STL container. - //for (int k = 0; k < narr; ++k) { - // Get the counter for the varying length array. - Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/)); - - //b << vlen; - if (vlen) { - // Get a pointer to the array of pointers. - char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/); - // Loop over each element of the array of pointers to varying-length arrays. - for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { - if (!pp[ndx]) { - // -- We do not have a pointer to a varying-length array. - // Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); - // ::ErrorHandler(kError, "::WriteStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName())); - printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()); - continue; - } - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - // Write the entire array of objects to the buffer. - // Note: Polymorphism is not allowed here. - buf.WriteFastArray(pp[ndx], cl, vlen, nullptr); - } else { - // -- We are a varying-length array of pointers to objects. - // Write the entire array of object pointers to the buffer. - // Note: The object pointers are allowed to be polymorphic. - buf.WriteFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr); - } // isPtrPtr - } // ndx - } else // vlen - if (kIsTextT) { - // special handling for the text-based streamers - for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) - buf.WriteFastArray((void *)nullptr, cl, -1, nullptr); + //b << vlen; + if (vlen) { + // Get a pointer to the array of pointers. + char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/); + // Loop over each element of the array of pointers to varying-length arrays. + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { + if (!pp[ndx]) { + // -- We do not have a pointer to a varying-length array. + // Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); + // ::ErrorHandler(kError, "::WriteStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName())); + printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()); + continue; } - //} // k + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Write the entire array of objects to the buffer. + // Note: Polymorphism is not allowed here. + buf.WriteFastArray(pp[ndx], cl, vlen, nullptr); + } else { + // -- We are a varying-length array of pointers to objects. + // Write the entire array of object pointers to the buffer. + // Note: The object pointers are allowed to be polymorphic. + buf.WriteFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr); + } // isPtrPtr + } // ndx + } else // vlen + if (kIsTextT) { + // special handling for the text-based streamers + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) + buf.WriteFastArray((void *)nullptr, cl, -1, nullptr); } - else { - // -- Older versions do *not* allow polymorphic pointers to objects. - // Loop over the entries in the clones array or the STL container. - //for (int k = 0; k < narr; ++k) { - // Get the counter for the varying length array. - Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/)); - //b << vlen; - if (vlen) { - // Get a pointer to the array of pointers. - char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/); - // -- Older versions do *not* allow polymorphic pointers to objects. - // Loop over each element of the array of pointers to varying-length arrays. - for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { - if (!pp[ndx]) { - // -- We do not have a pointer to a varying-length array. - //Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); - // ::ErrorHandler(kError, "::WriteTextStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName())); - printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()); - continue; - } - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - // Loop over the elements of the varying length array. - for (Int_t v = 0; v < vlen; ++v) { - // Write the object to the buffer. - cl->Streamer(pp[ndx] + (v * cl->Size()), buf); - } // v - } - else { - // -- We are a varying-length array of pointers to objects. - // Loop over the elements of the varying length array. - for (Int_t v = 0; v < vlen; ++v) { - // Get a pointer to the object pointer. - char** r = (char**) pp[ndx]; - // Write the object to the buffer. - cl->Streamer(r[v], buf); - } // v - } // isPtrPtr - } // ndx - } // vlen - //} // k - } // fileVersion - // Backpatch the byte count into the buffer. - buf.SetByteCount(pos, kTRUE); - return 0; } - /** Direct copy of code from TStreamerInfo::WriteBufferAux, - * potentially can be used later for non-text streaming */ - template - static INLINE_TEMPLATE_ARGS Int_t ReadStreamerLoop(TBuffer &buf, void *addr, const TConfiguration *config) - { - UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing - UInt_t ioffset = eoffset + config->fOffset; - + static Int_t WriteStreamerLoopStatic(TBuffer &buf, void *addr, const TConfiguration *config) { // Get the class of the data member. TClass* cl = config->fCompInfo->fClass; + UInt_t ioffset = config->fOffset; + bool isPtrPtr = ((TConfStreamerLoop*)config)->fIsPtrPtr; - // Check for a private streamer. - if (!kIsTextT && config->fCompInfo->fStreamer) { - // Get any private streamer which was set for the data member. - TMemberStreamer* pstreamer = config->fCompInfo->fStreamer; - // -- We have a private streamer. - // Read the class version and byte count from the buffer. - UInt_t start = 0; - UInt_t count = 0; - buf.ReadVersion(&pos, &count, config->fInfo->IsA()); + // Get the counter for the varying length array. + Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + config->fCompInfo->fMethod /*counter offset*/)); + //b << vlen; + if (vlen) { + // Get a pointer to the array of pointers. + char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/); + // -- Older versions do *not* allow polymorphic pointers to objects. + // Loop over each element of the array of pointers to varying-length arrays. + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { + if (!pp[ndx]) { + // -- We do not have a pointer to a varying-length array. + //Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); + // ::ErrorHandler(kError, "::WriteTextStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName())); + printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()); + continue; + } + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Loop over the elements of the varying length array. + for (Int_t v = 0; v < vlen; ++v) { + // Write the object to the buffer. + cl->Streamer(pp[ndx] + (v * cl->Size()), buf); + } // v + } + else { + // -- We are a varying-length array of pointers to objects. + // Loop over the elements of the varying length array. + for (Int_t v = 0; v < vlen; ++v) { + // Get a pointer to the object pointer. + char** r = (char**) pp[ndx]; + // Write the object to the buffer. + cl->Streamer(r[v], buf); + } // v + } // isPtrPtr + } // ndx + } // vlen + return 0; + } + + template + struct WriteStreamerLoop { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, Ts... args, const TConfiguration *config) + { + if (!kIsTextT && config->fCompInfo->fStreamer) { + // -- We have a private streamer. + UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + + // Loop over the entries in the clones array or the STL container. + Looper::template LoopOverCollection< StreamerLoopExternal > (buf, start, args..., config); + + buf.SetByteCount(pos, kTRUE); + // We are done, next streamer element. + return 0; + } - Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/); - // And call the private streamer, passing it the buffer, the object, and the counter. - (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter); + // By default assume the file version is the newest. + Int_t fileVersion = kMaxInt; + + if (!kIsTextT) { + // At this point we do *not* have a private streamer. + // Get the version of the file we are writing to. + TFile* file = (TFile*) buf.GetParent(); + if (file) { + fileVersion = file->GetVersion(); + } + } + // Write the class version to the buffer. + UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + if (fileVersion > 51508) { + // -- Newer versions allow polymorphic pointers to objects. + // Loop over the entries in the clones array or the STL container. + Looper::template LoopOverCollection< WriteStreamerLoopPoly > (buf, start, args..., config); + } + else { + // -- Older versions do *not* allow polymorphic pointers to objects. + // Loop over the entries in the clones array or the STL container. + Looper::template LoopOverCollection< ReadStreamerLoopStatic > (buf, start, args..., config); + } // fileVersion + // Backpatch the byte count into the buffer. + buf.SetByteCount(pos, kTRUE); - // } // for k - buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName()); - // We are done, next streamer element. return 0; } + }; + template + static Int_t ReadStreamerLoopPoly(TBuffer &buf, void *addr, const TConfiguration *config) { + // Get the class of the data member. + TClass* cl = config->fCompInfo->fClass; + UInt_t ioffset = config->fOffset; // Which are we, an array of objects or an array of pointers to objects? - Bool_t isPtrPtr = (strstr(config->fCompInfo->fElem->GetTypeName(), "**") != 0); - - // By default assume the file version is the newest. - Int_t fileVersion = kMaxInt; - if (!kIsTextT) { - // At this point we do *not* have a private streamer. - // Get the version of the file we are reading from. - TFile* file = (TFile*) buf.GetParent(); - if (file) { - fileVersion = file->GetVersion(); - } - } - // Read the class version and byte count from the buffer. - UInt_t start = 0; - UInt_t count = 0; - buf.ReadVersion(&start, &count, config->fInfo->IsA()); - if (fileVersion > 51508) { - // -- Newer versions allow polymorphic pointers. - // Loop over the entries in the clones array or the STL container. - // for (Int_t k = 0; k < narr; ++k) { - // Get the counter for the varying length array. - Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ + eoffset /*entry offset*/ + - config->fCompInfo->fMethod /*counter offset*/)); - // Int_t realLen; - // b >> realLen; - // if (realLen != vlen) { - // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen); - //} - // Get a pointer to the array of pointers. - char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/); - // Loop over each element of the array of pointers to varying-length arrays. - // if (!pp) { - // continue; - // } + bool isPtrPtr = ((TConfStreamerLoop*)config)->fIsPtrPtr; + + // Get the counter for the varying length array. + Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ + + config->fCompInfo->fMethod /*counter offset*/)); + // Int_t realLen; + // b >> realLen; + // if (realLen != vlen) { + // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen); + //} + // Get a pointer to the array of pointers. + char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/); + // Loop over each element of the array of pointers to varying-length arrays. + // if (!pp) { + // continue; + // } - if (pp) // SL: place it here instead of continue, which is related to for(k) loop - for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { - // if (!pp[ndx]) { - // -- We do not have a pointer to a varying-length array. - // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(), - // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); - // continue; + if (pp) // SL: place it here instead of continue, which is related to for(k) loop + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { + // if (!pp[ndx]) { + // -- We do not have a pointer to a varying-length array. + // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(), + // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); + // continue; + //} + // Delete any memory at pp[ndx]. + if (!isPtrPtr) { + cl->DeleteArray(pp[ndx]); + pp[ndx] = 0; + } else { + // Using vlen is wrong here because it has already + // been overwritten with the value needed to read + // the current record. Fixing this will require + // doing a pass over the object at the beginning + // of the I/O and releasing all the buffer memory + // for varying length arrays before we overwrite + // the counter values. + // + // For now we will just leak memory, just as we + // have always done in the past. Fix this. + // + // char** r = (char**) pp[ndx]; + // if (r) { + // for (Int_t v = 0; v < vlen; ++v) { + // cl->Destructor(r[v]); + // r[v] = 0; + // } //} - // Delete any memory at pp[ndx]. - if (!isPtrPtr) { - cl->DeleteArray(pp[ndx]); - pp[ndx] = 0; - } else { - // Using vlen is wrong here because it has already - // been overwritten with the value needed to read - // the current record. Fixing this will require - // doing a pass over the object at the beginning - // of the I/O and releasing all the buffer memory - // for varying length arrays before we overwrite - // the counter values. - // - // For now we will just leak memory, just as we - // have always done in the past. Fix this. - // - // char** r = (char**) pp[ndx]; - // if (r) { - // for (Int_t v = 0; v < vlen; ++v) { - // cl->Destructor(r[v]); - // r[v] = 0; - // } - //} - delete[] pp[ndx]; - pp[ndx] = 0; + delete[] pp[ndx]; + pp[ndx] = 0; + } + if (!vlen) { + if (kIsTextT) { + // special handling for the text-based streamers - keep calling to shift array index + buf.ReadFastArray((void *)nullptr, cl, -1, nullptr); } - if (!vlen) { - if (kIsTextT) { - // special handling for the text-based streamers - keep calling to shift array index - buf.ReadFastArray((void *)nullptr, cl, -1, nullptr); - } + continue; + } + // Note: We now have pp[ndx] is null. + // Allocate memory to read into. + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Note: Polymorphism is not allowed here. + // Allocate a new array of objects to read into. + pp[ndx] = (char *)cl->NewArray(vlen); + if (!pp[ndx]) { + Error("ReadBuffer", "Memory allocation failed!\n"); continue; } - // Note: We now have pp[ndx] is null. - // Allocate memory to read into. - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - // Note: Polymorphism is not allowed here. - // Allocate a new array of objects to read into. - pp[ndx] = (char *)cl->NewArray(vlen); - if (!pp[ndx]) { - Error("ReadBuffer", "Memory allocation failed!\n"); - continue; - } - } else { - // -- We are a varying-length array of pointers to objects. - // Note: The object pointers are allowed to be polymorphic. - // Allocate a new array of pointers to objects to read into. - pp[ndx] = (char *)new char *[vlen]; - if (!pp[ndx]) { - Error("ReadBuffer", "Memory allocation failed!\n"); - continue; - } - // And set each pointer to null. - memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx] - // = (char*) new char*[vlen]; + } else { + // -- We are a varying-length array of pointers to objects. + // Note: The object pointers are allowed to be polymorphic. + // Allocate a new array of pointers to objects to read into. + pp[ndx] = (char *)new char *[vlen]; + if (!pp[ndx]) { + Error("ReadBuffer", "Memory allocation failed!\n"); + continue; } - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - buf.ReadFastArray(pp[ndx], cl, vlen, nullptr); - } else { - // -- We are a varying-length array of object pointers. - buf.ReadFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr); - } // isPtrPtr - } // ndx - // } // k - } else { - // -- Older versions do *not* allow polymorphic pointers. - // Loop over the entries in the clones array or the STL container. - // for (Int_t k = 0; k < narr; ++k) { - // Get the counter for the varying length array. - Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ + eoffset /*entry offset*/ + - config->fCompInfo->fMethod /*counter offset*/)); - // Int_t realLen; - // b >> realLen; - // if (realLen != vlen) { - // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen); - //} - // Get a pointer to the array of pointers. - char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/); - // if (!pp) { - // continue; - //} + // And set each pointer to null. + memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx] + // = (char*) new char*[vlen]; + } + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + buf.ReadFastArray(pp[ndx], cl, vlen, nullptr); + } else { + // -- We are a varying-length array of object pointers. + buf.ReadFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr); + } // isPtrPtr + } // ndx + return 0; + }; // StreamerLoopPoly + + static Int_t ReadStreamerLoopStatic(TBuffer &buf, void *addr, const TConfiguration *config) { + // Get the class of the data member. + TClass* cl = config->fCompInfo->fClass; + UInt_t ioffset = config->fOffset; + // Which are we, an array of objects or an array of pointers to objects? + bool isPtrPtr = ((TConfStreamerLoop*)config)->fIsPtrPtr; + + // Get the counter for the varying length array. + Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ + + config->fCompInfo->fMethod /*counter offset*/)); + // Int_t realLen; + // b >> realLen; + // if (realLen != vlen) { + // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen); + //} + // Get a pointer to the array of pointers. + char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/); + // if (!pp) { + // continue; + //} - if (pp) // SL: place it here instead of continue, which is related to for(k) loop + if (pp) // SL: place it here instead of continue, which is related to for(k) loop - // Loop over each element of the array of pointers to varying-length arrays. - for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { - // if (!pp[ndx]) { - // -- We do not have a pointer to a varying-length array. - // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(), - // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); - // continue; + // Loop over each element of the array of pointers to varying-length arrays. + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { + // if (!pp[ndx]) { + // -- We do not have a pointer to a varying-length array. + // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(), + // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); + // continue; + //} + // Delete any memory at pp[ndx]. + if (!isPtrPtr) { + cl->DeleteArray(pp[ndx]); + pp[ndx] = 0; + } else { + // Using vlen is wrong here because it has already + // been overwritten with the value needed to read + // the current record. Fixing this will require + // doing a pass over the object at the beginning + // of the I/O and releasing all the buffer memory + // for varying length arrays before we overwrite + // the counter values. + // + // For now we will just leak memory, just as we + // have always done in the past. Fix this. + // + // char** r = (char**) pp[ndx]; + // if (r) { + // for (Int_t v = 0; v < vlen; ++v) { + // cl->Destructor(r[v]); + // r[v] = 0; + // } //} - // Delete any memory at pp[ndx]. - if (!isPtrPtr) { - cl->DeleteArray(pp[ndx]); - pp[ndx] = 0; - } else { - // Using vlen is wrong here because it has already - // been overwritten with the value needed to read - // the current record. Fixing this will require - // doing a pass over the object at the beginning - // of the I/O and releasing all the buffer memory - // for varying length arrays before we overwrite - // the counter values. - // - // For now we will just leak memory, just as we - // have always done in the past. Fix this. - // - // char** r = (char**) pp[ndx]; - // if (r) { - // for (Int_t v = 0; v < vlen; ++v) { - // cl->Destructor(r[v]); - // r[v] = 0; - // } - //} - delete[] pp[ndx]; - pp[ndx] = 0; + delete[] pp[ndx]; + pp[ndx] = 0; + } + if (!vlen) { + continue; + } + // Note: We now have pp[ndx] is null. + // Allocate memory to read into. + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Note: Polymorphism is not allowed here. + // Allocate a new array of objects to read into. + pp[ndx] = (char *)cl->NewArray(vlen); + if (!pp[ndx]) { + Error("ReadBuffer", "Memory allocation failed!\n"); + continue; } - if (!vlen) { + } else { + // -- We are a varying-length array of pointers to objects. + // Note: The object pointers are allowed to be polymorphic. + // Allocate a new array of pointers to objects to read into. + pp[ndx] = (char *)new char *[vlen]; + if (!pp[ndx]) { + Error("ReadBuffer", "Memory allocation failed!\n"); continue; } - // Note: We now have pp[ndx] is null. - // Allocate memory to read into. - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - // Note: Polymorphism is not allowed here. - // Allocate a new array of objects to read into. - pp[ndx] = (char *)cl->NewArray(vlen); - if (!pp[ndx]) { - Error("ReadBuffer", "Memory allocation failed!\n"); - continue; - } - } else { - // -- We are a varying-length array of pointers to objects. - // Note: The object pointers are allowed to be polymorphic. - // Allocate a new array of pointers to objects to read into. - pp[ndx] = (char *)new char *[vlen]; - if (!pp[ndx]) { - Error("ReadBuffer", "Memory allocation failed!\n"); + // And set each pointer to null. + memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx] + // = (char*) new char*[vlen]; + } + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Loop over the elements of the varying length array. + for (Int_t v = 0; v < vlen; ++v) { + // Read the object from the buffer. + cl->Streamer(pp[ndx] + (v * cl->Size()), buf); + } // v + } else { + // -- We are a varying-length array of object pointers. + // Get a pointer to the object pointer array. + char **r = (char **)pp[ndx]; + // Loop over the elements of the varying length array. + for (Int_t v = 0; v < vlen; ++v) { + // Allocate an object to read into. + r[v] = (char *)cl->New(); + if (!r[v]) { + // Do not print a second error message here. + // Error("ReadBuffer", "Memory allocation failed!\n"); continue; } - // And set each pointer to null. - memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx] - // = (char*) new char*[vlen]; - } - if (!isPtrPtr) { - // -- We are a varying-length array of objects. - // Loop over the elements of the varying length array. - for (Int_t v = 0; v < vlen; ++v) { - // Read the object from the buffer. - cl->Streamer(pp[ndx] + (v * cl->Size()), buf); - } // v - } else { - // -- We are a varying-length array of object pointers. - // Get a pointer to the object pointer array. - char **r = (char **)pp[ndx]; - // Loop over the elements of the varying length array. - for (Int_t v = 0; v < vlen; ++v) { - // Allocate an object to read into. - r[v] = (char *)cl->New(); - if (!r[v]) { - // Do not print a second error message here. - // Error("ReadBuffer", "Memory allocation failed!\n"); - continue; - } - // Read the object from the buffer. - cl->Streamer(r[v], buf); - } // v - } // isPtrPtr - } // ndx - // } // k - } // fileVersion - buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName()); + // Read the object from the buffer. + cl->Streamer(r[v], buf); + } // v + } // isPtrPtr + } // ndx return 0; - } + }; // action + + template + struct ReadStreamerLoop { + static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, Ts... args, const TConfiguration *config) + { + // Check for a private streamer. + if (!kIsTextT && config->fCompInfo->fStreamer) { + // -- We have a private streamer. + // Read the class version and byte count from the buffer. + UInt_t pos = 0; + UInt_t count = 0; + buf.ReadVersion(&pos, &count, config->fInfo->IsA()); + + // Loop over the entries in the clones array or the STL container. + Looper::template LoopOverCollection< StreamerLoopExternal > (buf, start, args..., config); + + buf.CheckByteCount(pos, count, config->fCompInfo->fElem->GetFullName()); + // We are done, next streamer element. + return 0; + } + + // By default assume the file version is the newest. + Int_t fileVersion = kMaxInt; + if (!kIsTextT) { + // At this point we do *not* have a private streamer. + // Get the version of the file we are reading from. + TFile* file = (TFile*) buf.GetParent(); + if (file) { + fileVersion = file->GetVersion(); + } + } + // Read the class version and byte count from the buffer. + UInt_t pos = 0; + UInt_t count = 0; + buf.ReadVersion(&pos, &count, config->fInfo->IsA()); + if (fileVersion > 51508) { + // -- Newer versions allow polymorphic pointers. + + // Loop over the entries in the clones array or the STL container. + Looper::template LoopOverCollection< ReadStreamerLoopPoly > (buf, start, args..., config); + } else { + // -- Older versions do *not* allow polymorphic pointers. + + // Loop over the entries in the clones array or the STL container. + Looper::template LoopOverCollection< ReadStreamerLoopStatic > (buf, start, args..., config); + } // fileVersion + buf.CheckByteCount(pos, count, config->fCompInfo->fElem->GetFullName()); + return 0; + } + }; }; // The Scalar 'looper' only process one element. struct ScalarLooper : public CollectionLooper { + using LoopAction_t = Int_t (*)(TBuffer &, void*, const TConfiguration*); + template - static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void * /* end */, const TLoopConfiguration *, const TConfiguration *config) + static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const TConfiguration *config) { iter_action(buf, start, config); return 0; } }; - struct VectorLooper : public CollectionLooper { + struct VectorLooper : public CollectionLooper + { + using LoopAction_t = Int_t (*)(TBuffer &, void*, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration*); + + template + using ReadStreamerLoop = CollectionLooper::ReadStreamerLoop; + template + using WriteStreamerLoop = CollectionLooper::WriteStreamerLoop; + + template + static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config) + { + const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement; + //Idea: can we factor out the addition of fOffset + // iter = (char*)iter + config->fOffset; + for(void *iter = start; iter != end; iter = (char*)iter + incr ) { + iter_action(buf, iter, config); + } + return 0; + } template static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config) @@ -2160,18 +2213,6 @@ namespace TStreamerInfoActions } }; - template - static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config) - { - const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement; - //Idea: can we factor out the addition of fOffset - // iter = (char*)iter + config->fOffset; - for(void *iter = start; iter != end; iter = (char*)iter + incr ) { - iter_action(buf, iter, config); - } - return 0; - } - static INLINE_TEMPLATE_ARGS Int_t ReadBase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config) { // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now @@ -2483,10 +2524,26 @@ namespace TStreamerInfoActions }; }; - struct VectorPtrLooper { + struct VectorPtrLooper : public CollectionLooper { // Can not inherit/use CollectionLooper, because this looper's // function do not take a `TLoopConfiguration`. + using LoopAction_t = Int_t (*)(TBuffer &, void *start, const void *end, const TConfiguration*); + + template + using ReadStreamerLoop = CollectionLooper::ReadStreamerLoop; + template + using WriteStreamerLoop = CollectionLooper::WriteStreamerLoop; + + template + static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TConfiguration *config) + { + for(void *iter = start; iter != end; iter = (char*)iter + sizeof(void*) ) { + action(buf, *(void**)iter, config); + } + return 0; + } + template static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *iter, const void *end, const TConfiguration *config) { @@ -2628,15 +2685,6 @@ namespace TStreamerInfoActions } }; - template - static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TConfiguration *config) - { - for(void *iter = start; iter != end; iter = (char*)iter + sizeof(void*) ) { - action(buf, *(void**)iter, config); - } - return 0; - } - static INLINE_TEMPLATE_ARGS Int_t ReadBase(TBuffer &buf, void *start, const void *end, const TConfiguration *config) { // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now @@ -2683,6 +2731,8 @@ namespace TStreamerInfoActions }; struct AssociativeLooper { + using LoopAction_t = void (*)(TBuffer&, void *, const void *, Next_t, Int_t, const TStreamerElement *elem); + protected: template @@ -2938,6 +2988,12 @@ namespace TStreamerInfoActions }; struct GenericLooper : public CollectionLooper { + using LoopAction_t = Int_t (*)(TBuffer &, void*, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration*); + + template + using ReadStreamerLoop = CollectionLooper::ReadStreamerLoop; + template + using WriteStreamerLoop = CollectionLooper::WriteStreamerLoop; template static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config) @@ -3685,6 +3741,12 @@ static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TSt case TStreamerInfo::kCacheDelete: case TStreamerInfo::kSTL: return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info, i, compinfo) ); case TStreamerInfo::kBase: return TConfiguredAction( Looper::ReadBase, new TGenericConfiguration(info, i, compinfo) ); + case TStreamerInfo::kStreamLoop: + case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: { + bool isPtrPtr = (strstr(compinfo->fElem->GetTypeName(), "**") != 0); + return TConfiguredAction(Looper::template ReadStreamerLoop::Action, + new TConfStreamerLoop(info, i, compinfo, offset, isPtrPtr)); + } case TStreamerInfo::kStreamer: if (info->GetOldVersion() >= 3) return TConfiguredAction( Looper::ReadStreamerCase, new TGenericConfiguration(info, i, compinfo) ); @@ -4568,9 +4630,12 @@ void TStreamerInfo::AddReadAction(TStreamerInfoActions::TActionSequence *readSeq break; } case TStreamerInfo::kStreamLoop: - case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: - readSequence->AddAction( ScalarLooper::ReadStreamerLoop, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); + case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: { + bool isPtrPtr = (strstr(compinfo->fElem->GetTypeName(), "**") != 0); + readSequence->AddAction(ScalarLooper::ReadStreamerLoop::Action, + new TConfStreamerLoop(this, i, compinfo, compinfo->fOffset, isPtrPtr)); break; + } case TStreamerInfo::kBase: if (compinfo->fStreamer) readSequence->AddAction( ReadStreamerCase, new TGenericConfiguration(this,i,compinfo, compinfo->fOffset) ); @@ -4666,10 +4731,12 @@ void TStreamerInfo::AddReadTextAction(TStreamerInfoActions::TActionSequence *rea break; case TStreamerInfo::kStreamLoop: - case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: - readSequence->AddAction(ScalarLooper::ReadStreamerLoop, new TConfiguration(this, i, compinfo, compinfo->fOffset)); + case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: { + bool isPtrPtr = (strstr(compinfo->fElem->GetTypeName(), "**") != 0); + readSequence->AddAction(ScalarLooper::ReadStreamerLoop::Action, + new TConfStreamerLoop(this, i, compinfo, compinfo->fOffset, isPtrPtr)); break; - + } case TStreamerInfo::kBase: isBase = kTRUE; break; case TStreamerInfo::kStreamer: @@ -4892,9 +4959,12 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS case TStreamerInfo::kTString: writeSequence->AddAction( WriteTString, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; case TStreamerInfo::kStreamLoop: - case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: - writeSequence->AddAction( ScalarLooper::WriteStreamerLoop, new TGenericConfiguration(this, i, compinfo, compinfo->fOffset) ); + case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: { + bool isPtrPtr = (strstr(compinfo->fElem->GetTypeName(), "**") != 0); + writeSequence->AddAction(ScalarLooper::WriteStreamerLoop::Action, + new TConfStreamerLoop(this, i, compinfo, compinfo->fOffset, isPtrPtr)); break; + } case TStreamerInfo::kBase: if (compinfo->fStreamer) writeSequence->AddAction( WriteStreamerCase, new TGenericConfiguration(this,i,compinfo, compinfo->fOffset) ); @@ -5047,10 +5117,11 @@ void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *wr break; case TStreamerInfo::kStreamLoop: - case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: - writeSequence->AddAction(ScalarLooper::WriteStreamerLoop, new TConfiguration(this, i, compinfo, compinfo->fOffset)); + case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: { + bool isPtrPtr = (strstr(compinfo->fElem->GetTypeName(), "**") != 0); + writeSequence->AddAction(ScalarLooper::WriteStreamerLoop::Action, new TConfStreamerLoop(this, i, compinfo, compinfo->fOffset, isPtrPtr)); break; - + } case TStreamerInfo::kBase: isBase = kTRUE; break; case TStreamerInfo::kStreamer: From f4736f7682cc5c1f28ee761db0c817017916abc3 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 21:15:54 -0600 Subject: [PATCH 30/46] NFC: remove trailing semi colon --- io/io/src/TStreamerInfoActions.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 48b4efa268279..b3e41e23028cd 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -203,7 +203,7 @@ namespace TStreamerInfoActions TClass *onfileClass, TClass *inMemoryClass) : TConfiguration(info, id, compinfo, offset), fOnfileClass(onfileClass), - fInMemoryClass(inMemoryClass ? inMemoryClass : onfileClass) {}; + fInMemoryClass(inMemoryClass ? inMemoryClass : onfileClass) {} TConfiguration *Copy() override { return new TConfObject(*this); } }; From 35cebb3e455696c89e34376842ce23a3e89df99f Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 21:20:42 -0600 Subject: [PATCH 31/46] io actions: Add creation of subsequence. We need to go with a specific action that hold the sub sequence (sequence for a base class) rather than insert of the action directly into the main sequence as (currently) the splicing of the action sequences needed to implemenent the split streaming in TTree relies on the order/index of the elements --- io/io/inc/TStreamerInfoActions.h | 2 + io/io/src/TStreamerInfoActions.cxx | 128 +++++++++++++++++++++++------ 2 files changed, 107 insertions(+), 23 deletions(-) diff --git a/io/io/inc/TStreamerInfoActions.h b/io/io/inc/TStreamerInfoActions.h index dfbaeec9db216..40f2ac9cf8419 100644 --- a/io/io/inc/TStreamerInfoActions.h +++ b/io/io/inc/TStreamerInfoActions.h @@ -216,7 +216,9 @@ namespace TStreamerInfoActions { TActionSequence *CreateCopy(); static TActionSequence *CreateReadMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy); + static TActionSequence *CreateReadMemberWiseActions(TVirtualStreamerInfo &info, TLoopConfiguration *loopConfig); // 2nd arg should be unique_ptr static TActionSequence *CreateWriteMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy); + static TActionSequence *CreateWriteMemberWiseActions(TVirtualStreamerInfo &info, TLoopConfiguration *loopConfig); // 2nd arg should be unique_ptr TActionSequence *CreateSubSequence(const std::vector &element_ids, size_t offset); TActionSequence *CreateSubSequence(const TIDs &element_ids, size_t offset, SequenceGetter_t create); diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index b3e41e23028cd..0c15394e65a9b 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -207,6 +207,35 @@ namespace TStreamerInfoActions TConfiguration *Copy() override { return new TConfObject(*this); } }; + struct TConfSubSequence : public TConfiguration + { + std::unique_ptr fActions; + + TConfSubSequence(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, + std::unique_ptr actions) : + TConfiguration(info, id, compinfo, offset), + fActions(std::move(actions)) + {} + + TConfSubSequence(const TConfSubSequence &input) : TConfiguration(input), + fActions(input.fActions->CreateCopy()) + {} + + void AddToOffset(Int_t delta) override + { + // Add the (potentially negative) delta to all the configuration's offset. This is used by + // TBranchElement in the case of split sub-object. + + if (fOffset != TVirtualStreamerInfo::kMissing) { + fOffset += delta; + if (fActions) + fActions->AddToOffset(delta); + } + } + + TConfiguration *Copy() override { return new TConfSubSequence(*this); }; + }; + struct TConfStreamerLoop : public TConfiguration { bool fIsPtrPtr = false; // Which are we, an array of objects or an array of pointers to objects? @@ -1596,9 +1625,36 @@ namespace TStreamerInfoActions } } + ESelectLooper SelectLooper(TVirtualCollectionProxy *proxy) + { + if (proxy) + return SelectLooper(*proxy); + else + return kVectorPtrLooper; + } + + template struct CollectionLooper { + static std::unique_ptr + CreateActionSquence(TStreamerInfo &info, TLoopConfiguration *loopConfig) + { + TLoopConfiguration *localLoopConfig = loopConfig ? loopConfig->Copy() : nullptr; + std::unique_ptr actions( + TActionSequence::CreateReadMemberWiseActions(info, localLoopConfig)); + return actions; + } + + static inline Int_t SubSequenceAction(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * /* loopconfig */, const TConfiguration *config) + { + auto conf = (TConfSubSequence*)config; + auto actions = conf->fActions.get(); + // FIXME: need to update the signature of ApplySequence. + buf.ApplySequence(*actions, start, const_cast(end)); + return 0; + } + static inline Int_t ReadStreamerCase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config) { UInt_t pos, count; @@ -2535,6 +2591,13 @@ namespace TStreamerInfoActions template using WriteStreamerLoop = CollectionLooper::WriteStreamerLoop; + static std::unique_ptr + CreateActionSquence(TStreamerInfo &info, TLoopConfiguration *) + { + using unique_ptr = std::unique_ptr; + return unique_ptr(info.GetReadMemberWiseActions(kTRUE)->CreateCopy()); + } + template static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TConfiguration *config) { @@ -2544,6 +2607,15 @@ namespace TStreamerInfoActions return 0; } + static inline Int_t SubSequenceAction(TBuffer &buf, void *start, const void *end, const TConfiguration *config) + { + auto conf = (TConfSubSequence*)config; + auto actions = conf->fActions.get(); + // FIXME: need to update the signature of ApplySequence. + buf.ApplySequenceVecPtr(*actions, start, const_cast(end)); + return 0; + } + template static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *iter, const void *end, const TConfiguration *config) { @@ -3689,7 +3761,9 @@ static TConfiguredAction GetConvertCollectionReadAction(Int_t oldtype, Int_t new } template -static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TStreamerElement *element, Int_t type, UInt_t i, TStreamerInfo::TCompInfo_t *compinfo, Int_t offset) +static TConfiguredAction +GetCollectionReadAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopConfig, TStreamerElement *element, + Int_t type, UInt_t i, TStreamerInfo::TCompInfo_t *compinfo, Int_t offset) { switch (type) { // Read basic types. @@ -4767,10 +4841,10 @@ void TStreamerInfo::AddReadMemberWiseVecPtrAction(TStreamerInfoActions::TActionS if (element->TestBit(TStreamerElement::kWrite)) return; if (element->TestBit(TStreamerElement::kCache)) { - TConfiguredAction action( GetCollectionReadAction(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); + TConfiguredAction action( GetCollectionReadAction(this,nullptr,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); readSequence->AddAction( UseCacheVectorPtrLoop, new TConfigurationUseCache(this,action,element->TestBit(TStreamerElement::kRepeat)) ); } else { - readSequence->AddAction( GetCollectionReadAction(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); + readSequence->AddAction( GetCollectionReadAction(this,nullptr,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); } } @@ -5183,37 +5257,44 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr return new TStreamerInfoActions::TActionSequence(0,0); } - TStreamerInfo *sinfo = static_cast(info); - - UInt_t ndata = info->GetElements()->GetEntriesFast(); - TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(info,ndata); + TLoopConfiguration *loopConfig = nullptr; if (IsDefaultVector(proxy)) { if (proxy.HasPointers()) { + TStreamerInfo *sinfo = static_cast(info); // Instead of the creating a new one let's copy the one from the StreamerInfo. - delete sequence; - - sequence = sinfo->GetReadMemberWiseActions(kTRUE)->CreateCopy(); - - return sequence; + return sinfo->GetReadMemberWiseActions(kTRUE)->CreateCopy(); } // 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(&proxy, increment, /* read */ kTRUE); + loopConfig = 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(&proxy, increment, /* read */ kTRUE); + loopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE); // sequence->fLoopConfig = new TAssocLoopConfig(proxy); } else { - sequence->fLoopConfig = new TGenericLoopConfig(&proxy, /* read */ kTRUE); + loopConfig = new TGenericLoopConfig(&proxy, /* read */ kTRUE); } + + return CreateReadMemberWiseActions(*info, loopConfig); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Create the bundle of the actions necessary for the streaming memberwise of the content described by 'info' into the collection described by 'proxy' + +TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(TVirtualStreamerInfo &info, TLoopConfiguration *loopConfig) +{ + UInt_t ndata = info.GetElements()->GetEntriesFast(); + TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(&info, ndata); + sequence->fLoopConfig = loopConfig; + for (UInt_t i = 0; i < ndata; ++i) { - TStreamerElement *element = (TStreamerElement*) info->GetElements()->At(i); + TStreamerElement *element = (TStreamerElement*) info.GetElements()->At(i); if (!element) { break; } @@ -5242,6 +5323,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr } } + TStreamerInfo *sinfo = static_cast(&info); TStreamerInfo::TCompInfo_t *compinfo = sinfo->fCompFull[i]; Int_t oldType = element->GetType(); @@ -5257,7 +5339,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr oldType += TVirtualStreamerInfo::kSkip; } } - switch (SelectLooper(proxy)) { + switch (SelectLooper(loopConfig ? loopConfig->fProxy : nullptr)) { case kAssociativeLooper: // } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset // || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) { @@ -5266,20 +5348,20 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr case kVectorPtrLooper: // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector. if (element->TestBit(TStreamerElement::kCache)) { - TConfiguredAction action( GetCollectionReadAction(info,element,oldType,i,compinfo,offset) ); - sequence->AddAction( UseCacheVectorLoop, new TConfigurationUseCache(info,action,element->TestBit(TStreamerElement::kRepeat)) ); + TConfiguredAction action( GetCollectionReadAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); + sequence->AddAction( UseCacheVectorLoop, new TConfigurationUseCache(&info,action,element->TestBit(TStreamerElement::kRepeat)) ); } else { - sequence->AddAction( GetCollectionReadAction(info,element,oldType,i,compinfo,offset)); + sequence->AddAction( GetCollectionReadAction(&info,loopConfig,element,oldType,i,compinfo,offset)); } break; case kGenericLooper: default: // The usual collection case. if (element->TestBit(TStreamerElement::kCache)) { - TConfiguredAction action( GetCollectionReadAction(info,element,oldType,i,compinfo,offset) ); - sequence->AddAction( UseCacheGenericCollection, new TConfigurationUseCache(info,action,element->TestBit(TStreamerElement::kRepeat)) ); + TConfiguredAction action( GetCollectionReadAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); + sequence->AddAction( UseCacheGenericCollection, new TConfigurationUseCache(&info,action,element->TestBit(TStreamerElement::kRepeat)) ); } else { - sequence->AddAction( GetCollectionReadAction(info,element,oldType,i,compinfo,offset) ); + sequence->AddAction( GetCollectionReadAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); } break; } From 63c711b082a36bde29b4c0bb2f1c569c9a2b77c1 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 19 Nov 2024 21:21:54 -0600 Subject: [PATCH 32/46] io actions: add kBase to memberwise streaming --- io/io/src/TStreamerInfoActions.cxx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 0c15394e65a9b..fef8e559cedf5 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -3814,7 +3814,19 @@ GetCollectionReadAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopConf case TStreamerInfo::kCacheNew: case TStreamerInfo::kCacheDelete: case TStreamerInfo::kSTL: return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info, i, compinfo) ); - case TStreamerInfo::kBase: return TConfiguredAction( Looper::ReadBase, new TGenericConfiguration(info, i, compinfo) ); + case TStreamerInfo::kBase: { + TStreamerBase *baseEl = dynamic_cast(element); + if (baseEl) { + auto baseinfo = (TStreamerInfo *)baseEl->GetBaseStreamerInfo(); + assert(baseinfo); + TLoopConfiguration *baseLoopConfig = loopConfig ? loopConfig->Copy() : nullptr; + auto baseActions = Looper::CreateActionSquence(*baseinfo, baseLoopConfig); + baseActions->AddToOffset(baseEl->GetOffset()); + return TConfiguredAction( Looper::SubSequenceAction, new TConfSubSequence(info, i, compinfo, 0, std::move(baseActions))); + + } else + return TConfiguredAction( Looper::ReadBase, new TGenericConfiguration(info, i, compinfo) ); + } case TStreamerInfo::kStreamLoop: case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: { bool isPtrPtr = (strstr(compinfo->fElem->GetTypeName(), "**") != 0); From 520b94646999629697def04d912554b5298aeb40 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 08:58:13 -0600 Subject: [PATCH 33/46] io actions: Rename CreateActionSquence to CreateReadActionSquence --- io/io/src/TStreamerInfoActions.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index fef8e559cedf5..1daf50482773e 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -1638,7 +1638,7 @@ namespace TStreamerInfoActions struct CollectionLooper { static std::unique_ptr - CreateActionSquence(TStreamerInfo &info, TLoopConfiguration *loopConfig) + CreateReadActionSquence(TStreamerInfo &info, TLoopConfiguration *loopConfig) { TLoopConfiguration *localLoopConfig = loopConfig ? loopConfig->Copy() : nullptr; std::unique_ptr actions( @@ -2592,7 +2592,7 @@ namespace TStreamerInfoActions using WriteStreamerLoop = CollectionLooper::WriteStreamerLoop; static std::unique_ptr - CreateActionSquence(TStreamerInfo &info, TLoopConfiguration *) + CreateReadActionSquence(TStreamerInfo &info, TLoopConfiguration *) { using unique_ptr = std::unique_ptr; return unique_ptr(info.GetReadMemberWiseActions(kTRUE)->CreateCopy()); @@ -3820,7 +3820,7 @@ GetCollectionReadAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopConf auto baseinfo = (TStreamerInfo *)baseEl->GetBaseStreamerInfo(); assert(baseinfo); TLoopConfiguration *baseLoopConfig = loopConfig ? loopConfig->Copy() : nullptr; - auto baseActions = Looper::CreateActionSquence(*baseinfo, baseLoopConfig); + auto baseActions = Looper::CreateReadActionSquence(*baseinfo, baseLoopConfig); baseActions->AddToOffset(baseEl->GetOffset()); return TConfiguredAction( Looper::SubSequenceAction, new TConfSubSequence(info, i, compinfo, 0, std::move(baseActions))); From 46749afe20129688458d18014aa85419a5947553 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 09:05:35 -0600 Subject: [PATCH 34/46] io actions: Remove unused comments --- io/io/src/TStreamerInfoActions.cxx | 140 ----------------------------- 1 file changed, 140 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 1daf50482773e..545a956a03eca 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -2283,27 +2283,6 @@ namespace TStreamerInfoActions } ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, arrptr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 ); delete [] arrptr; - - // // Idea: need to cache this result! - // TStreamerInfo *info = (TStreamerInfo*)config->fInfo; - // TStreamerElement *aElement = (TStreamerElement*)info->GetElem(config->fElemId); - // - // *Int_t clversion = ((TStreamerBase*)aElement)->Get BaseVersion(); - // *TClass *cle = aElement->GetNewBaseClass(); - // *(TSequence *actions = CreateReadMemberWiseActions( cle->GetStreamerInfo(clversion), ???? ); - // - // TSequence *actions = CreateReadMemberWiseActions( ((TStreamerBase*)aElement)->GetBaseStreamerInfo(), ???? ); - // - // actions->ReadBuffer(b,start,end); - // delete actions; - - // const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement; - // for(void *iter = start; iter != end; iter = (char*)iter + incr ) - // { - // ((TStreamerInfo*)(((TStreamerBase*)aElement)->GetBaseStreamerInfo())->ReadBuffer(b,arr,-1,narr,ioffset,arrayMode); - // - // ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, (char**)&iter, config->fElemId, 1, config->fOffset, 1|2 ); - // } return 0; } @@ -5245,19 +5224,7 @@ void TStreamerInfo::AddWriteMemberWiseVecPtrAction(TStreamerInfoActions::TAction // Skip artificial element used for reading purposes. return; } - -#if defined(CDJ_NO_COMPILE) - if (element->TestBit(TStreamerElement::kCache)) { - TConfiguredAction action( GetCollectionWriteAction(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); - writeSequence->AddAction( UseCacheVectorPtrLoop, new TConfigurationUseCache(this,action,element->TestBit(TStreamerElement::kRepeat)) ); - } else { - writeSequence->Addaction( GetCollectionWriteAction(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); - } -#else writeSequence->AddAction( GetCollectionWriteAction(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); - // writeSequence->AddAction( VectorPtrLooper::GenericWrite, new TGenericConfiguration(this,i,compinfo) ); -#endif - } //////////////////////////////////////////////////////////////////////////////// @@ -5408,12 +5375,6 @@ 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(&proxy, increment, /* read */ kFALSE); - /*} else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset - || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) - { - Long_t increment = proxy.GetIncrement(); - sequence->fLoopConfig = new TVectorLoopConfig(increment); - // sequence->fLoopConfig = new TAssocLoopConfig(proxy); */ } else { sequence->fLoopConfig = new TGenericLoopConfig(&proxy, /* read */ kFALSE); } @@ -5441,105 +5402,6 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr TStreamerInfo::TCompInfo *compinfo = sinfo->fCompFull[i]; Int_t oldType = element->GetType(); Int_t offset = element->GetOffset(); -#if defined(CDJ_NO_COMPILE) - Int_t newType = element->GetNewType(); - - if (newType != oldType) { - if (newType > 0) { - if (oldType != TVirtualStreamerInfo::kCounter) { - oldType += TVirtualStreamerInfo::kConv; - } - } else { - oldType += TVirtualStreamerInfo::kSkip; - } - } - if ( IsDefaultVector(proxy) - /*|| (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset - || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) */ ) - { - - // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector. - if (element->TestBit(TStreamerElement::kCache)) { - TConfiguredAction action( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); - sequence->AddAction( UseCacheVectorLoop, new TConfigurationUseCache(info,action,element->TestBit(TStreamerElement::kRepeat)) ); - } else { - sequence->AddAction(GetCollectionWriteAction(info,element,oldType,i,compinfo,offset)); - } - - // } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset - // || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) { - // sequence->AddAction( GenericAssocCollectionAction, new TConfigSTL(false, info,i,compinfo,offset,0,proxy.GetCollectionClass(),0,0) ); - } else { - // The usual collection case. - if (element->TestBit(TStreamerElement::kCache)) { - TConfiguredAction action( GetWriteAction(info,element,oldType,i,compinfo,offset) ); - sequence->AddAction( UseCacheGenericCollection, new TConfigurationUseCache(info,action,element->TestBit(TStreamerElement::kRepeat)) ); - } else { - switch (oldType) { - // read basic types - case TVirtualStreamerInfo::kBool: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kChar: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kShort: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kInt: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kLong: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kLong64: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kFloat: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kDouble: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kUChar: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kUShort: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kUInt: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kULong: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kULong64: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - // case TVirtualStreamerInfo::kBits: sequence->AddAction( WriteBasicTypeGenericLoop, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kFloat16: { - if (element->GetFactor() != 0) { - sequence->AddAction( GenericLooper >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); - } else { - Int_t nbits = (Int_t)element->GetXmin(); - if (!nbits) nbits = 12; - sequence->AddAction( GenericLooper >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); - } - break; - } - case TVirtualStreamerInfo::kDouble32: { - if (element->GetFactor() != 0) { - sequence->AddAction( GenericLooper >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) ); - } else { - Int_t nbits = (Int_t)element->GetXmin(); - if (!nbits) { - sequence->AddAction( GenericLooper >, new TConfiguration(info,i,compinfo,offset) ); - } else { - sequence->AddAction( GenericLooper >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); - } - } - break; - } - case TVirtualStreamerInfo::kTNamed: sequence->AddAction( GenericLooper, new TConfiguration(info,i,compinfo,offset) ); break; - // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the - // Streamer alltogether. - case TVirtualStreamerInfo::kTObject: sequence->AddAction( GenericLooper, new TConfiguration(info,i,compinfo,offset) ); break; - case TVirtualStreamerInfo::kTString: sequence->AddAction( GenericLooper, new TConfiguration(info,i,compinfo,offset) ); break; - default: - sequence->AddAction( GenericCollectionWriteAction, new TConfigSTL(false, info,i,0 /* the offset will be used from TStreamerInfo */,0,proxy.GetCollectionClass(),0,0) ); - break; - } - } - } -#else -#if 0 - if ( IsDefaultVector(proxy) - /*|| (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset - || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap)*/ ) - { - sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); - } else { - // NOTE: TBranch::FillLeavesCollection[Member] is not yet ready to handle the sequence - // as it does not create/use a TStaging as expected ... but then again it might - // not be the right things to expect ... - // sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); - sequence->AddAction( GenericLooper::GenericWrite, new TConfigSTL(false, info,i,compinfo,0 /* the offset will be used from TStreamerInfo */,0,proxy.GetCollectionClass(),0,0) ); - } -#else switch (SelectLooper(proxy)) { case kAssociativeLooper: sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); @@ -5555,8 +5417,6 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); break; } -#endif -#endif } return sequence; } From 128d8ff7202b7ddb4ac0d4835b1a1502b906149e Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 09:11:49 -0600 Subject: [PATCH 35/46] NFC: Correct indentation --- io/io/src/TStreamerInfoActions.cxx | 118 ++++++++++++++--------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 545a956a03eca..21917c8c2e9a7 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -5353,72 +5353,72 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateWriteMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy) { - if (info == 0) { - return new TStreamerInfoActions::TActionSequence(0,0); - } + if (info == 0) { + return new TStreamerInfoActions::TActionSequence(0,0); + } - UInt_t ndata = info->GetElements()->GetEntriesFast(); - TStreamerInfo *sinfo = static_cast(info); - TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(info,ndata); + UInt_t ndata = info->GetElements()->GetEntriesFast(); + TStreamerInfo *sinfo = static_cast(info); + TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(info,ndata); - if (IsDefaultVector(proxy)) - { - if (proxy.HasPointers()) { - // Instead of the creating a new one let's copy the one from the StreamerInfo. - delete sequence; + if (IsDefaultVector(proxy)) + { + if (proxy.HasPointers()) { + // Instead of the creating a new one let's copy the one from the StreamerInfo. + delete sequence; - sequence = sinfo->GetWriteMemberWiseActions(kTRUE)->CreateCopy(); + sequence = sinfo->GetWriteMemberWiseActions(kTRUE)->CreateCopy(); - return sequence; - } + return sequence; + } - // 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(&proxy, increment, /* read */ kFALSE); - } else { - sequence->fLoopConfig = new TGenericLoopConfig(&proxy, /* read */ kFALSE); + // 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(&proxy, increment, /* read */ kFALSE); + } else { + sequence->fLoopConfig = new TGenericLoopConfig(&proxy, /* read */ kFALSE); + } + for (UInt_t i = 0; i < ndata; ++i) { + TStreamerElement *element = (TStreamerElement*) info->GetElements()->At(i); + if (!element) { + break; } - for (UInt_t i = 0; i < ndata; ++i) { - TStreamerElement *element = (TStreamerElement*) info->GetElements()->At(i); - if (!element) { - break; - } - if (element->GetType() < 0) { - // -- Skip an ignored TObject base class. - // Note: The only allowed negative value here is -1, and signifies that Build() has found a TObject - // base class and TClass::IgnoreTObjectStreamer() was called. In this case the compiled version of the - // elements omits the TObject base class element, which has to be compensated for by TTree::Bronch() - // when it is making branches for a split object. - continue; - } - if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) { - // Skip element cached for reading purposes. - continue; - } - if (element->GetType() >= TVirtualStreamerInfo::kArtificial && !element->TestBit(TStreamerElement::kWrite)) { - // Skip artificial element used for reading purposes. - continue; - } - TStreamerInfo::TCompInfo *compinfo = sinfo->fCompFull[i]; - Int_t oldType = element->GetType(); - Int_t offset = element->GetOffset(); - switch (SelectLooper(proxy)) { - case kAssociativeLooper: - sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); - break; - case kVectorLooper: - sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); - break; - case kVectorPtrLooper: - sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); - break; - case kGenericLooper: - default: - sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); - break; - } + if (element->GetType() < 0) { + // -- Skip an ignored TObject base class. + // Note: The only allowed negative value here is -1, and signifies that Build() has found a TObject + // base class and TClass::IgnoreTObjectStreamer() was called. In this case the compiled version of the + // elements omits the TObject base class element, which has to be compensated for by TTree::Bronch() + // when it is making branches for a split object. + continue; } - return sequence; + if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) { + // Skip element cached for reading purposes. + continue; + } + if (element->GetType() >= TVirtualStreamerInfo::kArtificial && !element->TestBit(TStreamerElement::kWrite)) { + // Skip artificial element used for reading purposes. + continue; + } + TStreamerInfo::TCompInfo *compinfo = sinfo->fCompFull[i]; + Int_t oldType = element->GetType(); + Int_t offset = element->GetOffset(); + switch (SelectLooper(proxy)) { + case kAssociativeLooper: + sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + break; + case kVectorLooper: + sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + break; + case kVectorPtrLooper: + sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + break; + case kGenericLooper: + default: + sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + break; + } + } + return sequence; } void TStreamerInfoActions::TActionSequence::AddToOffset(Int_t delta) From b168e374ff34e6ab487ab937c2c010002b736084 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 09:26:10 -0600 Subject: [PATCH 36/46] io actions: Add creation of write subsequence. --- io/io/src/TStreamerInfoActions.cxx | 64 +++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 21917c8c2e9a7..4561f9069b1de 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -1646,6 +1646,15 @@ namespace TStreamerInfoActions return actions; } + static std::unique_ptr + CreateWriteActionSquence(TStreamerInfo &info, TLoopConfiguration *loopConfig) + { + TLoopConfiguration *localLoopConfig = loopConfig ? loopConfig->Copy() : nullptr; + std::unique_ptr actions( + TActionSequence::CreateWriteMemberWiseActions(info, localLoopConfig)); + return actions; + } + static inline Int_t SubSequenceAction(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * /* loopconfig */, const TConfiguration *config) { auto conf = (TConfSubSequence*)config; @@ -2577,6 +2586,13 @@ namespace TStreamerInfoActions return unique_ptr(info.GetReadMemberWiseActions(kTRUE)->CreateCopy()); } + static std::unique_ptr + CreateWriteActionSquence(TStreamerInfo &info, TLoopConfiguration *) + { + using unique_ptr = std::unique_ptr; + return unique_ptr(info.GetWriteMemberWiseActions(kTRUE)->CreateCopy()); + } + template static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TConfiguration *config) { @@ -4020,7 +4036,10 @@ static TConfiguredAction GetCollectionWriteConvertAction(Int_t newtype, TConfigu } template -static TConfiguredAction GetCollectionWriteAction(TVirtualStreamerInfo *info, TStreamerElement *element, Int_t type, UInt_t i, TStreamerInfo::TCompInfo_t *compinfo, Int_t offset) { +static TConfiguredAction +GetCollectionWriteAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopConfig, TStreamerElement *element, + Int_t type, UInt_t i, TStreamerInfo::TCompInfo_t *compinfo, Int_t offset) +{ switch (type) { // write basic types case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; @@ -5224,7 +5243,7 @@ void TStreamerInfo::AddWriteMemberWiseVecPtrAction(TStreamerInfoActions::TAction // Skip artificial element used for reading purposes. return; } - writeSequence->AddAction( GetCollectionWriteAction(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); + writeSequence->AddAction( GetCollectionWriteAction(this,nullptr,element,compinfo->fType,i,compinfo,compinfo->fOffset) ); } //////////////////////////////////////////////////////////////////////////////// @@ -5357,29 +5376,35 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr return new TStreamerInfoActions::TActionSequence(0,0); } - UInt_t ndata = info->GetElements()->GetEntriesFast(); - TStreamerInfo *sinfo = static_cast(info); - TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(info,ndata); - + TLoopConfiguration *loopConfig = nullptr; if (IsDefaultVector(proxy)) { if (proxy.HasPointers()) { + TStreamerInfo *sinfo = static_cast(info); // Instead of the creating a new one let's copy the one from the StreamerInfo. - delete sequence; - - sequence = sinfo->GetWriteMemberWiseActions(kTRUE)->CreateCopy(); - - return sequence; + return sinfo->GetWriteMemberWiseActions(kTRUE)->CreateCopy(); } // 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(&proxy, increment, /* read */ kFALSE); + loopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kFALSE); } else { - sequence->fLoopConfig = new TGenericLoopConfig(&proxy, /* read */ kFALSE); + loopConfig = new TGenericLoopConfig(&proxy, /* read */ kFALSE); } + return CreateWriteMemberWiseActions(*info, loopConfig); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Create the bundle of the actions necessary for the streaming memberwise of the content described by 'info' into the collection described by 'proxy' + +TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateWriteMemberWiseActions(TVirtualStreamerInfo &info, TLoopConfiguration *loopConfig) +{ + UInt_t ndata = info.GetElements()->GetEntriesFast(); + TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(&info, ndata); + sequence->fLoopConfig = loopConfig; + for (UInt_t i = 0; i < ndata; ++i) { - TStreamerElement *element = (TStreamerElement*) info->GetElements()->At(i); + TStreamerElement *element = (TStreamerElement*) info.GetElements()->At(i); if (!element) { break; } @@ -5399,22 +5424,23 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr // Skip artificial element used for reading purposes. continue; } + TStreamerInfo *sinfo = static_cast(&info); TStreamerInfo::TCompInfo *compinfo = sinfo->fCompFull[i]; Int_t oldType = element->GetType(); Int_t offset = element->GetOffset(); - switch (SelectLooper(proxy)) { + switch (SelectLooper(loopConfig ? loopConfig->fProxy : nullptr)) { case kAssociativeLooper: - sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); break; case kVectorLooper: - sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); break; case kVectorPtrLooper: - sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); break; case kGenericLooper: default: - sequence->AddAction( GetCollectionWriteAction(info,element,oldType,i,compinfo,offset) ); + sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); break; } } From 74f5825352bf44e2dfa9fabde31b9ab1184eb34d Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 12:15:58 -0600 Subject: [PATCH 37/46] io actions: add kBase to write memberwise streaming --- io/io/src/TStreamerInfoActions.cxx | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 4561f9069b1de..2425cdf8068e9 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -2295,6 +2295,23 @@ namespace TStreamerInfoActions return 0; } + static INLINE_TEMPLATE_ARGS Int_t WriteBase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config) + { + // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now + // punt. + + UInt_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement; + UInt_t n = (((char*)end)-((char*)start))/incr; + char **arrptr = new char*[n]; + UInt_t i = 0; + for(void *iter = start; iter != end; iter = (char*)iter + incr, ++i ) { + arrptr[i] = (char*)iter; + } + ((TStreamerInfo*)config->fInfo)->WriteBufferAux(buf, arrptr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 ); + delete [] arrptr; + return 0; + } + static INLINE_TEMPLATE_ARGS Int_t GenericRead(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config) { // Well the implementation is non trivial. For now punt. @@ -2760,6 +2777,14 @@ namespace TStreamerInfoActions return GenericRead(buf,start,end,config); } + static INLINE_TEMPLATE_ARGS Int_t WriteBase(TBuffer &buf, void *start, const void *end, const TConfiguration *config) + { + // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now + // punt. + + return GenericWrite(buf,start,end,config); + } + static inline Int_t ReadStreamerCase(TBuffer &buf, void *start, const void *end, const TConfiguration *config) { UInt_t pos, count; @@ -3395,6 +3420,14 @@ namespace TStreamerInfoActions return GenericRead(buf,start,end,loopconfig, config); } + static INLINE_TEMPLATE_ARGS Int_t WriteBase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config) + { + // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now + // punt. + + return GenericWrite(buf,start,end,loopconfig, config); + } + static INLINE_TEMPLATE_ARGS Int_t GenericRead(TBuffer &buf, void *, const void *, const TLoopConfiguration * loopconf, const TConfiguration *config) { TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf; @@ -4132,7 +4165,19 @@ GetCollectionWriteAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopCon // Streamer alltogether. case TStreamerInfo::kTObject: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; case TStreamerInfo::kTString: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kBase: { + TStreamerBase *baseEl = dynamic_cast(element); + if (baseEl) { + auto baseinfo = (TStreamerInfo *)baseEl->GetBaseStreamerInfo(); + assert(baseinfo); + TLoopConfiguration *baseLoopConfig = loopConfig ? loopConfig->Copy() : nullptr; + auto baseActions = Looper::CreateWriteActionSquence(*baseinfo, baseLoopConfig); + baseActions->AddToOffset(baseEl->GetOffset()); + return TConfiguredAction( Looper::SubSequenceAction, new TConfSubSequence(info, i, compinfo, 0, std::move(baseActions))); + } else + return TConfiguredAction( Looper::WriteBase, new TGenericConfiguration(info, i, compinfo) ); + } default: return TConfiguredAction( Looper::GenericWrite, new TConfiguration(info,i,compinfo,0 /* 0 because we call the legacy code */) ); } From 0dd2f6cbfadaaac0ad681d92ebd1fe5bfe61a67c Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 12:16:27 -0600 Subject: [PATCH 38/46] io actions: add kStreamer to write memberwise streaming --- io/io/src/TStreamerInfoActions.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 2425cdf8068e9..d670ed687f602 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -4178,6 +4178,11 @@ GetCollectionWriteAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopCon } else return TConfiguredAction( Looper::WriteBase, new TGenericConfiguration(info, i, compinfo) ); } + case TStreamerInfo::kStreamer: + if (info->GetOldVersion() >= 3) + return TConfiguredAction( Looper::WriteStreamerCase, new TGenericConfiguration(info, i, compinfo) ); + else + return TConfiguredAction( Looper::GenericWrite, new TGenericConfiguration(info, i, compinfo) ); default: return TConfiguredAction( Looper::GenericWrite, new TConfiguration(info,i,compinfo,0 /* 0 because we call the legacy code */) ); } From f0c362bf1afe427aa4c1d94553a2fc99b4673ced Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 12:16:40 -0600 Subject: [PATCH 39/46] io actions: add kStreamLoop to write memberwise streaming --- io/io/src/TStreamerInfoActions.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index d670ed687f602..05dfff5486b13 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -4178,6 +4178,12 @@ GetCollectionWriteAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopCon } else return TConfiguredAction( Looper::WriteBase, new TGenericConfiguration(info, i, compinfo) ); } + case TStreamerInfo::kStreamLoop: + case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: { + bool isPtrPtr = (strstr(compinfo->fElem->GetTypeName(), "**") != 0); + return TConfiguredAction(Looper::template WriteStreamerLoop::Action, + new TConfStreamerLoop(info, i, compinfo, offset, isPtrPtr)); + } case TStreamerInfo::kStreamer: if (info->GetOldVersion() >= 3) return TConfiguredAction( Looper::WriteStreamerCase, new TGenericConfiguration(info, i, compinfo) ); From 8fa3a8654a61b664588dc448db8e607291c432a7 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 12:16:52 -0600 Subject: [PATCH 40/46] io actions: add kAny to write memberwise streaming --- io/io/src/TStreamerInfoActions.cxx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 05dfff5486b13..073b63ab80950 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -4189,6 +4189,19 @@ GetCollectionWriteAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopCon return TConfiguredAction( Looper::WriteStreamerCase, new TGenericConfiguration(info, i, compinfo) ); else return TConfiguredAction( Looper::GenericWrite, new TGenericConfiguration(info, i, compinfo) ); + case TStreamerInfo::kAny: + if (compinfo->fStreamer) + return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info, i, compinfo,offset) ); + else { + if (compinfo->fNewClass && compinfo->fNewClass->HasDirectStreamerInfoUse()) + return TConfiguredAction( Looper::template LoopOverCollection, + new TConfObject(info, i, compinfo, compinfo->fOffset, compinfo->fClass, compinfo->fNewClass) ); + else if (compinfo->fClass && compinfo->fClass->HasDirectStreamerInfoUse()) + return TConfiguredAction( Looper::template LoopOverCollection, + new TConfObject(info, i, compinfo, compinfo->fOffset, compinfo->fClass, nullptr) ); + else // Use the slower path for unusual cases + return TConfiguredAction( Looper::GenericWrite, new TGenericConfiguration(info, i, compinfo) ); + } default: return TConfiguredAction( Looper::GenericWrite, new TConfiguration(info,i,compinfo,0 /* 0 because we call the legacy code */) ); } From fad599cea29fcf8b5d2ea1d01374ac7b6a58954b Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 17:39:47 -0600 Subject: [PATCH 41/46] io actions: memberwise write add support for conv and missing --- io/io/src/TStreamerInfoActions.cxx | 37 ++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 073b63ab80950..2cfb6848f94ba 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -5398,6 +5398,8 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr Int_t offset = element->GetOffset(); if (newType != oldType) { + // This 'prevents' the switch from base class (kBase (0)) to + // anything else. if (newType > 0) { if (oldType != TVirtualStreamerInfo::kCounter) { oldType += TVirtualStreamerInfo::kConv; @@ -5495,21 +5497,46 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr } TStreamerInfo *sinfo = static_cast(&info); TStreamerInfo::TCompInfo *compinfo = sinfo->fCompFull[i]; - Int_t oldType = element->GetType(); + Int_t onfileType = element->GetType(); + Int_t memoryType = element->GetNewType(); + if (memoryType != onfileType) { + // This 'prevents' the switch from base class (kBase (0)) to + // anything else. + if (memoryType > 0) { + if (onfileType != TVirtualStreamerInfo::kCounter) { + onfileType += TVirtualStreamerInfo::kConv; + } + } else { + // When reading we need to consume the data in the onfile buffer, + // so we do create a 'Skip' action for the missing elements. + // When writing we should probably write a default value, for + // now let's just ignore the request. + // We could issue an error here but we might too often issue a + // 'false positive' if the user only reads. + // FIXME: The 'right' solution is to add a new action that first print + // once the following error message: + // + // info.Error("TActionSequence::CreateWriteMemberWiseActions", + // "Ignoring request to write the missing data member %s in %s version %d checksum 0x%x", + // element->GetName(), info.GetName(), info.GetClassVersion(), info.GetCheckSum()); + continue; + } + } + Int_t offset = element->GetOffset(); switch (SelectLooper(loopConfig ? loopConfig->fProxy : nullptr)) { case kAssociativeLooper: - sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); + sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,onfileType,i,compinfo,offset) ); break; case kVectorLooper: - sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); + sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,onfileType,i,compinfo,offset) ); break; case kVectorPtrLooper: - sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); + sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,onfileType,i,compinfo,offset) ); break; case kGenericLooper: default: - sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,oldType,i,compinfo,offset) ); + sequence->AddAction( GetCollectionWriteAction(&info,loopConfig,element,onfileType,i,compinfo,offset) ); break; } } From dbd368eed41d734339bde45fac1d59ab2cdf0451 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 20:47:07 -0600 Subject: [PATCH 42/46] io actions: Remove unreachable break statement --- io/io/src/TStreamerInfoActions.cxx | 244 ++++++++++++----------------- 1 file changed, 97 insertions(+), 147 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 2cfb6848f94ba..08c6a411895a0 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -3615,25 +3615,24 @@ template static TConfiguredAction GetCollectionReadConvertAction(Int_t newtype, TConfiguration *conf) { switch (newtype) { - case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kFloat16: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kDouble32:return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kBits: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); break; + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kFloat16: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kDouble32:return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); + case TStreamerInfo::kBits: return TConfiguredAction( Looper::template ConvertBasicType::Action, conf ); default: return TConfiguredAction( Looper::GenericRead, conf ); - break; } R__ASSERT(0); // We should never be here return TConfiguredAction(); @@ -3648,19 +3647,19 @@ static TConfiguredAction GetNumericCollectionReadAction(Int_t type, TConfigSTL * // Read basic types. // Because of std::vector of bool is not backed up by an array of bool we have to converted it first. - case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; - case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ReadCollectionBasicType,conf ); break; - case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; - case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; - case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; - case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; - case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; - case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; - case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; - case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; - case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; - case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); break; + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ReadCollectionBasicType,conf ); + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ReadCollectionBasicType, conf ); case TStreamerInfo::kBits: Error("GetNumericCollectionReadAction","There is no support for kBits outside of a TObject."); break; case TStreamerInfo::kFloat16: { TConfigSTL *alternate = new TConfSTLNoFactor(conf,12); @@ -3673,7 +3672,6 @@ static TConfiguredAction GetNumericCollectionReadAction(Int_t type, TConfigSTL * // if (!nbits) nbits = 12; // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); // } - break; } case TStreamerInfo::kDouble32: { TConfigSTL *alternate = new TConfSTLNoFactor(conf,0); @@ -3689,7 +3687,6 @@ static TConfiguredAction GetNumericCollectionReadAction(Int_t type, TConfigSTL * // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); // } // } - break; } } Fatal("GetNumericCollectionReadAction","Is confused about %d",type); @@ -3701,22 +3698,22 @@ template static TConfiguredAction GetConvertCollectionReadActionFrom(Int_t newtype, TConfiguration *conf) { switch (newtype) { - case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kFloat16: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kDouble32:return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kBits: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); break; + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kFloat16: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kDouble32:return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kBits: return TConfiguredAction( Looper::template ConvertCollectionBasicType::Action, conf ); default: break; } @@ -3734,49 +3731,34 @@ static TConfiguredAction GetConvertCollectionReadAction(Int_t oldtype, Int_t new switch (oldtype) { case TStreamerInfo::kBool: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kChar: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kShort: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kInt: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kLong: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kLong64: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kFloat: return GetConvertCollectionReadActionFrom( newtype, conf ); - break; case TStreamerInfo::kDouble: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kUChar: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kUShort: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kUInt: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kULong: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kULong64: return GetConvertCollectionReadActionFrom(newtype, conf ); - break; case TStreamerInfo::kFloat16: return GetConvertCollectionReadActionFrom >( newtype, conf ); - break; case TStreamerInfo::kDouble32: return GetConvertCollectionReadActionFrom >( newtype, conf ); - break; case TStreamerInfo::kBits: Error("GetConvertCollectionReadAction","There is no support for kBits outside of a TObject."); break; @@ -3961,11 +3943,11 @@ static TConfiguredAction GetConvertCollectionWriteActionFrom(Int_t onfileType, T case TStreamerInfo::kFloat16: Error("GetConvertCollectionWriteActionFrom", "Write Conversion to Float16_t not yet supported"); return TConfiguredAction(); - // return TConfiguredAction( Looper::template WriteConvertCollectionBasicType>::Action, conf ); break; + // return TConfiguredAction( Looper::template WriteConvertCollectionBasicType>::Action, conf ); case TStreamerInfo::kDouble32: Error("GetConvertCollectionWriteActionFrom", "Write Conversion to Double32_t not yet supported"); return TConfiguredAction(); - // return TConfiguredAction( Looper::template WriteConvertCollectionBasicType>::Action, conf ); break; + // return TConfiguredAction( Looper::template WriteConvertCollectionBasicType>::Action, conf ); default: break; } @@ -3983,49 +3965,34 @@ static TConfiguredAction GetConvertCollectionWriteAction(Int_t onfileType, Int_t switch (memoryType) { case TStreamerInfo::kBool: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kChar: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kShort: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kInt: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kLong: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kLong64: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kFloat: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kDouble: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kUChar: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kUShort: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kUInt: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kULong: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kULong64: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kFloat16: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kDouble32: return GetConvertCollectionWriteActionFrom(onfileType, conf ); - break; case TStreamerInfo::kBits: Error("GetConvertCollectionWriteActionFrom","There is no support for kBits outside of a TObject."); break; @@ -4044,25 +4011,24 @@ template static TConfiguredAction GetCollectionWriteConvertAction(Int_t newtype, TConfiguration *conf) { switch (newtype) { - case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kFloat16: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kDouble32:return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kBits: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kFloat16: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kDouble32:return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); + case TStreamerInfo::kBits: return TConfiguredAction( Looper::template WriteConvertBasicType::Action, conf ); default: return TConfiguredAction( Looper::GenericRead, conf ); - break; } R__ASSERT(0); // We should never be here return TConfiguredAction(); @@ -4075,67 +4041,53 @@ GetCollectionWriteAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopCon { switch (type) { // write basic types - case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteBasicType,new TConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteBasicType, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteBasicType,new TConfiguration(info,i,compinfo,offset) ); // the simple type missing are kBits and kCounter. // Conversions. case TStreamerInfo::kConv + TStreamerInfo::kBool: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kChar: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kShort: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kInt: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kLong: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kLong64: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kFloat: return GetCollectionWriteConvertAction( element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kDouble: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kUChar: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kUShort: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kUInt: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kULong: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; case TStreamerInfo::kConv + TStreamerInfo::kULong64: return GetCollectionWriteConvertAction(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) ); - break; #ifdef NOT_YET /* The conversion writing acceleration was not yet written for kBits */ case TStreamerInfo::kConv + TStreamerInfo::kBits: return GetCollectionWriteConvertAction(element->GetNewType(), new TBitsConfiguration(info,i,compinfo,offset) ); - break; #endif case TStreamerInfo::kConv + TStreamerInfo::kFloat16: { if (element->GetFactor() != 0) { @@ -4160,11 +4112,11 @@ GetCollectionWriteAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopCon } break; } - case TStreamerInfo::kTNamed: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kTNamed: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the // Streamer alltogether. - case TStreamerInfo::kTObject: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; - case TStreamerInfo::kTString: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); break; + case TStreamerInfo::kTObject: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kTString: return TConfiguredAction( Looper::template LoopOverCollection, new TConfiguration(info,i,compinfo,offset) ); case TStreamerInfo::kBase: { TStreamerBase *baseEl = dynamic_cast(element); if (baseEl) { @@ -4217,19 +4169,19 @@ static TConfiguredAction GetNumericCollectionWriteAction(Int_t type, TConfigSTL switch (type) { // Write basic types. // Because of std::vector of bool is not backed up by an array of bool we have to converted it first. - case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); break; - case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; - case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteCollectionBasicType,conf ); break; - case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; - case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; - case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; - case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; - case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; - case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; - case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; - case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; - case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; - case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); break; + case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteConvertCollectionBasicType::Action, conf ); + case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); + case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteCollectionBasicType,conf ); + case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); + case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); + case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); + case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); + case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); + case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); + case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); + case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); + case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); + case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteCollectionBasicType, conf ); case TStreamerInfo::kBits: Error("GetNumericCollectionWriteAction","There is no support for kBits outside of a TObject."); break; case TStreamerInfo::kFloat16: { TConfigSTL *alternate = new TConfSTLNoFactor(conf,12); @@ -4242,7 +4194,6 @@ static TConfiguredAction GetNumericCollectionWriteAction(Int_t type, TConfigSTL // if (!nbits) nbits = 12; // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); // } - break; } case TStreamerInfo::kDouble32: { TConfigSTL *alternate = new TConfSTLNoFactor(conf,0); @@ -4258,7 +4209,6 @@ static TConfiguredAction GetNumericCollectionWriteAction(Int_t type, TConfigSTL // return TConfiguredAction( Looper::template LoopOverCollection >, new TConfNoFactor(info,i,compinfo,offset,nbits) ); // } // } - break; } } Fatal("GetNumericCollectionWriteAction","Is confused about %d",type); @@ -4519,7 +4469,7 @@ static void AddReadConvertAction(TStreamerInfoActions::TActionSequence *sequence switch (newtype) { case TStreamerInfo::kBool: sequence->AddAction( ConvertBasicType::Action, conf ); break; case TStreamerInfo::kChar: sequence->AddAction( ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kShort: sequence->AddAction( ConvertBasicType::Action, conf ); break; + case TStreamerInfo::kShort: sequence->AddAction( ConvertBasicType::Action, conf ); break; case TStreamerInfo::kInt: sequence->AddAction( ConvertBasicType::Action, conf ); break; case TStreamerInfo::kLong: sequence->AddAction( ConvertBasicType::Action,conf ); break; case TStreamerInfo::kLong64: sequence->AddAction( ConvertBasicType::Action, conf ); break; @@ -4531,7 +4481,7 @@ static void AddReadConvertAction(TStreamerInfoActions::TActionSequence *sequence case TStreamerInfo::kUShort: sequence->AddAction( ConvertBasicType::Action, conf ); break; case TStreamerInfo::kUInt: sequence->AddAction( ConvertBasicType::Action, conf ); break; case TStreamerInfo::kULong: sequence->AddAction( ConvertBasicType::Action, conf ); break; - case TStreamerInfo::kULong64: sequence->AddAction( ConvertBasicType::Action,conf ); break; + case TStreamerInfo::kULong64: sequence->AddAction( ConvertBasicType::Action,conf ); break; case TStreamerInfo::kBits: sequence->AddAction( ConvertBasicType::Action, conf ); break; } } @@ -4544,7 +4494,7 @@ static void AddWriteConvertAction(TStreamerInfoActions::TActionSequence *sequenc switch (newtype) { case TStreamerInfo::kBool: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; case TStreamerInfo::kChar: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kShort: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; + case TStreamerInfo::kShort: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; case TStreamerInfo::kInt: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; case TStreamerInfo::kLong: sequence->AddAction( WriteConvertBasicType::Action,conf ); break; case TStreamerInfo::kLong64: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; @@ -4556,7 +4506,7 @@ static void AddWriteConvertAction(TStreamerInfoActions::TActionSequence *sequenc case TStreamerInfo::kUShort: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; case TStreamerInfo::kUInt: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; case TStreamerInfo::kULong: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; - case TStreamerInfo::kULong64: sequence->AddAction( WriteConvertBasicType::Action,conf ); break; + case TStreamerInfo::kULong64: sequence->AddAction( WriteConvertBasicType::Action,conf ); break; case TStreamerInfo::kBits: sequence->AddAction( WriteConvertBasicType::Action, conf ); break; } } @@ -5105,7 +5055,7 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS break; } - case TStreamerInfo::kTNamed: writeSequence->AddAction( WriteTNamed, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; + case TStreamerInfo::kTNamed: writeSequence->AddAction( WriteTNamed, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the // Streamer alltogether. case TStreamerInfo::kTObject: writeSequence->AddAction( WriteTObject, new TConfiguration(this, i, compinfo, compinfo->fOffset) ); break; From c9d3c0780ebcc5c14c350f247b9600aba086e65e Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 20 Nov 2024 21:05:18 -0600 Subject: [PATCH 43/46] io actions: add ability to write zero for missing field --- io/io/src/TStreamerInfoActions.cxx | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 08c6a411895a0..7b74b288ccb22 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -371,6 +371,13 @@ namespace TStreamerInfoActions return 0; } + template + static INLINE_TEMPLATE_ARGS Int_t WriteBasicZero(TBuffer &buf, void *, const TConfiguration *) + { + buf << T{0}; + return 0; + } + template INLINE_TEMPLATE_ARGS Int_t WriteBasicType(TBuffer &buf, void *addr, const TConfiguration *config) { @@ -4056,6 +4063,33 @@ GetCollectionWriteAction(TVirtualStreamerInfo *info, TLoopConfiguration *loopCon case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteBasicType,new TConfiguration(info,i,compinfo,offset) ); // the simple type missing are kBits and kCounter. + // Handling of the error case where we are asked to write a missing data member. + case TStreamerInfo::kBool + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kChar + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kShort + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kInt + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kLong + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kLong64 + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kFloat + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kDouble + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kUChar + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kUShort + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kUInt + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kULong + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); + case TStreamerInfo::kULong64 + TStreamerInfo::kSkip: + return TConfiguredAction( Looper::template LoopOverCollection>, new TConfiguration(info,i,compinfo,offset) ); // Conversions. case TStreamerInfo::kConv + TStreamerInfo::kBool: @@ -5470,6 +5504,9 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr // "Ignoring request to write the missing data member %s in %s version %d checksum 0x%x", // element->GetName(), info.GetName(), info.GetClassVersion(), info.GetCheckSum()); continue; + // + // Instead of skipping the field we could write a zero there with: + // onfileType += TVirtualStreamerInfo::kSkip; } } From 138bc656feb91d6e9eeb6bbe03ef2c34c13692b3 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 21 Nov 2024 12:00:57 -0600 Subject: [PATCH 44/46] io: Swith ReadBuffer's kSTL and kSTp to call actions sequence --- io/io/src/TStreamerInfoReadBuffer.cxx | 49 +++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/io/io/src/TStreamerInfoReadBuffer.cxx b/io/io/src/TStreamerInfoReadBuffer.cxx index 7113f84f74815..f5d42d34d8e35 100644 --- a/io/io/src/TStreamerInfoReadBuffer.cxx +++ b/io/io/src/TStreamerInfoReadBuffer.cxx @@ -1183,7 +1183,29 @@ Int_t TStreamerInfo::ReadBuffer(TBuffer &b, const T &arr, Int_t nobjects; b >> nobjects; env = newProxy->Allocate(nobjects,true); - subinfo->ReadBufferSTL(b,newProxy,nobjects,/* offset */ 0, vers>=7 ); + if (!nobjects && (vers>=7)) { + // Do nothing but in version 6 of TStreamerInfo and below, + // we were calling ReadBuffer for empty collection. + } else { + TStreamerInfoActions::TActionSequence *actions = nullptr; + if (newProxy != oldProxy) { + actions = newProxy->GetConversionReadMemberWiseActions( oldProxy->GetValueClass(), vClVersion ); + } else { + actions = oldProxy->GetReadMemberWiseActions( vClVersion ); + } + char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + void *begin = &(startbuf[0]); + void *end = &(endbuf[0]); + newProxy->GetFunctionCreateIterators(/* read = */ kTRUE)(env, &begin, &end, newProxy); + // We can not get here with a split vector of pointer, so we can indeed assume + // that actions->fConfiguration != null. + b.ApplySequence(*actions, begin, end); + if (begin != &(startbuf[0])) { + // assert(end != endbuf); + newProxy->GetFunctionDeleteTwoIterators()(begin,end); + } + } newProxy->Commit(env); } } @@ -1271,7 +1293,30 @@ Int_t TStreamerInfo::ReadBuffer(TBuffer &b, const T &arr, Int_t nobjects; b >> nobjects; void* env = newProxy->Allocate(nobjects,true); - subinfo->ReadBufferSTL(b,newProxy,nobjects,/* offset */ 0, vers >= 7); + if (!nobjects && (vers>=7)) { + // Do nothing but in version 6 of TStreamerInfo and below, + // we were calling ReadBuffer for empty collection. + } else { + TStreamerInfoActions::TActionSequence *actions = nullptr; + if (newProxy != oldProxy) { + actions = newProxy->GetConversionReadMemberWiseActions( oldProxy->GetValueClass(), vClVersion ); + } else { + actions = oldProxy->GetReadMemberWiseActions( vClVersion ); + } + + char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize]; + void *begin_iter = &(startbuf[0]); + void *end_iter = &(endbuf[0]); + newProxy->GetFunctionCreateIterators(/* read = */ kTRUE)(env, &begin_iter, &end_iter, newProxy); + // We can not get here with a split vector of pointer, so we can indeed assume + // that actions->fConfiguration != null. + b.ApplySequence(*actions, begin_iter, end_iter); + if (begin_iter != &(startbuf[0])) { + // assert(end != endbuf); + newProxy->GetFunctionDeleteTwoIterators()(begin_iter,end_iter); + } + } newProxy->Commit(env); } } From 0b5f8b55e28cce33b9861f092d34de7acd47b876 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 21 Nov 2024 12:19:34 -0600 Subject: [PATCH 45/46] io actions: Simplify Read/Write kSTLp for text buffer --- io/io/src/TStreamerInfoActions.cxx | 164 +++-------------------------- 1 file changed, 17 insertions(+), 147 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 7b74b288ccb22..e7983f38521b3 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -470,163 +470,33 @@ namespace TStreamerInfoActions buf.WriteDouble32(addr, const_cast(elem)); } - /** Direct copy of code from TStreamerInfo::WriteBufferAux, - * potentially can be used later for non-text streaming */ - template - INLINE_TEMPLATE_ARGS Int_t WriteSTLp(TBuffer &buf, void *addr, const TConfiguration *config) + INLINE_TEMPLATE_ARGS Int_t TextWriteSTLp(TBuffer &buf, void *addr, const TConfiguration *config) { - TClass *cl = config->fCompInfo->fClass; + TClass *cl = config->fCompInfo->fClass; TMemberStreamer *pstreamer = config->fCompInfo->fStreamer; - TVirtualCollectionProxy *proxy = cl->GetCollectionProxy(); - TClass* vClass = proxy ? proxy->GetValueClass() : 0; - UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing - UInt_t ioffset = eoffset + config->fOffset; + UInt_t ioffset = config->fOffset; - if (!buf.TestBit(TBuffer::kCannotHandleMemberWiseStreaming) - && proxy && vClass - && config->fInfo->GetStreamMemberWise() - && cl->CanSplit() - && !(strspn(config->fCompInfo->fElem->GetTitle(),"||") == 2) - && !(vClass->HasCustomStreamerMember()) ) { - // Let's save the collection member-wise. - - UInt_t pos = buf.WriteVersionMemberWise(config->fInfo->IsA(),kTRUE); - buf.WriteVersion( vClass, kFALSE ); - - // TODO: subinfo used for WriteBufferSTL call, which is private for the moment - //TStreamerInfo *subinfo = (TStreamerInfo*)vClass->GetStreamerInfo(); - - //for (int k = 0; k < narr; ++k) { - char **contp = (char **)((char *)addr + ioffset); - for(int j=0;jfCompInfo->fLength;++j) { - char *cont = contp[j]; - TVirtualCollectionProxy::TPushPop helper( proxy, cont ); - Int_t nobjects = cont ? proxy->Size() : 0; - buf << nobjects; - - // TODO: method is private, should be made accesible from here - // subinfo->WriteBufferSTL(buf,proxy,nobjects); - } - //} - buf.SetByteCount(pos,kTRUE); - return 0; - } UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); - if (kIsTextT) { - // use same method which is used in kSTL - buf.WriteFastArray((void **)((char *)addr + ioffset), cl, config->fCompInfo->fLength, kFALSE, pstreamer); - } else if (pstreamer == nullptr) { - // for (int k = 0; k < narr; ++k) { - char **contp = (char **)((char *)addr + ioffset); - for (int j = 0; j < config->fCompInfo->fLength; ++j) { - char *cont = contp[j]; - cl->Streamer(cont, buf); - } - // } - } else { - // for (int k = 0; k < narr; ++k) { - (*pstreamer)(buf, (char *)addr + ioffset, config->fCompInfo->fLength); - //} - } + + // use same method which is used in kSTL + buf.WriteFastArray((void **)((char *)addr + ioffset), cl, config->fCompInfo->fLength, kFALSE, pstreamer); + buf.SetByteCount(pos, kTRUE); return 0; } - - /** Direct copy of code from TStreamerInfo::WriteBufferAux, - * potentially can be used later for non-text streaming */ - template - INLINE_TEMPLATE_ARGS Int_t ReadSTLp(TBuffer &buf, void *addr, const TConfiguration *config) + INLINE_TEMPLATE_ARGS Int_t TextReadSTLp(TBuffer &buf, void *addr, const TConfiguration *config) { - TClass *cle = config->fCompInfo->fClass; - TStreamerElement * aElement = (TStreamerElement*) config->fCompInfo->fElem; + TClass *cle = config->fCompInfo->fClass; TMemberStreamer *pstreamer = config->fCompInfo->fStreamer; - //TVirtualCollectionProxy *proxy = cl->GetCollectionProxy(); - //TClass* vClass = proxy ? proxy->GetValueClass() : 0; - - UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing - UInt_t ioffset = eoffset + config->fOffset; - - - UInt_t start,count; - Version_t vers = buf.ReadVersion(&start, &count, cle); - - if (!kIsTextT && (vers & TBufferFile::kStreamedMemberWise) ) { - // Collection was saved member-wise - - vers &= ~( TBufferFile::kStreamedMemberWise ); - - TClass *newClass = aElement->GetNewClass(); - TClass *oldClass = aElement->GetClassPointer(); - if( vers < 9 && newClass && newClass!=oldClass ) { - Error( "ReadBuffer", "Unfortunately, version %d of TStreamerInfo (used in %s) did not record enough information to convert a %s%s into a %s.", - vers, buf.GetParent() ? buf.GetParent()->GetName() : "memory/socket", oldClass ? oldClass->GetName() : aElement->GetTypeName(), oldClass ? "" : " (could not find the corresponding TClass)", newClass->GetName() ); - return 0; - } - - Version_t vClVersion = 0; // For vers less than 9, we have to use the current version. - if( vers >= 9 ) { - vClVersion = buf.ReadVersionForMemberWise( cle->GetCollectionProxy()->GetValueClass() ); - } - - TVirtualCollectionProxy *newProxy = (newClass ? newClass->GetCollectionProxy() : nullptr); - TVirtualCollectionProxy *oldProxy = (oldClass ? oldClass->GetCollectionProxy() : nullptr); - TStreamerInfo *subinfo = nullptr; - - if( newProxy ) { - // coverity[dereference] oldProxy->GetValueClass() can not be null since this was streamed memberwise. - subinfo = (TStreamerInfo*)newProxy->GetValueClass()->GetConversionStreamerInfo( oldProxy->GetValueClass(), vClVersion ); - } else if ( oldProxy ) { - subinfo = (TStreamerInfo*)oldProxy->GetValueClass()->GetStreamerInfo( vClVersion ); - newProxy = oldProxy; - } - if (subinfo) { - // DOLOOP { - void* env; - void **contp = (void**)((char *) addr + ioffset); - for(int j=0;jfCompInfo->fLength;j++) { - void *cont = contp[j]; - if (cont==nullptr) { - contp[j] = cle->New(); - cont = contp[j]; - } - TVirtualCollectionProxy::TPushPop helper( newProxy, cont ); - Int_t nobjects; - buf >> nobjects; - env = newProxy->Allocate(nobjects,true); - subinfo->ReadBufferSTL(buf,newProxy,nobjects,/* offset */ 0, vers>=7 ); - newProxy->Commit(env); - } - // } // DOLOOP - } - buf.CheckByteCount(start,count,aElement->GetFullName()); - return 0; - } + TStreamerElement *aElement = (TStreamerElement *)config->fCompInfo->fElem; + UInt_t ioffset = config->fOffset; + UInt_t start, count; + /* Version_t vers = */ buf.ReadVersion(&start, &count, cle); - if (kIsTextT) { - // use same method which is used in kSTL - buf.ReadFastArray((void **)((char *)addr + ioffset), cle, config->fCompInfo->fLength, kFALSE, pstreamer); - } else if (pstreamer == nullptr) { - // DOLOOP { - void **contp = (void **)((char *)addr + ioffset); - for (int j = 0; j < config->fCompInfo->fLength; j++) { - void *cont = contp[j]; - if (cont == nullptr) { - // int R__n; - // b >> R__n; - // b.SetOffset(b.GetOffset()-4); // rewind to the start of the int - // if (R__n) continue; - contp[j] = cle->New(); - cont = contp[j]; - } - cle->Streamer(cont, buf); - } - // } - } else { - (*pstreamer)(buf, (char *)addr + ioffset, config->fCompInfo->fLength); - } + // use same method which is used in kSTL + buf.ReadFastArray((void **)((char *)addr + ioffset), cle, config->fCompInfo->fLength, kFALSE, pstreamer); buf.CheckByteCount(start, count, aElement->GetFullName()); - return 0; } @@ -4864,7 +4734,7 @@ void TStreamerInfo::AddReadTextAction(TStreamerInfoActions::TActionSequence *rea case TStreamerInfo::kSTLp: // Pointer to container with no virtual table (stl) and no comment case TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL: // array of pointers to container with no virtual table (stl) and no comment - readSequence->AddAction(ReadSTLp, new TConfiguration(this, i, compinfo, compinfo->fOffset)); + readSequence->AddAction(TextReadSTLp, new TConfiguration(this, i, compinfo, compinfo->fOffset)); break; case TStreamerInfo::kStreamLoop: @@ -5250,7 +5120,7 @@ void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *wr case TStreamerInfo::kSTLp: // Pointer to container with no virtual table (stl) and no comment case TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL: // array of pointers to container with no virtual table (stl) and no comment - writeSequence->AddAction(WriteSTLp, new TConfiguration(this, i, compinfo, compinfo->fOffset)); + writeSequence->AddAction(TextWriteSTLp, new TConfiguration(this, i, compinfo, compinfo->fOffset)); break; case TStreamerInfo::kStreamLoop: From 17097bc78752e28fb9c5f886d7ebd2f6e5c2620b Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 1 Oct 2024 16:03:30 -0500 Subject: [PATCH 46/46] io actions: Remove redundant code in TextWriting. --- io/io/src/TStreamerInfoActions.cxx | 39 +++++++++++------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index e7983f38521b3..8b6e556716073 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -5064,43 +5064,32 @@ void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *wr switch (compinfo->fType) { // write basic types case TStreamerInfo::kBool: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kChar: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kShort: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kInt: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kLong: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kLong64: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kFloat: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kDouble: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kUChar: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kUShort: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kUInt: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kULong: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); - break; case TStreamerInfo::kULong64: - writeSequence->AddAction(WriteBasicType, new TConfiguration(this, i, compinfo, compinfo->fOffset)); + case TStreamerInfo::kFloat16: + case TStreamerInfo::kDouble32: + case TStreamerInfo::kConv + TStreamerInfo::kChar: + case TStreamerInfo::kConv + TStreamerInfo::kShort: + case TStreamerInfo::kConv + TStreamerInfo::kInt: + case TStreamerInfo::kConv + TStreamerInfo::kLong: + case TStreamerInfo::kConv + TStreamerInfo::kLong64: + case TStreamerInfo::kConv + TStreamerInfo::kUChar: + case TStreamerInfo::kConv + TStreamerInfo::kUShort: + case TStreamerInfo::kConv + TStreamerInfo::kUInt: + case TStreamerInfo::kConv + TStreamerInfo::kULong: + case TStreamerInfo::kConv + TStreamerInfo::kULong64: + // Actually same action for this level + AddWriteAction(writeSequence, i, compinfo); break; case TStreamerInfo::kTObject: