diff --git a/core/meta/inc/TClass.h b/core/meta/inc/TClass.h index 99d32417ebf1e..222bbb6595752 100644 --- a/core/meta/inc/TClass.h +++ b/core/meta/inc/TClass.h @@ -84,6 +84,7 @@ friend void ROOT::ResetClassVersion(TClass*, const char*, Short_t); friend class ROOT::TGenericClassInfo; friend class TProtoClass; friend class ROOT::Internal::TCheckHashRecursiveRemoveConsistency; +friend class TStreamerInfo; public: // TClass status bits @@ -222,7 +223,13 @@ friend class ROOT::Internal::TCheckHashRecursiveRemoveConsistency; ClassConvStreamerFunc_t fConvStreamerFunc; //Wrapper around this class custom conversion Streamer member function. Int_t fSizeof; //Sizeof the class. - Int_t fCanSplit; //!Indicates whether this class can be split or not. + // Bit field + Int_t fCanSplit : 3; //!Indicates whether this class can be split or not. Values are -1, 0, 1, 2 + + //! Indicates whether this class represent a pair and was not created from a dictionary nor interpreter info but has + //! compiler compatible offset and size (and all the info is in the StreamerInfo per se) + Bool_t fIsSyntheticPair : 1; //! + mutable std::atomic fProperty; //!Property See TClass::Property() for details mutable Long_t fClassProperty; //!C++ Property of the class (is abstract, has virtual table, etc.) @@ -367,7 +374,7 @@ friend class ROOT::Internal::TCheckHashRecursiveRemoveConsistency; TVirtualStreamerInfo *FindConversionStreamerInfo( const char* onfile_classname, UInt_t checksum ) const; TVirtualStreamerInfo *GetConversionStreamerInfo( const TClass* onfile_cl, Int_t version ) const; TVirtualStreamerInfo *FindConversionStreamerInfo( const TClass* onfile_cl, UInt_t checksum ) const; - Bool_t HasDataMemberInfo() const { return fHasRootPcmInfo || HasInterpreterInfo(); } + Bool_t HasDataMemberInfo() const { return fIsSyntheticPair || fHasRootPcmInfo || HasInterpreterInfo(); } Bool_t HasDefaultConstructor(Bool_t testio = kFALSE) const; Bool_t HasInterpreterInfoInMemory() const { return 0 != fClassInfo; } Bool_t HasInterpreterInfo() const { return fCanLoadClassInfo || fClassInfo; } @@ -479,6 +486,7 @@ friend class ROOT::Internal::TCheckHashRecursiveRemoveConsistency; Bool_t IsLoaded() const; Bool_t IsForeign() const; Bool_t IsStartingWithTObject() const; + Bool_t IsSyntheticPair() const { return fIsSyntheticPair; } Bool_t IsVersioned() const { return !( GetClassVersion()<=1 && IsForeign() ); } Bool_t IsTObject() const; static TClass *LoadClass(const char *requestedname, Bool_t silent); @@ -535,7 +543,8 @@ friend class ROOT::Internal::TCheckHashRecursiveRemoveConsistency; static void RemoveClass(TClass *cl); static void RemoveClassDeclId(TDictionary::DeclId_t id); static TClass *GetClass(const char *name, Bool_t load = kTRUE, Bool_t silent = kFALSE); - static TClass *GetClass(const std::type_info &typeinfo, Bool_t load = kTRUE, Bool_t silent = kFALSE); + static TClass *GetClass(const char *name, Bool_t load, Bool_t silent, size_t hint_pair_offset, size_t hint_pair_size); + static TClass *GetClass(const std::type_info &typeinfo, Bool_t load = kTRUE, Bool_t silent = kFALSE, size_t hint_pair_offset = 0, size_t hint_pair_size = 0); static TClass *GetClass(ClassInfo_t *info, Bool_t load = kTRUE, Bool_t silent = kFALSE); template static TClass *GetClass(Bool_t load = kTRUE, Bool_t silent = kFALSE); @@ -580,10 +589,26 @@ TClass *GetClassHelper(Bool_t, Bool_t, std::true_type) return T::Class(); } +template +struct TClassGetClassHelper { + static TClass *GetClass(Bool_t load, Bool_t silent) { + return TClass::GetClass(typeid(T), load, silent); + } +}; + +template +struct TClassGetClassHelper > { + static TClass *GetClass(Bool_t load, Bool_t silent) { + std::pair *p = nullptr; + size_t hint_offset = ((char*)&(p->second)) - (char*)p; + return TClass::GetClass(typeid(std::pair), load, silent, hint_offset, sizeof(std::pair)); + } +}; + template TClass *GetClassHelper(Bool_t load, Bool_t silent, std::false_type) { - return TClass::GetClass(typeid(T), load, silent); + return TClassGetClassHelper::GetClass(load, silent); } } // namespace Internal diff --git a/core/meta/inc/TVirtualStreamerInfo.h b/core/meta/inc/TVirtualStreamerInfo.h index 82113e243cb01..a7e04994ba662 100644 --- a/core/meta/inc/TVirtualStreamerInfo.h +++ b/core/meta/inc/TVirtualStreamerInfo.h @@ -185,8 +185,8 @@ class TVirtualStreamerInfo : public TNamed { // provokes the creation of the corresponding TClass. This relies on the dictionary for // std::pair to already exist (or the interpreter information being available) // as it is used as a template. - virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &pairclassname, bool silent) = 0; - virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent) = 0; + virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &pairclassname, bool silent, size_t hint_pair_offset, size_t hint_pair_size) = 0; + virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent, size_t hint_pair_offset, size_t hint_pair_size) = 0; virtual TVirtualCollectionProxy *GenEmulatedProxy(const char* class_name, Bool_t silent) = 0; virtual TClassStreamer *GenEmulatedClassStreamer(const char* class_name, Bool_t silent) = 0; diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index 81da4bafbbc02..2becd41a6ac6d 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -1053,7 +1053,7 @@ TClass::TClass() : fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kNoInfo), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1091,7 +1091,7 @@ TClass::TClass(const char *name, Bool_t silent) : fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kNoInfo), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1138,7 +1138,7 @@ TClass::TClass(const char *name, Version_t cversion, Bool_t silent) : fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kNoInfo), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1165,7 +1165,7 @@ TClass::TClass(const char *name, Version_t cversion, EState theState, Bool_t sil fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(theState), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1209,7 +1209,7 @@ TClass::TClass(ClassInfo_t *classInfo, Version_t cversion, fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kNoInfo), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1259,7 +1259,7 @@ TClass::TClass(const char *name, Version_t cversion, fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kNoInfo), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1290,7 +1290,7 @@ TClass::TClass(const char *name, Version_t cversion, fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kHasTClassInit), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -2927,6 +2927,11 @@ TVirtualIsAProxy* TClass::GetIsAProxy() const /// Returns 0 in case class is not found. TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent) +{ + return TClass::GetClass(name, load, silent, 0, 0); +} + +TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent, size_t hint_pair_offset, size_t hint_pair_size) { if (!name || !name[0]) return 0; @@ -3086,12 +3091,11 @@ TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent) // TClass if we have one. if (cl) return cl; - if (ispair) { - auto pairinfo = TVirtualStreamerInfo::Factory()->GenerateInfoForPair(normalizedName, silent); + if (ispair && hint_pair_offset && hint_pair_size) { + auto pairinfo = TVirtualStreamerInfo::Factory()->GenerateInfoForPair(normalizedName, silent, hint_pair_offset, hint_pair_size); //return pairinfo ? pairinfo->GetClass() : nullptr; if (pairinfo) return pairinfo->GetClass(); - } else if (TClassEdit::IsSTLCont( normalizedName.c_str() )) { return gInterpreter->GenerateTClass(normalizedName.c_str(), kTRUE, silent); @@ -3174,7 +3178,7 @@ TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent) //////////////////////////////////////////////////////////////////////////////// /// Return pointer to class with name. -TClass *TClass::GetClass(const std::type_info& typeinfo, Bool_t load, Bool_t /* silent */) +TClass *TClass::GetClass(const std::type_info& typeinfo, Bool_t load, Bool_t /* silent */, size_t hint_pair_offset, size_t hint_pair_size) { if (!gROOT->GetListOfClasses()) return 0; @@ -3239,12 +3243,23 @@ TClass *TClass::GetClass(const std::type_info& typeinfo, Bool_t load, Bool_t /* if (autoload_old && gInterpreter->AutoLoad(typeinfo,kTRUE)) { // Disable autoload to avoid potential infinite recursion TInterpreter::SuspendAutoLoadingRAII autoloadOff(gInterpreter); - cl = GetClass(typeinfo, load); + cl = GetClass(typeinfo, load, hint_pair_offset, hint_pair_size); if (cl) { return cl; } } + if (hint_pair_offset) { + int err = 0; + char* demangled_name = TClassEdit::DemangleTypeIdName(typeinfo, err); + if (!err) { + cl = TClass::GetClass(demangled_name, load, kTRUE, hint_pair_offset, hint_pair_size); + free(demangled_name); + if (cl) + return cl; + } + } + // last attempt. Look in the interpreter list of all (compiled+interpreted) // classes cl = gInterpreter->GetClass(typeinfo, load); diff --git a/core/meta/src/TProtoClass.cxx b/core/meta/src/TProtoClass.cxx index fce40ed1e5ee8..5fb2dc8356760 100644 --- a/core/meta/src/TProtoClass.cxx +++ b/core/meta/src/TProtoClass.cxx @@ -312,7 +312,9 @@ Bool_t TProtoClass::FillTClass(TClass* cl) { int prevLevel = 0; bool first = true; if (fPRealData.size() > 0) { + size_t element_next_idx = 0; for (auto element: fPRealData) { + ++element_next_idx; //if (element->IsA() == TObjString::Class()) { if (element.IsAClass() ) { // We now check for the TClass entry, w/o loading. Indeed we did that above. @@ -322,16 +324,34 @@ Bool_t TProtoClass::FillTClass(TClass* cl) { // will be issued. TInterpreter::SuspendAutoParsing autoParseRaii(gInterpreter); + const char *classname = GetClassName(element.fClassIndex); + // Disable autoparsing which might be triggered by the use of ResolvedTypedef // and the fallback new TClass() below. - currentRDClass = TClass::GetClass(GetClassName(element.fClassIndex), false /* Load */ ); + currentRDClass = TClass::GetClass(classname, false /* Load */ ); //printf("element is a class - name %s - index %d %s \n ",currentRDClass->GetName(), element.fClassIndex, GetClassName(element.fClassIndex) ); if (!currentRDClass && !element.TestFlag(TProtoRealData::kIsTransient)) { - if (gDebug>1) - Info("FillTClass()", - "Cannot find TClass for %s; Creating an empty one in the kForwardDeclared state.", - GetClassName(element.fClassIndex)); - currentRDClass = new TClass(GetClassName(element.fClassIndex),1,TClass::kForwardDeclared, true /*silent*/); + + if (TClassEdit::IsStdPair(classname) && element.fDMIndex == 0 && fPRealData.size() > element_next_idx) { + size_t hint_offset = fPRealData[element_next_idx].fOffset - element.fOffset; + size_t hint_size = 0; + // Now find the size. + size_t end = element_next_idx + 1; + while (end < fPRealData.size() && fPRealData[end].fLevel > element.fLevel) + ++end; + if (end < fPRealData.size()) { + hint_size = fPRealData[end].fOffset - element.fOffset; + } else { + hint_size = fSizeof - element.fOffset; + } + currentRDClass = TClass::GetClass(classname, true, false, hint_offset, hint_size); + } + if (!currentRDClass) { + if (gDebug > 1) + Info("FillTClass()", + "Cannot find TClass for %s; Creating an empty one in the kForwardDeclared state.", classname); + currentRDClass = new TClass(classname, 1, TClass::kForwardDeclared, true /*silent*/); + } } } //else { @@ -432,10 +452,10 @@ TRealData* TProtoClass::TProtoRealData::CreateRealData(TClass* dmClass, //TDataMember* dm = (TDataMember*)dmClass->GetListOfDataMembers()->FindObject(fName); TDataMember* dm = TProtoClass::FindDataMember(dmClass, fDMIndex); - if (!dm && dmClass->GetState()!=TClass::kForwardDeclared) { + if (!dm && dmClass->GetState()!=TClass::kForwardDeclared && !dmClass->fIsSyntheticPair) { ::Error("CreateRealData", - "Cannot find data member # %d of class %s for parent %s!", fDMIndex, dmClass->GetName(), - parent->GetName()); + "Cannot find data member # %d of class %s for parent %s!", fDMIndex, dmClass->GetName(), + parent->GetName()); return nullptr; } @@ -444,6 +464,9 @@ TRealData* TProtoClass::TProtoRealData::CreateRealData(TClass* dmClass, TString realMemberName; // keep an empty name if data member is not found if (dm) realMemberName = dm->GetName(); + else if (dmClass->fIsSyntheticPair) { + realMemberName = (fDMIndex == 0) ? "first" : "second"; + } if (TestFlag(kIsPointer) ) realMemberName = TString("*")+realMemberName; else if (dm){ @@ -530,7 +553,7 @@ TDataMember * TProtoClass::FindDataMember(TClass * cl, Int_t index) return dm; i++; } - if (cl->GetState()!=TClass::kForwardDeclared) + if (cl->GetState()!=TClass::kForwardDeclared && !cl->fIsSyntheticPair) ::Error("TProtoClass::FindDataMember","data member with index %d is not found in class %s",index,cl->GetName()); return nullptr; } diff --git a/io/io/inc/TStreamerInfo.h b/io/io/inc/TStreamerInfo.h index a9fccfde83ae8..fc76e461ee50e 100644 --- a/io/io/inc/TStreamerInfo.h +++ b/io/io/inc/TStreamerInfo.h @@ -283,8 +283,8 @@ class TStreamerInfo : public TVirtualStreamerInfo { // provokes the creation of the corresponding TClass. This relies on the dictionary for // std::pair to already exist (or the interpreter information being available) // as it is used as a template. - virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &pairclassname, bool silent); - virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent); + virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &pairclassname, bool silent, size_t hint_pair_offset, size_t hint_pair_size); + virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent, size_t hint_pair_offset, size_t hint_pair_size); virtual TVirtualCollectionProxy *GenEmulatedProxy(const char* class_name, Bool_t silent); virtual TClassStreamer *GenEmulatedClassStreamer(const char* class_name, Bool_t silent); diff --git a/io/io/src/TEmulatedCollectionProxy.cxx b/io/io/src/TEmulatedCollectionProxy.cxx index add1a99d9cecd..bd79155363aa8 100644 --- a/io/io/src/TEmulatedCollectionProxy.cxx +++ b/io/io/src/TEmulatedCollectionProxy.cxx @@ -183,7 +183,7 @@ TGenCollectionProxy *TEmulatedCollectionProxy::InitializeEx(Bool_t silent) if (0==TClass::GetClass(nam.c_str(), kTRUE, silent)) { // We need to emulate the pair - TVirtualStreamerInfo::Factory()->GenerateInfoForPair(inside[1],inside[2], silent); + TVirtualStreamerInfo::Factory()->GenerateInfoForPair(inside[1],inside[2], silent, 0, 0); } } fValue = new Value(nam,silent); diff --git a/io/io/src/TFile.cxx b/io/io/src/TFile.cxx index 6d41d5cdad26d..d15cd28be6e6c 100644 --- a/io/io/src/TFile.cxx +++ b/io/io/src/TFile.cxx @@ -3559,7 +3559,7 @@ void TFile::ReadStreamerInfo() Int_t asize = fClassIndex->GetSize(); if (uid >= asize && uid <100000) fClassIndex->Set(2*asize); if (uid >= 0 && uid < fClassIndex->GetSize()) fClassIndex->fArray[uid] = 1; - else if (!isstl) { + else if (!isstl && !info->GetClass()->IsSyntheticPair()) { printf("ReadStreamerInfo, class:%s, illegal uid=%d\n",info->GetName(),uid); } if (gDebug > 0) printf(" -class: %s version: %d info read at slot %d\n",info->GetName(), info->GetClassVersion(),uid); @@ -3675,7 +3675,6 @@ void TFile::WriteStreamerInfo() listOfRules.SetName("listOfRules"); std::set classSet; - while ((info = (TStreamerInfo*)next())) { Int_t uid = info->GetNumber(); if (fClassIndex->fArray[uid]) { diff --git a/io/io/src/TGenCollectionProxy.cxx b/io/io/src/TGenCollectionProxy.cxx index 3b4e02ba6a43d..bab4ddcf78e81 100644 --- a/io/io/src/TGenCollectionProxy.cxx +++ b/io/io/src/TGenCollectionProxy.cxx @@ -883,9 +883,29 @@ TGenCollectionProxy *TGenCollectionProxy::InitializeEx(Bool_t silent) { TInterpreter::SuspendAutoParsing autoParseRaii(gCling); - if (0==TClass::GetClass(nam.c_str())) { + if (0==TClass::GetClass(nam.c_str(), true, false, fValOffset, fValDiff)) { // We need to emulate the pair - TVirtualStreamerInfo::Factory()->GenerateInfoForPair(inside[1],inside[2], silent); + TVirtualStreamerInfo::Factory()->GenerateInfoForPair(inside[1], inside[2], silent, fValOffset, fValDiff); + } else { + TClass *paircl = TClass::GetClass(nam.c_str()); + if (paircl->GetClassSize() != fValDiff) { + if (paircl->GetState() >= TClass::kInterpreted) + Fatal("InitializeEx", + "The %s for %s reports a class size that is inconsistent with the one registered " + "through the CollectionProxy for %s: %d vs %d\n", + paircl->IsLoaded() ? "dictionary" : "interpreter information for", nam.c_str(), + cl->GetName(), (int)paircl->GetClassSize(), (int)fValDiff); + else { + gROOT->GetListOfClasses()->Remove(paircl); + TClass *newpaircl = TClass::GetClass(nam.c_str(), true, false, fValOffset, fValDiff); + if (newpaircl == paircl || newpaircl->GetClassSize() != fValDiff) + Fatal("InitializeEx", + "The TClass creation for %s did not get the right size: %d instead of%d\n", + nam.c_str(), (int)paircl->GetClassSize(), (int)fValDiff); + paircl->ReplaceWith(newpaircl); + delete paircl; + } + } } } newfValue = R__CreateValue(nam, silent); diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index 2648482db2161..d664466d57374 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -212,6 +212,12 @@ TStreamerInfo::TStreamerInfo(TClass *cl) TStreamerInfo::~TStreamerInfo() { + // Note: If a StreamerInfo is loaded from a file and is the same information + // as an existing one, it is assigned the same "unique id" and we need to double + // check before removing it from the global list. + if (fNumber >=0 && gROOT->GetListOfStreamerInfo()->At(fNumber) == this) + gROOT->GetListOfStreamerInfo()->RemoveAt(fNumber); + delete [] fComp; fComp = 0; delete [] fCompFull; fCompFull = 0; delete [] fCompOpt; fCompOpt = 0; @@ -566,8 +572,9 @@ void TStreamerInfo::Build(Bool_t isTransient) element = new TStreamerObjectPointer(dmName, dmTitle, offset, dmFull); } else { element = new TStreamerObjectAnyPointer(dmName, dmTitle, offset, dmFull); - if (!isTransient && !streamer && !clm->GetStreamer() && !clm->IsLoaded()) { - Error("Build", "%s: %s has no streamer or dictionary, data member %s will not be saved", GetName(), dmFull, dmName); + if (!isTransient && !streamer && !clm->GetStreamer() && !clm->IsLoaded() && !clm->fIsSyntheticPair) { + Error("Build", "%s: %s has no streamer or dictionary, data member %s will not be saved", + GetName(), dmFull, dmName); } } } @@ -577,8 +584,9 @@ void TStreamerInfo::Build(Bool_t isTransient) element = new TStreamerString(dmName, dmTitle, offset); } else { element = new TStreamerObjectAny(dmName, dmTitle, offset, dmFull); - if (!isTransient && !streamer && !clm->GetStreamer() && !clm->IsLoaded()) { - Warning("Build", "%s: %s has no streamer or dictionary, data member \"%s\" will not be saved", GetName(), dmFull, dmName); + if (!isTransient && !streamer && !clm->GetStreamer() && !clm->IsLoaded() && !clm->fIsSyntheticPair) { + Warning("Build", "%s: %s has no streamer or dictionary, data member \"%s\" will not be saved", + GetName(), dmFull, dmName); } } } @@ -768,6 +776,13 @@ void TStreamerInfo::BuildCheck(TFile *file /* = 0 */, Bool_t load /* = kTRUE */) return; } } + if (fClass->fIsSyntheticPair) { + // The format never change, no need to import the old StreamerInof + // (which anyway would have issue when being setup due to the lack + // of TDataMember in the TClass. + SetBit(kCanDelete); + return; + } if (0 == strcmp("string",fClass->GetName())) { // We know we do not need any offset check for a string @@ -2413,7 +2428,7 @@ void TStreamerInfo::BuildOld() element->SetOffset(kMissing); } - if (offset != kMissing && fClass->GetState() <= TClass::kEmulated) { + if (offset != kMissing && fClass->GetState() <= TClass::kEmulated && !fClass->fIsSyntheticPair) { // Note the initialization in this case are // delayed until __after__ the schema evolution // section, just in case the info has changed. @@ -3077,6 +3092,13 @@ Bool_t TStreamerInfo::CompareContent(TClass *cl, TVirtualStreamerInfo *info, Boo void TStreamerInfo::ComputeSize() { + if (this == fClass->GetCurrentStreamerInfo()) { + if (fClass->GetState() >= TClass::kInterpreted || fClass->fIsSyntheticPair) { + fSize = fClass->GetClassSize(); + return; + } + } + TStreamerElement *element = (TStreamerElement*)fElements->Last(); //faster and more precise to use last element offset +size //on 64 bit machines, offset may be forced to be a multiple of 8 bytes @@ -5650,7 +5672,7 @@ static TStreamerElement* R__CreateEmulatedElement(const char *dmName, const std: // provoke the creation of the corresponding TClass. This relies on the dictionary for // std::pair to already exist (or the interpreter information being available) // as it is used as a template. -TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent) +TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent, size_t hint_pair_offset, size_t hint_pair_size) { // Generate a TStreamerInfo for a std::pair // This TStreamerInfo is then used as if it was read from a file to generate @@ -5675,6 +5697,8 @@ TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firs delete i; return 0; } + if (hint_pair_offset) + size = hint_pair_offset; TStreamerElement *second = R__CreateEmulatedElement("second", secondname, size, silent); if (second) { i->GetElements()->Add( second ); @@ -5687,11 +5711,22 @@ TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firs gErrorIgnoreLevel = kError; i->BuildCheck(nullptr, kFALSE); // Skipping the loading part (it would leads to infinite recursion on this very routine) gErrorIgnoreLevel = oldlevel; + // In the state emulated, BuildOld would recalculate the offset and undo the offset update. + // Note: we should consider adding a new state just for this (the hints indicates that we are mapping a compiled class but + // then we would have to investigate all use of the state with <= and >= condition to make sure they are still appropriate). + if (hint_pair_size) { + i->GetClass()->SetClassSize(hint_pair_size); + i->GetClass()->fIsSyntheticPair = kTRUE; + } + i->BuildOld(); + + if (hint_pair_size) + i->GetClass()->SetClassSize(hint_pair_size); return i; } -TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &pairclassname, bool silent) +TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &pairclassname, bool silent, size_t hint_pair_offset, size_t hint_pair_size) { const static int pairlen = strlen("pair<"); if (pairclassname.compare(0, pairlen, "pair<") != 0) { @@ -5709,5 +5744,5 @@ TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &pair return nullptr; } - return GenerateInfoForPair(inside[1], inside[2], silent); + return GenerateInfoForPair(inside[1], inside[2], silent, hint_pair_offset, hint_pair_size); }